High current consuption using BME280 on Seeed Xiao BLE (nRF52840) in Zephyr RTOS

Hi,

I'm developing an IoT product using nRF52840 provided by Seeed (Xiao BLE) with a BME280 sensor connected via I2C on a custom PCB, without another peripheral that BME280 and passive components for I2C connection. I can't get low power consumption, even if I try the system_off Zephyr example.

When I try the bme_280 example of Zephyr and enable the PM/PM_DEVICE features, the consumption is still so high (about 1mA). I need that it consumes a few hundred uA . An strange ripple between BME280 measurements is seen when I measure current using PPK2:

  • My config file:

-

CONFIG_SENSOR=y
CONFIG_PM=y
CONFIG_PM_DEVICE=y

  • I2C circuit Diagram (VCC=3V3):

  • Overlay file:

&i2c1 {
	status = "okay";
	bme280@76 {
		compatible = "bosch,bme280";
		reg = <0x76>;
	};
};

  • Zephyr version: 3.2.99
  • nRF Connect version:2.3.0

I also tried:

I don't know what can I try.

Thanks

Parents
  • Hi there,

    1. Could you share your schematics?
    2. Can you try to reproduce the same with our development kit connected to the BME280 sensor?
    3. How is the PPK2 connected to your custom board? 

    even if I try the system_off Zephyr example.

    Can you share a PPK2 trace from this? 

    regards

    Jared 

  • Hi Jared,

    1) Here is my schematics:

    It's just a XIAO BLE connected to a SMD BME280 and electronic stuff (needed to connect BME280 via I2C, according to its datasheet (https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/).

    2)I'm sorry, I've not the nRF52840DK in my possession.

    3)I connect the PPK as source meter, directly to XIAO BLE BAT pins with 3V3. (here is the Xiao schematic https://files.seeedstudio.com/wiki/XIAO-BLE/Seeed-Studio-XIAO-nRF52840-Sense-v1.1.pdf)

    I could solve the ripple, by adding manually pm functions as follows:

    			pm_device_state_get(dev, &bme280_state);
    			if (bme280_state == PM_DEVICE_STATE_SUSPENDED)
    			{
    				pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
    			}
    			reftime_1 = k_uptime_get();
    			sensor_sample_fetch(dev);
    			pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);

    This has improved the consumption, but it's still high in idle thread (about 450uA):

    And here is the SYSTEM OFF sample PPK2 trace, with 200uA consumption:

  • Hi Jared,

    I've modified registers with debugger and power consuption has decreased a few dozen of uA. How can I set registers on code? There is some API?

    In the other hand, I realized that SAADC still idle consumes about 200uA. When I measure current with "CONFIG_ADC=n", power consumption turns as desired (just 6uA in idle vs 200uA with CONFIG_ADC=y):

    How can I set ADC to sleep mode between readings in Zephyr? In config file I've set:

    CONFIG_PM=y
    CONFIG_PM_DEVICE=y
    CONFIG_PM_DEVICE_RUNTIME=y

    And in overlay file:

    &adc {
    	#address-cells = <1>;
    	#size-cells = <0>;
    
    	channel@7 {
    		reg = <7>;
    		zephyr,gain = "ADC_GAIN_1_5";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,vref-mv = <750>;
    		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
    		zephyr,input-positive = <NRF_SAADC_AIN7>; /* P0.31 */
    		zephyr,resolution = <12>;
    	};
    };

    Thanks for your help

  • Hi,

    Very good progress on this,

    I see that there isn't any implementation for the power management module for the ADC yet. 

    What API are you using for the ADC, are you using the nrfx driver directly or using the Zephyr API?

    regards

    Jared

  • Hi Jared,

    I'm using Zephyr API to measure each 15 min battery level:

    int adc_init(void)
    {
    	int err;
    
    	gpio_pin_configure_dt(&vbat_pin, GPIO_OUTPUT);
    
    	if (!device_is_ready(adc_chan7.dev))
    	{
    		printk("ADC controller device not ready\n");
    		return -EINVAL;
    	}
    
    	err = adc_channel_setup_dt(&adc_chan7);
    	if (err < 0)
    	{
    		printk("Could not setup channel (%d)\n", err);
    		return err;
    	}
    }
    
    uint8_t get_battery_level(void)
    {
    	uint8_t err;
    	int16_t buf;
    	struct adc_sequence sequence = {
    		.buffer = &buf,
    		/* buffer size in bytes, not number of samples */
    		.buffer_size = sizeof(buf),
    	};
    	double vbat;
    
    	int32_t val_mv;
    	(void)adc_sequence_init_dt(&adc_chan7, &sequence);
    
    	err = adc_read(adc_chan7.dev, &sequence);
    	if (err < 0)
    	{
    		printk("Could not read (%d)\n", err);
    		return 1;
    	}
    	/* conversion to mV may not be supported, skip if not */
    	val_mv = buf;
    	err = adc_raw_to_millivolts_dt(&adc_chan7,
    								   &val_mv);
    	if (err < 0)
    	{
    		printk(" (value in mV not available)\n");
    		return 1;
    	}
    	else
    	{
    		vbat = val_mv * (1510.0 / 510.0); //Resistive divider
    		uint8_t bat_level = (vbat - VBAT_MIN) * 100 / (VBAT_MAX - VBAT_MIN);
    		return bat_level;
    	}
    }

    Has nrfx driver power management implementation? Or can I fix it with a workaround in Zephyr?

    Thanks

  • Hi,

    jelsesser said:
    Has nrfx driver power management implementation?

    No not quite, but you can easily disable the peripheral by calling the un init function. Unfortuantly, the Zephyr API lacks this kind of function which makes it difficult to disable the peripheral.

    regards

    Jared

  • Ok Jared, I'll try ASAP with the uninit/init funciton (I guess that I will use SAADC driver functions, because of NRF52840 has not ADC peripheral), instead of using Zephyr API, then I'll back with news.

    Maybe this is an opportunity to propose PM improvements in Zephyr API, I'll try it later.

    Regards

    Julian 

Reply Children
No Data
Related