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.

TM4C1294NCPDT: I2C FIFO Burst Master Rx without interrupts. NAK/NACK is delayed by 2 bytes - how to fix ?

Part Number: TM4C1294NCPDT

Hi there,

I note my same problem is reported elsewhere on the forum for another MCU, but there is no listed solution in that thread.

I am regularly Rx two bytes over I2C in the FIFO buffer on the TM4C129X. (at a 1kHz rate I get two more bytes to read).   I am using burst receive so I can let the two bytes fill up the FIFO before reading them back one after the other quickly.

The No-Acknowledge (NAK) response (bit) gets delayed by two bytes, so I have to read 4 bytes from the FIFO before a NAK is automatically generated by the TM4C129X's I2C Master for the slave to interpret.

If however I set the FIFO size to 1 with I2CMasterBurstLengthSet(i2c_base, 0x01); instead of 0x02 as per the code below, the NAK is correctly sent by the master and the slave correctly stops sending data after the second byte.  The problem with using a FIFO size of 1 is that it defeats the purpose of the FIFO buffer and the second read ends up taking in the order of 25-30us instead of a small fraction of that (a few us), as the I2C Tx speed is only 400kbps. This is a waste of CPU cycles for me.

I realise that the FIFO is better suited to work with interrupts, however that is not what I am using, and I would really like to get the code working with minor changes to my existing code shown below without employing interrupts. The three functions below are called one after the other, with a suitable delay of perhaps 150-200us between the initiate_Rx() and readFirstMeasByte().

My question: How can I use the FIFO buffer with *_ FIFO_BURST_RECEIVE_* while having the TMC129X Master issue a NAK after the second byte is automatically read into the Rx FIFO ?

 

void initiate_Rx(uint32_t i2c_base, uint8_t addr)
{
	I2CMasterSlaveAddrSet(i2c_base, addr, true);
	I2CRxFIFOConfigSet(i2c_base, (I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_2));
	I2CRxFIFOFlush(i2c_base);
	I2CMasterBurstLengthSet(i2c_base, 0x02);
	I2CMasterControl(i2c_base, I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START);
}

uint8_t readFirstMeasByte(uint32_t i2c_base)
{
	uint8_t meas_byte;
	while ((I2CFIFOStatus(i2c_base))&I2C_FIFO_RX_EMPTY);
	I2CFIFODataGetNonBlocking(i2c_base, &meas_byte);
	I2CMasterControl(i2c_base,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH);
	meas_byte&=(uint8_t)0x3F;//mask off the top two most significant bits as these are status bits 
	return meas_byte;
}

uint8_t readSecondMeasByte(uint32_t i2c_base)
{
	uint8_t meas_byte;
	while ((I2CFIFOStatus(i2c_base))&I2C_FIFO_RX_EMPTY);
	I2CFIFODataGetNonBlocking(i2c_base, &meas_byte);
	return meas_byte;
}

 

  • Hello Peter

    Can you please refer to the following Technical Application Note mentioned below. The SW collateral along with the application note should be able to perform the 2 byte transfer with NAK

    www.ti.com/.../spma073.pdf

    In our testing of the I2C we have never seen such an issue. Also is the issue only with 2 bytes or any other configuration of transfer?
  • Amit Ashara said:
    Can you please refer to the following Technical Application Note mentioned below. The SW collateral

    Hi Amit,

    I've read that application note but it didn't talk about using the FIFO without interrupts.  

    Which part of my code needs changing to align with the app notes?

    What do you mean by SW collateral?

    I have only tested with FIFO sizes of 1 and 2 giving the behavior I described. I could test with higher numbers but I'm unsure how that would help  you.  I got the impression  from the other post I referred that my problem was identical so it seems more than a coincidence I also see it. There must be something either common in our code or in the two MCU architectures.

    Peter

  • Hello Peter

    The example code uses FIFO with interrupts.

    Peter John said:
    What do you mean by SW collateral?

  • Hi Amit, Yes I've opened that code and because it used the FIFO with interrupts I didn't utilise it.
    Are you suggesting that my code looks fine as it is and you are unsure what is causing the problem?
    If you read the other thread I referred to above it might help you understand the problem and potential solutions canvassed

    Peter
  • Hello Peter,

    The FIFO and Burst model was primarily provided for use with interrupts and/or DMA to reduce the CPU intervention and bandwidth for managing the I2C controller.

    Now based on your code, I don't see what the sequence of operations are? Is it a pure Receive operation or is it a Transmit followed by a Repeated Start and Receive operation on the I2C bus.
  • Yes I realise the code and architecture is geared around around the FIFO with interrupts and dma, but that is not a strick requirement.
    The sensor I read from shares the bus with two others so regularly I need to populate the correct i2C parameters in the first function, then the second and third functions reach read out one bite each from the FIFO . Every 1kHz the cycle starts again. Any start command have been previously issued and the sensor runs continuously.
  • Hello Peter

    Instead of using the I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START when starting the transaction use I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH. Since you are starting from Idle state with FIFO and Burst mode.
  • Hi Amit,

    Unfortunately your suggestion didn't work, but I found the solution thanks to your explanation !  When I tried your suggestion, NO I2C transactions took place at all.

    To solve the problem all I had to do was replace I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START  with I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE in the first function named initiate_Rx() .  I still kept the I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH in the second function.   The Master now properly sends a NAK after reading the 2nd byte, using the following code:

    void initiate_Rx(uint32_t i2c_base, uint8_t addr)
    {
        I2CMasterSlaveAddrSet(i2c_base, addr, true);
        I2CRxFIFOConfigSet(i2c_base, (I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_2));
        I2CRxFIFOFlush(i2c_base);
        I2CMasterBurstLengthSet(i2c_base, 0x02);
        I2CMasterControl(i2c_base,I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);//Note, using I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START here does not result in the desired NAK from Master after it reads the second byte, instead at the 4th byte (and we only want to read 2 bytes) 
    }
    
    uint8_t readFirstMeasByte(uint32_t i2c_base)
    {
        uint8_t meas_byte;
        while ((I2CFIFOStatus(i2c_base))&I2C_FIFO_RX_EMPTY);
        I2CFIFODataGetNonBlocking(i2c_base, &meas_byte);
        I2CMasterControl(i2c_base,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH);
        meas_byte&=(uint8_t)0x3F;//mask off the top two most significant bits as these are status bits 
        return meas_byte;
    }
    
    uint8_t readSecondMeasByte(uint32_t i2c_base)
    {
        uint8_t meas_byte;
        while ((I2CFIFOStatus(i2c_base))&I2C_FIFO_RX_EMPTY);
        I2CFIFODataGetNonBlocking(i2c_base, &meas_byte);
        return meas_byte;
    }

    Thanks for your very timely assistance Amit.

    Peter

  • Hello Peter

    Thanks for posting back. I looked at my code also and realized that the code has already issues a Start condition during transmit section as the slave device required an memory address before it could return data. That was something I did not factor in.

    Thanks for updating...