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.

TM4C123GH6PM: I2C interrupts on TM4C123G Launchpad

Part Number: TM4C123GH6PM

My code was successfully using the polling method for I2C, interfacing with a MCP23017 bus expander.  However, due to some timing problems, I am moving to interrupt driven I2C comms to free up some CPU time.  I have based my code on the source files provided for SPMA073 found here on the TI site.  I realize that it was written for the Tm4C129x, but I was hoping to adapt it to the TM4C123.  

The first thing I noticed was that the sample code seems to be using a 16-bit register address, where I only need an 8-bit register address, so I corrected that.  I can set breakpoints in the interrupt handler and see if sends the register address and the two bytes of data (register address 0x00, data is 0x00 and 0x00, to set the bus expander ports to outputs.)  

I also see it send the last byte from  

 I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

 Then it hangs up in the while loop in the code below.  It never transitions to the I2C_OP_STOP state.  See snippet from interrupt handle at the bottom.  Any ideas??  


g_ui8MasterTxData[0] = 0x00;
g_ui8MasterTxData[1] = 0x00;
g_ui8MasterTxData[2] = 0x00;
g_ui8MasterBytesLength = 2;

//
// Set Transmit Flag and set the Page Address in
// external slave to 0x0000
//
g_bI2CDirection = false;
g_registerAddress = 0x00;
g_ui16SlaveWordAddress = 0x0;
g_ui8MasterBytes = 0;

IntTrigger(INT_I2C0);
while(g_ui8MasterCurrState != I2C_OP_STOP);
g_ui8MasterCurrState = I2C_OP_IDLE;

INTERRUPT HANDLER SNIPPET

case I2C_OP_TXDATA:
//
// Move the current state to the previous state
// Else continue with the transmission till last byte
//
g_ui8MasterPrevState = g_ui8MasterCurrState;

//
// If Address or Data has been NAK'ed then go to stop state
// If a Stop condition is seen due to number of bytes getting
// done then move to STOP state
//
if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
{
g_ui8MasterCurrState = I2C_OP_STOP;
}
else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_STOP)
{
g_ui8MasterCurrState = I2C_OP_STOP;
}
else
{
I2CMasterDataPut(I2C0_BASE, g_ui8MasterTxData[g_ui8MasterBytes++]);
if(g_ui8MasterBytes == g_ui8MasterBytesLength)
{
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
}
else
{
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
}

}

break;

  • By the way, this is the interrupt mask I use...

    // Enable the interrupts
    I2CMasterIntEnableEx(I2C0_BASE, (I2C_MASTER_INT_ARB_LOST | I2C_MASTER_INT_STOP | I2C_MASTER_INT_NACK |
    I2C_MASTER_INT_TIMEOUT | I2C_MASTER_INT_DATA));
  • Brian Savage said:

    IntTrigger(INT_I2C0);
    while(g_ui8MasterCurrState != I2C_OP_STOP);

    That, "IntTrigger()" caught my eye - is that an official function w/in the API?      (our group use (only) StellarisWare - I checked - IntTrigger() is not included, there.)

    If that suspicion proves correct (you've "invented" a function) and you become "entrapped" w/in the (immediately) following while loop - such points (much) to IntTrigger()'s failure.

    You speak of, "some timing problems" but do not detail - we've used that exact I/O expander - and no such "timing problems" were noted while polling. 

  • Hi Brian,
    I think you took the sample code from the app note, right?

    You said it finished the I2C_MASTER_CMD_BURST_SEND_FINISH. Did you see the stop bit being sent by the master? If you see the stop bit, did you see the STOPMIS bit in the I2CMMIS register getting set?
  • IntTrigger(), page 359 of the TivaWare Driver Library User Guide.  The timing issue is not the bus expander.  I use those devices in multiple designs.  The problem was my implementation of the I2C interface to them.  Writing 16-bits to two devices at 400Hz was causing an over-run in my 4kHz closed loop control system.

  • Charles -  Yes, I do see the stop bit, but it appears that the STOP interrupt is never generated?  I changed the code in the interrupt handler to force the change in state on the last byte sent. (See text in red below.  I've pasted the single case in the interrupt handler.

       case I2C_OP_TXDATA:

           //

           // Move the current state to the previous state

           // Else continue with the transmission till last byte

           //

           g_ui8MasterPrevState = g_ui8MasterCurrState;

           //

           // If Address or Data has been NAK'ed then go to stop state

           // If a Stop condition is seen due to number of bytes getting

           // done then move to STOP state

           //

           if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)

           {

               g_ui8MasterCurrState = I2C_OP_STOP;

           }

           else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_STOP)

           {

               g_ui8MasterCurrState = I2C_OP_STOP;

           }

           else

           {

               I2CMasterDataPut(I2C0_BASE, g_ui8MasterTxData[g_ui8MasterBytes++]);

               if(g_ui8MasterBytes == g_ui8MasterBytesLength)

               {

                   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

                   // Try this?

                   g_ui8MasterCurrState = I2C_OP_STOP;

               }

               else

               {

                   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

               }

           }

           break;

  • Hi Brian,

      I don't think you can use the sample code as is for TM4C123 as the sample code is written for TM4C129. If you see the below interrupt status register they are very different.

    TM4C129:

    TM4C123:

    I would tend to think that after you complete the I2C_MASTER_CMD_BURST_SEND_FINISH that is the end of the transmission. The TM4C123 will not separately generate another STOP interrupt. The I2C_OP_STOP is only a software implemented state. With your modification it should work, right?

  • Yes, I've hacked it up to work. Now I'm going to refactor it and clean it up. Thanks