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 Interrupt

Hi team,

I'm working on developing code for an I2C slave that triggers an interrupt once the FIFO is full.

I am successfully entering my ISR but I am having trouble clearing the interrupt bit. Once I exit my ISR it returns to it immediately afterwards.

Here is what I have in my main to enable the interrupt:

I2CSlaveIntEnableEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_FULL);

And here is what I have in my ISR to clear the interrupt:

I2CSlaveIntClearEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_FULL);

Looking at the I2C registers, I see that the RXFFRIS bit is not cleared in the I2CSRIS register.

Regards,

Akash Patel

  • Hello Akash

    When the RX FIFO is full, does the CPU read the FIFO to clear the condition?
  • Hi Amit,

    I wait for the FIFO to contain 8 elements (i.e. be full) to call the interrupt. Then, once in the ISR I go ahead and read them. Here is the whole code for my ISR:

    void I2CSlaveISR(void)
    {
    
    	I2CSlaveIntClearEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_FULL);
    
    	UARTprintf("In I2C0 ISR\n");
    
    	uint8_t i;
    
    	for (i = 0 ; i < 8; ++i){
    
    		// Get the data from the FIFO
    		pui32DataRx[i] = I2CFIFODataGet(I2C0_BASE);
    
    		// Display the data that the slave has received.
    		UARTprintf("Received: '%c'\n", pui32DataRx[i]);
    
    	}
    
    	I2CRxFIFOFlush(I2C0_BASE);
    
    }

  • Hello Akash

    First read the data based on the interrupt status, then clear the interrupt status. Once it is completed make sure by checking via the debugger, that no other interrupt status bit in the I2CSMIS register are set.
  • Hi Amit,

    Thanks for suggestion, I can give that a try tomorrow, however, I see the below note in the User's Guide. If I read the data and then clear the interrupt status, then it will be last action in my interrupt handler which is contrary to the below note.

    "Because there is a write buffer in the Cortex-M processor, it may take several clock cycles before the interrupt source is actually cleared. Therefore, it is recommended that the interrupt source be cleared early in the interrupt handler (as opposed to the very last action) to avoid returning from the interrupt handler before the interrupt source is actually cleared. Failure to do so may result in the interrupt handler being immediately reentered (because the interrupt controller still sees the interrupt source asserted)."

    Regards,
    Akash Patel
  • Hello Akash

    Yes, that is correct, when the interrupt source has to be synchronized across clock domains during the clear operation..

    I am more interested in knowing which all interrupt sources for the I2C slave are enabled and which one are not cleared....
  • Hi Amit,

    Thanks for your help! I am now clearing the interrupt at the end and it seems to be working!

    Here is my new ISR code:

    void I2CSlaveISR(void)
    {
    
    	UARTprintf("In I2C0 ISR\n");
    
    	uint8_t i;
    
    	for (i = 0 ; i < 8; ++i){
    
    		// Get the data from the FIFO
    		pui32DataRx[i] = I2CFIFODataGet(I2C0_BASE);
    
    		// Display the data that the slave has received.
    		UARTprintf("Received: '%c'\n", pui32DataRx[i]);
    
    	}
    
    	I2CSlaveIntClearEx(I2C0_BASE, I2C_SLAVE_INT_RX_FIFO_FULL);
    
    }

    Here is what my interrupt register looks like as I exit the ISR:

    Regards,

    Akash Patel

  • Hello Akash

    Sorry, but I should have asked for the content of I2C_SIM register as well.
  • Hi Amit,

    Sorry about that, here is the I2C_SIMR register:

    Another question that I had was with regards to configuring the FIFO and the FIFO trigger.

    I have this piece of code to configure the FIFO:

    I2CRxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_RX_SLAVE | I2C_FIFO_CFG_RX_TRIG_7));

    Can you explain the trigger operation?

    I have the trigger level set to 7. From my understanding this trigger is used if you want to trigger when there are 7 or more items in the FIFO. Is there an associated interrupt that will fire so when there are >= 7 in the FIFO? As you see above right now I am using the FIFO Full interrupt.

    Regards,

    Akash Patel

  • Hello Akash

    Thanks for the info on the IM register. As for the trigger question, it is the RXMIS bit that shall be set when the trigger level is crossed when RXIM bit is set for interrupt generation.
  • Hi Amit,

    I am now trying to build the accompanying master code for this. I want to set up multiple I2C Masters on one TIVA board to continuously transmit data. I am starting out with just one I2C first and then will expand to multiple. Below is the code that I have, however, I am having issues triggering the interrupt and entering the ISR. Any suggestions on what I can do to enter the ISR?

    int
    main(void)
    {
    
    	g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    			SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
    			SYSCTL_CFG_VCO_480), 120000000);
    
    	// Set up the serial console
    	InitConsole();
    
    	// Display title
    	UARTprintf("I2C Evaluation - Master\n");
    
    	// Enable & configure I2C0, pb2 - scl, pb3 - sda
    	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);
    
    	IntMasterEnable();
    
    	// Enable the I2C0 master module.
    	I2CMasterEnable(I2C0_BASE);
    
    	// Initialize the I2C clock
    	I2CMasterInitExpClk(I2C0_BASE, g_ui32SysClock, false);
    
    	// Set the slave address
    	I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS0, false);
    
    	// Set up the TX FIFO
    	I2CTxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_TX_MASTER);
    
    	// Enable I2C0 interrupts
    	I2CMasterIntEnableEx(I2C0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    	IntEnable(INT_I2C0);
    
    	I2CTxFIFOFlush(I2C0_BASE);
    
    	// Indicate the direction of the data.
    
    	UARTprintf("Tranferring from: Master -> Slave\n");
    
    	I2CFIFODataPut(I2C0_BASE, 0x48);
    
    	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_SINGLE_SEND);
    
    	while (1);
    
    }
    
    void I2C0MasterISR(void)
    {
    
    	UARTprintf("In I2C0 ISR\n");
    
    	uint8_t i;
    
    	for (i = 0 ; i < 8; ++i){
    
    		// Put the data on the FIFO
    		I2CFIFODataPut(I2C0_BASE, (i + 72));
    
    		// Display the data put on the FIFO
    		UARTprintf("Put onto FIFO: '%c'\n", (i + 72));
    
    	}
    
    	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	I2CMasterIntClearEx(I2C0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
    }

    Regards,

    Akash Patel

  • Hello Akash

    1. Do you have an external pull up resistor on the SCL and SDA on the board?
    2. You need to program the burst length when using the FIFO. I don't see that being programmed
    3. Also the FIFO trigger level is not programmed either.

    As I mentioned, please use the example in the Application Note as a starting point.

    www.ti.com/.../spma073.pdf
  • Hi Amit,

    Thanks for the quick response again.

    1. I do have an external pull up resistors. I'm using an Aardvark I2C tool as a slave to receive the data from the TIVA master and it is able to receive the data that I am transmitting on line 49.
    2. I realize that the burst length is not programmed but given that is it not entering the ISR yet I figured I would do that afterwards. I can program it using: I2CMasterBurstLengthSet(I2C0_BASE, 8), correct?
    3. Do I have to use a FIFO trigger? I only want the interrupt to be fired when the FIFO is empty as in line 38.

    I looked through the example in the application note but I saw that it is more relevant to triggers and could not figure out why my code is not causing the FIFO_EMPTY interrupt to fire.

    Regards,
    Akash Patel
  • Hello Akash

    How does the FIFO know which level to use for the trigger. If it is not programmed, then the API may program something which is not expected by the application. As for programming the Burst Length, that is the correct usage model.

    Also since you have a Slave already, I would suggest using the Application Note example as a starting point.

    On the master side you need I2C_MASTER_INT_TX_FIFO_REQ for the starting interrupt mask.
  • Hi Amit,

    I added the trigger functionality although I'm still not sure why I need that because I only wanted the interrupt to fire when my FIFO is empty and there is an interrupt for that already. I looked at the app note and now I have the code going into the ISR once but then it doesn't fire another interrupt after that even though the FIFO is empty and I am below the trigger.

    int
    main(void)
    {
    
    	g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    			SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
    			SYSCTL_CFG_VCO_480), 120000000);
    
    	// Set up the serial console
    	InitConsole();
    
    	// Display title
    	UARTprintf("I2C Evaluation - Master\n");
    
    	// Enable & configure I2C0, pb2 - scl, pb3 - sda
    	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);
    
    	IntMasterEnable();
    
    	// Enable the I2C0 master module.
    	I2CMasterEnable(I2C0_BASE);
    
    	// Initialize the I2C clock
    	I2CMasterInitExpClk(I2C0_BASE, g_ui32SysClock, false);
    
    	// Set the slave address
    	I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS0, false);
    
    	// Set up the TX FIFO
    	I2CTxFIFOConfigSet(I2C0_BASE, I2C_FIFO_CFG_TX_MASTER | I2C_FIFO_CFG_TX_TRIG_4);
    
    	I2CTxFIFOFlush(I2C0_BASE);
    
    	// Enable I2C0 interrupts
    	I2CMasterIntEnableEx(I2C0_BASE, (I2C_MASTER_INT_TX_FIFO_REQ|I2C_MASTER_INT_TX_FIFO_EMPTY));
    	I2CMasterBurstLengthSet(I2C0_BASE, 8);
    	IntEnable(INT_I2C0);
    
    	// Indicate the direction of the data.
    
    	UARTprintf("Tranferring from: Master -> Slave\n");
    
    	I2CFIFODataPut(I2C0_BASE, 0x48);
    
    	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_SINGLE_SEND);
    
    	while (1){
    	}
    
    }
    
    void I2C0MasterISR(void)
    {
    
    	UARTprintf("In I2C0 ISR\n");
    
    	uint8_t i;
    
    	for (i = 0 ; i < 8; ++i){
    
    		// Put the data on the FIFO
    		I2CFIFODataPut(I2C0_BASE, (i + 72));
    
    		// Display the data put on the FIFO.
    		UARTprintf("Put onto FIFO: '%c'\n", (i + 72));
    
    	}
    
    
    	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	I2CMasterIntClearEx(I2C0_BASE, (I2C_MASTER_INT_TX_FIFO_REQ | I2C_MASTER_INT_TX_FIFO_EMPTY));
    
    }

    Regards,

    Akash Patel

  • Hello Akash

    The Busrt length decides if any further interrupt needs to be asserted. if the burst length worth of data has been received by the I2C controller, no further interrupts w.r.t to the transaction and FIFO are needed.