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.

I2C Master Interrupt

Other Parts Discussed in Thread: CC3200, TMP006

I am trying to write a driver for the CC3200's I2C library in master mode.  I want to use interrupts - no polling.  However, my code does not work when only a single byte is written to the slave - the message is sent on the bus, but the I2C_MASTER_INT_TX_FIFO_EMPTY interrupt fires constantly.  If I try to write multiple bytes of data, then the I2C_MASTER_INT_TX_FIFO_REQ interrupt fires once per byte, which is what I want (although other interrupts fire too).  I must figure this out so I can do Write-Then-Read operations.

Below is an excerpt from my driver, containing the initialization and read functions, as well as interrupt service routine and applicable global variables.  Anyone see something I'm doing wrong?

#define I2C_READ    1                   // address bit to read from I2C device
#define I2C_WRITE   0                   // address bit to write to I2C device

volatile uint8_t *txDataPtr;            // pointer to TX data
volatile uint32_t txByteCount;          // num bytes to TX
volatile uint32_t txBytesDone;          // num bytes sent

volatile uint8_t *rxDataPtr;            // pointer to RX data
volatile uint32_t rxByteCount;          // num bytes to RX
volatile uint32_t rxBytesDone;          // num bytes received

static uint8_t i2cAddress;              // I2C address of slave

/******************************************************************************
 *
 *  Function:       I2C_ISR
 *
 *  Description:    This is the interrupt service routine registered to the
 *                  CC3200's I2C peripheral.
 *
 *****************************************************************************/

static void I2C_ISR(void)
{
    uint32_t isrSourceMask;             // bit-flags for interrupt source

    // Identify the source of the interrupt by reading Masked Interrupt Status.
    // The second argument of this function allows us to specify if we want
    // to mask the results so only enabled interrupts are returned to us.
    isrSourceMask = I2CMasterIntStatusEx(I2CA0_BASE, TRUE);

    // Search for a bit that is set, and deal with it.  Other bits will trigger
    // the ISR after this function returns, and will be dealt with later.  So
    // this block sets the precedence of the interrupt sources.
    // Also, we must clear the interrupt bit of anything we service, or it will
    // cause another interrupt once this function exits.
    if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_REQ)
    {
        // Clear the interrupt flag.
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ);

        // Process received data.
        if (ISMASKCLEAR(MAP_I2CFIFOStatus(I2CA0_BASE), I2C_FIFO_RX_EMPTY))
        {
            // Fetch data from the FIFO.
            MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,
                (uint8_t *)&rxDataPtr[rxBytesDone]);

            // Increment the counter.
            if (rxByteCount > rxBytesDone)
                rxBytesDone++;

            // If we're done reading...
            if (rxByteCount == rxBytesDone)
            {
                // If we're done, sent STOP.
                if (txByteCount == 0)
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

                // If we're doing a Read-Then-Write, configure the FIFO
                // and then send a re-START.
                else
                {
                    // Set the I2C address + WRITE bit.
                    MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_WRITE);

                    // Set the length of the operation.
                    MAP_I2CMasterBurstLengthSet(I2CA0_BASE, txByteCount);

                    // Place the first byte into the FIFO.
                    MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE, txDataPtr[0]);

                    // Initiate I2C write operation.
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_FIFO_BURST_SEND_START |
                        I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);
                }
            }
        }
    }
    else if (isrSourceMask & I2C_MASTER_INT_TX_FIFO_REQ)
    {
        // Clear the interrupt flag.
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_REQ);

        // Initiate sending of more data (maybe?).
        if (MAP_I2CFIFOStatus(I2CA0_BASE) & I2C_FIFO_TX_EMPTY)
        {
            MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,
                txDataPtr[txBytesDone]);

            if (txByteCount > txBytesDone)
                txBytesDone++;

            // If we're done with the write...
            if (txByteCount == txBytesDone)
            {
                // If we're done, send STOP.
                if (rxByteCount == 0)
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_BURST_SEND_FINISH);

                // If we're doing a Write-Then-Read, configure the FIFO
                // and then send a re-START.
                else
                {
                    // Set the I2C address + READ bit.
                    MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_READ);

                    // Set the length of the operation.
                    MAP_I2CMasterBurstLengthSet(I2CA0_BASE, rxByteCount);

                    // Initiate I2C read operation.
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START |
                        I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);
                }
            }
        }
    }
    
    // These interrupts are not used in this sample.
    else if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_FULL)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_FULL);
    
    else if (isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
    // This interrupt is disabled in my example code.
    else if (isrSourceMask & I2C_MASTER_INT_ARB_LOST)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_ARB_LOST);
    
    // This interrupt fires whenever a START condition occurs.
    else if (isrSourceMask & I2C_MASTER_INT_START)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_START);
    
    // This interrupt fires whenever a STOP condition occurs.
    else if (isrSourceMask & I2C_MASTER_INT_STOP)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_STOP);
    
    // This interrupt fires whenever a NACK condition occurs.
    else if (isrSourceMask & I2C_MASTER_INT_NACK)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_NACK);
    
    // This interrupt seems to never fire.
    else if (isrSourceMask & I2C_MASTER_INT_TIMEOUT)
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TIMEOUT);

    // This interrupt will fire every time there is a transfer of data.
    // I'm using it to check for errors, and then reset the bus if an error
    // occurs.
    else if (isrSourceMask & I2C_MASTER_INT_DATA)
    {
        // Clear the interrupt flag.
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_DATA);

        // Check for errors.
        if(MAP_I2CMasterErr(I2CA0_BASE) != I2C_MASTER_ERR_NONE)
        {
            // Send STOP to reset the bus.
            MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_STOP);
        }
    }
}

/******************************************************************************
 *
 *  Function:       I2CInit
 *
 *  Description:    Initialize the specified I2C with the provided settings.
 *                  If the I2C was initialized previously, I2CDisable() must be
 *                  called before re-initializing.
 *
 *  Parameters:     slaveAddress - address of device we wish to talk to
 *                  fastModeFlag - setting for fast mode
 *
 *****************************************************************************/

void I2CInit(uint8_t slaveAddress, bool fastModeFlag)
{
    // Enable clock to I2C.
    MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, PRCM_RUN_MODE_CLK);

    // Reset the I2C peripheral.
    MAP_PRCMPeripheralReset(PRCM_I2CA0);

    // Initialize the I2C peripheral.
    // (Also enables master mode.)
    MAP_I2CMasterInitExpClk(I2CA0_BASE, I2C_CLOCK_FREQ_HZ, fastModeFlag);

    // Disable master mode (because Enable function will turn it on later).
    MAP_I2CMasterDisable(I2CA0_BASE);

    // Set the time-out. Not to be used with breakpoints.
    MAP_I2CMasterTimeoutSet(I2CA0_BASE, I2C_TIMEOUT_VAL);

    // Store address for later.
    i2cAddress = slaveAddress;
    
        // Enable the I2C master module.
    MAP_I2CMasterEnable(I2CA0_BASE);

    // Register software ISR with the DriverLib.
    MAP_I2CIntRegister(I2CA0_BASE, I2C_ISR);

    // Clear all interrupts.
    MAP_I2CMasterIntClearEx(I2CA0_BASE, MAP_I2CMasterIntStatusEx(I2CA0_BASE, FALSE));

    // Enable interrupts.
    MAP_I2CMasterIntEnableEx(I2CA0_BASE,
//      I2C_MASTER_INT_RX_FIFO_FULL |   // RX FIFO is full
        I2C_MASTER_INT_RX_FIFO_REQ |    // RX FIFO service required
//      I2C_MASTER_INT_TX_FIFO_EMPTY |  // TX FIFO is empty
        I2C_MASTER_INT_TX_FIFO_REQ |    // TX FIFO service required
//      I2C_MASTER_INT_NACK |           // no acknowledgment received
//      I2C_MASTER_INT_START |          // START sequence received
//      I2C_MASTER_INT_STOP |           // STOP sequence received
        I2C_MASTER_INT_TIMEOUT |        // timeout
        I2C_MASTER_INT_DATA |           // data transaction complete
        I2C_MASTER_INT_RX_FIFO_REQ |    // FIFO
        I2C_MASTER_INT_TX_FIFO_REQ |
        I2C_MASTER_INT_TX_FIFO_EMPTY |
        I2C_MASTER_INT_RX_FIFO_FULL);

    // Flush FIFOs.
    MAP_I2CTxFIFOFlush(I2CA0_BASE);
    MAP_I2CRxFIFOFlush(I2CA0_BASE);

    // Enable FIFOs.
    MAP_I2CTxFIFOConfigSet(I2CA0_BASE, I2C_FIFO_CFG_TX_MASTER | I2C_FIFO_CFG_TX_TRIG_1);
    MAP_I2CRxFIFOConfigSet(I2CA0_BASE, I2C_FIFO_CFG_RX_MASTER | I2C_FIFO_CFG_RX_TRIG_1);
}

/******************************************************************************
 *
 *  Function:       I2CWrite
 *
 *  Description:    Perform a read transaction on the bus (as a master).
 *
 *  Parameters:     dataArray - array of bytes to write to device
 *                  count - number of bytes to write
 *
 *****************************************************************************/

void I2CWrite(uint8_t *dataArray, uint32_t count)
{
    // Set TX array start address.
    txDataPtr = dataArray;

    // Set TX byte count & reset count of bytes sent.
    // Note that before we finish this function, we'll have sent 1 byte.
    txByteCount = count;
    txBytesDone = 1;

    // Indicate that we're not reading.
    rxByteCount = 0;

    // Set the I2C address + WRITE bit.
    MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_WRITE);

    // Set the length of the operation.
    MAP_I2CMasterBurstLengthSet(I2CA0_BASE, count);

    // Place the first byte into the FIFO.
    MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE, txDataPtr[0]);

    // Initiate I2C write operation.
    MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_START |
        I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);
}

  • Hi Adam,

    We will look into this and respond.

    Thanks and Regards,
    Siddaram
  • Hi Adam,

    As you have set the I2C_FIFO_CFG_TX_TRIG_1 as the TX FIFO trigger level below descriptions apply.

    I2C_MASTER_INT_TX_FIFO_EMPTY : This comes when TX FIFO is empty.
    I2C_MASTER_INT_TX_FIFO_REQ : The trigger level (1) for the TX FIFO has been reached and more data is needed to complete the burst. Thus, a TX FIFO request interrupt is pending.

    If you start with just one byte you will never hit I2C_MASTER_INT_TX_FIFO_REQ and you will always start to hit I2C_MASTER_INT_TX_FIFO_REQ after first byte is sent. As your routine to complete the burst is in I2C_MASTER_INT_TX_FIFO_REQ Your burst request would still be pending. I changed your code to complete the burst request in I2C_MASTER_INT_TX_FIFO_EMPTY condition also then continuous trigger of interrupt doesn't happen.

    I think driver should be such that if you want to transfer bytes in burst fashion.
    1. once you get I2C_MASTER_INT_TX_FIFO_REQ you should put further bytes in FIFO till you exhaust alll the bytes.
    2. Finally I2C_MASTER_INT_TX_FIFO_EMPTY would get triggered then you should complete the burst.

    Thanks and Regards,
    Siddaram
  • Unfortunately, that does not solve my problem. To be clear, the case I'm having trouble with is where there is only one byte to write to the I2C slave.

    I tried to implement your suggestion by changing line 82 in my original post to check for I2C_MASTER_INT_TX_FIFO_REQ and I2C_MASTER_INT_TX_FIFO_EMPTY, but then if I try to send a one-byte message, two bytes are sent.

    I've sent my source code to my TI representative Michael Schultis, who has hopefully been in touch with you. If not, I'd be happy to send the sample to you. I'd post it here but it's rather long for a forum post.
  • I had some luck by also changing the logic in the interrupt (beginning on line 82 in original post) to this, which allows a one-byte write transaction to complete correctly, but now if I try a Write-then-Read transaction the only interrupt I get is I2C_MASTER_INT_DATA and the bus status (fetched from MAP_I2CMasterBusBusy) is busy indefinitely.

    else if ((isrSourceMask & I2C_MASTER_INT_TX_FIFO_REQ) ||
            (isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY))
    {
        // Clear the interrupt flag.
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_REQ);
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
        // If we're done with the write...
        if (txByteCount[I2C0] == txBytesDone[I2C0])
        {
            // If we're done, send STOP.
            if (rxByteCount[I2C0] == 0)
                MAP_I2CMasterControl(I2CA0_BASE,
                    I2C_MASTER_CMD_BURST_SEND_FINISH);
    
            // If we're doing a Write-Then-Read, configure the FIFO
            // and then send a re-START.
            else
            {
                // Set the I2C address + READ bit.
                MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_READ);
    
                // Set the length of the operation.
                MAP_I2CMasterBurstLengthSet(I2CA0_BASE, rxByteCount[I2C0]);
    
                // Initiate I2C read operation.
                MAP_I2CMasterControl(I2CA0_BASE,
                    I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START |
                    I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);
            }
    
            // If the associated callback exists, call it.
            if (CallbackArray[I2C0][I2C_CB_TX] != NULL)
                CallbackArray[I2C0][I2C_CB_TX](NULL);
        }
    
        // If there's more to send...
        else
        {
            // Put more data in the FIFO.
            MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,
                txDataPtr[I2C0][txBytesDone[I2C0]]);
    
            if (txByteCount[I2C0] > txBytesDone[I2C0])
                txBytesDone[I2C0]++;
        }
    }
  • Actually, no, I'm still getting two bytes sent instead of one (but if I put a breakpoint in my ISR then I only get one byte sent).
  • Hi Adam,

    I have your code with me, I will try this on Monday and get back to you.

    Thanks and Regards,
    Siddaram
  • Hi Adam,

    I changed your code as below to make the WriteTheanRead of 1 byte work. Note that change are related to your handling of rxByteCount,rxBytesDone,txByteCount and txBytesDone. Please see if you agree. After you get the first interrupt for TX_FIFO_REQ or TX_FIFO_EMPTY you have already sent the first byte and you should increment txBytesDone.

    	if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_REQ)
    	{
    		// Clear the interrupt flag.
    		MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ);
    
    		// Process received data.
    		if (!(MAP_I2CFIFOStatus(I2CA0_BASE) & I2C_FIFO_RX_EMPTY))
    		{
    			// Fetch data from the FIFO.
    			MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,
    				(uint8_t *)&rxDataPtr[I2C0][rxBytesDone[I2C0]]);
    
    			// Increment the counter.
    			if (rxByteCount[I2C0] > rxBytesDone[I2C0])
    				rxBytesDone[I2C0]++;
    
    			// If we're done reading...
    			if (rxByteCount[I2C0] == rxBytesDone[I2C0])
    			{
    				// If we're done, sent STOP.
    				if (txByteCount[I2C0] == txBytesDone[I2C0])
    					MAP_I2CMasterControl(I2CA0_BASE,
    						I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
    				// If we're doing a Read-Then-Write, configure the FIFO
    				// and then send a re-START.
    				else
    				{
    					// Set the I2C address + WRITE bit.
    					MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_WRITE);
    
    					// Set the length of the operation.
    					MAP_I2CMasterBurstLengthSet(I2CA0_BASE, txByteCount[I2C0]);
    
    					// Place the first byte into the FIFO.
    					MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE, txDataPtr[I2C0][0]);
    
    					// Initiate I2C write operation.
    					MAP_I2CMasterControl(I2CA0_BASE,
    						I2C_MASTER_CMD_FIFO_BURST_SEND_START |
    						I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);
    				}
    
    				// If the associated callback is enabled and exists, call it.
    				if ((txCallbackEnable[I2C0] == true) &&
    					(CallbackArray[I2C0][I2C_CB_RX] != NULL))
    				CallbackArray[I2C0][I2C_CB_RX](NULL);
    			}
    		}
    	}
    	else if ((isrSourceMask & I2C_MASTER_INT_TX_FIFO_REQ) ||
                     (isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY))
            {
                // Clear the interrupt flag.
                MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_REQ);
                MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
                if (txByteCount[I2C0] > txBytesDone[I2C0])
                      txBytesDone[I2C0]++;            
                
                // If we're done with the write...
                if (txByteCount[I2C0] == txBytesDone[I2C0])
                {
                    // If we're done, send STOP.
                    if (rxByteCount[I2C0] == rxBytesDone[I2C0])
                    { 
    
                      MAP_I2CMasterControl(I2CA0_BASE,
                            I2C_MASTER_CMD_BURST_SEND_FINISH);
                    }
                    // If we're doing a Write-Then-Read, configure the FIFO
                    // and then send a re-START.
                    else
                    {
                        // Set the I2C address + READ bit.
                        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_READ);
    
                        // Set the length of the operation.
                        MAP_I2CMasterBurstLengthSet(I2CA0_BASE, rxByteCount[I2C0]);
    
                        // Initiate I2C read operation.
                        MAP_I2CMasterControl(I2CA0_BASE,
                            I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START |
                            I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);
                       
                    
                    }
    
                    // If the associated callback exists, call it.
                    if (CallbackArray[I2C0][I2C_CB_TX] != NULL)
                        CallbackArray[I2C0][I2C_CB_TX](NULL);
                }
    
                // If there's more to send...
                else
                {
                    // Put more data in the FIFO.
                    MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,
                        txDataPtr[I2C0][txBytesDone[I2C0]]);
                }
            }

    Thanks and Regards,

    Siddaram

  • Siddaram,

    Unfortunately, I2CWriteThenRead() now works correctly, but nothing else does.  Here is the order of function calls in my I2C test function, along with the interrupts that fire and what I do in response.  The I2C_MASTER_INT_TX_FIFO_EMPTY interrupt seems to fire in ways I didn't think it would (highlighed in red), and that's messing me up:

    I2CWrite()

    • I2C_MASTER_INT_TX_FIFO_EMPTY,
      • Send STOP.
    • I2C_MASTER_INT_TX_FIFO_EMPTY - why does this happen?
      • Send STOP (this causes an extra byte to be transferred over I2C).
    • I2C_MASTER_INT_DATA

    I2CRead()

    • I2C_MASTER_INT_TX_FIFO_EMPTY - why does this happen?
      • Send re-START + STOP.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Fetch 1 byte.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Fetch 1 byte.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Send STOP.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Send STOP.
    • I2C_MASTER_INT_DATA

    I2CWriteThenRead()

    • I2C_MASTER_INT_TX_FIFO_EMPTY
      • Send re-START.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Fetch 1 byte.
    • I2C_MASTER_INT_RX_FIFO_REQ
      • Fetch 1 byte.
      • Send STOP.
    • I2C_MASTER_INT_RX_FIFO_REQ
    • I2C_MASTER_INT_TX_FIFO_EMPTY - why does this happen?
      • Send STOP.

    Below is my I2CTest function, which I have edited slightly to make sure that I2C commands are correct for the TMP006 sensor on the CC3200 LaunchPad.  It writes 0xFE to the TMP006's pointer register, then reads the manufacturer ID (expected value is 0x5449), then does a write-then-read to get register 0x00 (sensor voltage).

    /******************************************************************************
     *  Test Function
     *****************************************************************************/
    
    #define I2C_ADDR    0x41            // I2C address of LaunchPad sensor
    #define I2C_SPEED   100000          // 100 kHz
    
    // First message:  Write to sensor.
    const uint8_t writeMsg[] = {
        0xFE,   // register to access
    };
    
    // Second message:  Read from sensor.  This is for the "write-then-read" test.
    const uint8_t readMsg[] = {
        0x00,   // register to read from
    };
    
    /******************************************************************************
     *
     *  @brief Test the I2C Master Driver
     *
     *  @return I2C_RESULT_OK on success, other on failure.
     *
     *****************************************************************************/
    
    i2cResult_t I2CTest(i2cChannel_t channel, uint8_t repeatFlag)
    {
        i2cResult_t result = I2C_RESULT_OK; // an optimistic return value :)
        i2cConfig_t config;                 // module config data
        volatile uint8_t response[2];       // bytes received from sensor
    
        do  // I'm afraid of goto statements, so I'll use this instead ;}
        {
            // Setup the I2C configuration.
            config.channel = channel;
            config.speed = I2C_SPEED;
            config.slaveAddress = I2C_ADDR;
    
            // Setup the I2C driver with the setup configuration
            result = I2CInit(&config);
            if (result != I2C_RESULT_OK)
                break;
    
            // Enable the I2C peripheral.
            result = I2CEnable(channel);
            if (result != I2C_RESULT_OK)
                break;
    
            do  // This part can (optionally) be repeated.
            {
                // Try a write.
                result = I2CWrite(channel, (uint8_t *)writeMsg, sizeof(writeMsg));
                if (result != I2C_RESULT_OK)
                    break;
    
                // Wait until the device is not busy from the previous operation.
                while (I2CIsBusy(channel));
    
                // Try a read.
                result = I2CRead(channel, (uint8_t *)response, sizeof(response));
                if (result != I2C_RESULT_OK)
                    break;
    
                // Wait until the device is not busy from the previous operation.
                while (I2CIsBusy(channel));
    
                // Try a write-then-read.
                result = I2CWriteThenRead(channel, (uint8_t *)readMsg,
                    sizeof(readMsg), (uint8_t *)response, sizeof(response));
                if (result != I2C_RESULT_OK)
                    break;
    
                // Wait until the device is not busy from the previous operation.
                while (I2CIsBusy(channel));
    
            } while (repeatFlag);           // Repeat if requested.
        } while (false);                    // Don't repeat the initialization.
    
        return result;
    }

  • The CC3200 Technical Reference Manual states (SWRU367B, revised Oct. 2014, p. 188), "Note that if we clear the TXFERIS interrupt (by setting the TXFEIC bit) when the TX FIFO is empty, the TXFERIS interrupt does not reassert even though the TX FIFO remains empty in this situation." That doesn't seem to be what's happening. In my case, is it reasserting because I write to the I2CMCS register?

  • Hi Adam,

    I was able to get your code working with below changes, Please let me know if this works as expected at your end as well. In general i would suggest once you review the handling of txByteCount, txBytesDone,rxByteCount and rxBytesDone.

    1. I2CRead : To start in a clean way you need to add txBytesDone[channel] = 0;

    2.I2CWriteThenRead : Change to set txBytesDone to 1 i.e.  txBytesDone[channel] = 1;

    3. I2C_ISR : As below

    	if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_REQ)
    	{
    		// Clear the interrupt flag.
    		MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ);
    
    		// Process received data.
    		while (!(MAP_I2CFIFOStatus(I2CA0_BASE) & I2C_FIFO_RX_EMPTY))
    		{
    			// Fetch data from the FIFO.
    			MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,
    				(uint8_t *)&rxDataPtr[I2C0][rxBytesDone[I2C0]]);
    
    			// Increment the counter.
    			if (rxByteCount[I2C0] > rxBytesDone[I2C0])
    				rxBytesDone[I2C0]++;
    
    			// If we're done reading...
    			if (rxByteCount[I2C0] == rxBytesDone[I2C0])
    			{
    				// If we're done, sent STOP.
    				if (txByteCount[I2C0] == txBytesDone[I2C0])
    					MAP_I2CMasterControl(I2CA0_BASE,
    						I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
    				// If we're doing a Read-Then-Write, configure the FIFO
    				// and then send a re-START.
    				else
    				{
    					// Set the I2C address + WRITE bit.
    					MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_WRITE);
    
    					// Set the length of the operation.
    					MAP_I2CMasterBurstLengthSet(I2CA0_BASE, txByteCount[I2C0]);
    
    					// Place the first byte into the FIFO.
    					MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE, txDataPtr[I2C0][0]);
    
    					// Initiate I2C write operation.
    					MAP_I2CMasterControl(I2CA0_BASE,
    						I2C_MASTER_CMD_FIFO_BURST_SEND_START |
    						I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);
    				}
    
    				// If the associated callback is enabled and exists, call it.
    				if ((txCallbackEnable[I2C0] == true) &&
    					(CallbackArray[I2C0][I2C_CB_RX] != NULL))
    				CallbackArray[I2C0][I2C_CB_RX](NULL);
    			}
    		}
    	}
    	else if ((isrSourceMask & I2C_MASTER_INT_TX_FIFO_REQ) ||
                     (isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY))
            {
                // Clear the interrupt flag.
                MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_REQ);
                MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
              
                
                // If we're done with the write...
                if (txByteCount[I2C0] == txBytesDone[I2C0])
                {
                    // If we're done, send STOP.
                    if (rxByteCount[I2C0] == rxBytesDone[I2C0])
                    { 
    
                      MAP_I2CMasterControl(I2CA0_BASE,
                            I2C_MASTER_CMD_BURST_SEND_FINISH);
                    }
                    // If we're doing a Write-Then-Read, configure the FIFO
                    // and then send a re-START.
                    else
                    {
                        // Set the I2C address + READ bit.
                        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_READ);
    
                        // Set the length of the operation.
                        MAP_I2CMasterBurstLengthSet(I2CA0_BASE, rxByteCount[I2C0]);
    
                        // Initiate I2C read operation.
                        MAP_I2CMasterControl(I2CA0_BASE,
                            I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START |
                            I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);
                       
                    
                    }
    
                    // If the associated callback exists, call it.
                    if (CallbackArray[I2C0][I2C_CB_TX] != NULL)
                        CallbackArray[I2C0][I2C_CB_TX](NULL);
                }
    
                // If there's more to send...
                else
                {
                    // Put more data in the FIFO.
                    MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,
                        txDataPtr[I2C0][txBytesDone[I2C0]]);
                    
                if (txByteCount[I2C0] > txBytesDone[I2C0])
                      txBytesDone[I2C0]++;                  
                }
            }
    	else if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_FULL)
    

    Thanks and Regards,

    Siddaram

  • When I implement your changes, the test code functions, but I still see extra interrupts firing (see list in previous post). Can you place a breakpoint in the ISR and run the test code, and see what happens on your end? Of particular concern is the I2C_MASTER_INT_TX_FIFO_EMPTY interrupt.

    Am I using the I2C_MASTER_INT_TX_FIFO_EMPTY interrupt incorrectly?
  • I also see an extra byte 0x00 being written as a result of the call to I2CWrite(). The CC3200 is sending 0xFE 0x00 to the sensor instead of 0xFE. If I place a breakpoint in the ISR, the extra 0x00 does not appear. Any idea what's going on?
  • Hi Adam,

    I will need some more time to try your code and reproduce this specific issue. It will take about 3-4 days. Sorry about that.

    Thanks and Regards,
    Siddaram
  • Has there been any progress on these open questions?

    For reference, I have placed my sample driver code on GitHub here:  https://github.com/adamj537/Code-Library/tree/master/Drivers/I2C_CC3200

  • Hi Adam,

    Yes when i try your code i can see 0xFE and 0x00 being sent to the sensor instead of 0xFE. So i tried just the I2CWrite by commenting out I2CRead and I2CWriteThenRead in I2CTest.

    Within the below code if i comment out I2CIsBusy 0xFE alone gets sent out. If i keep I2CIsBusy then 0xFE and 0x00 are sent out.
    I will try to spend some more time, but please see if this gives any pointer to the code you have put together and why is I2CIsBusy making difference.

    // Try a write.
    result = I2CWrite(channel, (uint8_t *)writeMsg, sizeof(writeMsg));
    if (result != I2C_RESULT_OK)
    break;

    // Wait until the device is not busy from the previous operation.
    // while (I2CIsBusy(channel));

    Thanks and Regards,
    Siddaram
  • Hi Adam,

    Actually it doesn't matter what code is present after I2CWrite. Even if there is just a delay loop instead of while (I2CIsBusy(channel)) additional 0x00 is being sent. We are looking into this. Either me me or one of my colleague will respond on this thread next week with our observations.


    Thanks and Regards,
    Siddaram
  • Siddaram,

    Thank you for your continued investigation. I appreciate it.

    Adam J.
  • Hi Adam,


    Can you pls try the following change in static void I2C_ISR(void) and let me know if it helped


                // If we're done with the write...
                if (txByteCount[I2C0] == txBytesDone[I2C0])
                {
                    // If we're done, send STOP.
                    if (rxByteCount[I2C0] == rxBytesDone[I2C0])
                    {

                      MAP_I2CMasterControl(I2CA0_BASE,
                            I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);  // instead of I2C_MASTER_CMD_BURST_SEND_FINISH);

                    }
                    // If we're doing a Write-Then-Read, configure the FIFO
                    // and then send a re-START.
                    else
                    {
                        // Set the I2C address + READ bit.

     

     

    I2C_MASTER_CMD_BURST_SEND_FINISH command mean a data transfer followed by a stop.

    I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP command mean an immediate stop

    Thanks and Regards,

    Praveen

  • Praveen,

    Yes, that prevents the extra 0x00 from occurring!

    However, I'm still unsure if I'm using the I2C_MASTER_INT_TX_FIFO_EMPTY interrupt correctly.  See my previous post on Apr 20, 2015 2:20 PM that had all the interrupt calls listed.  Can you test my driver, placing a breakpoint in the interrupt service routine, and let me know if I am doing something to cause the "extra" interrupts?  Or perhaps you could suggest logic to handle the interrupts better (I think I'm responding to certain interrupts incorrectly)?

    I have updated my sample driver code on GitHub here to reflect the latest changes:  https://github.com/adamj537/Code-Library/tree/master/Drivers/I2C_CC3200.

    Thank you,

    Adam J.

    EDIT:  The link above no longer works.  I'm restructuring my microcontroller code library, and the resulting driver will end up here:  https://github.com/adamj537/Code-Library/blob/master/Processor_Peripherals/TI_CC3200/I2CDriver.c

  • Hi Adam,

    Pls see my implementation below for I2C_Read() and I2C_Write() APIs

    static tBoolean bDone;
    static unsigned char g_ucBuffer[256];
    static unsigned long g_ulTransSize;
    static unsigned long g_ulNdx;
    static unsigned char *g_pucBuff;
    
    #define I2C_RW_FLAG_SEND_START          1
    #define I2C_RW_FLAG_SEND_STOP           2
    
    //*****************************************************************************
    // Int handler for I2C
    //*****************************************************************************
    void I2CIntHandler()
    {
        unsigned long ulIntStatus;
    
        //
        // Get the interrupt status
        //
        ulIntStatus = MAP_I2CMasterIntStatusEx(I2CA0_BASE,true);
    
        //
        // See if fifo fill request
        //
        if( ulIntStatus & I2C_MASTER_INT_TX_FIFO_REQ )
        {
            MAP_I2CFIFODataPut(I2CA0_BASE,g_pucBuff[g_ulNdx]);
            g_ulNdx++;
            g_ulTransSize--;
            if( 0 == g_ulTransSize )
            {
              bDone = true;
            }
        }
    
        if( ulIntStatus & I2C_MASTER_INT_RX_FIFO_REQ )
        {
            g_pucBuff[g_ulNdx] = MAP_I2CFIFODataGet(I2CA0_BASE);
            g_ulNdx++;
            g_ulTransSize--;
            if( 0 == g_ulTransSize )
            {
              bDone = true;
            }
        }
    
        //
        // Clear the interrupt
        //
        MAP_I2CMasterIntClearEx(I2CA0_BASE,ulIntStatus);
    }
    
    //*****************************************************************************
    // Read API
    //*****************************************************************************
    int I2C_Read(unsigned char ucDevAddr, unsigned char *ucBuffer,
                 unsigned long ulSize, unsigned long ulFlags)
    {
        unsigned long ulCmd;
    
        //
        // Set the Master Address
        //
        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,true);
    
        //
        // Set the transfer size
        //
        g_ulTransSize = ulSize;
    
        //
        // Reset the index to 0
        //
        g_ulNdx = 0;
    
        //
        // Set the buffer
        //
        g_pucBuff = ucBuffer;
    
        //
        // Set the burst length
        //
        MAP_I2CMasterBurstLengthSet(I2CA0_BASE,g_ulTransSize);
    
        //
        // Set the flag to flase
        //
        bDone = false;
    
        //
        // Form the command
        //
        ulCmd = I2C_MASTER_CMD_FIFO_BURST_RECEIVE_CONT;
    
        if( ulFlags & I2C_RW_FLAG_SEND_START)
        {
            ulCmd |= I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START;
        }
    
        if( ulFlags & I2C_RW_FLAG_SEND_STOP)
        {
            ulCmd |= I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH;
        }
    
    
        //
        // Issue the command
        //
        MAP_I2CMasterControl(I2CA0_BASE, ulCmd);
    
        //
        // Wait for done
        //
        while( !bDone )
        {
    
        }
    
        //
        // Wait for master to complete
        //
        while( MAP_I2CMasterBusy(I2CA0_BASE) )
        {
          if( MAP_I2CMasterIntStatusEx(I2CA0_BASE,false) & I2C_MASTER_INT_NACK )
          {
            return -1;
          }
        }
    
        return 0;
    }
    
    //*****************************************************************************
    // Write API
    //*****************************************************************************
    int I2C_Write(unsigned char ucDevAddr, unsigned char *ucBuffer,
                  unsigned long ulSize, unsigned long ulFlags)
    {
        unsigned long ulCmd;
    
        //
        // Set the Master Address
        //
        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,false);
    
        //
        // Set the transfer size
        //
        g_ulTransSize = ulSize;
    
        //
        // Reset the index to 0
        //
        g_ulNdx = 0;
    
        //
        // Set the buffer
        //
        g_pucBuff = ucBuffer;
    
        //
        // Set the burst length
        //
        MAP_I2CMasterBurstLengthSet(I2CA0_BASE,g_ulTransSize);
    
        //
        // Set the flag to flase
        //
        bDone = false;
    
        //
        // Form the command
        //
        ulCmd = I2C_MASTER_CMD_FIFO_BURST_SEND_CONT;
    
        if( ulFlags & I2C_RW_FLAG_SEND_START)
        {
            ulCmd |= I2C_MASTER_CMD_FIFO_BURST_SEND_START;
        }
    
        if( ulFlags & I2C_RW_FLAG_SEND_STOP)
        {
            ulCmd |= I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH;
        }
    
    
        //
        // Issue the command
        //
        MAP_I2CMasterControl(I2CA0_BASE, ulCmd);
    
        //
        // Wait for done
        //
        while( !bDone )
        {
    
        }
    
        //
        // Wait for master to complete
        //
        while( MAP_I2CMasterBusy(I2CA0_BASE) )
        {
          if( MAP_I2CMasterIntStatusEx(I2CA0_BASE,false) & I2C_MASTER_INT_NACK )
          {
            return -1;
          }
        }
    
        return 0;
    }
    
    

    Thanks and Regards,

    Praveen

  • Adam,


    Here is my main() function.

    void main()
    {
        //
        // Mux out I2C Lines
        //
        MAP_PinTypeI2C(PIN_01,PIN_MODE_1);
        MAP_PinTypeI2C(PIN_02,PIN_MODE_1);
    
        //
        // Initialize
        //
        BoardInit();
    
        //
        // Enable the I2C module
        //
        MAP_PRCMPeripheralClkEnable(PRCM_I2CA0,PRCM_RUN_MODE_CLK);
    
        //
        // Configure the clock
        //
        MAP_I2CMasterInitExpClk(I2CA0_BASE,80000000,true);
    
        //
        // Configure I2C Interurpts
        //
        MAP_I2CIntRegister(I2CA0_BASE,I2CIntHandler);
    
        //
        // Clean all interrupts
        //
        MAP_I2CMasterIntClearEx(I2CA0_BASE,0xFFFF);
    
        //
        // Enable the required interrupts
        //
        MAP_I2CMasterIntEnableEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ|
                                             I2C_MASTER_INT_TX_FIFO_REQ);
    
        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER|
                                          I2C_FIFO_CFG_TX_TRIG_4);
    
    
    
        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER|
                                          I2C_FIFO_CFG_TX_TRIG_1);
    
    
        //
        // Enable the I2C Master
        //
        MAP_I2CMasterEnable(I2CA0_BASE);
    
        //
        // Set the register address for ID register
        //
        g_ucBuffer[0]= 0xFE;
    
        //
        // Do transaction without STOP flag
        //
        if ( 0 == I2C_Write(0x41,g_ucBuffer,1,I2C_RW_FLAG_SEND_START) )
        {
          //
          // Do the read and stop
          //
          I2C_Read(0x41,g_ucBuffer,5,
                   I2C_RW_FLAG_SEND_START|I2C_RW_FLAG_SEND_STOP);
        }
    
        //
        // Infinite loop
        //
        while(1)
        {
    
        }
    }

    Thanks and Regards,

    Praveen

  • Praveen,

    I will need some more time to try your code, and hope to post here in a few days.

    Thank you,

    Adam J.
  • Which of these lines is meant to configure the RX FIFO?

        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER|
                                          I2C_FIFO_CFG_TX_TRIG_4);
    
    
    
        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER|
                                          I2C_FIFO_CFG_TX_TRIG_1);

  • Praveen,

    I'm nearly done making your sample fit my API. Having some trouble with a Write-Then-Read transaction. When I'm finished, I'll post my example here.

    Adam J.

  • Hi Adam,

    Did your queries got answered. If yes please press the "Verify Answer" button to close this thread.

    Thanks and Regards,

    Siddaram

  • Siddaram,

    I'm still working on the solution. I need an interrupt-driven I2C driver that has Write, Read, and Write-then-Read functions. The functions must also be non-blocking.  Praveen's sample solution uses blocking functions, and does not have a Write-then-Read function, and I've been unable to add one successfully.

    Thank you,

    Adam J.

  • Hi Adam,

    I assume you want to use I2CFIFODataPutNonBlocking() and I2CFIFODataGetNonBlocking() in the ISR. I replaced the functions in the ISR with NonBlocking variants and is working fine for me. Can you try that ?

    For Write-then-Read, did you meant first write then do a re-start (no stop) and then read ? If so here how you can use my APIs, (pls see the main() that I had posted earlier for the full code)

        //
        // Do transaction without STOP flag
        //
        if ( 0 == I2C_Write(0x41,g_ucBuffer,1,I2C_RW_FLAG_SEND_START) )
        {
          //
          // Do the read and stop
          //
          I2C_Read(0x41,g_ucBuffer,5,
                   I2C_RW_FLAG_SEND_START|I2C_RW_FLAG_SEND_STOP);
        }

    Pls let me know if I am missing something.

    Regards,

    Praveen

    Screenshot :

  • Praveen,

    Yes, by "Write-then-Read," I mean first write then do a re-start (no stop) and then read.

    By "non-blocking," I mean that the functions I2C_Write or I2C_Read or I2C_WriteThenRead should not need to wait to return until a transaction completes.  I want the functions to return as soon as the transaction starts, and then the library should notify me (at the end of the last ISR call) that the transaction is done.  So the offending code is this part, which I can't have in my I2C_Write or I2C_Read or I2C_WriteThenRead functions:

    //
        // Wait for done
        //
        while( !bDone )
        {
    
        }
    
        //
        // Wait for master to complete
        //
        while( MAP_I2CMasterBusy(I2CA0_BASE) )
        {
          if( MAP_I2CMasterIntStatusEx(I2CA0_BASE,false) & I2C_MASTER_INT_NACK )
          {
            return -1;
          }
        }

    I was able to modify this code to make a I2C_IsBusy function, like this:

    bool I2CIsBusy(void)
    {
        bool busyFlag = false;              // is the I2C peripheral busy?
    
    	// We're busy if the "done" flag is not set.
    	if (!bDone)
    		busyFlag = true;
    
    	// We're also busy if the DriverLib says so.
    	if (MAP_I2CMasterBusy(I2CA0_BASE))
    	{
    		// Not sure what this if statement is for.
    		if (MAP_I2CMasterIntStatusEx(I2CA0_BASE, false) & I2C_MASTER_INT_NACK)
    			busyFlag = true;
    	}
    
        return busyFlag;
    }

    So then I can call I2C_Read or I2C_Write and wait until I2C_IsBusy returns false before starting a new transaction.  But I couldn't figure out how to make a I2C_WriteThenRead function that did not require while loops inside it.  I tried to do this by initiating the re-start in the ISR, but that didn't appear to be easily possible.  Does that make more sense?

    Thank you,

    Adam J.

  • Hi Adam,

    My bad, misunderstood your query. Let me tryout that at my end.


    Thanks and Regards,

    Praveen

  • Praveen,

    Has there been any progress on this issue?

    Thank you,

    Adam J.

  • Any progress update on this issue?

    Thank you,

    Adam J.
  • Hi Adam,

    Apologies for the delayed response.

    I was able to recreate you issue of getting multiply TX_FIFO_EMPTY interrupts, the solution is to reset the BURST bit in MCS register

     if ( ulIntStatus & I2C_MASTER_INT_STOP )
     {
            bDone = true;
            MAP_I2CMasterControl(I2CA0_BASE, 0);
     }

    Here is my code.

    static tBoolean bDone;
    static unsigned char *g_pucWriteBuff;
    static unsigned char *g_pucReadBuff;
    static unsigned long g_ulWriteSize;
    static unsigned long g_ulReadSize;
    static unsigned long g_PrevState;
    static unsigned long g_CurState;
    static unsigned char g_ucDevAddr;
    static unsigned long g_ulDebugReadCount;
    static unsigned long g_ulDebugWriteCount;
    
    #define I2C_RW_FLAG_SEND_START          1
    #define I2C_RW_FLAG_SEND_STOP           2
    
    #define I2C_STATE_WRITE         0
    #define I2C_STATE_READ          1
    
    //*****************************************************************************
    // Int handler for I2C
    //*****************************************************************************
    void I2CIntHandler()
    {
        unsigned long ulIntStatus;
    
        //
        // Get the interrupt status
        //
        ulIntStatus = MAP_I2CMasterIntStatusEx(I2CA0_BASE,true);
    
        //
        // See if fifo fill request
        //
        if( ( ulIntStatus & I2C_MASTER_INT_TX_FIFO_REQ ) &&  ( 0 != g_ulWriteSize) )
        {
            MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,(uint8_t)(*g_pucWriteBuff));
            g_ulWriteSize--;
            g_pucWriteBuff++;
            g_ulDebugWriteCount++;
            if( 0 == g_ulWriteSize && 0 != g_ulReadSize )
            {
              g_CurState = I2C_STATE_READ;
            }
    
        }
        else if (ulIntStatus & I2C_MASTER_INT_TX_FIFO_EMPTY )
        {
            if( (g_CurState == I2C_STATE_READ) && (g_PrevState == I2C_STATE_WRITE))
            {
                //
                // Set the Master Address
                //
                MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,g_ucDevAddr,true);
    
                //
                // Set the burst length
                //
                MAP_I2CMasterBurstLengthSet(I2CA0_BASE,(uint8_t)g_ulReadSize);
    
                g_PrevState   = I2C_STATE_READ;
    
                //
                // Issue the command
                //
                MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);
            }
    
        }
        else if( (ulIntStatus & I2C_MASTER_INT_RX_FIFO_REQ ) && ( 0 != g_ulReadSize ) )
        {
            MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,(uint8_t *)g_pucReadBuff);
            g_ulReadSize--;
            g_pucReadBuff++;
            g_ulDebugReadCount++;
        }
    
        if ( ulIntStatus & I2C_MASTER_INT_STOP )
        {
            bDone = true;
            MAP_I2CMasterControl(I2CA0_BASE, 0);
        }
    
        //
        // Clear the interrupt
        //
        MAP_I2CMasterIntClearEx(I2CA0_BASE,ulIntStatus);
    }
    
    
    //*****************************************************************************
    // Read API
    //*****************************************************************************
    int I2C_Transfer( unsigned char ucDevAddr, unsigned char *ucWriteBuffer,
                      unsigned char *ucReadBuffer, unsigned long ulWriteSize,
                      unsigned long ulReadSize)
    {
    
        unsigned long ulCmd;
    
        //
        // Set the device Addr
        //
        g_ucDevAddr =  ucDevAddr;
    
        //
        // Set the transfer size
        //
        if( 0 != ulWriteSize || 0 != ulReadSize )
        {
          g_ulWriteSize = ulWriteSize;
          g_ulReadSize  = ulReadSize;
        }
        else
        {
          //
          // Error
          //
          return -1;
        }
    
        //
        // Set the buffer
        //
        g_pucWriteBuff = ucWriteBuffer;
        g_pucReadBuff  = ucReadBuffer;
    
        //
        // Form the command
        //
        if( 0 != g_ulWriteSize )
        {
          //
          // Set the Master Address
          //
          MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,false);
    
          //
          // Set the burst length
          //
          MAP_I2CMasterBurstLengthSet(I2CA0_BASE,(uint8_t)ulWriteSize);
    
          //
          // Current state
          //
          g_PrevState   = I2C_STATE_WRITE;
          g_CurState    = I2C_STATE_WRITE;
    
          //
          // Set the start
          //
          ulCmd = I2C_MASTER_CMD_FIFO_BURST_SEND_START;
    
          if( 0 == ulReadSize )
          {
              ulCmd = I2C_MASTER_CMD_FIFO_SINGLE_SEND;
          }
        }
        else
        {
          //
          // Set the Master Address
          //
          MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,true);
    
          //
          // Set the burst length
          //
          MAP_I2CMasterBurstLengthSet(I2CA0_BASE,(uint8_t)ulReadSize);
    
          g_PrevState   = I2C_STATE_READ;
          g_CurState    = I2C_STATE_READ;
    
          ulCmd = I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE;
        }
    
        //
        // Issue the command
        //
        MAP_I2CMasterControl(I2CA0_BASE, ulCmd);
    
        //
        // Success
        //
        return 0;
    }

    And the main()

    void main()
    {
    
    
        MAP_PinTypeI2C(PIN_01,PIN_MODE_1);
        MAP_PinTypeI2C(PIN_02,PIN_MODE_1);
        BoardInit();
        MAP_PRCMPeripheralClkEnable(PRCM_I2CA0,PRCM_RUN_MODE_CLK);
        MAP_I2CMasterInitExpClk(I2CA0_BASE,80000000,true);
        MAP_I2CIntRegister(I2CA0_BASE,I2CIntHandler);
        MAP_I2CMasterIntClearEx(I2CA0_BASE,0xFFFF);
    
        //
        // Enable the required interrupts
        //
        MAP_I2CMasterIntEnableEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ   |
                                             I2C_MASTER_INT_TX_FIFO_REQ   |
                                             I2C_MASTER_INT_TX_FIFO_EMPTY |
                                             I2C_MASTER_INT_STOP);
    
        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER|
                                          I2C_FIFO_CFG_TX_TRIG_4);
    
    
    
        //
        // Configure the I2C TX FIFO
        //
        MAP_I2CRxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_RX_MASTER|
                                          I2C_FIFO_CFG_RX_TRIG_4);
    
    
        //
        // Enable the I2C Master
        //
        MAP_I2CMasterEnable(I2CA0_BASE);
    
        ucWriteBuff[0] = 0xFE;
    
        bDone = false;
    
        //
        // Do Write Only
        //
        I2C_Transfer(0x41,ucWriteBuff,ucReadBuff,3,0);
    
        while( !bDone )
        {
    
        }
    
        bDone = false;
    
        //
        // Do Write Only
        //
        I2C_Transfer(0x41,ucWriteBuff,ucReadBuff,3,0);
    
        //
        //
        //
        while( !bDone )
        {
    
        }
    
        bDone = false;
    
        //
        // Do Read Only Only
        //
        I2C_Transfer(0x41,ucWriteBuff,ucReadBuff,0,3);
    
        while( !bDone )
        {
    
        }
    
        bDone = false;
    
        //
        // Do Write-then-Read transfer
        //
        I2C_Transfer(0x41,ucWriteBuff,ucReadBuff,1,3);
    
        while( !bDone )
        {
    
        }
    
        //
        // Infinite loop
        //
        while(1)
        {
    
        }
    }



    Pls let me know if this helps.


    Thanks and Regards,
    Praveen
  • Praveen,

    Thank you for the code sample.  So far, it seems to be working!  It will take me some more time to fully evaluate.

    Adam J.

  • Praveen,

    I've copied your code to an example project here:  https://github.com/adamj537/Code-Library/tree/master/Examples/CC3200-I2CSample.

    At first, it worked great.  However, in my application, I'm reading 32 bytes of data from a slave (which is a separate processor), and if I run it overnight this code will hang.  Unfortunately, no sensor on the CC3200 Launchpad has 32 bytes to give me, or I would use it instead.

    Can you run this sample project with any slave device, reading 32 bytes of data, and see if the code will run continuously for 24 hours?

    Thank you,

    Adam J.

    EDIT:  The link above no longer works.  I'm restructuring my microcontroller code library, and the resulting driver will end up here:  https://github.com/adamj537/Code-Library/blob/master/Processor_Peripherals/TI_CC3200/I2CDriver.c

  • Praveen,

    I think that the I2CIntHandler function in your most recent example should probably clear the interrupt flags near the beginning of the interrupt routine, instead of right before it exits. It should probably also handle NACK interrupts. Not sure if either of these are causing the bus to hang in my case, but they're probably worth mentioning.

    Adam J.
  • This piece of code (from the most recent example) has a strange behavior.  In the case where there is data in the receive FIFO, but we weren't expecting it, it will hang forever since we never remove the data from the FIFO.

    else if( (ulIntStatus & I2C_MASTER_INT_RX_FIFO_REQ ) && ( 0 != g_ulReadSize ) )
    {
        MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,(uint8_t *)g_pucReadBuff);
        g_ulReadSize--;
        g_pucReadBuff++;
        g_ulDebugReadCount++;
    }

    Instead, perhaps we should do this:

    else if(ulIntStatus & I2C_MASTER_INT_RX_FIFO_REQ )
    {
        MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,(uint8_t *)g_pucReadBuff);
    
        if( 0 != g_ulReadSize )
        {
            g_ulReadSize--;
            g_pucReadBuff++;
            g_ulDebugReadCount++;
        }
    }

  • Hi Siddaram,

    This solution for us was to enable the I2C_MASTER_INT_TX_FIFO_EMPTY just prior to sending a command using MAP_I2CMasterControl(). then disabling I2C_MASTER_INT_TX_FIFO_EMPTY when the interrupt fired with I2C_MASTER_INT_TX_FIFO_EMPTY flag set.

    Send Snippet:

    //This is needed to stop the interrupt from continuously firing
    //We disable the interrupt in the ISR, we enable it here.
    MAP_I2CMasterIntEnableEx(base,I2C_MASTER_INT_TX_FIFO_EMPTY);
    // Issue the command
    MAP_I2CMasterControl(base, ulCmd);

    ISR Snippet:

    if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_REQ)
    {
        // Clear the interrupt flag.
        MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_RX_FIFO_REQ);
    
     
        // Process received data.
        while (!(MAP_I2CFIFOStatus(I2CA0_BASE) & I2C_FIFO_RX_EMPTY))
        {
            // Fetch data from the FIFO.
            MAP_I2CFIFODataGetNonBlocking(I2CA0_BASE,
                (uint8_t *)&rxDataPtr[I2C0][rxBytesDone[I2C0]]);
    
     
            // Increment the counter.
            if (rxByteCount[I2C0] > rxBytesDone[I2C0])
                rxBytesDone[I2C0]++;
    
     
            // If we're done reading...
            if (rxByteCount[I2C0] == rxBytesDone[I2C0])
            {
                // If we're done, sent STOP.
                if (txByteCount[I2C0] == txBytesDone[I2C0])
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
     
                // If we're doing a Read-Then-Write, configure the FIFO
                // and then send a re-START.
                else
                {
                    // Set the I2C address + WRITE bit.
                    MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_WRITE);
    
     
                    // Set the length of the operation.
                    MAP_I2CMasterBurstLengthSet(I2CA0_BASE, txByteCount[I2C0]);
    
     
                    // Place the first byte into the FIFO.
                    MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE, txDataPtr[I2C0][0]);
    
     
                    // Initiate I2C write operation.
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_FIFO_BURST_SEND_START |
                        I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);
                }
    
     
                // If the associated callback is enabled and exists, call it.
                if ((txCallbackEnable[I2C0] == true) &&
                    (CallbackArray[I2C0][I2C_CB_RX] != NULL))
                CallbackArray[I2C0][I2C_CB_RX](NULL);
            }
        }
    }
    else if ((isrSourceMask & I2C_MASTER_INT_TX_FIFO_REQ) ||
                 (isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY))
        {
            // Clear the interrupt flag.
            MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_REQ);
            MAP_I2CMasterIntClearEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    
    		if(isrSourceMask & I2C_MASTER_INT_TX_FIFO_EMPTY)
    		{
    			//This is needed to stop the interrupt from continuously firing
    			//This interrupt should be enabled just prior to issuing
    			//a send command.
    			MAP_I2CMasterIntDisableEx(I2CA0_BASE, I2C_MASTER_INT_TX_FIFO_EMPTY);
    		}
          
            
            // If we're done with the write...
            if (txByteCount[I2C0] == txBytesDone[I2C0])
            {
                // If we're done, send STOP.
                if (rxByteCount[I2C0] == rxBytesDone[I2C0])
                { 
    
     
                  MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_BURST_SEND_FINISH);
                }
                // If we're doing a Write-Then-Read, configure the FIFO
                // and then send a re-START.
                else
                {
                    // Set the I2C address + READ bit.
                    MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, i2cAddress, I2C_READ);
    
     
                    // Set the length of the operation.
                    MAP_I2CMasterBurstLengthSet(I2CA0_BASE, rxByteCount[I2C0]);
    
     
                    // Initiate I2C read operation.
                    MAP_I2CMasterControl(I2CA0_BASE,
                        I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START |
                        I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);
                   
                
                }
    
     
                // If the associated callback exists, call it.
                if (CallbackArray[I2C0][I2C_CB_TX] != NULL)
                    CallbackArray[I2C0][I2C_CB_TX](NULL);
            }
    
     
            // If there's more to send...
            else
            {
                // Put more data in the FIFO.
                MAP_I2CFIFODataPutNonBlocking(I2CA0_BASE,
                    txDataPtr[I2C0][txBytesDone[I2C0]]);
                
            if (txByteCount[I2C0] > txBytesDone[I2C0])
                  txBytesDone[I2C0]++;                  
            }
        }
    else if (isrSourceMask & I2C_MASTER_INT_RX_FIFO_FULL)

    Thanks,

    -justin