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.

Interfacing multiple I2C devices to Tiva C?

Other Parts Discussed in Thread: INA226, ADS1115

Does Tivaware have any examples about interfacing multiple I2C devices to Tiva C? If not, suggest me some ideas?

Thanks!

  • Happy Smile said:
    Does Tivaware have any examples about interfacing multiple I2C devices to Tiva C?

    None, from my Tivaware copy.

    - kel

  • Hello Happy Smile,

    I have a 3 Slave device Initialization and Access. The 3 slave devices are ADC's and require Start of Conversion and then polling for data read. If it sounds useful for your application then may be I can post it to the forum.

    Also do remember that I don't have any RTOS, so it is a very basic access code based on TM4C129.


    Regards

    Amit

  • Actually, i bought a sensorhub for TM4C123G Lanchpad. I want to get data from MPU9150 and other sensors like pressure, humidity...via I2C Bus.

    So, your project will help me a lot.

    Please post it!

    Thanks very much!

    Best Regards!

    -Happy-

  • Hello Happy Smile,

    Oh boy!!! I should have been careful. Now knowing what you want to do, my project may not be much useful.

    But anyways I will commit this as a project. Would need some time (depends on the workload) to see how to get all of the slaves talking!!! I hope that should be OK for your project timelines.

    Regards

    Amit

  • Amit, (writing to, "Happy Smile"), "My project may not be much useful." 

    In that light - we note forum identities/sign-ons: "Half Smile" and "Slight Frown" appear (still) available...  (but not, "cb1")

    Amit's, "3 slave devices are ADC's" - seems sub-optimal (to be kind) to this reporter.  (way too focused/repetitive...Boring!) 

    Would not an ADC; Temperature sensor (your firm has neat, new, I2C based one; and some form of Motion sensor (i.e. accel. or ultra-sound ranging (position) prove vastly more attractive & useful?  And - buys you "more time" to design/test-verify and deliver!  (here)  And - surely more "enriching, challenging - fun" for you.  (some do consider that...)

  • Can you post your project, i will refer to your project with my care. I think it will help me a lot about how to interface multiple i2c devices to Tiva C!

    Thanks!

  • Hello Happy Smile,

    Would require a day to move the functions I have into a single file. Will post the code as soon I have made the changes mentioned in the post and tested it.

    Regards

    Amit

  • Such a modification would be better for me, but if you are busy at work. Just send me what you had done. It would be ok for me too.

    Best Regards! 

  • Hello Happy Smile

    Attached are .c and .h files for the library I have created for multiple I2C Slave Devices.

    //*****************************************************************************
    //
    // zeuslib.c - Driver for ZEUS interface PSV Database.
    //
    // Copyright (c) 2005 Texas Instruments Incorporated.  All rights reserved.
    // TI Information - Selective Disclosure
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! \addtogroup zeus_api
    //! @{
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_types.h"
    #include "inc/hw_i2c.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/zeuslib.h"
    
    //*******************************************************************
    //
    // Get the System Clock Frequency
    //
    //*******************************************************************
    static
    uint32_t ZEUSLibSystemClkGet()
    {                                      //Get system clk freq
        return(120000000);
    }
    
    //*******************************************************************
    //
    //! Initializes I2C for Transfer
    //!
    //! \param ui32BaseAddress is the Base Address of I2C
    //!
    //! The \e ui32BaseAddress parameter should be one of the following values:
    //!
    //! \b I2C0_BASE
    //! \b I2C1_BASE
    //! \b I2C2_BASE
    //! \b I2C3_BASE
    //!
    //! \return None.
    //
    //*******************************************************************
    void 
    ZEUSLibInit(uint32_t ui32BaseAddress)
    {
        uint32_t ui32SysCtlPeripheral;
        uint32_t ui32I2CClock;
        
        
        switch(ui32BaseAddress)
        {
          case I2C0_BASE:
                         ui32SysCtlPeripheral = SYSCTL_PERIPH_I2C0;
          break;
          case I2C1_BASE:
                         ui32SysCtlPeripheral = SYSCTL_PERIPH_I2C1;
          break;
          case I2C2_BASE:
                         ui32SysCtlPeripheral = SYSCTL_PERIPH_I2C2;
          break;
          case I2C3_BASE:
                         ui32SysCtlPeripheral = SYSCTL_PERIPH_I2C3;
          break;
          default:
                         ui32SysCtlPeripheral = SYSCTL_PERIPH_I2C0;
          break;
        }
    
        //
        // Disable, Reset and Enable the I2C Module Instance
        //
        SysCtlPeripheralDisable(ui32SysCtlPeripheral); 
        SysCtlPeripheralReset(ui32SysCtlPeripheral); 
        SysCtlPeripheralEnable(ui32SysCtlPeripheral); 
          
        //    
        // Configure the I2C Baud Rate for 400KHz
        //
        ui32I2CClock = ZEUSLibSystemClkGet();
    
        I2CMasterInitExpClk(ui32BaseAddress,ui32I2CClock,true);
    
        //
        // Enable I2C Master Operation
        //
        I2CMasterEnable(ui32BaseAddress);
    
    }
    
    //*******************************************************************
    //
    //! Gets the voltage from corresponding channel
    //!
    //! \param ui32BaseAddress is the Base Address of I2C
    //! \param ui32Channel is the address of analog input channel
    //! \param *ui32Quotient is the address of Integer part of the voltage
    //! \param *ui32Remainder is the address of Fractional part of the voltage
    //!
    //! The \e ui32BaseAddress parameter should be one of the following values:
    //!
    //! \b I2C0_BASE
    //! \b I2C1_BASE
    //! \b I2C2_BASE
    //! \b I2C3_BASE
    //!
    //! The \e ui32Channel parameter should be one of the following values:
    //!
    //! \b ZEUS_AIN_CHA
    //! \b ZEUS_AIN_CHB
    //! \b ZEUS_AIN_CHC
    //! \b ZEUS_AIN_CHD
    //!
    //! \return Returns code corresponding to voltage at specified channel 
    //
    //*******************************************************************
    uint32_t 
    ZEUSLibGetVoltage(uint32_t ui32BaseAddress,
                      uint32_t ui32Channel,
                      uint32_t *ui32Quotient,
                      uint32_t *ui32Remainder)
    {
        uint32_t ui32ADS1115ConfigRegValue;
        uint32_t ui32ADSOut;
        uint8_t  ui8PointerReg;
        uint8_t  ui8ConvRegHighByte;
        uint8_t  ui8ConvRegLowByte;
        float    fComputeVariable;
       
        ui32ADS1115ConfigRegValue = ZEUS_ADS1115_OPMODE |
                                    ZEUS_ADS1115_PGA << 1 |
                                    (ui32Channel+0x4) << 4 | 
                                    ZEUS_ADS1115_SINGLE_CONVERSION_START << 7;
    
        //            
        // Write to the Config Register of ADS1115
        //
        ui8PointerReg = ZEUS_ADS1115_CONFIG_REG; 
        I2CMasterSlaveAddrSet(ui32BaseAddress, ZEUS_ADS1115_ADDR, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ui8PointerReg);
        I2CMasterControl(ui32BaseAddress,I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        ui8PointerReg = ui32ADS1115ConfigRegValue;
        I2CMasterDataPut(ui32BaseAddress, ui8PointerReg);
        I2CMasterControl(ui32BaseAddress,I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        ui8PointerReg = ZEUS_ADS1115_CONF_REG_L;
        I2CMasterDataPut(ui32BaseAddress, ui8PointerReg);
        I2CMasterControl(ui32BaseAddress,I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        SysCtlDelay(20000);
      
        //
        // Read the Conversion Register
        //
        ui8PointerReg = ZEUS_ADS1115_CONV_REG;  
    
        I2CMasterSlaveAddrSet(ui32BaseAddress, ZEUS_ADS1115_ADDR, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ui8PointerReg);
        I2CMasterControl(ui32BaseAddress,I2C_MASTER_CMD_BURST_SEND_START );
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        I2CMasterSlaveAddrSet(ui32BaseAddress, ZEUS_ADS1115_ADDR, ZEUS_READ);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegHighByte = I2CMasterDataGet(ui32BaseAddress);
    
        I2CMasterControl(ui32BaseAddress,I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegLowByte = I2CMasterDataGet(ui32BaseAddress);
    
        ui32ADSOut        = ((ui8ConvRegHighByte<<8)|ui8ConvRegLowByte);
    
        fComputeVariable  = (float) (ui32ADSOut * 0.000125);
        *ui32Quotient     = (int32_t) fComputeVariable;
        *ui32Remainder    = (int32_t) (fComputeVariable * 1000.0f);
        *ui32Remainder    = *ui32Remainder - (*ui32Quotient * 1000);
        if(*ui32Remainder < 0)
        {
           *ui32Remainder *= -1;
        }
    
       
        return ui32ADSOut;
    }
    
    //**************************************************************************
    //
    //! Checks voltage of corresponding channel and compares with expected voltage
    //!
    //! \param ui32BaseAddress is the Base Address of I2C
    //! \param ui32Channel is the address of analog input channel
    //! \param ui32RefCode is the expected voltage at corresponding channel
    //!
    //! The \e ui32BaseAddress parameter should be one of the following values:
    //!
    //! \b I2C0_BASE
    //! \b I2C1_BASE
    //! \b I2C2_BASE
    //! \b I2C3_BASE
    //!
    //! The \e ui32Channel parameter should be one of the following values:
    //!
    //! \b ZEUS_AIN_CHA
    //! \b ZEUS_AIN_CHB
    //! \b ZEUS_AIN_CHC
    //! \b ZEUS_AIN_CHD
    //!
    //! The \e ui32RefCode parameter can take one of the value from \b ZEUS_REF_CODE_3V3, 
    //! \b ZEUS_REF_CODE_3V2 through \b ZEUS_REF_CODE_0V0
    //!
    //! \return Returns ZEUS_VOLT_LOW0 if DUT voltage is less than expected
    //! \return Returns ZEUS_VOLT_HIGH1 if DUT voltage is greater than expected
    //! \return Returns ZEUS_VOLT_OK2 if DUT voltage is equal to expected voltage
    //
    //**************************************************************************
    uint32_t 
    ZEUSLibCheckVoltage(uint32_t ui32BaseAddress,
                        uint32_t ui32Channel,
                        uint32_t ui32RefCode)
    {
        uint32_t ui32ADSOutput;
        uint32_t ui32ReadQ;
        uint32_t ui32ReadR;
    
        ui32ADSOutput = ZEUSLibGetVoltage(ui32BaseAddress,ui32Channel,&ui32ReadQ,&ui32ReadR);
       
        if((ui32RefCode-ZEUS_MARGIN) > ui32ADSOutput)
        {
            return(ZEUS_VOLT_LOW);
        }
        else if(ui32ADSOutput > (ui32RefCode+ZEUS_MARGIN))
        {
            return(ZEUS_VOLT_HIGH);
        }   
        else
        {
            return(ZEUS_VOLT_OK);
        }
         
    }
    
    //*******************************************************************
    //
    //! Initializes INA226 for Current Measurement
    //!
    //! \param ui32BaseAddress is the Base Address of I2C
    //! \param ui32Channel is the INA226A or INA226B to Configure
    //! \param ui32Resistor is the Resistance Value in milli-ohms
    //! \param ui32MaxCurrentInmA is the Maximum Current to measure in mA
    //!
    //! The \e ui32BaseAddress parameter should be one of the following values:
    //!
    //! \b I2C0_BASE
    //! \b I2C1_BASE
    //! \b I2C2_BASE
    //! \b I2C3_BASE
    //!
    //! The \e ui32Channel parameter should be one of the following values:
    //!
    //! \b ZEUS_CURR_CHA
    //! \b ZEUS_CURR_CHB
    //!
    //! The \e ui32Resistor parameter should be a value between 1 to 3300
    //! milli-ohms
    //!
    //! The \e ui32MaxCurrentInmA is the Maximum Current to measure in mA and
    //! should be set to 150mA
    //!
    //! \return None.
    //
    //*******************************************************************
    void
    ZEUSLibConfigureCurrentSense(uint32_t ui32BaseAddress,
                                 uint32_t ui32Channel,
                                 uint32_t ui32Resistor,
                                 uint32_t ui32MaxCurrentInmA)
    {
        uint32_t ui32CalibrationValue;
        uint32_t ui32CalibrationRem;
    
        ui32CalibrationValue = (512*32768*10)/(ui32MaxCurrentInmA*ui32Resistor);
        ui32CalibrationRem   = (512*32768*10)%(ui32MaxCurrentInmA*ui32Resistor);
    
        //
        // INA 226 advises Trunc. Hence check if the Remained is more than
        // 0.5 and increment the Calibration Value by 1
        //
        if(ui32CalibrationRem > (ui32MaxCurrentInmA*ui32Resistor)/2)
        {
         ui32CalibrationValue++;
        }
    
        //
        // Reset INA226
        //
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CONFIG_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, (ZEUS_INA226_CONFIG_DEF_H|ZEUS_INA226_CONFIG_RESET));
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CONFIG_DEF_L);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
     
        SysCtlDelay(10000);
    
        //
        // Write INA226 Configuration Register
        //
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CONFIG_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CONFIG_CNT_SV_H);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CONFIG_CNT_SV_L);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
     
        SysCtlDelay(10000);
    
        //
        // Write INA226 Calibration Register
        //
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_CAL_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ((ui32CalibrationValue & 0xFF00) >> 8));
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ((ui32CalibrationValue & 0x00FF) >> 0));
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        //
        // Write INA226 Mask Register for Over Voltage on Shunt
        //
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_MASK_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_MASK_OVF_EN_H);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_MASK_OVF_EN_L);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
        //
        // Write INA226 Alert Register
        //
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ALERT_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ALERT_80MV_H);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_CONT);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ALERT_80MV_L);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
    
    }
    
    //*******************************************************************
    //
    //! Gets the current from corresponding channel
    //!
    //! \param ui32BaseAddress is the Base Address of I2C
    //! \param ui32Channel is the address of analog input channel
    //! \param *bSign is the sign value of the current
    //! \param *ui32Quotient is the address of Integer part of the current
    //! \param *ui32Remainder is the address of Fractional part of the current
    //!
    //! The \e ui32BaseAddress parameter should be one of the following values:
    //! \param ui32Channel is the INA226A or INA226B to Configure
    //!
    //! \b I2C0_BASE
    //! \b I2C1_BASE
    //! \b I2C2_BASE
    //! \b I2C3_BASE
    //!
    //! The \e ui32Channel parameter should be one of the following values:
    //!
    //! \b ZEUS_CURR_CHA
    //! \b ZEUS_CURR_CHB
    //!
    //! \return Returns code corresponding to voltage at specified channel in 
    //! hex notation, quotient and remainder for float and Sign of the current 
    //
    //*******************************************************************
    uint32_t
    ZEUSLibGetCurrent(uint32_t ui32BaseAddress,
                      uint32_t ui32Channel,
                      bool     *bSign,
                      uint32_t *ui32Quotient,
                      uint32_t *ui32Remainder)
    {
        uint32_t ui32ADSOut;
        uint8_t  ui8ConvRegHighByte;
        uint8_t  ui8ConvRegLowByte;
        float    fComputeVariable;
    
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ICONV_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_READ);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegHighByte = I2CMasterDataGet(ui32BaseAddress);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegLowByte = I2CMasterDataGet(ui32BaseAddress);
    
        ui32ADSOut = ui8ConvRegHighByte << 8 | ui8ConvRegLowByte;
    
        //
        // If Negative Number then run 2's complement
        //
        *bSign  = false; 
        if((ui32ADSOut & 0x8000) == 0x8000) {
          ui32ADSOut = ~(ui32ADSOut);
          ui32ADSOut = ui32ADSOut + '1';
          ui32ADSOut = ui32ADSOut && 0xFFFF;
          *bSign  = true; 
        }
    
        fComputeVariable  = (float) (ui32ADSOut * 0.00457);
        *ui32Quotient     = (int32_t) fComputeVariable;
        *ui32Remainder    = (int32_t) (fComputeVariable * 1000.0f);
        *ui32Remainder    = *ui32Remainder - (*ui32Quotient * 1000);
        if(*ui32Remainder < 0)
        {
           *ui32Remainder *= -1;
        }
    
        return(ui32ADSOut);
    }
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    1004.zeuslib.h

    The Functions that I call in the main code are in the following order

    uint16_t ulLowByte      = 0;
    bool     bSign;
    uint32_t i32IntegerPart;
    uint32_t i32FractionPart;

    ZEUSLibInit(I2C0_BASE);
    ZEUSLibConfigureCurrentSense(I2C0_BASE,ZEUS_INA226A_ADDR,500,150);
    ZEUSLibConfigureCurrentSense(I2C0_BASE,ZEUS_INA226B_ADDR,500,150);

     while(1) {
              ulLowByte = ZEUSLibGetCurrent(I2C0_BASE,ZEUS_INA226A_ADDR,&bSign,&i32IntegerPart,&i32FractionPart);
              if(bSign) {
                UARTprintf("Ia -%3d.%03d\n", i32IntegerPart, i32FractionPart);
              } else {
                UARTprintf("Ia %3d.%03d\n", i32IntegerPart, i32FractionPart);
              }
              ulLowByte = ZEUSLibGetCurrent(I2C0_BASE,ZEUS_INA226B_ADDR,&bSign,&i32IntegerPart,&i32FractionPart);
              if(bSign) {
                UARTprintf("Ib -%3d.%03d\n", i32IntegerPart, i32FractionPart);
              } else {
                UARTprintf("Ib %3d.%03d\n", i32IntegerPart, i32FractionPart);
              }
              ulLowByte = ZEUSLibGetVoltage(I2C0_BASE,ZEUS_AIN_CHA,&i32IntegerPart,&i32FractionPart);
              UARTprintf("Va %3d.%03d\n", i32IntegerPart, i32FractionPart);
              ulLowByte = ZEUSLibGetVoltage(I2C0_BASE,ZEUS_AIN_CHB,&i32IntegerPart,&i32FractionPart);
              UARTprintf("Vb %3d.%03d\n", i32IntegerPart, i32FractionPart);
              ulLowByte = ZEUSLibGetVoltage(I2C0_BASE,ZEUS_AIN_CHC,&i32IntegerPart,&i32FractionPart);
              UARTprintf("Vc %3d.%03d\n", i32IntegerPart, i32FractionPart);
    }

    I interface the I2C to 2x Current Sense INA226 ADC and 1x Voltage Sense Quad Channel ADS1115 ADC

    Regards

    Amit

  • Great help!

    Thanks very much, Amit!

    But i still need some help from you. What is the functionality of the I2CMasterDataPut and I2CMasterControl?

        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);
        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ICONV_REG);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_READ);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegHighByte = I2CMasterDataGet(ui32BaseAddress);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));
        ui8ConvRegLowByte = I2CMasterDataGet(ui32BaseAddress);
    
        ui32ADSOut = ui8ConvRegHighByte << 8 | ui8ConvRegLowByte;

  • Hello Happy Smile,

    The function of the I2CMasterDataPut is to write to the Transmit buffer when i2C Master is in Transmit Mode. The function of the I2CMasterControl is to write to the master Control Register which decides what kind of transfer needs to be done e.g. Start, continue transmit, continue recieve, stop

    The detailed description of these API's can be found in the Driverlib User Guide which comes along with the TIVAWare docs

    Regards

    Amit

  • Oh, actually, i wanna know the purposes of these two functions in your code.

    And can you tell me what is the procedure to communicate with multiple slaves?

    Thanks!

  • Hello Happy Smile,

    I program the Slave Address using I2CMasterSlaveAddrSet for each of the 3 devices, program the register address as data using I2CMasterDataPut send the SA+RA using I2CMasterControl with a Start condition, then issue issue Slave Address in Read mode, with repeated start and read the bytes of data. Once complete a Stop condition is put back on the bus.

    Regards

    Amit

  • Amit, can you also explain what you implemented in the ZEUSLibGetCurrent(). Because i actually havenot understood the steps in this function?

    Thanks

  • Hello Happy Smile,

    I have added comments for every section

    // Select INA226 Slave Address

        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_WRITE);

    // Select RA= Conversion Register

        I2CMasterDataPut(ui32BaseAddress, ZEUS_INA226_ICONV_REG);

    // Send Start Condition with Slave Address as INA226 and Write Mode in RnW of the Address Frame
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_SEND_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));

    // Send Repeated Start with Slave Address as INA226 and in Read Mode in RnW of the Address Frame
        I2CMasterSlaveAddrSet(ui32BaseAddress, ui32Channel, ZEUS_READ);
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_START);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));

    // Read the Higher byte of A/D conversion
        ui8ConvRegHighByte = I2CMasterDataGet(ui32BaseAddress);

    // Put Stop condition on the bus after the next byte
        I2CMasterControl(ui32BaseAddress, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
        while(!(I2CMasterBusy(ui32BaseAddress)));
        while(I2CMasterBusy(ui32BaseAddress));

    // Read the Lowerbyte of A/D conversion

        ui8ConvRegLowByte = I2CMasterDataGet(ui32BaseAddress);

    Regards

    Amit

  • Sorry to ask you so many questions! But i am still so confused!

    Why do you have to send START, STOP to the slaves like this!

    Is the way i think about communication between 1 master vs multiple senors as below right or wrong?

    I2CMInit();

    MPU9150Init();

    BMP180Init();

    while(1)

    {

    SetSlaveAdress(MPU9150);

    // Get data and do some calculations

    SetSlaveAdress(BMP180);

    // Get data and do some calculations

    }

  • Hello Happy Smile,

    Slave devices which support I2C as the control/communication interface, at times need a method where a read and write to specific address is required. The I2C Frame always has Address+RnW (direction) followed by Data (read or write). It would be lot troublesome if the Registers are to be directly address as for some of the devices it may exhaust the 7-bit address. Also it would limit the number of slaves that can be connected on the shared bus. Thus most vendors now use indirect addressing where the transaction is Start->Slave Address+W->register Address->Start->Slave Address+R->Read Data(Register Address->Stop or Start->Slave Address+W->register Address->Start->Slave Address+W->WriteData(Register Address->Stop.

    How have you setup the API SetSlaveAddress and Get data functions will be critical to set up the full sensor board example. Without having created a sample program it would be a long forum thread

    P.S: No problems, on the question...

    Regards

    Amit

  • I forgot to change the address of the slave when communicating with MPU9150 and BMP180, but i still got the reasonable result. Do you know what is the reason for that?

    And also i run the sample project BMP180 and i get the altitude, but when i change the vertical position, the displayed result seems not to change very much!

  • Hello Happy Smile

    I reckon you would have accessed the same slave device.

    Regards

    Amit

  • It means that when operating, i just need to set the slave address and then i can get the correct data from the expected data!

  • Hello happy,

    Yes, that is true provided the format of communication over I2C is same for the Slave Devices

    Regards

    Amit

  • Thanks very much, Amit!

    I will try that and let you know the result later!

  • I saw that the data from BMP180 varies so quickly, so do we have to filter the result?

  • Hello Happy Smile,

    The raw data from the sensor would change rapidly, You would need to convert/process the same in decimal format as the original example do in TivaWare,

    Regards

    Amit

  •  while(1)
        {
            //
            // Go to sleep mode while waiting for data ready.
            //
            while(!g_vui8I2CDoneFlag)
            {
                ROM_SysCtlSleep();
            }
    
            //
            // Clear the flag
            //
            g_vui8I2CDoneFlag = 0;
    
            //
            // Get floating point version of the Accel Data in m/s^2.
            //
            MPU9150DataAccelGetFloat(&g_sMPU9150Inst, pfAccel, pfAccel + 1,
                                     pfAccel + 2);
    				
            //
            // Get floating point version of angular velocities in rad/sec
            //
            MPU9150DataGyroGetFloat(&g_sMPU9150Inst, pfGyro, pfGyro + 1,
                                    pfGyro + 2);
    
            //
            // Get floating point version of magnetic fields strength in tesla
            //
            MPU9150DataMagnetoGetFloat(&g_sMPU9150Inst, pfMag, pfMag + 1,
                                       pfMag + 2);
    
            //
            // Check if this is our first data ever.
            //
            if(ui32CompDCMStarted == 0)
            {
                //
                // Set flag indicating that DCM is started.
                // Perform the seeding of the DCM with the first data set.
                //
                ui32CompDCMStarted = 1;
                CompDCMMagnetoUpdate(&g_sCompDCMInst, pfMag[0], pfMag[1],
                                     pfMag[2]);
                CompDCMAccelUpdate(&g_sCompDCMInst, pfAccel[0], pfAccel[1],
                                   pfAccel[2]);
                CompDCMGyroUpdate(&g_sCompDCMInst, pfGyro[0], pfGyro[1],
                                  pfGyro[2]);
                CompDCMStart(&g_sCompDCMInst);
            }
            else
            {
                //
                // DCM Is already started.  Perform the incremental update.
                //
                CompDCMMagnetoUpdate(&g_sCompDCMInst, pfMag[0], pfMag[1],
                                     pfMag[2]);
                CompDCMAccelUpdate(&g_sCompDCMInst, pfAccel[0], pfAccel[1],
                                   pfAccel[2]);
                CompDCMGyroUpdate(&g_sCompDCMInst, -pfGyro[0], -pfGyro[1],
                                  -pfGyro[2]);
                CompDCMUpdate(&g_sCompDCMInst);
            }
    
            //
            // Increment the skip counter.  Skip counter is used so we do not
            // overflow the UART with data.
            //
            g_ui32PrintSkipCounter++;
            if(g_ui32PrintSkipCounter >= PRINT_SKIP_COUNT)
            {
                //
                // Reset skip counter.
                //
                g_ui32PrintSkipCounter = 0;
    
                //
                // Get Euler data. (Roll Pitch Yaw)
                //
                CompDCMComputeEulers(&g_sCompDCMInst, pfEulers, pfEulers + 1,
                                     pfEulers + 2);
    
                //
                // Get Quaternions.
                //
                CompDCMComputeQuaternion(&g_sCompDCMInst, pfQuaternion);
    
                //
                // convert mag data to micro-tesla for better human interpretation.
                //
                pfMag[0] *= 1e6;
                pfMag[1] *= 1e6;
                pfMag[2] *= 1e6;
    
                //
                // Convert Eulers to degrees. 180/PI = 57.29...
                // Convert Yaw to 0 to 360 to approximate compass headings.
                //
                pfEulers[0] *= 57.295779513082320876798154814105f;
                pfEulers[1] *= 57.295779513082320876798154814105f;
                pfEulers[2] *= 57.295779513082320876798154814105f;
                if(pfEulers[2] < 0)
                {
                    pfEulers[2] += 360.0f;
                }
    						
    						//
    						//	Assign Eulers to global variables for the purpose of PID Controller
    						//
    						g_actualRoll = pfEulers[0];
    						g_actualPitch = pfEulers[1];
    						g_actualYaw = pfEulers[2];
    						
    						
    						//
                // Now drop back to using the data as a single array for the
                // purpose of decomposing the float into a integer part and a
                // fraction (decimal) part.
                //
                for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
                {
                    //
                    // Conver float value to a integer truncating the decimal part.
                    //
                    i32IPart[ui32Idx] = (int32_t) pfData[ui32Idx];
    
                    //
                    // Multiply by 1000 to preserve first three decimal values.
                    // Truncates at the 3rd decimal place.
                    //
                    i32FPart[ui32Idx] = (int32_t) (pfData[ui32Idx] * 1000.0f);
    
                    //
                    // Subtract off the integer part from this newly formed decimal
                    // part.
                    //
                    i32FPart[ui32Idx] = i32FPart[ui32Idx] -
                                        (i32IPart[ui32Idx] * 1000);
    
                    //
                    // make the decimal part a positive number for display.
                    //
                    if(i32FPart[ui32Idx] < 0)
                    {
                        i32FPart[ui32Idx] *= -1;
                    }
                }
    						
                //
                // Print the acceleration numbers in the table.
                //
                UARTprintf("\033[5;17H%3d.%03d", i32IPart[0], i32FPart[0]);
                UARTprintf("\033[5;40H%3d.%03d", i32IPart[1], i32FPart[1]);
                UARTprintf("\033[5;63H%3d.%03d", i32IPart[2], i32FPart[2]);
    
                //
                // Print the angular velocities in the table.
                //
                UARTprintf("\033[7;17H%3d.%03d", i32IPart[3], i32FPart[3]);
                UARTprintf("\033[7;40H%3d.%03d", i32IPart[4], i32FPart[4]);
                UARTprintf("\033[7;63H%3d.%03d", i32IPart[5], i32FPart[5]);
    
                //
                // Print the magnetic data in the table.
                //
                UARTprintf("\033[9;17H%3d.%03d", i32IPart[6], i32FPart[6]);
                UARTprintf("\033[9;40H%3d.%03d", i32IPart[7], i32FPart[7]);
                UARTprintf("\033[9;63H%3d.%03d", i32IPart[8], i32FPart[8]);
    
                //
                // Print the Eulers in a table.
                //
                UARTprintf("\033[14;17H%3d.%03d", i32IPart[9], i32FPart[9]);
                UARTprintf("\033[14;40H%3d.%03d", i32IPart[10], i32FPart[10]);
                UARTprintf("\033[14;63H%3d.%03d", i32IPart[11], i32FPart[11]);
    
                //
                // Print the quaternions in a table format.
                //
                UARTprintf("\033[19;14H%3d.%03d", i32IPart[12], i32FPart[12]);
                UARTprintf("\033[19;32H%3d.%03d", i32IPart[13], i32FPart[13]);
                UARTprintf("\033[19;50H%3d.%03d", i32IPart[14], i32FPart[14]);
                UARTprintf("\033[19;68H%3d.%03d\n", i32IPart[15], i32FPart[15]);
    						
    						//
    						//	Set address of the BMP180. False indicates a write to the sensor
    						//
    						
    						I2CMasterSlaveAddrSet(I2C3_BASE, BMP180_I2C_ADDRESS, true);
    
    						//
    						// Go to sleep mode while waiting for data ready.
    						//
    						while(!g_vui8I2CDoneFlag)
    						{
    								ROM_SysCtlSleep();
    						}
    
    						//
    						// Clear the flag
    						//
    						g_vui8I2CDoneFlag = 0;
    						
    						//
    						// Get a local copy of the latest temperature data in float format.
    						//
    						BMP180DataRead(&g_sBMP180Inst, BMP180AppCallback, &g_sBMP180Inst);
    						BMP180AppI2CWait();
    						
    						//
    						// Get a local copy of the latest temperature data in float format.
    						//
    						BMP180DataTemperatureGetFloat(&g_sBMP180Inst, &fTemperature);
    						
    						//
    						// Convert the floats to an integer part and fraction part for easy
    						// print.
    						//
    						i32IntegerPart = (int32_t) fTemperature;
    						i32FractionPart =(int32_t) (fTemperature * 1000.0f);
    						i32FractionPart = i32FractionPart - (i32IntegerPart * 1000);
    						if(i32FractionPart < 0)
    						{
    								i32FractionPart *= -1;
    						}
    
    						//
    						// Print temperature with three digits of decimal precision.
    						//
    						UARTprintf("Temperature %3d.%03d\t\t", i32IntegerPart, i32FractionPart);
    
    						//
    						// Get a local copy of the latest air pressure data in float format.
    						//
    						BMP180DataPressureGetFloat(&g_sBMP180Inst, &fPressure);
    
    						//
    						// Convert the floats to an integer part and fraction part for easy
    						// print.
    						//
    						i32IntegerPart = (int32_t) fPressure;
    						i32FractionPart =(int32_t) (fPressure * 1000.0f);
    						i32FractionPart = i32FractionPart - (i32IntegerPart * 1000);
    						if(i32FractionPart < 0)
    						{
    								i32FractionPart *= -1;
    						}
    
    						//
    						// Print Pressure with three digits of decimal precision.
    						//
    						UARTprintf("Pressure %3d.%03d\t\t", i32IntegerPart, i32FractionPart);
    
    						//
    						// Calculate the altitude.
    						//
    						fAltitude = 44330.0f * (1.0f - powf(fPressure / 101325.0f,
                                                1.0f / 5.255f));
    
    						//
    						// Convert the floats to an integer part and fraction part for easy
    						// print.
    						//
    						i32IntegerPart = (int32_t) fAltitude;
    						i32FractionPart =(int32_t) (fAltitude * 1000.0f);
    						i32FractionPart = i32FractionPart - (i32IntegerPart * 1000);
    						if(i32FractionPart < 0)
    						{
    								i32FractionPart *= -1;
    						}
    
    						//
    						// Print altitude with three digits of decimal precision.
    						//
    						UARTprintf("Altitude %3d.%03d", i32IntegerPart, i32FractionPart);
    						I2CMasterSlaveAddrSet(I2C3_BASE, MPU9150_I2C_ADDRESS, true);
    
    						
            }

    Is the way i implemented right?

  • Hello Happy Smile,

    If I were to implement it then would call ROM_SysCtlSleep mode only once. Any interrupt from the sensors should wake it up at which time the code can make a read of the sensor which caused the wakeup and then go back to Sleep Mode

    I am still not through with my code for integrated Sensor Read out.

    Regards

    Amit

  • Ok. I got it. But one more question!

    In your code ZEUSLibGetCurrent(); why do you have to manually send

    I2C_MASTER_CMD_BURST_SEND_START

    I2C_MASTER_CMD_BURST_RECEIVE_START

    I2C_MASTER_CMD_BURST_RECEIVE_FINISH

    I think the master will automatically send these commands!

  • Hello Happy Smile,

    No, the master has to be instructed the type of transfer to be done. If you look at the functions in the code you have and trace it, it will end up into same kind of functions and parameters.

    Regards

    Amit

  • Amit,

    I wish to use the library for obtaining current greater than 150mA. However when I change the expected current value to something greater, it returns ~150mA at most. How can I fix this? Thank you.
  • Hello Chan

    Which library, What current!!! Please give some details on what is that you are using as current sense, ADC, uC?

    Regards
    Amit