Communicating with i2c devices in jetson TX1

Hi
I have used the BME280 pressure and temperature sensor on my Jetson TX1 board.
I connect the SDA and SCL pins to pull up resistors (4.7K) just like the sensor’s datasheet says.
when I run the command i2cdetect -r -y 1 on bus one, the result of the command:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- 4a -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 --

the 0x76 address is the slave address of the BME280 sensor.
when I try to read the values of the register on the sensor with this code, I get some non-sense data from the sensor. all bits of the data for some registers are 1…
I don’t know why…
this is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

#ifdef __cplusplus
extern "C" {
    #endif
    #include <linux/i2c-dev.h>
    #include <i2c/smbus.h>

#ifdef __cplusplus
}
#endif

struct BME280_DATA_TEMPLATE{
	unsigned char press_msb;
	unsigned char press_lsb;
	unsigned char press_xlsb;
	
	unsigned char temp_msb;
	unsigned char temp_lb;
	unsigned char temp_xlsb;

	unsigned char hum_msb;
	unsigned char hum_lsb;
};

int main(){

    // init data template struct:

    struct BME280_DATA_TEMPLATE template;

    template.press_msb = 0xF7;
    template.press_lsb = 0xF8;
    template.press_xlsb = 0xF9;
    template.temp_msb = 0xFA;
    template.temp_lsb = 0xFB;
    template.temp_xlsb = 0xFC;
    template.hum_msb = 0xFD;
    template.hum_lsb = 0xFE;

    int file;
    int adapter_nr = 1;
    char filename[20];
    snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
    file = open(filename, O_RDWR);
    if (file < 0){
        printf("error about opening i2c-0 \n");
        exit(1);
    }
    printf("not error about openning \n");

    int addr = 0x76;

    if(ioctl(file, I2C_SLAVE, addr) < 0){
        printf("error abour openning address \n");
        exit(1);
    }

    __s32 res;
    char buf[10];
    for (int c = 0; c <= 8; c++)
    {
        __u8 reg = template.press_msb + c;
        res = i2c_smbus_read_word_data(file, reg);
        if (res < 0){
            printf("reg is: %c \t res is : %i \n", reg, res);
            printf("read error \n");
            exit(1);
        }
        else{
            printf("res is: %i ",res);
            printf("read success \n");
            // exit(1);
        }
    }
    return 0;
}

the output of this code is:

not error about openning 
res is: 128 read success 
res is: 0 read success 
res is: 32768 read success 
res is: 128 read success 
res is: 0 read success 
res is: 32768 read success 
res is: 128 read success 
res is: 32768 read success 
res is: 128 read success

is that a valid output of the sensor?
what can I do?

Please use i2cutils like i2cget to confirm.

Thanks

with this command, I am able to read and write the sensor data…
but all values just like those above are nonsense…

For that you may need to probe the i2c signal to confirm the data on the waveform.

Thanks

First: Don’t use smbus commands. Use plain I2C read and write methods as described in the Linux kernel doc:
https://www.kernel.org/doc/Documentation/i2c/dev-interface

Second: Use an logic analyzer to verify that what your program received is what the chip sends. One of the cheap 24MHz 8Channel parts on Amazon or ebay will do the job just fine.

Third: The sensor has a chip id register on index 0xd0. Try this register (and only this register!) first. You should receive always the same value, and the value should be 0x60 for a BME280.

@fchkjwlsq
thank you so much for your response and your help.
I tried the third solution and tried to read the value of the 0xD0 register from the sensor
as you say, when I read the register value I received 96 (decimal) 0x60 hex from the sensor.
another thing…
How can I get the final value of the sensor temperature and pressure?
Apparently, to get the actual value of the temperature and pressure, a lot of complicated calculations are needed…
Do you know a way that I can get this number well?
in your first way, do you mean I use this code?

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }

Great. Communication works.

Look here:

I’ve never tried this code, but this is for Linux and should work for you out of the box.

yes, this is how I access I2C, and the library above does this as well.

1 Like

thank you so much for your help

@fchkjwlsq
Thank you so much for your advice
the sample code you gave me works and finally I got the final result of the sensor.
my code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include "libs/serial/serialib.h"
extern "C" {
#include "libs/sensor/bme280.h"
}
#include <iostream>

using namespace std;

int main(){

serialib ser;

int T, P, H;

int i = bme280Init(1, 0x76);

if (i != 0){

cout << "Error for openning sensor" << endl;

return -1;

}

bme280ReadValues(&T, &P, &H);

T -= 150;

printf("Calibrated temp. = %3.2f C, pres. = %6.2f Pa, hum. = %2.2f%%\n", (float)T/100.0, (float)P/256.0, (float)H/1024.0);

cout << "Hello World" << endl;

return 0;

}

my output:

Calibrated temp. = 21.29 C, pres. = 694.32 Pa, hum. = 77.70%
Hello World

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.