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.

TM4C129x I2C FIFO Operation

Other Parts Discussed in Thread: TMP100

Hi, Everyone

I need your help. I want to use I2C with FIFO on TM4C129x. but I do not understand FIFO Operation.

I try to loopback mode. How to store data to TX FIFO and How to get data from RX FIFO.

Tivaware has I2CFIFODataGet(). but it can get only single byte.

I do not understand this operation.

===================================

int main(void)

{     uint8_t ui8DataTx[8];

    SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |                                                  SYSCTL_CFG_VCO_480), 120000000);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    GPIOPinConfigure(GPIO_PB2_I2C0SCL);

    GPIOPinConfigure(GPIO_PB3_I2C0SDA);

    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);

    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

     HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;

    IntEnable(INT_I2C0);

    I2CSlaveIntEnableEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_FULL);

    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);

    I2CSlaveEnable(I2C0_BASE);

    I2CSlaveInit(I2C0_BASE, SLAVE_ADDRESS);

    I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false);

    I2CSlaveIntEnable(I2C0_BASE);

    //Tx FIFO Config

    I2CTxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_TX_MASTER|I2C_FIFO_CFG_TX_TRIG_8);     I2CRxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_RX_SLAVE|I2C_FIFO_CFG_RX_TRIG_8);     I2CSlaveFIFOEnable(I2C0_BASE,I2C_SLAVE_RX_FIFO_ENABLE);

    //     // Enable interrupts to the processor.     //

    IntMasterEnable();

    //     // Initialize the data to send.     //

    ui8DataTx[0] = 0x11;

    ui8DataTx[1] = 0x22;

    ui8DataTx[2] = 0x33;

    ui8DataTx[3] = 0x44;

    ui8DataTx[4] = 0x55;

    ui8DataTx[5] = 0x66;

    ui8DataTx[6] = 0x77;

    ui8DataTx[7] = 0x88;

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[0]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[1]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[2]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[3]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[4]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[5]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[6]);

    I2CFIFODataPut(I2C0_BASE,ui8DataTx[7]);

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_START);

    while( I2CMasterBusy(I2C0_BASE));

    //     // Loop forever.     //

    while(1)     {     } }

void I2C0SlaveIntHandler(void)

{

    //     // Clear the I2C0 interrupt flag.     //

    I2CSlaveIntClear(I2C0_BASE);

    //     // Read the data from the slave.     // //

    I2CFIFODataGetNonBlocking(I2C0_BASE,&g_ui8DataRx);

}

============================

Best Regards

Hiroyasu

  • Hello Hiroyasu,

    The I2C FIFO is accessible through the FIFO Data register at offset 0xF00. When a write is done the data goes to the TXFIFO. When a Read is done the data comes from the RXFIFO.

    The I2CFIFODataGet will get only one byte at a time. The true value of the FIFO comes when the uDMA is used.

    Regards

    Amit

  • Hi Amit,

    I need help using the I2C FIFO with the TM4C129X under software (not uDMA) control .   There are no examples showing what to do.

    I intend to transfer two or three bytes from a slave sensor into the I2C Rx FIFO for the Master to read in one go (well in three fast back to back sequential calls to I2CFIFODataGet) once all 2 or 3 bytes have arrived in the FIFO.

    I do not want to use interrupts but instead will poll the I2CFIFOStatus or even I2CMasterBurstCountGet (I will be polling many other sensors too waiting for their data to be ready because that's all I need to do in this loop).  For all but the last byte arriving at the FIFO I need the master to send an ACK which will initiate the slave to transmit the next byte.   So far I can only read one byte from the I2C Rx FIFO.  I have tried setting I2CMasterBurstLengthSet to 2 or 3 but it hangs and only works with I2CMasterBurstLengthSet =1.  I also try reading I2CMasterBurstCountGet but it is always zero even when data is clearly in the FIFO (I know this because I read out the data after the I2CFIFOStatus changes from I2C_FIFO_RX_EMPTY to I2C_FIFO_RX_BELOW_TRIG_LEVEL).

    Another thing I don't understand, irrespective of whether I use I2CRxFIFOConfigSet to set the I2C_FIFO_CFG_RX_TRIG_1 or I2C_FIFO_CFG_RX_TRIG_2 , when one byte is in the FIFO the FIFO Status always reads I2C_FIFO_RX_BELOW_TRIG_LEVEL.  I would expect that only to be the case when I set the trigger level to 2 but not 1.

    So my questions are:

    1. Can I use the Rx FIFO in the manner I describe ?  If so how ?
    2. Why does setting I2CMasterBurstLengthSet to 2 or higher cause a hang?
    3. Should I see I2CMasterBurstCountGet decrementing from an initial non zero value ?

    So here is my code.

    //the following code successfully reads two bytes with the FIFO only filling up 1 byte full each time before each byte is read.
    
    I2CRxFIFOConfigSet(I2C0_BASE,I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_1)
    I2CMasterBurstLengthSet(I2C0_BASE,1); //appears to have no effect on I2CMasterBurstCountGet
    I2CMasterControl(I2C0_BASE,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START);
    ROM_SysCtlDelay(300);//only for debugging purposes to show that the I2CFIFOStatus changes once data is in Rx FIFO
    //I2CFIFOStatus(I2C0_BASE) returns I2C_FIFO_RX_BELOW_TRIG_LEVEL just prior to data being available
    raw_flow_high_byte =(uint8_t) I2CFIFODataGet(I2C0_BASE)
    //I2CFIFOStatus(I2C0_BASE) returns I2C_FIFO_RX_EMPTY just after data is read
    I2CMasterControl(I2C0_BASE,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH); //read last byte with FINISH.  This means NACK is given and thus no CRC will be sent out by the slave.
    raw_flow_low_byte =(uint8_t) I2CFIFODataGet(I2C0_BASE)
    raw_flow_two_bytes=raw_flow_high_byte<<8|raw_flow_low_byte;

  • Hello Peter,

    What you have mentioned is possible. You can setup the Burst Count to transfer the data. Now it depends on how the sensor is supposed to send the data to the master. Does it accept a simple read I2C Frame or does it require a Transmit frame followed by a repeated start and a receive frame. That detail is not clear here.

    Typically when set up the Cortex has to wait for the I2C Burst Count to decrement to 0, before issuing any new command. So in the code you need to put a while loop for the I2CMasterBurstCountGet to become 0 before issuing the FINISH.

    Regards

    Amit

  • Amit Ashara said:
    . Does it accept a simple read I2C Frame or does it require a Transmit frame followed by a repeated start and a receive frame. That detail is not clear here.

    the slave sensor requires the Master MCU/cortex to send the address and then the slave responds with 2 or 3 bytes, after each byte the master must send an ACK.  If the Master sends a NACK after the 2nd byte then no more data will be sent from the slave.  here is the communication sequence:

    Amit Ashara said:
    Typically when set up the Cortex has to wait for the I2C Burst Count to decrement to 0, before issuing any new command. So in the code you need to put a while loop for the I2CMasterBurstCountGet to become 0 before issuing the FINISH.

    OK, but will the Cortex MCU automatically issue an ACK after it receives each data byte until I issue FINISH  ?. Up until now this ACK or NACK is only issues after I call either I2CMasterDataGet or I2CFIFODataGet.  This FIFO will only be useful if the MCU automatically issues the ACK so the code can be off doing other things.

  • Amit, will the Cortex MCU automatically issue an ACK after it receives each data byte until I issue FINISH  ?. Up until now this ACK or NACK is only issued after I call either I2CMasterDataGet or I2CFIFODataGet.  This FIFO will only be useful if the MCU automatically issues the ACK so the code can be off doing other things.

  • Hello Peter,

    Yes, it will ACK all bytes till the FINISH is issued. If the FIFO gets FULL, it will stall the bus till the FIFO has space available. I am working on a version of the FIFO code, and should be able to share the same next week.

    Regards

    Amit

  • Excellent, thanks Amit !    I look forward to seeing your example code :)

  • Amit Ashara said:
    I am working on a version of the FIFO code, and should be able to share the same next week.

    Hi Amit,  any progress on this ?

  • Hello Peter

    Yes, Code is in Testing Phase. The forum should have it soon...

    Regards

    Amit

  • Hello Peter

    Attached is the CCS project for using I2CFIFO Mode. I have tested this on the DK-TM4C129 with a Temp Sensor on I2C-6 Bus.

    2626.TM4C129_I2CFIFO.7z

    Regards

    Amit

  • Amit Ashara said:
    Attached is the CCS project for using I2CFIFO Mode.

    THANK YOU Amit !!  I plan to test it out today.

  • Proect compiled and ran fine, however the data being returned from the TMP100 (U4) temp sensor was constant (not varying when I heated up U4 with my breath or finger) and I think the data is incorrect.  I added a watch expression for ui8I2CReceiveData but it gave me null values in the IDE, so then I added the following line to print out the data

    UARTprintf("I2CReceiveData[0..2]=0x%02x%02x%02x,\n",ui8I2CReceiveData[0],ui8I2CReceiveData[1],ui8I2CReceiveData[2]);

    which always gave:

    I2CReceiveData[0..2]=0x81F0FF

    Looking at p.6 of the TMP100 datasheet from Farnell here (TI website had hung when I tried locating the datasheet) only the first 12 bits are valid and you only need to read 2 x 8 bit bytes of data (not three as you did).

    I think the temp range -128,..,0,..,+128  linearly maps between -0x7FF,..,0x000,..,0x7FF = -2047,..+2047

    i.e. 1/16th of a degree LSB.

    So why is the result incorrect and constant ?

    regards

    Peter

  • Hello Peter

    My apologies: I should have mentioned the register that I used in the example.

    The register write and read is to the Temp Conversion low Threshold Register. It will not change. If you wish to change it to temp conversion register then in the Read Section of the code the Pointer register needs to be changed from 0x2 to 0x0 (Line 98) besides any configuration register changes.

    The intent of the example was to help build the command set for I2C Transaction using FIFO. As I mentioned true value of the FIFO is with the uDMA.

    Regards

    Amit

  • OK, thanks for clarifying Amit.  Yes the main thing you have certainly achieved was to give an example of the FIFO usage with S/W (non uDMA) reads - thank you for that.

    I will study it and apply the same to my code and let you know if I have any more questions.

    regards

    Peter

  • Amit,

    I'd like to use I2CMasterBurstCount() to determine how many more bytes are left to read in the FIFO buffer.  Is that what I2CMasterBurstCount() is used for ? Or is I2CMasterBurstCount simply I2CMasterBurstLengthSet decremented by one for each FIFO read and instead I should be using I2CFIFOStatus ?

    Here is some code I added to your project at lines 58 and 105.  Why does it seem to take hundreds of clock cycles before the I2CMasterBurstCount matches what it should be ?  I say this because unless I have the line SysCtlDelay(300); I2CMasterBurstCounts[5]=1 rather than =0 as per my UART output.

    Firstly the UART output:

    I2CReceiveData[0..2]=0x81F0FF,
    BurstCounts[0..5]=0,0,3,2,1,0

    now the code:

        uint8_t		I2CMasterBurstCounts[6] = 0x00;
    
        I2CMasterBurstLengthSet(I2C6_BASE,0x3);
        I2CMasterBurstCounts[0]=I2CMasterBurstCountGet(I2C6_BASE);
        I2CMasterSlaveAddrSet(I2C6_BASE, SLAVE_ADDRESS, true);
        I2CMasterControl(I2C6_BASE, I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);
        I2CMasterBurstCounts[1]=I2CMasterBurstCountGet(I2C6_BASE);
        for(ui32Index=0;ui32Index<3;ui32Index++)
        {
        	ui8I2CReceiveData[ui32Index] = I2CFIFODataGet(I2C6_BASE);
            I2CMasterBurstCounts[ui32Index+2]=I2CMasterBurstCountGet(I2C6_BASE);
        }
        SysCtlDelay(300);
        I2CMasterBurstCounts[5]=I2CMasterBurstCountGet(I2C6_BASE);
        UARTprintf("I2CReceiveData[0..2]=0x%02x%02x%02x,\n",ui8I2CReceiveData[0],ui8I2CReceiveData[1],ui8I2CReceiveData[2]);
        UARTprintf("BurstCounts[0..5]=%d,%d,%d,%d,%d,%d\n",I2CMasterBurstCounts[0],I2CMasterBurstCounts[1],I2CMasterBurstCounts[2],I2CMasterBurstCounts[3],I2CMasterBurstCounts[4],I2CMasterBurstCounts[5]);
    
        while(1);

  • Hello Peter,

    The primary aim of the I2CMasterBurstCount is to determine that when a Stop condition got put on the bus, then did the Transfer Complete with the Burst Length programmed. It can be used to determine the last byte read from the FIFO but do note that the last byte may not have been transferred on the bus yet.

    As mentioned earlier the Burst Count means that the byte is read from the FIFO but not yet full transmitted. The I2C Baud rate is far much less than the system clock so no wonder it will take 100's of System Clock before the Burst Count actually changes again. Did you try reading the register when the code hits the while(1) loop

    Regards

    Amit

  • Amit Ashara said:
    The I2C Baud rate is far much less than the system clock so no wonder it will take 100's of System Clock before the Burst Count actually changes again

    Thanks Amit, that makes perfect sense.

    Amit Ashara said:
    Did you try reading the register when the code hits the while(1) loop

    No I didn't,  but given how long a UARTprintf statement takes, I'm certain the I2CMasterBurstCountGet would have dropped to zero by the while(1) loop.

  • Hello Peter,

    That is what I think as well that by the time UART print is done the Burst Count register would have become 0.

    Regards

    Amit