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.

MSPM0G1505: Can`t get the latest TX data from I2C

Part Number: MSPM0G1505

Tool/software:

Dear Ti teams,

I want to get some info from MSPM0G1505 through I2C.

Now I can successfully get the response from MSPM0G1505, but it seems I got the last time TX buffer.

For example, I send 0x1, I want to receive 0x1, but I receive 0x00 the first time, unless I send 0x1 again, then I receive 0x1.

Then, I send 0x2, I hope to receive 0x2 0x1 the first time, but I still receive 0x1, unless I send it again.

The same issue occurs when sending 0x1 0x2, it seems I always get the TX buffer from the last time. I want to know why and how to optimize my code.

I have uploaded the logs and some key parts of the code. Could you help to review if there are any issues?

void I2C_0_INST_IRQHandler(void)
{
    static bool dataRx = false;

    switch (DL_I2C_getPendingInterrupt(I2C_0_INST))
    {
        case DL_I2C_IIDX_TARGET_START:
            // Initialize RX or TX after Start condition is received
            //gTxCount = 0;
            gRxCount = 0;
            // Flush TX FIFO to refill it
            //DL_I2C_flushTargetTXFIFO(I2C_0_INST);
            break;
        case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
            // Store received data in buffer
            dataRx = true;
            while (DL_I2C_isTargetRXFIFOEmpty(I2C_0_INST) != true)
            {
                uint8_t receivedData = DL_I2C_receiveTargetData(I2C_0_INST);
                if (gRxCount < gRxLen)
                {
                    gRxPacket[gRxCount++] = receivedData;
                }
                else
                {
                    DL_I2C_receiveTargetData(I2C_0_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_0_INST, gTxPacket, gTxLen);
                gTxCount += DL_I2C_fillTargetTXFIFO(I2C_0_INST, &gTxPacket[gTxCount], (gTxLen - gTxCount));
            }
            else
            {
                //
                // Fill FIFO with 0x00 if more data is requested than
                // expected gTxLen
                //
                while (DL_I2C_transmitTargetDataCheck(I2C_0_INST, 0x00) != false);
            }
            break;
        case DL_I2C_IIDX_TARGET_STOP:
            //  If data was received, echo to TX buffer
            if (dataRx == true)
            {
                if(gRxPacket[0] == 0x1)
                {
                    if(gRxPacket[1] == 0x2)
                    {
                        gTxPacket[0] = 0xf;
                        gTxPacket[1] = 0x4;
                        gTxLen = 2;
                        DL_I2C_flushTargetTXFIFO(I2C_0_INST);
                    }
                    else 
                    {
                        gTxPacket[0] = 0x1;
                        gTxLen = 1;
                        DL_I2C_flushTargetTXFIFO(I2C_0_INST);
                    }
                }


                if(gRxPacket[0] == 0x2)
                {
                    gTxPacket[0] = 0x2;
                    gTxPacket[1] = 0x1;
                    gTxLen = 2;
                    DL_I2C_flushTargetTXFIFO(I2C_0_INST);
                }

                if(gRxPacket[0] == 0x3)
                {
                    uint16_t temp_vgs1 = 500; //500 = -3.87V
                    DL_Timer_setCaptureCompareValue(PWM_1_INST, temp_vgs1, GPIO_PWM_1_C1_IDX);    //PWM_Vgs_PA0(10)  Vgs-PA0
                    DL_Timer_setCaptureCompareValue(PWM_2_INST, temp_vgs1, GPIO_PWM_2_C0_IDX);    //PWM_Vgs_PA1(11)  Vgs-PA1
                    DL_Timer_setCaptureCompareValue(PWM_0_INST, temp_vgs1, GPIO_PWM_0_C3_IDX);    //PWM_Vgs_PA2(14)  Vgs-PA2
                    DL_Timer_setCaptureCompareValue(PWM_0_INST, temp_vgs1, GPIO_PWM_0_C1_IDX);
                    gTxPacket[0] = 0x6;
                    gTxLen = 1;
                }

                //DL_I2C_flushTargetTXFIFO(I2C_0_INST);
                gTxCount = 0;
                dataRx = false;
                //cleanRxPacket();
            }
            //  Toggle LED to indicate successful RX or TX
            //  DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
            break;
        case DL_I2C_IIDX_TARGET_RX_DONE:
            //  Not used for this example
        case DL_I2C_IIDX_TARGET_RXFIFO_FULL:
            //  Not used for this example
        case DL_I2C_IIDX_TARGET_GENERAL_CALL:
            //  Not used for this example
        case DL_I2C_IIDX_TARGET_EVENT1_DMA_DONE:
            //  Not used for this example
        case DL_I2C_IIDX_TARGET_EVENT2_DMA_DONE:
            //  Not used for this example
        default:
            break;
    }

  • some additional info

    As shown in the code, when I send 0x3 to MSPM0G1505 the first time, although I get the last time buffer[wrong buffer, not 0x6], I observed that the voltage was actually changed in fact.

    So I guess it might just be that the TX buffer seems to be delayed for some unknown reason.

  • Hi Miao,
    What pins are you using for this code implementation? Are you using any pull-up resistors? What values for the resistors are you using? I recommend updating/reinstalling your current CCS version to the latest one (CCS 20.0.2) and the latest MSPM0 SDK and SYSCONFIG. Then, try any I2C TX example and see if the same behavior is happening.

    Best Regards,

    Diego Abad

  • This logic appears to require a Stop between the write and the read, in order to turn the buffer around. As I read the i2ctransfer(8) man page, all of the "messages" on the command line are sent in one "transfer" (transaction), which uses Repeated-Start (no Stop-s) between messages.

    Is there a way you can fit your Stop logic into the Start case? Alternatively, try sending one message per i2ctransfer run.

  • Hi Bruce,

    Thanks for the idea you provided. I used i2cget/set to separately write and write, and it seems to work. I will write another app to do write and read with an internal stop.

    But I noticed the TXFIFO buffer was not cleared after the last time sending. 

    the first read, i get 0x0000, because there is no data in TXFIFO, it`s okay

    the second read, i get 0x040f, since i write 0x01 0x02 to RX, it`s also should be fine.

    but for the thrid read, i still get 0x040f, It seems the TXFIFO was`t cleared successfully.

    I think this should be like a queue, but it seems the DL_I2C_flushTargetTXFIFO function didn't clean the TXFIFO successfully. Do you have any comments about this issue?

    Thanks a lot

    Mervyn

  • some updates

    About this issue, i try to add the blow case code part in my code, It seems can`t solve the issue. I still receive last time TXFIFO data

            case DL_I2C_IIDX_TARGET_TX_DONE:
                DL_I2C_flushTargetTXFIFO(I2C_0_INST);
                break;

  • Hi miao,
    Can you try adding a while(DL_I2C_isTargetTXFIFOEmpty()) to the code? This should make it stop until all the contents in TX FIFO are empty.

    Best Regards,

    Diego Abad

  • Though it doesn't say explicitly, it appears i2cget(8) is designed to read a "register", which implies it performs the sequence (a) write one byte (b) repeated-Start [no Stop] (c) read one {byte or word} (d) Stop.

    This is a variant of your earlier problem. Since the Stop is only happening after the read, the next i2cget repeats the 0x01 request, and the 0x02 is still left in the gRxPacket, so it gives back the same result -- it's not left over in the FIFO, your code puts it there again.

    To make sure you know what you're sending/receiving, I suggest you go back to i2ctransfer and limit yourself to one "message" per "transfer". [I'm using quotes since that isn't the terminology used in the I2C spec.]

  • I don't think you need this feature (yet), but since you're concerned about the Tx FIFO, I suggest you read over TRM Sec 20.2.3.12.1, which describes the "stale data" feature.

    Briefly: On certain events (Start, Stop, Timeout are mentioned) any data in the Tx FIFO is marked as "stale". You can enable a feature which prevents this data from being (automatically) sent, and provides an indication that this has happened. That gives you a chance to empty the Tx FIFO of the stale data before writing the data you want to send. 

    Right now, your target provides only the data the controller asks for, so (I think) you never over-fill the Tx FIFO, but you might keep this in mind for the future.

  • Hi Bruce,

    I wrote a simple C app to write and read through I2C. It seems that separating the operations indeed works, and I can read the values I need each time.

    Regarding the "stale" TXFIFO data, I think this functionality is not necessary in my scenario.

    However, out of an engineer's spirit, I hope to resolve this issue. I haven't found the corresponding Digital Media Processor for MSPM0G1505 yet. Can I refer to other series?

    I would greatly appreciate it if you could provide me with the corresponding link. 

        if (write(i2c_bus_address, write_buffer, write_length) != write_length)
        {
            perror("Failed to write to the i2c bus");
            close(i2c_bus_address);
            return 1;
        }
    
    
        if (read(i2c_bus_address, read_buffer, read_length) != read_length)
        {
            perror("Failed to read from the i2c bus");
            close(i2c_bus_address);
            return 1;
        }
  • If by Digital Media Processor you mean the TMS320DM6 series, I don't know much about them. 

    [*Cue TI Sales Department*]