nRF52DK with BME280 Sensor

Hi All,

I have been trying to get the BME280 to work with the nRF52 Development Kit using the Zephyr Framework,

I can't seem to get the firmware to pick-up the BME280 sensor, although I have define the correct I2C address, below is the code Main.c code and the bme.c and the bme.h as well as my prj.conf and the overlay file.

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/printk.h>
#include <sys/util.h>
#include <zephyr/types.h>
#include "bme280.h"
#include <logging/log.h>

#define ADV_PARAM \
BT_LE_ADV_PARAM(0, BT_GAP_ADV_SLOW_INT_MIN, \
BT_GAP_ADV_SLOW_INT_MAX, NULL)

static struct bt_data ad[] = {
		BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
		BT_DATA_BYTES(
		BT_DATA_MANUFACTURER_DATA, 0xff, 0xff, /* Test company ID */
		0x00, 0x00, /* Temperature, int16, little-endian */
		0x00, 0x00, /* Pressure - 50000, uint16, little-endian */
		0x00, 0x00) /* Humidity, uint16, little-endian */
		};


void update_ad_bme280(const struct device *dev) {

	int16_t temperature;
	uint16_t pressure, humidity;
	bme280_fetch_sample(dev);
	temperature = bme280_get_temperature(dev);
	memcpy(&(ad[1].data[2]), &temperature, 2);
	pressure = bme280_get_pressure(dev);
	memcpy(&(ad[1].data[4]), &pressure, 2);
	humidity = bme280_get_humidity(dev);
	memcpy(&(ad[1].data[6]), &humidity, 2);

}

void main(void) {

	int err;
	printk("Starting firmware...\n");
	// Initialize BME280
	const struct device *bme280 = bme280_get_device();

		if (bme280 == NULL) {
		return;
		}

		// Initialize the Bluetooth subsystem
		err = bt_enable(NULL);

		if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
			return;
		}

		printk("Bluetooth initialized\n");
		// Start advertising sensor values
		update_ad_bme280(bme280);
		err = bt_le_adv_start(ADV_PARAM, ad, ARRAY_SIZE(ad), NULL, 0);

		if (err) {
			printk("Advertising failed to start (err %d)\n", err);
			return;
		}

			while (1) {

		k_sleep(K_MSEC(980));
		// Update advertised sensor values
		update_ad_bme280(bme280);
		err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), NULL, 0);
		
		if (err) {
			printk("Advertising update failed (err %d)\n", err);
			return;
		}
	}
}

Here is the bme.c code

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

/*
 * Get a device structure from a devicetree node with compatible
 * "bosch,bme280". (If there are multiple, just pick one.)
 */
const struct device *bme280_get_device(void) {
  const struct device *dev = DEVICE_DT_GET_ANY(bosch_bme280);

  if (dev == NULL) {
    /* No such node, or the node does not have status "okay". */
    printk("\nError: no device found.\n");
    return NULL;
  }

  if (!device_is_ready(dev)) {
    printk("\nError: Device \"%s\" is not ready; "
           "check the driver initialization logs for errors.\n",
           dev->name);
    return NULL;
  }

  printk("Found device \"%s\", getting sensor data\n", dev->name);
  return dev;
}

void bme280_fetch_sample(const struct device *dev) {
  sensor_sample_fetch(dev);
}

int16_t bme280_get_temperature(const struct device *dev) {
  struct sensor_value temperature;

  sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temperature);
  return (int16_t)(temperature.val1 * 100 + temperature.val2 / 10000);
}

uint16_t bme280_get_pressure(const struct device *dev) {
  struct sensor_value pressure;
  uint32_t p; // Pressure without offset

  sensor_channel_get(dev, SENSOR_CHAN_PRESS, &pressure);
  p = (uint32_t)(pressure.val1 * 1000 + pressure.val2 / 10000);
  return (uint16_t)(p - 50000);
}

uint16_t bme280_get_humidity(const struct device *dev) {
  struct sensor_value humidity;

  sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity);
  return (uint16_t)(humidity.val1 * 100 + humidity.val2 / 10000);
}

here is the bme.h code

#ifndef BME280_H_
#define BME280_H_

const struct device *bme280_get_device(void);
void bme280_fetch_sample(const struct device *dev);
int16_t bme280_get_temperature(const struct device *dev);
uint16_t bme280_get_pressure(const struct device *dev);
uint16_t bme280_get_humidity(const struct device *dev);

#endif /* BME280_H_ */

here is the overlay file

 &i2c0 {
  status = "okay";
  sda-pin = <26>;
  scl-pin = <27>;
  bme280@77 {
    compatible = "bosch,bme280";
    reg = <0x77>;
    label = "BME280_I2C";
  };
};
  &uart0 {
    current-speed = <115200>;
    status = "okay";
    tx-pin = <6>;
    rx-pin = <8>;
};

here is the prj.conf

CONFIG_BT=y
# Enable BME280 sensor
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_BME280=y

#CONFIG_BT_DEVICE_NAME="GAVO_IV"
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_LOG=y

and the cmake:

cmake_minimum_required(VERSION 3.13.1)
#include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(ZEPHYR_BME280)

FILE(GLOB app_sources ../src/*.c*)
target_sources(app PRIVATE ${app_sources})
#target_sources(app PRIVATE src/bme280.c src/main.c)

message(STATUS "Current source directory: ${CMAKE_CURRENT_SOURCE_DIR}")

Any help would be greatly appreciated!

  • Hi,

    There is a sample for the BME280 Sensor that you can refer to. You need to adjust the board configuration for your board though, as I see you have done.

    I don't see any error in the CMake log snippet, but from your text I get the feeling this fails at run-time? Can you elaborate?

    Note that if the problem is run-time, a quite common issue with I2C is that the internal pull resistors in the nRF are quite weak, so you should add external pull-up resistors (typically 4.7 k).

  • Hi Einar, my apologies for the delay, I tried the sample and same as my previous code, this is what I see in TeraTerm

    *** Booting Zephyr OS build zephyr-v20701  ***


    Error: no device found.

    Both the code above the Zephyr sample code as well.

    I will try a 4K7 resistor but I am using the nRF52DK, surely there are Pins that I can use that have strong pull ups for the I2C?

    I am also using Platform IO and below is my .ini file

    [env:nrf52_dk]
    platform = nordicnrf52
    board = nrf52_dk
    framework = zephyr
    board_build.mcu = nrf52832
  • Hi,

    Which nRF Connect SDK version are you using? If you are using >= 2.0.0, then pinctrl is in use, and you need to configure the pins differently. You can refer to zephyr/boards/arm/bl654_sensor_board/bl654_sensor_board.dts for an exmaple. This part is relevant:

    &i2c0 {
    	compatible = "nordic,nrf-twi";
    	status = "okay";
    
    	pinctrl-0 = <&i2c0_default>;
    	pinctrl-1 = <&i2c0_sleep>;
    	pinctrl-names = "default", "sleep";
    	bme280@76 {
    		compatible = "bosch,bme280";
    		status = "okay";
    		reg = <0x76>;
    	};
    };

    And for the pinctrl part where the i2c0 pins are defined, you can refer to zephyr/boards/arm/bl654_sensor_board/bl654_sensor_board-pinctrl.dtsi:

    	i2c0_default: i2c0_default {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
    				<NRF_PSEL(TWIM_SCL, 0, 27)>;
    		};
    	};
    
    	i2c0_sleep: i2c0_sleep {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
    				<NRF_PSEL(TWIM_SCL, 0, 27)>;
    			low-power-enable;
    		};
    	};

    gavo said:

    I will try a 4K7 resistor but I am using the nRF52DK, surely there are Pins that I can use that have strong pull ups for the I2C?

    The internal pull resistors are typically strong enough for 100 kHz, but if you want to use a higher frequency, external pull resistors make sense.

    gavo said:
    I am also using Platform IO and below is my .ini file

    I have no experience with platform IO unfortunately, so I cannot say if there is any problem with that part. Generally though, I would recomend using nRF Connect SDK for VS Code, which is the only IDE we support

  • Hi Einar,

    I saw this in the Zephyr.dts file in the project

    I changed it to 0x26 and 0x27 but it made no difference.

    I also tried your suggestion about but it still shows no device connected

  • My New overlay file below:

     &i2c0 {
      compatible = "nordic,nrf-twim";
      status = "okay";
      sda-pin = <26>;
      scl-pin = <27>;
         bme280@77 {
        compatible = "bosch,bme280";
        reg = <0x77>;
        label = "BME280_I2C";
         };
     
      // Other properties like clock-frequency can also be set here
    };


      &uart0 {
        current-speed = <115200>;
        status = "okay";
        tx-pin = <6>;
        rx-pin = <8>;
    };


    and I made changes to the Zephyr Projects.dts files to this below and it still did not work...

    i2c0: arduino_i2c: i2c@40003000 {
                #address-cells = < 0x1 >;
                #size-cells = < 0x0 >;
                reg = < 0x40003000 0x1000 >;
                clock-frequency = < 0x186a0 >;
                interrupts = < 0x3 0x1 >;
                status = "okay";
                label = "I2C_0";
                compatible = "nordic,nrf-twi";
                sda-pin = < 0x26 >;
                scl-pin = < 0x27 >;
            };
Related