0
\$\begingroup\$

I'm new to the Tiva Platform for the past two days I'm trying to read data from bme280's data registers. However, it always returns a 0(I2C bus not working). So far I've tried using this sensor with Arduino and it works perfectly fine.

#include<stdint.h>
#include<stdbool.h>
#include<stdio.h>
#include <string.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/i2c.h"
#include "utils/uartstdio.h"
#include "functions.h"
#include "bme280.h"
#include "bme280_defs.h"
int8_t stream_sensor_data_normal_mode(struct bme280_dev *dev);
void print_sensor_data(struct bme280_data *comp_data);
void main()
{
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    InitConsole();
    UARTprintf("UART OK \n");
    InitI2C1();
    UARTprintf("I2C OK \n");
    struct bme280_dev dev;
    int8_t rslt = BME280_OK;
    dev.dev_id = 0x77;
    dev.intf = BME280_I2C_INTF;
    dev.read = user_i2c_read;
    dev.write = user_i2c_write;
    dev.delay_ms = user_delay_ms;
    rslt = bme280_init(&dev);
    stream_sensor_data_normal_mode(&dev);
}

int8_t stream_sensor_data_normal_mode(struct bme280_dev *dev)
{
    int8_t rslt;
    uint8_t settings_sel;
    struct bme280_data comp_data;

    /* Recommended mode of operation: Indoor navigation */
    dev->settings.osr_h = BME280_OVERSAMPLING_1X;
    dev->settings.osr_p = BME280_OVERSAMPLING_16X;
    dev->settings.osr_t = BME280_OVERSAMPLING_2X;
    dev->settings.filter = BME280_FILTER_COEFF_16;
    dev->settings.standby_time = BME280_STANDBY_TIME_62_5_MS;

    settings_sel = BME280_OSR_PRESS_SEL;
    settings_sel |= BME280_OSR_TEMP_SEL;
    settings_sel |= BME280_OSR_HUM_SEL;
    settings_sel |= BME280_STANDBY_SEL;
    settings_sel |= BME280_FILTER_SEL;
    rslt = bme280_set_sensor_settings(settings_sel, dev);
    rslt = bme280_set_sensor_mode(BME280_NORMAL_MODE, dev);

    UARTprintf("Temperature, Pressure, Humidity\r\n");
    while (1) {
        /* Delay while the sensor completes a measurement */
        dev->delay_ms(1000);
        rslt = bme280_get_sensor_data(BME280_ALL, &comp_data, dev);
        print_sensor_data(&comp_data);
    }

    return rslt;
}

void print_sensor_data(struct bme280_data *comp_data)
{
#ifdef BME280_FLOAT_ENABLE
        UARTprintf("%0.2f, %0.2f, %0.2f\r\n",comp_data->temperature, comp_data->pressure, comp_data->humidity);
#else
        UARTprintf("%l, %l, %l\r\n",comp_data->temperature, comp_data->pressure, comp_data->humidity);
#endif
}



void InitConsole(void)
{
    SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure (GPIO_PA0_U0RX);
    GPIOPinConfigure (GPIO_PA1_U0TX);
    SysCtlPeripheralEnable (SYSCTL_PERIPH_UART0);
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_SYSTEM);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioConfig(0, 115200, SysCtlClockGet());
}

void InitI2C1(void)
{
    SysCtlPeripheralEnable (SYSCTL_PERIPH_I2C1);
    GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    GPIOPinConfigure (GPIO_PA6_I2C1SCL);
    GPIOPinConfigure (GPIO_PA7_I2C1SDA);
    I2CMasterInitExpClk(I2C1_BASE, SysCtlClockGet(), false);
}

void I2CSend(uint8_t slave_addr, uint8_t num_of_args, ...)
{   int i;
    // Tell the master module what address it will place on the bus when
    // communicating with the slave.
    I2CMasterSlaveAddrSet(I2C1_BASE, slave_addr, false);

    //stores list of variable number of arguments
    va_list vargs;

    //specifies the va_list to "open" and the last fixed argument
    //so vargs knows where to start looking
    va_start(vargs, num_of_args);

    //put data to be sent into FIFO
    I2CMasterDataPut(I2C1_BASE, va_arg(vargs, uint32_t));

    //if there is only one argument, we only need to use the
    //single send I2C function
    if (num_of_args == 1)
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_SEND);

        // Wait until MCU is done transferring.
        while (I2CMasterBusy(I2C1_BASE))
            ;

        //"close" variable argument list
        va_end(vargs);
    }

    //otherwise, we start transmission of multiple bytes on the
    //I2C bus
    else
    {
        //Initiate send of data from the MCU
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);

        // Wait until MCU is done transferring.
        while (I2CMasterBusy(I2C1_BASE))
            ;

        //send num_of_args-2 pieces of data, using the
        //BURST_SEND_CONT command of the I2C module
        for (i = 1; i < (num_of_args - 1); i++)
        {
            //put next piece of data into I2C FIFO
            I2CMasterDataPut(I2C1_BASE, va_arg(vargs, uint32_t));
            //send next data that was just placed into FIFO
            I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

            // Wait until MCU is done transferring.
            while (I2CMasterBusy(I2C1_BASE))
                ;
        }

        //put last piece of data into I2C FIFO
        I2CMasterDataPut(I2C1_BASE, va_arg(vargs, uint32_t));
        //send next data that was just placed into FIFO
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
        // Wait until MCU is done transferring.
        while (I2CMasterBusy(I2C1_BASE))
            ;

        //"close" variable args list
        va_end(vargs);
    }
}

void user_delay_ms(uint32_t period)
{
    SysCtlDelay((SysCtlClockGet() / 1000) * (uint32_t) period);
}

int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
                     uint16_t len)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
    /*
     * The parameter dev_id can be used as a variable to store the I2C address of the device
     */

    /*
     * Data on the bus should be like
     * |------------+---------------------|
     * | I2C action | Data                |
     * |------------+---------------------|
     * | Start      | -                   |
     * | Write      | (reg_addr)          |
     * | Stop       | -                   |
     * | Start      | -                   |
     * | Read       | (reg_data[0])       |
     * | Read       | (....)              |
     * | Read       | (reg_data[len - 1]) |
     * | Stop       | -                   |
     * |------------+---------------------|
     */
    I2CMasterSlaveAddrSet(I2C1_BASE, (uint8_t) dev_id, false);
    I2CMasterDataPut(I2C1_BASE, (uint8_t) reg_addr);
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    while (I2CMasterBusy (I2C1_BASE))
        ;
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    I2CMasterSlaveAddrSet(I2C1_BASE, dev_id, true);
    while (len--)
    {
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
        while (I2CMasterBusy (I2C1_BASE))
            ;
        *reg_data = I2CMasterDataGet(I2C1_BASE);
        reg_data++;
    }
    return rslt;
}

int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
                      uint16_t len)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

    /*
     * The parameter dev_id can be used as a variable to store the I2C address of the device
     */

    /*
     * Data on the bus should be like
     * |------------+---------------------|
     * | I2C action | Data                |
     * |------------+---------------------|
     * | Start      | -                   |
     * | Write      | (reg_addr)          |
     * | Write      | (reg_data[0])       |
     * | Write      | (....)              |
     * | Write      | (reg_data[len - 1]) |
     * | Stop       | -                   |
     * |------------+---------------------|
     */
    I2CSend(dev_id,1,reg_addr);
    while(len--)
    {
       I2CSend(dev_id,1,*reg_data);
       reg_data++;

    }

}
\$\endgroup\$
  • \$\begingroup\$ Use an oscilloscope or logic analyzer to view what is happening on the clock and data lines. \$\endgroup\$ – kkrambo Apr 18 at 12:40
  • \$\begingroup\$ @kkrambo: Hooked up an oscilloscope both SDA and SCL remain high(No switching) throughout the code. Maybe an initialization issue but I can't figure out what. \$\endgroup\$ – V.Singh Apr 18 at 17:25
0
\$\begingroup\$

You are not configuring the I2C Pins.

From the source file GPIO.c

//! \note This function cannot be used to turn any pin into an I2C SDA pin; it
//! only configures an I2C SDA pin for proper operation.  Note that a
//! GPIOPinConfigure() function call is also required to properly configure a
//! pin for the I2C SDA function.

There is a similar statement about the clock pin.

So you need to add the following two lines:

GPIOPinConfigure(GPIO_PA6_I2C1SCL);

GPIOPinConfigure(GPIO_PA7_I2C1SDA);
\$\endgroup\$
  • \$\begingroup\$ Added those two lines still no luck! \$\endgroup\$ – V.Singh Apr 18 at 17:22
  • \$\begingroup\$ Have you read through Chapter 16 in the manual? \$\endgroup\$ – Tyler Apr 18 at 17:40
  • \$\begingroup\$ Which manual? Are you talking about the Workshop lab manual? \$\endgroup\$ – V.Singh Apr 18 at 17:47
  • \$\begingroup\$ ti.com/lit/ds/symlink/tm4c123gh6pm.pdf \$\endgroup\$ – Tyler Apr 18 at 17:54
  • \$\begingroup\$ I don't see where you initialize the SCL Clock speed. \$\endgroup\$ – Tyler Apr 18 at 17:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.