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: TM4C129 Repeated Start Condition and TI-RTOS driver

Part Number: TM4C1294NCPDT

Does anyone know if the I2C driver library in TI-RTOS works with chips that require repeated start condition? I have a RTC chip I'm trying communicate with, but it requires repeated start condition. 

Regards,

Bob Starr

  • I believe the answer is yes. The Tiva TI-RTOS I2C driver source is in the file:   C:\ti\tirtos_tivac_2_16_00_08\products\tidrivers_tivac_2_16_00_08\packages\ti\drivers\i2c\I2CTiva.c

    The function I2CTiva_hwiFxn() is called by the handler to send either the stop condition, or an additional start condition if a read is required following the write. Look at lines 210 through 321:

                case I2CTiva_WRITE_MODE:
                    /* Decrement write Counter */
                    object->writeCountIdx--;
    
                    /* Check if more data needs to be sent */
                    if (object->writeCountIdx) {
                        Log_print3(Diags_USER2,
                                   "I2C:(%p) ISR I2CTiva_WRITE_MODE: Data to write: "
                                   "0x%x; To slave: 0x%x",
                                   hwAttrs->baseAddr,
                                   *(object->writeBufIdx),
                                   object->currentTransaction->slaveAddress);
    
                        /* Write data contents into data register */
                        I2CMasterDataPut(hwAttrs->baseAddr, *(object->writeBufIdx));
                        object->writeBufIdx++;
    
                        if ((object->writeCountIdx < 2) && !(object->readCountIdx)) {
                            /* Everything has been sent, nothing to receive */
                            /* Next state: Idle mode */
                            object->mode = I2CTiva_IDLE_MODE;
    
                            /* Send last byte with STOP bit */
                            I2CMasterControl(hwAttrs->baseAddr,
                                             I2C_MASTER_CMD_BURST_SEND_FINISH);
    
                            Log_print1(Diags_USER2,
                                       "I2C:(%p) ISR I2CTiva_WRITE_MODE: ACK received; "
                                       "Writing w/ STOP bit",
                                       hwAttrs->baseAddr);
                        }
                        else {
                            /*
                             * Either there is more date to be transmitted or some
                             * data needs to be received next
                             */
                            I2CMasterControl(hwAttrs->baseAddr,
                                             I2C_MASTER_CMD_BURST_SEND_CONT);
    
                            Log_print1(Diags_USER2,
                                       "I2C:(%p) ISR I2CTiva_WRITE_MODE: ACK received; "
                                       "Writing",
                                       hwAttrs->baseAddr);
                        }
                    }
    
                    /* At this point, we know that we need to receive data */
                    else {
                        /*
                         * We need to check after we are done transmitting data, if
                         * we need to receive any data.
                         * In a corner case when we have only one byte transmitted
                         * and no data to receive, the I2C will automatically send
                         * the STOP bit. In other words, here we only need to check
                         * if data needs to be received. If so, how much.
                         */
                        if (object->readCountIdx) {
                            /* Next state: Receive mode */
                            object->mode = I2CTiva_READ_MODE;
    
                            /* Switch into Receive mode */
                            I2CMasterSlaveAddrSet(hwAttrs->baseAddr,
                                                  object->currentTransaction->slaveAddress,
                                                  true);
    
                            if (object->readCountIdx > 1) {
                                /* Send a repeated START */
                                I2CMasterControl(hwAttrs->baseAddr,
                                                 I2C_MASTER_CMD_BURST_RECEIVE_START);
    
                                Log_print1(Diags_USER2,
                                           "I2C:(%p) ISR I2CTiva_WRITE_MODE: -> "
                                           "I2CTiva_READ_MODE; Reading w/ RESTART and ACK",
                                           hwAttrs->baseAddr);
                            }
                            else {
                                /*
                                 * Send a repeated START with a NACK since it's the
                                 * last byte to be received.
                                 * I2C_MASTER_CMD_BURST_RECEIVE_START_NACK is
                                 * is locally defined because there is no macro to
                                 * receive data and send a NACK after sending a
                                 * start bit (0x00000003)
                                 */
                                I2CMasterControl(hwAttrs->baseAddr,
                                                 I2C_MASTER_CMD_BURST_RECEIVE_START_NACK);
    
                                Log_print1(Diags_USER2,
                                           "I2C:(%p) ISR I2CTiva_WRITE_MODE: -> "
                                           "I2CTiva_READ_MODE; Reading w/ RESTART and NACK",
                                           hwAttrs->baseAddr);
                            }
                        }
                        else {
                            /* Done with all transmissions */
                            object->mode = I2CTiva_IDLE_MODE;
                            /*
                             * No more data needs to be received, so follow up with
                             * a STOP bit
                             * Again, there is no equivalent macro (0x00000004) so
                             * I2C_MASTER_CMD_BURST_RECEIVE_STOP is used.
                             */
                            I2CMasterControl(hwAttrs->baseAddr,
                                             I2C_MASTER_CMD_BURST_RECEIVE_STOP);
    
                            Log_print1(Diags_USER2,
                                       "I2C:(%p) ISR I2CTiva_WRITE_MODE: -> "
                                       "I2CTiva_IDLE_MODE; Sending STOP bit",
                                       hwAttrs->baseAddr);
                        }
                    }
                    break;
    

  • Many thanks for the reply, I'm no I2C expert and limited experience with this bus. Yes it looks like it should support repeated start condition. I'm confused how to do a simple register read from the RTC clock chip and new to the RTC part also. I'm trying to do a single register read from a MCP79410 part to check the running status.

    I'm attempting to write the command byte and read a byte back. I don't understand if there's a stop/start condition between writing the read register command and reading back the result byte. It seems like the part wants a repeated start between the write/read operation. The driver interrupt is giving an error in the section below.

            /* Some sort of error happened! */
            object->mode = I2CTiva_ERROR;
    
            if (errStatus & (I2C_MASTER_ERR_ARB_LOST | I2C_MASTER_ERR_ADDR_ACK)) {
                I2CTiva_completeTransfer((I2C_Handle) arg);
            }
    

    #define  RTCC_WRITE     0xDE       //  DEVICE ADDR for RTCC MCHP  (writes)
    #define  RTCC_READ      0xDF       //  DEVICE ADDR for RTCC MCHP  (reads)
    
    uint8_t MCP79410_Read(MCP79410_Handle handle, uint8_t rtcc_reg)
    {
        //IArg key;
        I2C_Transaction i2cTransaction;
        uint8_t txBuffer[2];
        uint8_t rxBuffer[2];
    
        txBuffer[0] = rtcc_reg;
    
        /* Write a dummy byte with address */
        i2cTransaction.slaveAddress = RTCC_WRITE;
        i2cTransaction.writeBuf     = &txBuffer;
        i2cTransaction.writeCount   = 1;
        i2cTransaction.readBuf      = &rxBuffer;
        i2cTransaction.readCount    = 0;
    
        if (!I2C_transfer(handle->i2cHandle, &i2cTransaction))
        {
            System_printf("Unsuccessful I2C transfer\n");
            System_flush();
        }
    
        txBuffer[0] = rtcc_reg;
    
        /* Initialize master SPI transaction structure */
        i2cTransaction.slaveAddress = RTCC_READ;
        i2cTransaction.writeBuf     = &txBuffer;
        i2cTransaction.writeCount   = 0;
        i2cTransaction.readBuf      = &rxBuffer;
        i2cTransaction.readCount    = 1;
    
        if (!I2C_transfer(handle->i2cHandle, &i2cTransaction))
        {
            System_printf("Unsuccessful I2C transfer\n");
            System_flush();
        }
    
        return rxBuffer[0];
    }

  • This is what the RTC chip wants to see with repeated start condition. 

    I'm not sure how to achieve this with the I2C driver I2C_Transaction API. Is this even possible through I2C driver interface? Seems like a special flag would be needed somewhere to tell it not to send the STOP condition after writing the control byte and address. It appears to me this is not even possible through TI-RTOS I2C API?

    Best Regards,

    Bob Starr

  • Also ran across another example with "chained read", but no luck with this so far either.

    bool transferDone = false;
    
    void I2C3writeCallback(I2C_Handle handle, I2C_Transaction *transaction, bool result)
    {
        // Set length bytes
        if (result) {
            transferDone = true;
        } else {
            // Transaction failed, act accordingly...
            System_printf("Unsuccessful I2C transfer\n");
            System_flush();
        }
    }
    
    uint8_t MCP79410_Read(MCP79410_Handle handle, uint8_t regadd)
    {
        I2C_Transaction i2cTrans1;
        I2C_Transaction i2cTrans2;
        uint8_t txBuffer1[2];
        uint8_t rxBuffer1[2];
        uint8_t txBuffer2[2];
        uint8_t rxBuffer2[2];
    
        txBuffer1[0] = regadd;
    
        // Initialize first master I2C transaction structure
        i2cTrans1.slaveAddress = RTCC_WRITE;        // 0xDE
        i2cTrans1.writeCount   = 1;
        i2cTrans1.writeBuf     = txBuffer1;
        i2cTrans1.readCount    = 0;
        i2cTrans1.readBuf      = rxBuffer1;
    
        txBuffer2[0] = regadd;
    
        // Second transaction
        i2cTrans2.slaveAddress = RTCC_READ;         // 0xDF
        i2cTrans2.writeCount   = 0;
        i2cTrans2.writeBuf     = txBuffer2;
        i2cTrans2.readCount    = 1;
        i2cTrans2.readBuf      = rxBuffer2;
    
        // Do chained I2C transfers (in callback mode).
        I2C_transfer(handle->i2cHandle, &i2cTrans1);
        I2C_transfer(handle->i2cHandle, &i2cTrans2);
    
        // Do other stuff while I2C is handling the transfers
    
        // Do something if I2C transfers are finished
    
        Task_sleep(1000);
    
        if (transferDone) {
    
        }
        // Continue...
    
        return rxBuffer2[0];
    }
    

  • What you want is to do a single call to I2C_transfer with a write count of 1 and a read count of 1. You need to set the slave address using only 7 bits. The last read/write bit is added by the driver. For example an RTCC address of 0x6F instead of 0xDE and 0xDF.

  • Hi Bob,

    Many, many thanks!! Finally have this annoying part working! My goof, I changed my address macros per below.

    #define RTCC_WRITE (0xDE >> 1) // DEVICE ADDR for RTCC MCHP (writes)
    #define RTCC_READ (0xDF >> 1) // DEVICE ADDR for RTCC MCHP (reads)

    Originally, I had the code writing and reading one byte, but couldn't understand why it wasn't working.

    I had forgotten all about the addressing bit shift issue due to my own oversight. Thanks so much for your help!

    Best Regards,