This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2C communication between MSP and AD5933

Hello dear all,
I would like to establish an I2C communication between the MSP432 and the AD5933 to read and write at the AD5933 level. The MSP432 being the master and the AD5933 the exclave. I wrote my code which I share with  you but nothing happens. I don't know where the problem is because I don't have an oscilloscope. Can you help me.

#include <msp432p401r.h>
#include <stdint.h>
#include <stdio.h>

#define SLAVE_ADDRESS 0x0D

#define PCMKEY_value 0x695A0000
#define CS_KEY_value 0x0000695A


#define CTRL_1                  0x81       // Registre control 1
uint8_t RXData;

// Delay function
void delay(int n)
{
    int i, j;
    for (j = 0; j < n; j++)
        for (i = 0; i < 1000; i++);
}

void DCO_clock(int clock_speed) {
    CS->KEY = CS_KEY_value;
    switch (clock_speed) {
        case 0: {
            CS->CTL0 = CS_CTL0_DCORSEL_0; // 1.5MHz
            break;
        }
        case 1: {
            CS->CTL0 = CS_CTL0_DCORSEL_1; // 3MHz
            break;
        }
        case 2: {
            CS->CTL0 = CS_CTL0_DCORSEL_2; // 6MHz
            break;
        }
        case 3: {
            CS->CTL0 = CS_CTL0_DCORSEL_3; // 12MHz
            break;
        }
        case 4: {
            CS->CTL0 = CS_CTL0_DCORSEL_4; // 24MHz
            break;
        }
        case 5: {
            PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_1; // LDO_Vcore1 choice
            while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
            PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_5; // DCDC_Vcore1 choice
            while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
            FLCTL->BANK0_RDCTL = FLCTL_BANK0_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank0
            FLCTL->BANK1_RDCTL = FLCTL_BANK1_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank1
            CS->CTL0 = CS_CTL0_DCORSEL_5; // 48MHz
            break;
        }
    }
    CS->KEY = 0;
}

void clock(void) {
    CS->KEY = CS_KEY_value;
    CS->CTL1 = CS_CTL1_SELA_3 + CS_CTL1_SELS_3 + CS_CTL1_SELM_3;
    CS->KEY = 0;
}

void I2C_Init(void)
{
  UCB0CTLW0 |= UCSWRST;                  //reset the l'I2C for modification registers
  P1->SEL0 |= BIT6 + BIT7;    //SDA = P1.6 et SCL = P1.7
  P1->SEL1 &= ~(BIT6 + BIT7);
  P1->REN |= BIT6 | BIT7;  // Activation of internal pull-up resistors
  P1->OUT |= BIT6 | BIT7;  // Configuration of pull-up resistors
  EUSCI_B0->CTLW0 = UCMST + UCMODE_3 + UCSYNC + UCSSEL_2 + UCSWRST; //I2C type communication in master mode + synchro, SMCLK, and maintained reset
  EUSCI_B0->CTLW0 = 30;                         //fSCL = SMCLK/30 = 100kHz
  EUSCI_B0->CTLW0 &= ~UCSWRST;                 //fonctionnement normal
  EUSCI_B0->IE |= UCRXIE | UCNACKIE | UCBCNTIE;

}
/*
 * FUNCTION THAT MANAGES INTERRUPTIONS
 *
 * The interest of this function is to process the different sources of interruptions that can occur during I2C operations, such as:

UCNACKIFG: This flag is set when the I2C module receives a NACK (Not Acknowledge) during a data transmission. In the corrected code, it is used to reset the UCNACKIFG flag, enable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and restart transmission by setting the UCTXSTT bit to 1.

UCRXIFG0: This flag is set when data is successfully received by the I2C module. In the corrected code, it is used to reset the UCRXIFG0 flag, disable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and store received data in the RXData variable.

UCBCNTIFG: This flag is set when the number of bytes expected during an I2C operation is reached. In the corrected code, it is used to reset the UCBCNTIFG flag, enable sleep-on-output mode (SCB_SCR_SLEEPONEXIT), and invert the state of pin P1.0 (P1OUT ^= BIT0).
 */
void EUSCIB0_IRQHandler(void)
{
    if (UCB0IFG & UCNACKIFG)
    {
        UCB0IFG &= ~UCNACKIFG;
        SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
        UCB0CTLW0 |= UCTXSTT;
    }

    if (UCB0IFG & UCRXIFG0)
    {
        UCB0IFG &= ~UCRXIFG0;
        SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
        RXData = UCB0RXBUF;
    }

    if (UCB0IFG & UCBCNTIFG)
    {
        UCB0IFG &= ~UCBCNTIFG;
        SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
        P1OUT ^= BIT0;
    }
}


/*
 * Writing a byte (Write Byte/Command Byte):

1.The master device sends a start condition (START) on SDA.
2.The master sends the 7-bit slave address followed by the write bit (0).
3. The addressed slave device sends an ACK on SDA.
4.The master sends a register address.
5.The slave sends an ACK on SDA.
6.The master sends a data byte.
7.The slave sends an ACK on SDA.
8.The master sends an end condition (STOP) on SDA to terminate the transaction.
 */
// Function to write a byte in an AD5933 register via the I2C interface

void I2C_writeRegister(uint8_t reg, int data)
{
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR;   // Transmission
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // Start signal generation
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));   // Waiting for start signal to be sent
    EUSCI_B0->I2CSA = SLAVE_ADDRESS; // Send AD5933 address
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for start signal to be sent
    EUSCI_B0->TXBUF = reg;    // Send register address
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for register address to be sent
    EUSCI_B0->TXBUF = data; // Sending data
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for data to be sent
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;    // Waiting for data to be sent
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP); // Waiting for the end of the transmission
    // Handwriting verification
    if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
    {
        // Failed to write
        // Handle the error accordingly
        printf("Write failed");
    }
    else
    {
        // The write was successful
        printf("Number %u write operation completed successfully", data);
    }
}

/*
  * Reading a byte (Receive Byte):

1.The master device sends a start condition (START) on SDA.
2.The master sends the 7-bit slave address followed by the read bit (1).
3. The addressed slave device sends an ACK on SDA.
4.The master receives a data byte.
5.The master sends a NO ACK on SDA (the slave must verify that the master has received the data).
6.The master sends an end condition (STOP) on SDA and the transaction ends.
  */


// Function to read a register from the AD5933 via the I2C interface


// Function to write a byte in an AD5933 register via the I2C interface


uint8_t I2C_readRegister(uint8_t reg)
{
    uint8_t AD5933_address = (SLAVE_ADDRESS << 1) | 0x01; // Combination of slave address and read bit

    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR;   // Transmission
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate the start signal
    EUSCI_B0->I2CSA = AD5933_address; // Send the address of the register to write
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));  // Wait for start signal to be sent
    EUSCI_B0->TXBUF = reg; // // Send register address
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for register address to be sent
    EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR;  // Reception
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate a repetition of the start signal
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT); // Wait for the end of the start signal repetition
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;    // Generation of the stop signal
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)); // // Wait for the reception of the data
    // Verification of the reading
    if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
    {
        // Failed to read
        printf("Failed to read register %u", reg);
    }
    else
    {
        // The write was successful
        printf("%u register read operation completed successfully", reg);
    }
    RXData = EUSCI_B0->RXBUF;      // Lecture de la donnée reçue
    return RXData;
}

/**
 * main.c
 */
void main(void)
{
    WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer
    clock();
    DCO_clock(1);
    I2C_Init();
    // Exemple d'écriture et de lecture d'un registre de l'AD5933
    delay(100);                     // Délai de stabilisation de l'AD5933
    I2C_writeRegister(CTRL_1, 2); // Écriture dans le registre de contrôle 1
    uint8_t data = I2C_readRegister(CTRL_1); // Lecture du registre de contrôle 1
    printf("Data read from register: %u\n", data);

}


  • For one thing, you probably need to make your delay variables volatile so they don't get optimised away.

  • >  EUSCI_B0->IE |= UCRXIE | UCNACKIE | UCBCNTIE;

    Your Read/WriteRegister functions do not expect interrupts, so enabling them here will interfere. I recommend you remove this line.

    -----------

    >  EUSCI_B0->I2CSA = SLAVE_ADDRESS; // Send AD5933 address

    This must be done before setting TXSTT. You should move this line up a few lines. (Similarly for ReadRegister.)

    -----------

    >  uint8_t AD5933_address = (SLAVE_ADDRESS << 1) | 0x01; // Combination of slave address and read bit

    The I2CSA register does not include the R/W bit (this is inserted by the EUSCI based on the TR bit). Try instead:

    >  uint8_t AD5933_address = SLAVE_ADDRESS; // Slave address 

  • Good morning,
    I have taken your suggestions into account. I made delay function variables volatile, removed interrupts in I2C_Init() function, Offset line EUSCI_B0->I2CSA=SLAVE_ADDRESS before setting TXSTT and change uint8_t AD5933_address=SLAVE_ADDRESS in the I2C_readRegister() function.
    But I still didn't get an answer. Nothing is displayed

  • I missed this before:

    >  EUSCI_B0->CTLW0 = 30; //fSCL = SMCLK/30 = 100kHz

    This should be

    >  EUSCI_B0->BRW = 30; //fSCL = SMCLK/30 = 100kHz

    ----------------------

    If you pause your program in the debugger, (1) where are you executing? (2) what are the values of UCB0STATW and UCB0IFG?

  • If you have two launchpads, you can use the example code in resource explorer to verify that you can get IIC communication between the boards with known good software. Then you can make the modifications to work with your chip.

  • I manage to communicate but there is still a problem. When I write 1 in the CTRL_1 register (0x81), when I read to us in the register I get the value 255. This is what the terminal displays:

    [CORTEX_M4_0] Number 1 write operation in register 129 completed successfully
    129 register read operation completed successfully
    Data read from register 129 is: 255

  • Sounds like the AD5933 is not responding. 255 is what you get because of the pull-ups.

  • Please do you have any solution for this

  • You have picked one of the most complicated I2C chips I have seen.

    I think you are going to need a scope.

    The chip does not even have an error flag you can monitor for independent confirmation of communication.

  • Further to Keith's comment: looking at data sheet (Rev F) Tables 16 and Figures 33 and 31, it appears you can't read a register using the usual "write register number, then read" sequence. Rather you need to send a command code to set the register number ("address pointer").

    I think you can picture the sequence [Fig 31] as writing to register 0xB0 [Ref Table 16] using the register number you want (0x81). After that you can do the read [Ref Fig 33].

  • Thank you for answering but you mean that the address pointer should be used only for writing

  • I recommend you read over "Writing/Reading to the AD5933", which starts on p. 28 in the datasheet. As Keith pointed out, the method(s) is somewhat different from other devices.

    Setting the address pointer is not required for a Write Byte [Ref Fig 30], but it is required for Read Byte and Block Read/Write. If you only want to do Write/Read Byte, the code change needed (in readRegister) is fairly small -- just send {0xB0, reg} instead of just {reg} at the beginning (you may also have to do a Stop after that). Do you want to do Block Read/Write? [Writing 0x81 can't be done with a Block Write.]

    Unsolicited: It looks like you're trying to write 0x02 to register 0x81, but bit D1 is "Reserved" per Table 11.

  • I tried what you suggested to me. I manage to write in register 0x81 and read the same value with the address pointer. My problem now is in the case where I write in registers 0x82, 0x83 and 0x84 (Frequency start register). With these three registers, when I read, I don't get the same values. Here is the function for the Frequency Start Register. I get the following output at the terminal 

    (I must have w = 0!
    y=125!
    z = 2!°
    #include <math.h>
    
    // Les registres de la fréquence de démarrage. C'est un registre lecture-écriture de 3 bites
    #define FREQ_0   (0x82)
    #define FREQ_1    (0x83)
    #define FREQ_2    (0x84)
    
    #define MCLK 16776000.0 // Source d'horloge interne de l'AD5933. Elle est de 16.776 MHz
    
    int reussit;
    
    
    // Function to read a pointer register from the AD5933 via the I2C interface
    
    uint8_t I2C_readRegister(uint8_t reg)
    {
        //uint8_t AD5933_address = (SLAVE_ADDRESS << 1) | 0x01; // Combination of slave address and read bit
    
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR;   // Transmission
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate the start signal
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for register address to be sent
        EUSCI_B0->TXBUF = Adress_pointer;    // Send register address
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));  // Wait for start signal to be sent
        EUSCI_B0->TXBUF = reg; // // Send register address
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for register address to be sent
        EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR;  // Reception
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate a repetition of the start signal
        while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT); // Wait for the end of the start signal repetition
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;    // Generation of the stop signal
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)); // // Wait for the reception of the data
        // Verification of the reading
        if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
        {
            // Failed to read
            printf("Failed to read register %u\n", reg);
        }
        else
        {
            // The write was successful
            printf("%u register read operation completed successfully\n", reg);
        }
        RXData = EUSCI_B0->RXBUF;      // Lecture de la donnée reçue
        return RXData;
    }
    
    int Start_Frequency(unsigned long x) {
        // Check that MCLK is not zero to avoid a division by zero
        if (MCLK == 0) {
            printf("Error: MCLK sucks\n");
            return -1;
        }
    
        // Check that the value of x is valid
        if (x <= 0) {
            printf("Error: The value of x is invalid\n");
            return -1;
        }
    
        // Calculate the start frequency
        long freq = (x / (MCLK / 4.0)) * pow(2, 27);
    
        // Extract the bytes from the frequency
        uint8_t freq_high = 0;
        uint8_t freq_mid = 0;
        uint8_t freq_low = 0;
    
        freq_high = (uint8_t)((freq >> 16) & 0xFF);
        freq_mid = (uint8_t)((freq >> 8) & 0xFF);
        freq_low = (uint8_t)(freq & 0xFF);
    
        // Write the data in the concerned registers
        I2C_writeRegister(FREQ_0, 0);
        I2C_writeRegister(FREQ_1, 125);
        I2C_writeRegister(FREQ_2, 2);
    
      // Checking for write success
        reussit = (I2C_readRegister(FREQ_0) == freq_high) &&
                  (I2C_readRegister(FREQ_1) == freq_mid) &&
                  (I2C_readRegister(FREQ_2) == freq_low);
        // Read again in the frequency registers
        uint8_t w = I2C_readRegister(FREQ_0);
        uint8_t y = I2C_readRegister(FREQ_1);
        uint8_t z = I2C_readRegister(FREQ_2);
        delay(100);
        printf("freq_high = %u !\n", freq_high);
        printf("freq_mid = %u !\n", freq_mid);
        printf("freq_low = %u !\n", freq_low);
        delay(100);
        printf("w = %u !\n", x);
        printf("y = %u !\n", y);
        printf("z = %u !\n", z);
    
        printf("The start frequency has been set with %s !\n", reussit ? "succès" : "échec");
    
        return reussit ? 0 : -1;
    }
    
    
    /**
     * main.c
     */
    void main(void)
    {
        WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer
        clock();
        DCO_clock(5);
        delay(100);
        I2C_Init();
        delay(100);
    
        // Exemple d'écriture et de lecture d'un registre de l'AD5933
    
        I2C_writeRegister(CTRL_1, 2); // Écriture dans le registre de contrôle 1
        delay(100);
       // I2C_write_Adress_Pointer(CTRL_1);
        uint8_t data = I2C_readRegister(CTRL_1); // Lecture du registre de contrôle 1
        printf("Data read from register %u is: %u\n", CTRL_1, data);
        delay(1000);
        Start_Frequency(1000);
    
    }
    
    
    

    [CORTEX_M4_0] Number 2 write operation in register 129 completed successfully
    129 register read operation completed successfully
    Data read from register 129 is: 2
    Number 0 write operation in register 130 completed successfully
    Number 125 write operation in register 131 completed successfully
    Number 2 write operation in register 132 completed successfully
    130 register read operation completed successfully
    130 register read operation completed successfully
    131 register read operation completed successfully
    132 register read operation completed successfully
    freq_high = 0 !
    freq_mid = 125 !
    freq_low = 2 !
    w = 1000 !
    y = 243 !
    z = 249 !
    The start frequency has been set with échec !

  • [I should mention at this point that I have no experience with this device -- I don't even quite know what it does.]

    But this looks suspicious, since w is  a uint8_t:

    w = 1000 !

    I suggest you replace: 

    >  printf("w = %u !\n", x);

    with

    >  printf("w = %u !\n", (unsigned)w);

    [Edit: Fixed variable reference.]

  • Also, Fig 31 shows a Stop condition, rather than a Repeated Start, following the Address Pointer setting. It may be that that is required.

  • At this point, since the MSP430 is working correctly, you might want to switch to the AD forums, where there should be people more knowledgeable about this chip.

    Community | Analog Devices

  • Hello dear all,
    For the problem,

    #include <msp432p401r.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <math.h>
    
    #define SLAVE_ADDRESS 0x0D
    #define Adress_pointer 0xB0
    
    #define PCMKEY_value 0x695A0000
    #define CS_KEY_value 0x0000695A
    
    #define MCLK 16776000.0 // Source d'horloge interne de l'AD5933. Elle est de 16.776 MHz
    
    
    uint8_t RXData;
    
    // Delay function
    void delay(int n)
    {
        volatile int i, j;
        for (j = 0; j < n; j++)
            for (i = 0; i < 1000; i++);
    }
    
    void DCO_clock(int clock_speed) {
        CS->KEY = CS_KEY_value;
        switch (clock_speed) {
            case 0: {
                CS->CTL0 = CS_CTL0_DCORSEL_0; // 1.5MHz
                break;
            }
            case 1: {
                CS->CTL0 = CS_CTL0_DCORSEL_1; // 3MHz
                break;
            }
            case 2: {
                CS->CTL0 = CS_CTL0_DCORSEL_2; // 6MHz
                break;
            }
            case 3: {
                CS->CTL0 = CS_CTL0_DCORSEL_3; // 12MHz
                break;
            }
            case 4: {
                CS->CTL0 = CS_CTL0_DCORSEL_4; // 24MHz
                break;
            }
            case 5: {
                PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_1; // LDO_Vcore1 choice
                while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
                PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_5; // DCDC_Vcore1 choice
                while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
                FLCTL->BANK0_RDCTL = FLCTL_BANK0_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank0
                FLCTL->BANK1_RDCTL = FLCTL_BANK1_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank1
                CS->CTL0 = CS_CTL0_DCORSEL_5; // 48MHz
                break;
            }
        }
        CS->KEY = 0;
    }
    
    void clock(void) {
        CS->KEY = CS_KEY_value;
        CS->CTL1 = CS_CTL1_SELA_3 + CS_CTL1_SELS_3 + CS_CTL1_SELM_3;
        CS->KEY = 0;
    }
    
    void I2C_Init(void)
    {
      UCB0CTLW0 |= UCSWRST;                  //reset the l'I2C for modification registers
      P1->SEL0 |= BIT6 + BIT7;    //SDA = P1.6 et SCL = P1.7
      P1->SEL1 &= ~(BIT6 + BIT7);
      P1->REN |= BIT6 | BIT7;  // Activation of internal pull-up resistors
      P1->OUT |= BIT6 | BIT7;  // Configuration of pull-up resistors
      //EUSCI_B0->CTLW0 = UCMST + UCMODE_3 + UCSYNC + UCSSEL_2 + UCSWRST; //I2C type communication in master mode + synchro, SMCLK, and maintained reset
      EUSCI_B0->CTLW0 = EUSCI_A_CTLW0_SWRST |
                        EUSCI_B_CTLW0_MODE_3|
                        EUSCI_B_CTLW0_MST   |
                        EUSCI_B_CTLW0_SYNC  |
                        EUSCI_B_CTLW0_SSEL__SMCLK;
      EUSCI_B0->BRW = 30; //fSCL = SMCLK/30 = 100kHz
      EUSCI_B0->I2CSA = SLAVE_ADDRESS; // Send AD5933 address
      EUSCI_B0->CTLW0 &= ~UCSWRST;                 //fonctionnement normal
      //EUSCI_B0->IE |= UCRXIE | UCNACKIE | UCBCNTIE;
    
    }
    
    /*
     * FUNCTION THAT MANAGES INTERRUPTIONS
     *
     * The interest of this function is to process the different sources of interruptions that can occur during I2C operations, such as:
    
    UCNACKIFG: This flag is set when the I2C module receives a NACK (Not Acknowledge) during a data transmission. In the corrected code, it is used to reset the UCNACKIFG flag, enable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and restart transmission by setting the UCTXSTT bit to 1.
    
    UCRXIFG0: This flag is set when data is successfully received by the I2C module. In the corrected code, it is used to reset the UCRXIFG0 flag, disable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and store received data in the RXData variable.
    
    UCBCNTIFG: This flag is set when the number of bytes expected during an I2C operation is reached. In the corrected code, it is used to reset the UCBCNTIFG flag, enable sleep-on-output mode (SCB_SCR_SLEEPONEXIT), and invert the state of pin P1.0 (P1OUT ^= BIT0).
     */
    void EUSCIB0_IRQHandler(void)
    {
        if (UCB0IFG & UCNACKIFG)
        {
            UCB0IFG &= ~UCNACKIFG;
            SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
            UCB0CTLW0 |= UCTXSTT;
        }
    
        if (UCB0IFG & UCRXIFG0)
        {
            UCB0IFG &= ~UCRXIFG0;
            SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
            RXData = UCB0RXBUF;
        }
    
        if (UCB0IFG & UCBCNTIFG)
        {
            UCB0IFG &= ~UCBCNTIFG;
            SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
            P1OUT ^= BIT0;
        }
    }
    
    /*
     * BLOCK WRITE 
    In this operation, the master device writes a block of data to a slave device (see Figure 32). The start address
     for a block write must previously have been set. In the case of the AD5933 this is done by setting a pointer to 
     set the register address. 
    1. The master device asserts a start condition on SDA. 
    2. The master sends the 7-bit slave address followed by the write bit (low). 
    3. The addressed slave device asserts an acknowledge on SDA. 
    4. The master sends an 8-bit command code (1010 0000) that tells the slave device to expect a block write. 
    5. The slave asserts an acknowledge on SDA. 
    6. The master sends a data byte that tells the slave device the number of data bytes to be sent to it. 
    7. The slave asserts an acknowledge on SDA. 
    8. The master sends the data bytes. 
    9. The slave asserts an acknowledge on SDA after each data byte. 
    10. The master asserts a stop condition on SDA to end the transaction. 
     */
    
    void I2C_blockWrite(uint8_t reg_Address, uint8_t *data, uint8_t byte_number) {
    
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR;   // Transmission
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate the start signal
    
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Wait for start signal to be sent
        EUSCI_B0->TXBUF = reg_Address; // Send register address
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for register address to be sent
        EUSCI_B0->TXBUF = 0xA0; // Send Command pointer
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for address pointer to be sent
        // Envoi du nombre de bytes à écrire
        EUSCI_B0->TXBUF = byte_number; // Send register number of byte
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for number of byte to be sent
        int i;
        // Envoi des données
        for (i = 0; i < byte_number; i++) {
            EUSCI_B0->TXBUF = data[i];
            while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));
        }
    
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;    // Waiting for data to be sent
        while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP); // Waiting for the end of the transmission
    }
    
    /*
     * Block Read 
    In this operation, the master device reads a block of data from a slave device (see Figure 34). The start address 
    for a block read must previously have been set by setting the address pointer. 
    1. The master device asserts a start condition on SDA. 
    2. The master sends the 7-bit slave address followed by the write bit (low). 
    3. The addressed slave device asserts an acknowledge on SDA. 
    4. The master sends a command code (1010 0001) that tells the slave device to expect a block read. 
    5. The slave asserts an acknowledge on SDA. 
    6. The master sends a byte-count data byte that tells the slave how many data bytes to expect. 
    7. The slave asserts an acknowledge on SDA. 
    8. The master asserts a repeat start condition on SDA. This is required to set the read bit high. 
    9. The master sends the 7-bit slave address followed by the read bit (high). 
    10. The slave asserts an acknowledge on SDA. 
    11. The master receives the data bytes. 
    12. The master asserts an acknowledge on SDA after each data byte. 
    13. A no acknowledge is generated after the last byte to signal the end of the read. 
    14. The master asserts a stop condition on SDA to end the transaction. 
     */
    
    void I2C_blockRead(uint8_t reg_Address, uint8_t *data, uint8_t byte_number) {
        //
    
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR;   // Transmission
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate the start signal
    
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Wait for start signal to be sent
        EUSCI_B0->TXBUF = reg_Address; // Send register address
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for register address to be sent
        EUSCI_B0->TXBUF = 0xA1; // Send Command pointer
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for address pointer to be sent
        EUSCI_B0->TXBUF = byte_number; // Send register number of byte
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for number of byte to be sent
        EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR;  // Reception
        EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;    // // Generate a repetition of the start signal
        while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT); // Wait for the end of the start signal repetition
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)); // // Wait for the reception of the data
        int i;
        // Reading data
        for (i = 0; i < byte_number; i++) {
            data[i] = EUSCI_B0->RXBUF;
            while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)); // // Wait for the reception of the data
    
            // Si c'est le dernier byte, envoyer NACK pour signaler la fin de la lecture
            if (i == byte_number - 1) {
                EUSCI_B0->CTLW0 |= UCTXNACK;
            } else {
                EUSCI_B0->CTLW0 &= ~UCTXNACK;
            }
        }
    
        // Arrêt de la transmission
       EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT; // Wait for the end of the start signal repetition
    }
    
    void Test_Block_()
    {
        // Écrire les données dans les registres concernés
         uint8_t regAddress = 0x82;
         uint8_t data[] = {0x12, 0x03, 0x11};
         uint8_t dataSize = 3;
    
        I2C_blockWrite(regAddress, data, dataSize);
    
         // Exemple d'utilisation du Block Read
         uint8_t readDataSize = 3;
         uint8_t readData[readDataSize];
    
         I2C_blockRead(regAddress, readData, readDataSize);
    
         // Stockage des données lues dans trois variables distinctes
         uint8_t byte0 = readData[0];
         uint8_t byte1 = readData[1];
         uint8_t byte2 = readData[2];
    
        printf("La valeur de byte0 est : %u\n", byte0);
        printf("La valeur de byte1 est : %u\n", byte1);
        printf("La valeur de byte2 est : %u\n", byte2);
    }
    /**
     * main.c
     */
    void main(void)
    {
        WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer
        clock();
        DCO_clock(5);
        delay(100);
        I2C_Init();
        delay(100);
        Test_Block_();
    
    }
    
    
    
    I tried to write two functions one to write in block and the other to read in block. When I run my code I get nothing on the output. Here is the code

  • When you pause in the debugger, where is your program executing?

    -----------

    >  DCO_clock(5);

    I haven't vetted the code for this case, but the comments say that this runs the CPU (and SMCLK) at 48MHz. If so, BRW=30 runs the I2C at 48MHz/30=1.6MHz which is much too fast. I suggest you stick with DCO_clock(1) until you have everything else working, but if not you should set BRW=(48MHz/100kHz)=480.

  • I tried this but it doesn't work. I'm completely stuck

  • When you pause in the debugger, where is your program executing?

  • Well for the moment I don't know with the CCS how to know where the program is executing 

  • While your program is running, click on the button with the two vertical bars ("||" for Pause).

  • It looks like your blockWrite function sends {reg, 0xA0, N, bytes..}, but Fig 32 shows {0xA0, N, bytes..} [the I2C sends the "Slave Address" automatically]. I'm not sure what the AD5933 will do with this.

    The blockWrite register number comes from a separate operation [Fig 31] which sets the Address Pointer, for which you probably want a separate C function.

    I think blockRead has a similar flaw.

  • This is where the program executing

  • See if you can find the "Registers" view ["Window->Show View->Registers" or some such]. Of particular interest are UCB0IFG and UCB0STATW.

    The section on p. 28 (ff) doesn't mention the conditions under which it will give a NACK. It may be that the AD5933 is interpreting your sequence as a byte-write and giving a NACK when you send too many bytes.

  • This may be because I gave {reg, 0xA0, N, bytes..} instead of {0xA0, N, bytes..}. But in the window section I don't see the register option

  • The Registers view is only useful when you're paused in the debugger. It usually opens automatically when you start the debugger.

    [I don't have the debugger started, and I got to it via Window->Show View->Other->Debug->Registers, but first you need to get back where you were when you paused earlier, and look towards the top right of the window.]

  • Good morning,
    I tried to do this but still nothing

  • I'm not sure I understand.

    What did you try, and what was the result?

  • Good morning,
    I came to work with the MSP432 and the AD5933. The communication between the two devices is done by the I2C protocol. I wrote functions to read and write to AD5933 registers. However, there are some registers where when I write a byte of data, I don't read the value I wrote. On the other hand there are other registers with which when I write a byte, I read the same value that I wrote.

  • Depending on the device and the register, you might not get what you wrote. For example, some bits might be read only and writes to them are ignored. You need to become *very* familiar with the data sheet.

  • Yes I have used the data sheet well. If we take for example the addresses of the control register, we write and read there. For these registers I manage to read what I write there without any problem. On the other hand if we take for example the register of the start frequency, it is indicated in the data sheet that we can write and read there but when I write in these registers and that I read again in these same registers, I don't get the same bytes I wrote

  • Again, I suggest you go to the AD board for help with this chip.

  • Another tool you might want to get is an I2C sniffer that will monitor the traffic and tell you exactly what you are sending and receiving. I have never used one, so I don't have a recommendation, but google I2C sniffer and there are many options.

  • In your previous report it appeared that (a) you weren't sending the correct sequence for Block Read/Write (b) you weren't setting the Address Pointer (required for reads). Has this changed?

**Attention** This is a public forum