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.

TM4C129 I2C FIFO trigger levels - documentation bug in datasheet?

Other Parts Discussed in Thread: TM4C1294NCPDT

Hi,

I'm working with the I2C FIFO operation (without DMA for now), and discovered what I think is a bug in the datasheet. The device I have is the TM4C1294NCPDT on the Connected LaunchPad. The datasheet I'm looking at is dated June 18, 2014 and is what TI currently links to from the MCU product page.

On pages 1350-1351 you'll find the register description for I2CFIFOCTL. The datasheet says that the RX trigger level is defined by bits 18:16 and TX by 2:0. Thus, the effective values one can write to those bits range from 0 to 7.

When I look at the current version of TivaWare (2.1.0.12573, past it's 1st birthday, by the way), in driverlib/i2c.h on lines 246-263 I can see the definitions for the RX/TX trigger levels. What baffles me are the _RX/TX_TRIG_8 options, as they occupy bits 19 and 3, respectively.

Now, given the general quality of the current TivaWare, I thought it's just another bug. But I decided to look further - hooked up a logic analyzer and set up an interrupt handler for I2C_MASTER_INT_RX_FIFO_REQ. It appears that at least _RX_TRIG_8 does indeed work as expected - didn't test any of the TX triggers. Also, _RX_NO_TRIG seems to equal _RX_TRIG_1.

For what it's worth, I tried all _RX_TRIG_n/_RX_NO_TRIG options and with the exception of _RX_NO_TRIG, they function as one would expect. And if it makes any difference, I used GPIO_PN5_I2C2SCL + GPIO_PN4_I2C2SDA and the slave device was an Atmel 24C256 EEPROM.

So, are bits 19 and 3 in I2CFIFOCTL indeed operational contrary to what the datasheet says? The author of the TivaWare I2C driver seems to know their true function... The TM4C129 errata doesn't list any I2C related issues.

  • May I note 2nd "great" post arriving this (early USA) Sunday morn? Past it's 1st birthday indeed - and for sure - PF0/PD7 will (still) lurk buried in monochromatic/size conformity - escaping their (much & long needed) proper highlight.

    Loved the organization of your post - and how you "rolled out" point by point - your investigatory findings.

    Our group has long feared both "rebrandWare" and this Cadillac device family. One wonders if the base 123 devices employ similar internals - and if - due to their greater maturity - review of their "internals" sheds added light?

    Good job though - especially your (cover) w/"I think is a bug..." (beware those w/100% confidence - too often proves their test/methodology was/is inadequate...)

  • Thanks for your kind words, cb1. The 123 I2C does not have a FIFO to begin with, so no help from there, I'm afraid.
  • @Veikko,

    Veikko Immonen said:
    The 123 I2C does not have a FIFO

    Bloody strange that - especially as LX4F/TM4C123 enjoys FIFO upon SPI, UART, ADC, & other peripherals - but indeed - you're right!   (and - some note - flawed test/methodology "did in" my suggestion...)   (may result from our use of many vendor's ARM MCUs - locking oneself in too often (always) proves unwise...)

    I did recall using the LX4F's SPI FIFO (recently) to "talk to" one of our firm's TFTs - led me to my mistaken "promotion" of FIFO to I2C. 

    Amit should (shortly) arrive w/insider info...

  • Veikko Immonen said:
    So, are bits 19 and 3 in I2CFIFOCTL indeed operational contrary to what the datasheet says?

    I created a simple test program for a TM4C1294NCPDT which wrote different values to the I2CFIFOCTL registers, and then read back the registers to detect which bits were writeable (since reserved bits are read-only).

    The bits which were detected as writeable were 31, 29, 19-15, 13, 3-0. i.e. since bits 19 and 3 are writeable that suggests they are actually control bits and there is an error in the datasheet.

    Note that this simple test didn't detect bits 30 (RXFLUSH) or 14 (TXFLUSH) as writeable since those bits are documented as self-clearing and during the simple test there was no data in the FIFOs at the time.

  • Thanks Chester, this is good info. And what a wonderful simple idea to employ in the future should one wonder the validity of register documentation.

    Meanwhile, I digged a little further - in the inc/hw_i2c.h file, on lines 430-439, there are defines regarding the values of the I2CFIFOCTL register. I2C_FIFOCTL_RXTRIG_M for example has a value of 0x00070000, which is in agreement with the datasheet.

    The only thing that makes sense is that different people wrote the "register access" and "software driver" files and the one who wrote the "software" version had more intimate knowledge of the I2C module internals.

  • Hello Veikko,

    Really appreciate taking time to minutely incising the i2c file and design. So a genuine "Thank You".

    Now to the issue at hand: The FIFO is 8 locations deep and not 16 locations deep. However the FIFOCTL has 4 bit location for the trigger which would give it the impression that the FIFO is 16 locations deep. The 4th bit (bit-3 as referred to in your original post) is a place holder if the FIFO needs to be expanded. Having 1 FLOP for future changes is not as costly as having a 16 location FIFO, hence it remains there. In fact there are other registers in the device which have the capability for expansion and so spare flops are there in the register interface. But with no connectivity to the core design they remain user viewable but not user code affected.
    Why it still works is because by writing the value 0x8, the actual value being used is 0x0 which is NO TRIG. Also in the data sheet for RXTRIG there is a NOTE
    "Note: Programming RXTRIG to 0x0 has no effect since no data is present to transfer out of RX FIFO."
    So your device will still work but with the TRIG value of 0x8.

    Now the data sheet mentions unused locations to be at their reset values, and this macro define violates the rule...

    Regards
    Amit
  • Amit,

    Thanks for the reply, I thought it must be something like that. But there's a problem, the described behaviour is not what I'm seeing...

    When I have:

    I2CRxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_NO_TRIG));

    I see the FIFO request interrupt being fired after every byte. The same with _RX_TRIG_1. But when I change that to:

    I2CRxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_8));

    I see the interrupt firing only every 8 bytes... Which would be equal to having an interrupt on RX FULL, but I don't have that interrupt enabled.

    EDIT: I'll add the source of my test program (Amit, you might find some similarities to one of your demo codes.. :-) ):

    #include <driverlib/i2c.h>
    
    #define SLAVE_ADDRESS 0x50
    
    uint8_t* I2C2_RX_ReadPtr;
    uint8_t I2C2_RX_ReadCounter = 0;
    uint32_t I2C2_IntCounter = 0;
    
    void I2C2_IntHandler(void) {
    	// Set debug pin 0
    	GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, GPIO_PIN_0);
    	while(I2CFIFODataGetNonBlocking(I2C2_BASE, I2C2_RX_ReadPtr) != 0) {
    		I2C2_RX_ReadPtr++;
    		I2C2_RX_ReadCounter++;
    		if(I2C2_RX_ReadCounter == 12) {
    			break;
    		}
    	}
    	I2CMasterIntClearEx(I2C2_BASE, I2C_MASTER_INT_RX_FIFO_REQ);
    	// Unset debug pin 0
    	GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0);
    	I2C2_IntCounter++;
    }
    
    void main(void) {
        uint8_t 	ui8I2CTransmitData[2] = {0x42, 0x65}; // The EEPROM memory location
        uint8_t 	ui8I2CReceiveData[12]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        uint32_t 	ui32SysClock;
        uint32_t    ui32Index;
    
        ui32SysClock = SysCtlClockFreqSet(SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_CFG_VCO_480, 120000000);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
        SysCtlDelay(10);
    
        GPIOPinConfigure(GPIO_PN5_I2C2SCL);
        GPIOPinConfigure(GPIO_PN4_I2C2SDA);
        GPIOPinTypeI2CSCL(GPIO_PORTN_BASE, GPIO_PIN_5);
        GPIOPinTypeI2C(GPIO_PORTN_BASE, GPIO_PIN_4);
    
        GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_0|GPIO_PIN_1);
        GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0|GPIO_PIN_1, 0);
    
        //
        // Configure The I2C Master
        //
        I2CMasterInitExpClk(I2C2_BASE, ui32SysClock, false);
        I2CTxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_TX_MASTER|I2C_FIFO_CFG_TX_TRIG_3));
        //I2CRxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_NO_TRIG));
        I2CRxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_1));
        //I2CRxFIFOConfigSet(I2C2_BASE,(I2C_FIFO_CFG_RX_MASTER|I2C_FIFO_CFG_RX_TRIG_8));
        I2CTxFIFOFlush(I2C2_BASE);
        I2CRxFIFOFlush(I2C2_BASE);
    
        // Configure the RX FIFO request interrupt
        I2CMasterIntEnableEx(I2C2_BASE, I2C_MASTER_INT_RX_FIFO_REQ);
        I2CIntRegister(I2C2_BASE, I2C2_IntHandler);
    
        // Write the EEPROM memory address
        I2CMasterBurstLengthSet(I2C2_BASE,2);
        I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, false);
        for(ui32Index=0;ui32Index<2;ui32Index++)
        {
        	I2CFIFODataPut(I2C2_BASE, ui8I2CTransmitData[ui32Index]);
        }
        I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_START);
        while(!(I2CMasterBusy(I2C2_BASE)));
        while(I2CMasterBusy(I2C2_BASE));
    
        // Set debug pin 1
        GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, GPIO_PIN_1);
    
        // Read data from the EEPROM
        I2CMasterBurstLengthSet(I2C2_BASE,12);
        I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, true);
        I2C2_RX_ReadPtr = ui8I2CReceiveData;
        I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);
        while(!(I2CMasterBusy(I2C2_BASE)));
        while(I2CMasterBusy(I2C2_BASE));
    //    for(ui32Index=0;ui32Index<8;ui32Index++)
    //    {
    //    	ui8I2CReceiveData[ui32Index] = I2CFIFODataGet(I2C2_BASE);
    //    }
    
        // Unset debug pin 1
        GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0);
    
        while(1);
    }
    

  • Hello Veikko,

    Yes, I agree with you. After my last post I had to dig deep into the I2C FIFO workings and it seems that you are right and I was mistaken-ed. The path exists for comparison of the bit-3 since it has a equal to function as well. However I would still need to run some tests to see that the path is active (not that I do not trust your observations and results).
    I believe at this point the right approach would be to correct TivaWare for excluding this define and keep DS and SW inline.

    Regards
    Amit
  • Amit Ashara said:
    with no connectivity to the core design they remain user viewable but not user code affected. 

    May I memorialize Amit's "very clever/precise" writing - above.   I'd have assumed/guessed that "viewable" = code affected/impacted.

    Clearly something's in the air/water this Sunday - cascade of well thought/composed (and responded) posts - nary a, "Don't Work" in the bunch.   (but they're surely "at the gates.")

  • One last gasp here:

    Not to "silence the applause" but Veikko's findings (seemingly) point to a "breakdown" between MCU documentation staff and/or work-flow "check-balance."   As he noted (twice) someone knew "what's what" - yet the manual was released w/out the "irregularity" being properly flagged - and that should not be...  (i.e. points to a potential "system weakness" - suggests that necessary documentation management "inter-locks" are not fully - nor correctly emplaced...)

    As proof - even heralded "insider information" could not quickly bring this issue to bay.   Little (i.e. NO) chance for we outsiders...