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 Interrupt quesiton

Part Number: TM4C123GH6PM


I'm confused...

I2cStateMachine.slaveAddress = MCP23017_BUS_ADDRESS_AZ;
I2cStateMachine.registerAddress = MCP23017_GPIOA_DIR_REG;
memset(&I2cStateMachine.dataBytes, 0, 2);
I2cStateMachine.dataSize = 2;
IntTrigger(INT_I2C0);
while (I2cStateMachine.currentState != I2C_STATE_STOP);
I2cStateMachine.currentState = I2C_STATE_IDLE;

int i = 0;
while (i < 1000000) { i++;}

When I run the following code, I get a total of five interrupts generated by the I2C master.  The first is 0x00 which I assume is a result of the call to IntTrigger(INT_I2C0) used to initiate the transaction.  I am sending two bytes.  The first is the register address of the remote device and the second byte is the data to write to that register.  My interrupt handler is called four more times, all with the interrupt bit 0x0001

#define I2C_MASTER_INT_DATA     0x00000001  // Data Interrupt   <===  from the I2c.h file in driverlib.

I only expected two interrupts, one at the completion of each byte.  What am I missing??

  • Hi Brian,
    Please check the ISR and make sure the flag is not cleared too late before the ISR is exited. If the clearing of the interrupt flag is done at the very end of the ISR then it can re-enter again after it exited. There is some race condition because it takes some cycle before the write to clear the flag to reach the actual flip-flop.
  • Clearing the interrupt is the first thing I do in the ISR.

    void I2C0IntHandler(void) {

         uint32_t ui32I2CMasterInterruptStatus;

         // Get the masked interrupt status and clear the flags

         ui32I2CMasterInterruptStatus = I2CMasterIntStatusEx(I2C0_BASE, true);

         I2CMasterIntClearEx(I2C0_BASE, ui32I2CMasterInterruptStatus);

         switch(I2cStateMachine.currentState) {

         case I2C_STATE_IDLE:

    // Send the address byte

    I2CMasterSlaveAddrSet(I2C0_BASE, I2cStateMachine.slaveAddress, I2C_OP_WRITE);

    I2CMasterDataPut(I2C0_BASE, I2cStateMachine.registerAddress);

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    I2cStateMachine.currentState = I2C_STATE_DATA;

    byteCount = 0;

    break;

    case I2C_STATE_DATA:

    if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK) {

    I2cStateMachine.currentState = I2C_STATE_STOP;

    } else {

    I2CMasterDataPut(I2C0_BASE, (uint8_t)(I2cStateMachine.dataBytes[byteCount]));

    byteCount++;

    if (byteCount < I2cStateMachine.dataSize) {

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

    I2cStateMachine.currentState = I2C_STATE_DATA;

    } else {

    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

    I2cStateMachine.currentState = I2C_STATE_STOP;

    }

    }

    break;

    }

    }

     

  • One things I've noticed is that if I read the I2C Master Control/Status (I2CMCS) register in the ISR, it toggles between IDLE and BUSBUSY.

    interrupt 0 - IntTrigger() call, the IDLE bit is set, the first byte is written.
    Interrupt 1 - BUSBUSY is set, the second byte is written
    Interrupt 2 - IDLE
    Interrupt 3 - BUSBUSY
    Interrupt 4 - IDLE

    I tried exiting the ISR and doing nothing when the BUSBUSY bit was set and it just hung up.
  • According to the data sheet, the interrupt is asserted upon completion of a transaction, which I would assume to mean that when the bus state changes from busy to idle it would generate the interrupt, but it seems to generate the interrupt when is starts and completes?
  • Brian,
    I will suggest some experiments. What if you send just one byte instead of two bytes? What about not sending any byte? How many interrupts do you get for each? Please also setup a watchpoint for write to address 0x4002_0004 which is the I2CMCS register. Check how many times the I2CMCS is written to and for each write what values are written.
  • Charles  - 

    I was able to get it working.  I'm not sure that it is the best approach, but here it is...

    These three lines were added to he interrupt handler, so that I only transition to the next state of my state machine when the interrupt occurs and the bus is idle.

    Thoughts?

    uint32_t MRIS_R = I2C0_MRIS_R;

    I2CMasterIntClear(I2C0_BASE);

    if ((I2C0_MCS_R & 0x00000020) && (MRIS_R & 0x00000001)) { return; }

  • Hi Brian,

     I believe you had below line shown in another post:

    I2CMasterIntEnableEx(I2C0_BASE, (I2C_MASTER_INT_ARB_LOST | I2C_MASTER_INT_STOP | I2C_MASTER_INT_NACK |

    I2C_MASTER_INT_TIMEOUT | I2C_MASTER_INT_DATA));

    Can you try with:

    I2CMasterIntEnableEx(I2C0_BASE, (I2C_MASTER_INT_TIMEOUT | I2C_MASTER_INT_DATA));

    The reason is that you ported the sample code that was created for TM4C129 to TM4C123. The TM4C123 has only two sources of interrupt. Please see below. I just wanted to make sure the extra interrupts are not due to some phantom events. 

  • Is there an example or sample code for interrupt driven I2C on the Tm4C123? I thought I had it, but it's still not working.
  • Hi Brian,
    The i2c examples are under <TivaWare_Installation>\examples\peripherals\i2c. However, only one of them is interrupt driven and it is for the slave, not master. I think if you search a bit in the forum you will find some interrupt-driven code for TM4C123. I will do some searching too.