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.

MSPM0C1104: MSPM0C1104 I2C controller can not read register data

Part Number: MSPM0C1104


Tool/software:

I develop a SW code on a MSPM0C1104 EVB.

Now, we need to read the register contents from the slave I2C device.

The spec. of this I2C device reading timing is 

 Reading flow of this device is: 

I2C_START, Slave_Addr+W, Reg_Addr, 

I2C_START, Slave_Addr+R, Data1, Data2, Data3, Data4, I2C_STOP.

I use and modify from the sample code "C:\ti\mspm0_sdk_2_03_00_07\examples\nortos\LP_MSPM0C1104\driverlib\i2c_controller_rw_multibyte_fifo_poll".

 

#include "ti_msp_dl_config.h"

/*
 * Number of bytes to send from Controller to target.
 *  This example uses FIFO with polling, and the maximum FIFO size is 4.
 *  Refer to interrupt examples to handle larger packets
 */
#define I2C_TX_PACKET_SIZE (3)

/*
 * Number of bytes to received from target.
 *  This example uses FIFO with polling, and the maximum FIFO size is 4.
 *  Refer to interrupt examples to handle larger packets
 */
#define I2C_RX_PACKET_SIZE (3)

/* Data sent to the Target */
uint8_t gTxPacket[I2C_TX_PACKET_SIZE] = {0x00, 0x61, 0x00};

/*  Read Register Address*/
uint8_t gRegisterAddr[2] = {0x10, 0x14};

/* Data received from Target */
volatile uint8_t gRxPacket[I2C_RX_PACKET_SIZE];

/* I2C Target address */
#define I2C_TARGET_ADDRESS (0x29)

int main(void)
{
    SYSCFG_DL_init();

    /* Set LED to indicate start of transfer */
    DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);

    /*
     * Fill FIFO with data. This example will send a MAX of 4 bytes since it
     * doesn't handle the case where FIFO is full
     */
    DL_I2C_fillControllerTXFIFO(I2C_INST, &gTxPacket[0], I2C_TX_PACKET_SIZE);

    /* Wait for I2C to be Idle */
    while (!(
        DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
        ;

    /* Send the packet to the controller.
     * This function will send Start + Stop automatically.
     */
    DL_I2C_startControllerTransfer(I2C_INST, I2C_TARGET_ADDRESS,
        DL_I2C_CONTROLLER_DIRECTION_TX, I2C_TX_PACKET_SIZE);

    /* Poll until the Controller writes all bytes */
    while (DL_I2C_getControllerStatus(I2C_INST) &
           DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
        ;

    /* Trap if there was an error */
    if (DL_I2C_getControllerStatus(I2C_INST) &
        DL_I2C_CONTROLLER_STATUS_ERROR) {
        /* LED will remain high if there is an error */
        __BKPT(0);
    }

    /* Wait for I2C to be Idle */
    while (!(
        DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
        ;

    /* Add delay between transfers */
    delay_cycles(1000);

    /* Send a read request to Target */
    DL_I2C_startControllerTransfer(I2C_INST, I2C_TARGET_ADDRESS,
        DL_I2C_CONTROLLER_DIRECTION_RX, I2C_RX_PACKET_SIZE);

    /*
     * Receive all bytes from target. LED will remain high if not all bytes
     * are received
     */
    for (uint8_t i = 0; i < I2C_RX_PACKET_SIZE; i++) {
        while (DL_I2C_isControllerRXFIFOEmpty(I2C_INST))
            ;
        gRxPacket[i] = DL_I2C_receiveControllerData(I2C_INST);
    }

    // Test: read target register data
    /* 1: Do Dummy Write  */
        DL_I2C_fillControllerTXFIFO(I2C_INST, &gRegisterAddr[0], 1);
        // Wait for I2C to be Idle */
        while (!(
            DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
            ; 
        // Transfer register address w/o i2c_STOP
        DL_I2C_startControllerTransferAdvanced(I2C_INST, I2C_TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_TX,\
            1, DL_I2C_CONTROLLER_START_ENABLE, DL_I2C_CONTROLLER_STOP_DISABLE, DL_I2C_CONTROLLER_ACK_ENABLE);
        
        // wait Poll until the Controller writes all bytes */
        while (DL_I2C_getControllerStatus(I2C_INST) &
            DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
            ;

    /* 2: Read data */
        /* Wait for I2C to be Idle */
        while (!(
            DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
            ;

            /* Add delay between transfers */
            delay_cycles(1000);

            /* Send a read request to Target */
            //DL_I2C_startControllerTransfer(I2C_INST, I2C_TARGET_ADDRESS,
            //    DL_I2C_CONTROLLER_DIRECTION_RX, I2C_RX_PACKET_SIZE);
            DL_I2C_startControllerTransferAdvanced(I2C_INST, I2C_TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_RX,\
            I2C_RX_PACKET_SIZE, DL_I2C_CONTROLLER_START_ENABLE, DL_I2C_CONTROLLER_STOP_ENABLE, DL_I2C_CONTROLLER_ACK_DISABLE);

        /*
        * Receive all bytes from target. LED will remain high if not all bytes
        * are received
        */
        for (uint8_t i = 0; i < I2C_RX_PACKET_SIZE; i++) {
            while (DL_I2C_isControllerRXFIFOEmpty(I2C_INST))
                ;
            gRxPacket[i] = DL_I2C_receiveControllerData(I2C_INST);
        }    


    /* If write and read were successful, toggle LED */
    while (1) {
        DL_GPIO_togglePins(GPIO_LEDS_PORT,
            GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
        delay_cycles(12000000);
    }
}

In ths main function, I add this read fucntion before the final while loop.

Unfortunately, the program is halt in I2C read because the SCK kept low

Could anyone has soltuion for this problem. Thanks

  • I think this should be 2 not 1. Can you try again?

  • Hi, Eason

       As your sugggestion, the number was modified to 2 

            DL_I2C_fillControllerTXFIFO(I2C_0_INST, &regAddr[0], 2);
    It is the same, 
    Thanks for your reply.
  • Can you change this to be enable and also change the value from 1 to 2.

  • >while (DL_I2C_getControllerStatus(I2C_INST) &
    >   DL_I2C_CONTROLLER_STATUS_BUSY_BUS)

    BUSBSY will be set until the STOP, so it won't clear here. Try instead:

    >while (DL_I2C_getControllerStatus(I2C_INST) &
    >  DL_I2C_CONTROLLER_STATUS_BUSY)

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

    Or better yet: Use the RD_ON_TXEMPTY feature. Don't do the initial (TX) half-transaction, but instead call:

    DL_I2C_resetControllerTransfer(I2C_INST);  // Set MCTR=0 to avoid enableControllerReadOnTXEmpty hazard
    DL_I2C_enableControllerReadOnTXEmpty(I2C_INST); // Write then read

    then do the RX part of the transaction. The I2C unit will write the bytes in the Tx FIFO, then perform the Rx transaction.