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.

LP-MSPM0G3507: I2C Data transmission and Reception

Part Number: LP-MSPM0G3507
Other Parts Discussed in Thread: MSPM0G3507, SYSCONFIG

Tool/software:

Hi,

Can we transmit data from one I2C port to another I2C port within the same controller?
Launchpad which I am using is: MSPM0G3507

Thank you 

  • Hi Tejal,

    Sure. You could set one I2C as controller and another as slave and just connect SCL and SDA pin together.

  • Do I also need to connect pull-up resistors for I2C communication? and could you provide a simple sample code for setting up I2C communication.

    Thank you,
    Tejal

  • Hi Tejal,

    Yes, you could either use the internal pull-up resistors or external pull-up resistors.

    As for example, you could merge the i2c controller and target example into one project for you application. The interrupt example could be used for i2c target.

  • Hi Pengfei,

    I tried merging the I2C controller and target example, but I am not getting an acknowledgment from the target device. I am also attaching the output which I observed on the logic analyzer.

    Thank you,
    Tejal

  • Which examples did you merge? I expect you'd want to use an interrupt-driven model on the target side.

    Did you change the target I2C address on both sides?

  • Yes I changed the I2C address on both side and also, I am using interrupt driven code on target side, and following 2 examples I merged:

    1) i2c_controller_multibyte_fifo_poll and 2) i2c_target_multibyte_fifo_interrupt

  • Hi Tejal,

    It is correct that you are using the interrupt example for I2C target.

    There are some items you could check:

    • You are writing to address 0x10 from I2C master, have you change the I2C target address as 0x10?
    • Have you pull-up the SCL and SDA pin?
    • For I2C target code, make sure it is completely follow the SDK example, especially for the enabling of interrupt and interrupt handler achievement.  

    Best Regards,

    Pengfei

  • Can you post your resulting (merged) code? Sometimes all it takes is a typo.

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

    For the target side, the contents of main() should be suitable for a "target_init()" function, except for:

        DL_SYSCTL_enableSleepOnExit();

    This should be removed, since it has a global effect on the program. (It could produce the symptom you're seeing.)

        while (1) {
            __WFI();
        }

    This should be removed. (I'm guessing you already did this one.)

  • Thank you for your feedback. I have made the necessary adjustments to the code as per your suggestions. I am attaching the updated code for your review. Could you please check the resulting (merged) code? 

    #include <ti/driverlib/m0p/dl_interrupt.h>
    #include "ti_msp_dl_config.h"
    
    #define I2C_TX_PACKET_SIZE (8)
    
    #define I2C_RX_PACKET_SIZE (5)
    
    #define I2C_TX_MAX_PACKET_SIZE (16)
    
    #define I2C_RX_MAX_PACKET_SIZE (16)
    
    uint8_t gTxPacket[I2C_TX_PACKET_SIZE] = {
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    
    volatile uint8_t gRxPacket[I2C_RX_PACKET_SIZE];
    
    uint32_t gTxLen, gTxCount;
    
    /* Data sent to Controller in response to Read transfer */
    uint8_t gTxPacket1[I2C_TX_MAX_PACKET_SIZE] = {0x00};
    volatile uint8_t gRxPacket1[I2C_RX_MAX_PACKET_SIZE];
    
    uint32_t gRxLen, gRxCount;
    
    
    int main(void)
    {
        SYSCFG_DL_init();
    
        gTxCount = 0;
        gTxLen   = I2C_TX_MAX_PACKET_SIZE;
        DL_I2C_enableInterrupt(I2C_1_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);
    
        /* Initialize variables to receive data inside RX ISR */
        gRxCount = 0;
        gRxLen   = I2C_RX_MAX_PACKET_SIZE;
    
    
        DL_I2C_fillControllerTXFIFO(I2C_0_INST, &gTxPacket[0], I2C_TX_PACKET_SIZE);
    
        /* Wait for I2C to be Idle */
        while (!(
            DL_I2C_getControllerStatus(I2C_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
            ;
    
        DL_I2C_startControllerTransfer(I2C_0_INST, I2C_1_TARGET_OWN_ADDR,
            DL_I2C_CONTROLLER_DIRECTION_TX, I2C_TX_PACKET_SIZE);
    
        /* Poll until the Controller writes all bytes */
        while (DL_I2C_getControllerStatus(I2C_0_INST) &
               DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
            ;
    
        /* Trap if there was an error */
        if (DL_I2C_getControllerStatus(I2C_0_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_0_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
            ;
    
        /* Add delay between transfers */
        delay_cycles(1000);
    
        DL_I2C_startControllerTransfer(I2C_0_INST, I2C_1_TARGET_OWN_ADDR,
            DL_I2C_CONTROLLER_DIRECTION_RX, I2C_RX_PACKET_SIZE);
    
        for (uint8_t i = 0; i < I2C_RX_PACKET_SIZE; i++) {
            while (DL_I2C_isControllerRXFIFOEmpty(I2C_0_INST));
            gRxPacket[i] = DL_I2C_receiveControllerData(I2C_0_INST);
        }
    
        while (1) {
        }
    }
    
    void I2C_1_INST_IRQHandler(void)
    {
        static bool dataRx = false;
    
        switch (DL_I2C_getPendingInterrupt(I2C_1_INST)) {
            case DL_I2C_IIDX_TARGET_START:
                /* Initialize RX or TX after Start condition is received */
                gTxCount = 0;
                gRxCount = 0;
                dataRx   = false;
                /* Flush TX FIFO to refill it */
                DL_I2C_flushTargetTXFIFO(I2C_1_INST);
                break;
            case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
                /* Store received data in buffer */
                dataRx = true;
                while (DL_I2C_isTargetRXFIFOEmpty(I2C_1_INST) != true) {
                    if (gRxCount < gRxLen) {
                        gRxPacket1[gRxCount++] = DL_I2C_receiveTargetData(I2C_1_INST);
                    } else {
                        /* Prevent overflow and just ignore data */
                        DL_I2C_receiveTargetData(I2C_1_INST);
                    }
                }
                break;
            case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
                /* Fill TX FIFO if there are more bytes to send */
                if (gTxCount < gTxLen) {
                    gTxCount += DL_I2C_fillTargetTXFIFO(
                            I2C_1_INST, &gTxPacket1[gTxCount], (gTxLen - gTxCount));
                } else {
                    while (DL_I2C_transmitTargetDataCheck(I2C_1_INST, 0x00) != false)
                        ;
                }
                break;
            case DL_I2C_IIDX_TARGET_STOP:
                /* If data was received, echo to TX buffer */
                if (dataRx == true) {
                    for (uint16_t i = 0;
                         (i < gRxCount) && (i < I2C_TX_MAX_PACKET_SIZE); i++) {
                        gTxPacket1[i] = gRxPacket1[i];
                        DL_I2C_flushTargetTXFIFO(I2C_1_INST);
                    }
                    dataRx = false;
                }
                break;
    
            default:
                break;
        }
    }

  • >  DL_I2C_enableInterrupt(I2C_1_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);

    After this, I think you need additionally (I'm guessing at the IRQN name):

    > NVIC_EnableIRQ(I2C_1_IRQN); // Enable Target interrupt in NVIC

    ----------

    But this wouldn't result in a NACK. I wonder if the I2C_1 (target) setup in ti_msp_dl_config.c is missing a call to:

    >  DL_I2C_setTargetOwnAddress(I2C_1_INST, I2C_1_TARGET_OWN_ADDR);

    This is generated by sysconfig in the Example, but maybe it got lost in the merge?

    ----------

    More generally, it seems that you're using the same Tx/Rx buffers for both sides. Maybe you've checked that it works OK, but it seems hazardous at first glance.