nRF5340 Audio DK with BMP280 sensor

Hello,

I am fairly new to the development with nRF and am having problems getting sensor data from a connected BMP280 to the nRF5340 audio dk.

The first thing I did was look at the sample for the BME280 (unfortunately there is no pre-made sample for the BMP280 as far as I know). I thought I could rewrite it to work with the BMP280, but it didn't find the device. Then I tried to repeate exercise 2 from "Lesson 6 - Serial Communication (I2C)" and adapt it to the BMP280 datasheet. Is this the best way to get sensor data from the BMP280? I've also found this BMP2 SensorAPI https://github.com/BoschSensortec/BMP2-Sensor-API/#sensor-overview, but I haven't figured out how to use it in nRF yet. What is the most elegant and easiest way to get sensor data from the BMP280?

My development setup:

OS: macOS Sonoma 14.0

SW versions: VS Code 1.84.1, newest nRF Connect for VS Code extension pack

Best regards,

Lukas

Parents
  • Hi,

    Could I see what you have so far, so that I can see if it's just something small that is missing?

    Have you made sure to use the correct address?

    A logic trace would also be nice if possible, to see if the correct data is being sent from the board.

  • Thanks for your reply! 

    This is the error message I am getting in Serial Terminal with my current code:

    *** Booting nRF Connect SDK v2.5.0-rc2 ***
    Found device "I2C_1", getting sensor data
    [00:00:02.254,089] <err> os: ***** USAGE FAULT *****
    [00:00:02.254,089] <err> os: Attempt to execute undefined instruction
    [00:00:02.254,119] <err> os: r0/a1: 0x200022e8 r1/a2: 0x00000000 r2/a3: 0x00000004
    [00:00:02.254,119] <err> os: r3/a4: 0x00008cfb r12/ip: 0x0000000c r14/lr: 0x000082bb
    [00:00:02.254,119] <err> os: xpsr: 0x49000000
    [00:00:02.254,150] <err> os: Faulting instruction address (r15/pc): 0x000082ac
    [00:00:02.254,180] <err> os: >>> ZEPHYR FATAL ERROR 36: Unknown error on CPU 0
    [00:00:02.254,211] <err> os: Current thread: 0x200007f8 (unknown)
    [00:00:00.753,509] <err> i2c_nrfx_twim: Error on I2C line occurred for message 0
    [00:00:00.753,570] <err> INA230: Failed to write configuration register!
    [00:00:01.253,662] <err> i2c_nrfx_twim: Error on I2C line occurred for message 0
    [00:00:01.253,692] <err> INA230: Failed to write configuration register!
    [00:00:01.753,814] <err> i2c_nrfx_twim: Error on I2C line occurred for message 0
    [00:00:01.753,845] <err> INA230: Failed to write configuration register!
    [00:00:02.253,936] <err> i2c_nrfx_twim: Error on I2C line occurred for message 0
    [00:00:02.253,997] <err> INA230: Failed to write configuration register!

    and this is my code in main.c:

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/sensor.h>
    #include <zephyr/drivers/i2c.h>
    
    #define I2C_NODE DT_NODELABEL(bmp280)
    
    // TODO: This information typically goes into a separate header file
    #define BMP280_I2C_ADDR 								0x76 // BMP280 I2C address, 0x77 if ADDR pin is high
    
    #define BMP280_REG_CTRL_MEAS 							0xF4
    #define BMP280_REG_CONFIG 								0xF5
    #define BMP280_REG_PRESS_MSB 							0xF7
    #define BMP280_REG_TEMP_MSB 							0xFA
    
    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C_NODE);
    
    void bmp280_init() {
        if (dev_i2c.bus == NULL) {
    		/* No such node, or the node does not have status "okay". */
    		printk("\nError: no device found.\n");
    		return;
        }
    
    	if (!device_is_ready(dev_i2c.bus)) {
    		printk("I2C bus %s is not ready!\n\r", dev_i2c.bus->name);
    		return;
    	}
    
    	printk("Found device \"%s\", getting sensor data\n", dev_i2c.bus->name);
    }
    
    void bmp280_read_calibration_data(uint16_t *calib_data) {
        uint8_t calib[24];
    
        if (i2c_burst_read(&dev_i2c, BMP280_I2C_ADDR, 0x88, calib, sizeof(calib)) < 0) {
            printk("Failed to read calibration data\n");
            return;
        }
    
        // Parse calibration data (16-bit values)
        for (int i = 0; i < 12; i++) {
            calib_data[i] = (calib[2 * i] << 8) | calib[2 * i + 1];
        }
    }
    
    void bmp280_configure() {
        uint8_t ctrl_meas = 0x57; // Temperature oversampling x1, Pressure oversampling x16, Normal mode
        uint8_t config = 0x00;    // Filter off, 3-wire SPI disabled
    
        if (i2c_reg_write_byte(&dev_i2c, BMP280_I2C_ADDR, BMP280_REG_CTRL_MEAS, ctrl_meas) < 0) {
            printk("Failed to configure BMP280 control measurement\n");
            return;
        }
    
        if (i2c_reg_write_byte(&dev_i2c, BMP280_I2C_ADDR, BMP280_REG_CONFIG, config) < 0) {
            printk("Failed to configure BMP280 config\n");
            return;
        }
    }
    
    void bmp280_read_data(int16_t *temperature, uint32_t *pressure) {
        uint8_t data[6];
    
        if (i2c_burst_read(&dev_i2c, BMP280_I2C_ADDR, BMP280_REG_TEMP_MSB, data, sizeof(data)) < 0) {
            printk("Failed to read BMP280 data\n");
            return;
        }
    
        int32_t adc_temp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
        int32_t t_fine = 0; // I need to calculate t_fine using calibration data, right?
    
        *temperature = ((t_fine * 5 + 128) >> 8) / 100;
        *pressure = 0; // I need to calculate pressure using calibration data, right?
    }
    
    int main(void) {
        int16_t temperature;
        uint32_t pressure;
        uint16_t calib_data[12];
    
        bmp280_init();
        bmp280_read_calibration_data(calib_data);
        bmp280_configure();
    
        while (1) {
            bmp280_read_data(&temperature, &pressure);
            printk("Temperature: %d°C, Pressure: %u Pa\n", temperature, pressure);
            k_sleep(K_MSEC(1000)); // Sleep for 1 second
        }
    }

    overlay file:

    &i2c1 {
    	status = "okay";
    	compatible = "nordic,nrf-twim";
    	label = "I2C_1";
    	pinctrl-0 = <&i2c1_default>;
    	pinctrl-1 = <&i2c1_sleep>;
    	pinctrl-names = "default", "sleep";
    	clock-frequency = <100000>; 
    	bmp280: bmp280@76 {
    		compatible = "i2c-device";
    		reg = < 0x76 >;
    		label = "BMP280";
    	};
    };
    
    &pinctrl {
    	i2c1_default: i2c1_default{
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 5)>,
    				<NRF_PSEL(TWIM_SCL, 0, 4)>;
    		};
    	};
    
    	i2c1_sleep: i2c1_sleep{
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 5)>,
    				<NRF_PSEL(TWIM_SCL, 0, 4)>;
    			low-power-enable;
    		};
    	};
    
    };
    

    Here is the datasheet for the BMP280: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf

    It seems like the SensorAPI might be useful to get it working, but I haven't figured out how to embed and use it in nRF correctly. 

    BMP280 seems to be on the market for quite some time, but I couldn't find any useful resources to get sensor data from it in nRF. Maybe I missed something?

    I'd appreciate any kind of help!

    Best regards,

    Lukas

  • It seems that changing the pins for i2c1 may be interfering with the default setup for the board. Also P0.04 and P0.05 are routed to the hardware buttons.

    Could you try using pins that are not already in use, and perhaps enabling and using i2c2 instead of i2c1?

    Or perhaps setting CONFIG_INA230=n?

  • Thanks for your reply, Oivind! As far as I can tell from the Devicetree, there is only one I2C (i2c1) on the nRF5340 audio dk and no i2c2 available. I've also tried setting CONFIG_INA230=n in my prj.conf. Unfortunately, I'm still not able to get sensor data.

Reply Children
  • There is a i2c2, but not all peripherals are pre-defined in the devicetree. If you add something like this to the devicetree, for example by using an overlay file, you should have access to i2c2:

    &pinctrl {
    
    	i2c2_default: i2c2_default {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 1, 2)>,
    				<NRF_PSEL(TWIM_SCL, 1, 3)>;
    		};
    	};
    
    	i2c2_sleep: i2c2_sleep {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 1, 2)>,
    				<NRF_PSEL(TWIM_SCL, 1, 3)>;
    			low-power-enable;
    		};
    	};
    };
    
    &i2c2 {
    	compatible = "nordic,nrf-twim";
    	status = "okay";
    	pinctrl-0 = <&i2c2_default>;
    	pinctrl-1 = <&i2c2_sleep>;
    	pinctrl-names = "default", "sleep";
    	
    };

    Make sure to change the pins to your desired pins, and add the device to the i2c2 node.

    Let me know what the log output is if you try this.

  • I hope above problem was resolved.

    Warm regards
    Rajendra.

Related