0
votes

I've been trying to write a I2C device driver for the BMP 180 barometer and temperature sensor found on the E310 (as seen in sheet 9 of the schematic.) I have been basing my code off of the example driver given by bosch.

The driver requires function pointers to block read and write, as well as a sleep, which are basically the only original code:

int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr,uint8_t *data, uint16_t len)   
int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr,uint8_t *data, uint16_t len)
void user_delay_ms(uint32_t period)

The problem I am having is that this driver (as well as simpler SMBUS command only programs I have written) have always failed to read or write the i2c address 0x77, where the sensor should be located on the bus.

readBytes for device ID 0x77: -1 - No such device or address

Even though my code seems to work for locations that other devices are located at (though I haven't done more than ping them)

Motion Sensor:

readBytes for device ID 0x69: 0 - Success

Temperature Sensor:

readBytes for device ID 0x19: 0 - Success

I was wondering either what is wrong with my code that the device would be completely unresponsive, or what hardware configuration am I missing that would explain the lack of communication with the barometer at 0x77.

I notice that the BMP-180 barometer is placed on the auxiliary i2c of the Gyro MPU-9150, but the wiring and datasheet make me think it is in pass through mode and not master mode. Just a thought I had though.

Here is all of the code I have that interacts with the bmpDriver.

Compiled with the following

gcc test.c -o test -std=c11 -D _DEFAULT_SOURCE

#include "bmp280.c"
#include <linux/i2c-dev-user.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr,uint8_t *data, uint16_t len){
    int file;
    file = open("/dev/i2c-0", O_RDWR);
    if(file < 0)
    {
        printf("Failed to open /dev/i2c-0\n");
        close(file);
        return -1;
    }
    if(ioctl(file, I2C_SLAVE, dev_id) < 0)
    {
        printf("ioctl failed for /dev/i2c-0 at %x - %s\n", dev_id, strerror(errno));
        close(file);
        return -2;
    }
    int readBytes;
    readBytes = i2c_smbus_read_block_data(file, reg_addr, data);
    printf("readBytes for device ID 0x%x: %d - %s\n", dev_id, readBytes, strerror(errno));
    close(file);
    return readBytes;
}

int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr,uint8_t *data, uint16_t len){
    int file;
    file = open("/dev/i2c-0", O_RDWR);
    if(file < 0)
    {
        printf("Failed to open /dev/i2c-0\n");
        close(file);
        return -1;
    }
    if(ioctl(file, I2C_SLAVE, dev_id) < 0)
    {
        printf("ioctl failed for /dev/i2c-0 at %x - %s\n", dev_id, strerror(errno));
        close(file);
        return -2;
    }
    int writeBytes;
    uint8_t shortLen = len;
    writeBytes = i2c_smbus_write_block_data(file, reg_addr, shortLen, data);
    printf("writeBytes for device ID 0x%x: %d - %s\n", dev_id, writeBytes, strerror(errno));
    close(file);
    return writeBytes;
}

void user_delay_ms(uint32_t period){
    unsigned int sleep = period;
    usleep(sleep * 1000);
}

int main(){
    int8_t rslt;
    struct bmp280_dev user_bmp;
    user_bmp.dev_id = BMP280_I2C_ADDR_SEC;
    user_bmp.intf = BMP280_I2C_INTF;
    user_bmp.read = user_i2c_read;
    user_bmp.write = user_i2c_write;
    user_bmp.delay_ms = user_delay_ms;
    rslt = bmp280_init(&user_bmp);
    if (rslt == BMP280_OK) {
      printf("Device found with chip id 0x%x\n", user_bmp.chip_id);
    }
    else {
      printf("Device not found, exiting...\n");
      return -1;
    }
    struct bmp280_config conf;
    rslt = bmp280_get_config(&conf, &user_bmp);
    conf.filter = BMP280_FILTER_COEFF_2;
    conf.os_pres = BMP280_OS_16X;
    conf.os_temp = BMP280_OS_4X;
    conf.odr = BMP280_ODR_1000_MS;
    rslt = bmp280_set_config(&conf, &user_bmp);
    rslt = bmp280_set_power_mode(BMP280_NORMAL_MODE, &user_bmp);
    struct bmp280_uncomp_data ucomp_data;
    uint8_t meas_dur = bmp280_compute_meas_time(&user_bmp);
    printf("Measurement duration: %dms\r\n", meas_dur);
    uint8_t i;
    for (i = 0; (i < 10) && (rslt == BMP280_OK); i++) {
        printf("Running measurement: %d\n", i+1);
        user_bmp.delay_ms(meas_dur); 
        rslt = bmp280_get_uncomp_data(&ucomp_data, &user_bmp);
        int32_t temp32 = bmp280_comp_temp_32bit(ucomp_data.uncomp_temp, &user_bmp);
        uint32_t pres32 = bmp280_comp_pres_32bit(ucomp_data.uncomp_press, &user_bmp);
        uint32_t pres64 = bmp280_comp_pres_64bit(ucomp_data.uncomp_press, &user_bmp);
        double temp = bmp280_comp_temp_double(ucomp_data.uncomp_temp, &user_bmp);
        double pres = bmp280_comp_pres_double(ucomp_data.uncomp_press, &user_bmp);
        printf("UT: %d, UP: %d, T32: %d, P32: %d, P64: %d, P64N: %d, T: %f, P: %f\r\n", \
          ucomp_data.uncomp_temp, ucomp_data.uncomp_press, temp32, \
          pres32, pres64, pres64 / 256, temp, pres);
        user_bmp.delay_ms(1000);
    }
    if(rslt != BMP280_OK){
        printf("Result not okay at measurement: %d\n", i);
    }
}
1

1 Answers

0
votes

Before starting off with a speculation I would make sure that the transmission is actually reaching the sensor behind the gyro. Just use any scope to measure SCL and SDA. If the device is getting the transmission, the scope reading will provide additional information on where the device NAKs.

One difference between the BMP and the other i2c devices you were able to address that gave me multiple headaches in the past: the BMP seems to require a repeated start condition between device address and register read.

As far as I can remember, standard i2c libraries do not support this and you usually have to build your own read / write functions using linux/i2c-dev.h.