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.

TMS570LS1115: I2C Interrupt not working

Part Number: TMS570LS1115
Other Parts Discussed in Thread: LDC1614, HALCOGEN

Hello,

I'm implementing my firmware to communicate with an LDC1614 through I2C protocol. I want to implement interrupt based communication.

However, I noticed that when I set the data length to '1', the interrupt is not generated. I'm reading a register here, for that I need to send the register address (8 bit) and then read two bytes for data.

If I write 1 byte as follows, it does not generate the TX interrupt.

i2cSend(i2cREG1, 1U, LDC1614_TX_Data_Buffer);

However, if I change the code as follows, it generates the TX interrupt.

i2cSend(i2cREG1, 2U, LDC1614_TX_Data_Buffer);

Please note that i2cREG1 and buffer has correct data.

Please let me know whether I'm doing something irregular here.

Thanks.

PS:

I dug into the i2c library and found something which looks like a bug, 

void i2cSend(i2cBASE_t *i2c, uint32 length, uint8 * data)
{

/* USER CODE BEGIN (17) */
/* USER CODE END */

    if ((g_i2cTransfer_t.mode & (uint32)I2C_TX_INT) != 0U)
    {
        /* Interrupt mode */
        /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
        g_i2cTransfer_t.data   = data;
        /* start transmit by sending first byte */
        /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
        i2c->DXR = (uint32)(*g_i2cTransfer_t.data);
        /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
        /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
        g_i2cTransfer_t.data++;

        /* Length -1 since one data is written already */
        g_i2cTransfer_t.length = (length - 1U);

        /* Enable Transmit Interrupt */
        i2c->IMR |= (uint32)I2C_TX_INT;
    }

When i2cSend deals wtih 1 byte messages as above, it sets the g_i2cTransfer_t.length to 0.

In the interrupt function,

case 5U:
/* USER CODE BEGIN (42) */
/* USER CODE END */
        /* transmit */

        if (g_i2cTransfer_t.length > 0U)
        {
            i2cREG1->DXR = *g_i2cTransfer_t.data;
            /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
            g_i2cTransfer_t.data++;
            g_i2cTransfer_t.length--;
            if(g_i2cTransfer_t.length == 0U)
            {   /* Disable TX interrupt after desired data count transfered*/
                i2cREG1->IMR &= (uint32)(~(uint32)I2C_TX_INT);
                i2cNotification(i2cREG1, (uint32)I2C_TX_INT);
            }
        }
        break;

The notification is generated only if 'length > 0'. I think the (length == 0) condition should come out from (length > 0) condition as this will never generate a notification when i2c data length is 1.

I will check this further tomorrow, please confirm.

Thanks!

  • Hello Pradeepa,

    If the data length is 1, the transmit data ready interrupt is generated too, but the data transfer (writing data to DXR register) is done in i2cSend(..) function rather than in the ISR.
  • QJ Wang said:
    Hello Pradeepa,

    If the data length is 1, the transmit data ready interrupt is generated too, but the data transfer (writing data to DXR register) is done in i2cSend(..) function rather than in the ISR.

    Let me go through the sequence of function calls I execute, because I can't seem to get the TXD interrupt when the data length is set to 1.

    i2cClearSCD(i2cREG1); // Clears any stop condition available
    
    i2cSetSlaveAdd(i2cREG1, LDC1614_ADDR); // Set the I2C address (address is correct)
    
    i2cSetDirection(i2cREG1, I2C_TRANSMITTER); // Set the direction: This should initially be transmitter to send the register address across
    
    i2cSetMode(i2cREG1, I2C_MASTER); // Set the mode as master (this is correct mode)
    
    i2cSetStop(i2cREG1); // Enable stop condition generation
    
    LDC1614_TX_Data_Buffer[0] = LDC1614_STATUS; // Data buffer which contains the register address to be read
    
    i2cSetCount(i2cREG1, 1U); // Stop condition count set to zero, this will generate SCD interrupt once this byte is transmitted and the stop condition is detected
    
    i2cSetStart(i2cREG1); // Set the start condition
    
    i2cSend(i2cREG1, 1U, LDC1614_TX_Data_Buffer); // Submit data to the buffer

    I was expecting two interrupts after this data transfer,

    1. When the device detects the stop condition

    2. When the transmit data is successfully submitted

    However, I don't get this second interrupt.

    If I change the function sequence as follows, I can get the transmit data interrupt. I can't understand the reason for this behavior.

    i2cClearSCD(i2cREG1); // Clears any stop condition available
    
    i2cSetSlaveAdd(i2cREG1, LDC1614_ADDR); // Set the I2C address (address is correct)
    
    i2cSetDirection(i2cREG1, I2C_TRANSMITTER); // Set the direction: This should initially be transmitter to send the register address across
    
    i2cSetMode(i2cREG1, I2C_MASTER); // Set the mode as master (this is correct mode)
    
    i2cSetStop(i2cREG1); // Enable stop condition generation
    
    LDC1614_TX_Data_Buffer[0] = LDC1614_STATUS; // Data buffer which contains the register address to be read
    
    /* ************************ */
    /* Comment the following line */
    // i2cSetCount(i2cREG1, 1U); // Stop condition count set to zero, this will generate SCD interrupt once this byte is transmitted and the stop condition is detected
    /* ************************ */
    
    i2cSetStart(i2cREG1); // Set the start condition
    
    i2cSend(i2cREG1, 1U, LDC1614_TX_Data_Buffer); // Submit data to the buffer

    Please check whether I'm doing something irregular.

    Thanks!

  • Some more information:

    Please check the images below which confirms that I2CSTR register behaves properly. Nevertheless, I don't get the interrupt for I2C vector number 5.

    Please refer to the images below:

    I'm just about to transfer the data, as you can see Interrupt flags are all set to one. The STR register confirms that TXRDY is also '1' at this moment.

    When I hit the next breakpoint I get the following register values. As you can see the STR register has TXRDY cleared, which shows that data is available in the data register.

    The next screenshot shows a breakpoint in the i2cInterrupt() function. As you can see, the stop condition interrupt is generated. Also, it is evident that STR register has TXRDY bit set to '1' which means I should be get the TXD interrupt as well. However, this is not happening. I never get the TXD interrupt for this transfer.

    Please check whether I'm doing something wrong. 

    Thanks!

  • Hello,

    It looks like no one is able to help here.

    For now I decided to use i2cSendByte function to send one byte of data to the LDC1614. However, this is not what I want to do.

    I can't get i2c tx interrupt when the data length is '1' and when I have the stop condition generation enabled with data count set to 1.

    The only interrupt I receive is the SCD interrupt, which ideally should follow TXD interrupt.

    If someone can look into this, it will be a great help.

  • Hello,

    I will do a test today, and let you know my test result.
  • Hello,

    The i2CSend() generated through HALCoGen won't generate TX interrupt for the 1st byte or if the data length is 1. The TX interrupt is not enabled. I will check with SW team if to enable the interrupt for the 1st data.