NRF52840 I2C INTERFACE WITH BMP280

Hi everybody,

I am trying my best to make my nrf52840dk communicating with an external bmp280 sensor using i2c, but I could not even read the cip id.

Maybe I completely misunderstood how to do it.

Here's my prj.conf:

CONFIG_I2C=y
Here's my nrf52840dk_nrf52840.overlay:
&i2c0 {
    mysensor: mysensor@76{
        compatible = "i2c-device";
        reg = < 0x76 >;
        label = "MYSENSOR";
    };
};
Neglecting for a moment my main.c, I would like to show that the sensor node is correctly recognized by the build system:
As you can see i2c0 has got a node named mysensor whose i2c address is 0x76. This is what I have found inside the bmp's datasheet in order to choose the right address:
Here you can see the bmp280's pins:

I connected SDO to GND so that the device address is 0x76. As for the rest, here's my physical connections:

  • VCC --> VDD
  • GND --> GND
  • SCL -->P0.27
  • SDA -->P0.26
  • CSB-->VDD

I decided to tie CSB high because I read this inside the datasheet:

Now here's my main.c:

#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <sys/printk.h>
#include <drivers/i2c.h>

#define SLEEP_TIME_MS   3*1000

#define I2C0_NODE DT_NODELABEL(mysensor)

void main(void)
{

    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C0_NODE);
    if (!device_is_ready(dev_i2c.bus)) {
        printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);
        return;
    }

    uint8_t sensor_reading[2]= {0};
    uint8_t sensor_regs[2] ={0xEC, 0xD0};
   
    int ret = i2c_write_read_dt(&dev_i2c,&sensor_regs[0],1,&sensor_reading[0],1);
    if(ret != 0){
        printk("Failed to write/read I2C device address %x at Reg. %x \r\n", dev_i2c.addr,sensor_regs[0]);
    }

    while (1) {

    k_msleep(SLEEP_TIME_MS);
    }
}
You are probably wondering about the content of vector sensor_regs...
0xEC should be the first address to be sent according to the following notation...
0xD0 is the address of the id register which I would like to read.
My program returns "Failed to write/read..." every time because ret<0.
I really don't know what to do. I hope I gave you enough information to help me.
Thanks in advance.
Gianmarco
Parents
  • Hi Markus,

    Sorry for my delayed response.

    I tried to run the code you suggested but it didn't work. But actually the main problem was a bad soldering of the connectors which prevented electrical communications between the dk and the sensor.

    Soldering a new device and flashing your code, I finally managed to communicate with my sensor!

    I attach here a working application that may helps other interested users:

    prj.confg:

    CONFIG_I2C=y

    nrf52840dk_nrf52840.overlay:

    &i2c0 {
       bmp280: bmp280@76{
          compatible = "bosch,bmp280";
          reg = <0x76>;
          label = "BOSCH_BMP280_SENSOR";
       };
    };

    main.c:

    #include <zephyr.h>
    #include <device.h>
    #include <devicetree.h>
    #include <sys/printk.h>
    #include <drivers/i2c.h>


    #define BMP_REG_ID 0xD0

    #define BMP280_NODE DT_NODELABEL(bmp280)

    void main(void)
    {

       static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(BMP280_NODE);
       if (!device_is_ready(dev_i2c.bus)) {
          printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);
          return;
       }

       uint8_t read_buf_id[1];
       uint8_t write_reg_buffer[1];

       write_reg_buffer[0] = BMP_REG_ID;

       printf("writing %x to the device\n", write_reg_buffer[0]);
       int err = i2c_write_read_dt(&dev_i2c, write_reg_buffer, 1, read_buf_id, 1);
       if(err < 0){
          printk("BMP CHIP ID read failed: %d\n", err);
          return;
       }

       printf("reading %x from the device\n", read_buf_id[0]);

       while (1) { }
    }

    As for your second observation. Let me say that I used the i2c-bus because I was kinda desperated. I tried to use the driver as well as I feel more confident with that, and it worked.

    I noticed that, using the driver, it is not even necessary to define the bmp280 as a child node of the i2c node. It is enough to send commands over i2c specifyng the address of the slave device directly in the write, read, write/read command. Is it true?

    I mean, using the driver model I left my overlay file empty.

    Which model would you suggest me to use? bus or driver?

    Regards,

    Gianmarco

Reply
  • Hi Markus,

    Sorry for my delayed response.

    I tried to run the code you suggested but it didn't work. But actually the main problem was a bad soldering of the connectors which prevented electrical communications between the dk and the sensor.

    Soldering a new device and flashing your code, I finally managed to communicate with my sensor!

    I attach here a working application that may helps other interested users:

    prj.confg:

    CONFIG_I2C=y

    nrf52840dk_nrf52840.overlay:

    &i2c0 {
       bmp280: bmp280@76{
          compatible = "bosch,bmp280";
          reg = <0x76>;
          label = "BOSCH_BMP280_SENSOR";
       };
    };

    main.c:

    #include <zephyr.h>
    #include <device.h>
    #include <devicetree.h>
    #include <sys/printk.h>
    #include <drivers/i2c.h>


    #define BMP_REG_ID 0xD0

    #define BMP280_NODE DT_NODELABEL(bmp280)

    void main(void)
    {

       static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(BMP280_NODE);
       if (!device_is_ready(dev_i2c.bus)) {
          printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);
          return;
       }

       uint8_t read_buf_id[1];
       uint8_t write_reg_buffer[1];

       write_reg_buffer[0] = BMP_REG_ID;

       printf("writing %x to the device\n", write_reg_buffer[0]);
       int err = i2c_write_read_dt(&dev_i2c, write_reg_buffer, 1, read_buf_id, 1);
       if(err < 0){
          printk("BMP CHIP ID read failed: %d\n", err);
          return;
       }

       printf("reading %x from the device\n", read_buf_id[0]);

       while (1) { }
    }

    As for your second observation. Let me say that I used the i2c-bus because I was kinda desperated. I tried to use the driver as well as I feel more confident with that, and it worked.

    I noticed that, using the driver, it is not even necessary to define the bmp280 as a child node of the i2c node. It is enough to send commands over i2c specifyng the address of the slave device directly in the write, read, write/read command. Is it true?

    I mean, using the driver model I left my overlay file empty.

    Which model would you suggest me to use? bus or driver?

    Regards,

    Gianmarco

Children
  • Hi Gianmarco,

    if you are using the driver you have to define an overlay file with a child node, since you get the device from the command  DEVICE_DT_GET_ANY(bosch_bmp280) and there is the I2C-Adress stored.

    I think you mean if you are use an i2c device and not  i2c_dt_spec. There you dont need to define an bmp-node.

    Its depends on the use case what model its better to use. The driver is in a lot cases a good choice. But the sensor needs also to be connected at the power up from the SoC. And sometimes the driver is just overloaded when you need only specific things. Sometimes it's also more easy to use special functionalities from one sensor when you configure it directly over i2c.

    Regards
    Markus

Related