ATC_MiThermometer icon indicating copy to clipboard operation
ATC_MiThermometer copied to clipboard

Power consumption when measuring temperature and humidity.

Open pvvx opened this issue 4 years ago • 44 comments

Consumption optimization expected?

The total power consumption is reduced when CPU CLK to 16 MHz. The power consumption for battery measurement is the short measurement cycle. The number of voltage measurements can be increased - these will be small percentages of the total consumption. The main energy consumption that can be reduced is the temperature and humidity sensor reading cycle.

Original firmware (XiaomiLYWSD03MMC): image

Firmware ATC_Thermometer.bin: image

Test variant (GPIO Wake Up): image

pvvx avatar Dec 16 '20 16:12 pvvx

Awesome, I guess the 3 peaks are while advertising?

hallard avatar Dec 16 '20 18:12 hallard

Awesome, I guess the 3 peaks are while advertising?

yes. In the original firmware, the amplitude is less - lower the RF TX level

Module GY-169 (INA169) 100 ohm shunt + oscilloscope

pvvx avatar Dec 16 '20 18:12 pvvx

Original firmware (XiaomiLYWSD03MMC): SenserOriginalFW

pvvx avatar Dec 16 '20 18:12 pvvx

@pvvx Could you provide the code for the sensor.c module (? only here ? ) where you have used the GPIO wakeup?

Thanks!

michapr avatar Dec 16 '20 19:12 michapr

ATC_Thermometr differs in consumption 5..6 times (3.6 mA / 0.6 mA) when measuring temperature. One ATC_Thermometr measurement is equal to 5 measurements Original XiaomiLYWSD03MMC.

Could you provide the code for the sensor.c module (? only here ? ) where you have used the GPIO wakeup?

If there was a working code, I would have posted it long ago. It has an unresolved problem...

After sending a command to the sensor for measurement, it is necessary to send the start + sensor address to the bus. https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf SCL to low. Chip goes into deep sleep -> I2C controller reset. On return (wake up), initialization of the I2C controller causes failure of subsequent read data from the sensor.

pvvx avatar Dec 16 '20 20:12 pvvx

#include <stdint.h>
#include "tl_common.h"
#include "drivers.h"
#include "vendor/common/user_config.h"
#include "app_config.h"
#include "drivers/8258/gpio_8258.h"
#include "drivers/8258/pm.h"
#include "stack/ble/ll/ll_pm.h"

#include "i2c.h"
#include "sensor.h"

#define GPIO_WAKEUP_SENS GPIO_PC3 // GPIO_PC2 or GPIO_PC3 ?

int32_t temp;
uint32_t humi;

wakeup_callback_t wakeup_cb; // typedef void (*wakeup_callback_t)(void);

//const uint8_t sens_wakeup[] = {0x35,0x17};
//const uint8_t sens_sleep[] = {0xB0,0x98};
//const uint8_t sens_reset[] = {0x80,0x5D};

void send_sensor(uint16_t cmd) {
	if((reg_clk_en0 & FLD_CLK0_I2C_EN)==0)
			init_i2c();
	reg_i2c_id = 0xE0;
	reg_i2c_adr_dat = cmd;
	reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO | FLD_I2C_CMD_STOP;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
}

void init_sensor(){
	send_sensor(0x1735); //	send_i2c(0xE0,(uint8_t *) sens_wakeup, sizeof(sens_wakeup));
	sleep_us(240);
	send_sensor(0x5d80); //send_i2c(0xE0,(uint8_t *)sens_reset, sizeof(sens_reset));
	sleep_us(240);
	send_sensor(0x98b0); //send_i2c(0xE0,(uint8_t *)sens_sleep, sizeof(sens_sleep));
}

_attribute_ram_code_ void read_sensor_start(void) {
	send_sensor(0x1735); //	send_i2c(0xE0,(uint8_t *) sens_wakeup, sizeof(sens_wakeup));
	sleep_us(240);
	reg_i2c_mode &= ~FLD_I2C_HOLD_MASTER;// Enable clock stretching for Sensor
	reg_i2c_id = 0xE0;
	reg_i2c_adr_dat = 0xA27C;
	reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	reg_i2c_id = 0xE0 |  FLD_I2C_WRITE_READ_BIT;
	reg_i2c_ctrl = FLD_I2C_CMD_ID | FLD_I2C_CMD_START;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
}

_attribute_ram_code_ void read_sensor_cb(void) {
	int16_t _temp;
	uint16_t _humi;

	wakeup_cb = NULL;
	cpu_set_gpio_wakeup(GPIO_WAKEUP_SENS, Level_High, 0);  // pad high wakeup deepsleep
	init_i2c();
	reg_i2c_id = 0xE0 | FLD_I2C_WRITE_READ_BIT;
//	int i = 10;
//	do {
	reg_i2c_ctrl = FLD_I2C_CMD_ID | FLD_I2C_CMD_START;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
//	} while((reg_i2c_status & FLD_I2C_NAK) && i--);

	reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	_temp = reg_i2c_di << 8;
	reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	_temp |= reg_i2c_di;
	reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID;
	temp = 1750*_temp - 450;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	(void)reg_i2c_di;
	reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	_humi = reg_i2c_di << 8;
	reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID;
	_humi |= reg_i2c_di;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	reg_i2c_ctrl = reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID | FLD_I2C_CMD_ACK;
	humi = 100*_humi;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
	(void)reg_i2c_di;
	reg_i2c_ctrl = FLD_I2C_CMD_STOP;
	while(reg_i2c_status & FLD_I2C_CMD_BUSY);
//	sleep_us(240);
	send_sensor(0x98b0); //send_i2c(0xE0,(uint8_t *)sens_sleep, sizeof(sens_sleep));
}

_attribute_ram_code_ void read_sensor_deep_sleep(void) {
	read_sensor_start();
	gpio_setup_up_down_resistor(GPIO_PC2, PM_PIN_PULLUP_1M);
	gpio_setup_up_down_resistor(GPIO_PC3, PM_PIN_PULLUP_1M);
	wakeup_cb = read_sensor_cb;
}


_attribute_ram_code_ void read_sensor_go_sleep(void) {
	if(((bls_pm_getSystemWakeupTick() - clock_time())) > 30 * CLOCK_16M_SYS_TIMER_CLK_1MS) {
		cpu_set_gpio_wakeup(GPIO_WAKEUP_SENS, Level_High, 1);  // pad high wakeup deepsleep
		bls_pm_setWakeupSource(PM_WAKEUP_PAD);  //gpio pad wakeup suspend/deepsleep
	} else {
		WaitMs(11);
		read_sensor_cb();
	}
}

Other ATC_Thermometr code changes:

typedef void (*wakeup_callback_t)(void);


_attribute_ram_code_ void user_init_deepRetn(void){//after sleep this will get executed
	....
	if(pm_is_deepPadWakeup()){
		if (wakeup_cb) {
			wakeup_cb();
			temp += temp_offset;
			humi += humi_offset;
			if((temp-last_temp > temp_alarm_point)||(last_temp-temp > temp_alarm_point)||(humi-last_humi > humi_alarm_point)||(last_humi-humi > humi_alarm_point)){// instant advertise on to much sensor difference
				set_adv_data(temp, humi, battery_level, battery_mv);
			}
			last_temp = temp;
			last_humi = humi;
		}
	}
}

_attribute_ram_code_ int app_suspend_enter(void) {
	if (ota_is_working) {
		bls_pm_setSuspendMask(SUSPEND_DISABLE);
		bls_pm_setManualLatency(0);
		return 0;
	} else {
		if (wakeup_cb) read_sensor_go_sleep();
		bls_pm_setSuspendMask(
				SUSPEND_ADV | DEEPSLEEP_RETENTION_ADV | SUSPEND_CONN
						| DEEPSLEEP_RETENTION_CONN);
		return 1;
	}
}


void main_loop(){	
	blt_sdk_main_loop();
	....
	if (!wakeup_cb)
		read_sensor_deep_sleep();
	....
	app_suspend_enter();
}

pvvx avatar Dec 16 '20 20:12 pvvx

Is timer used in the original firmware? The current power diagram does not show wake up from GPIO.

pvvx avatar Dec 16 '20 20:12 pvvx

Turning on and switching the power supply in chip -> pulse on SCL -> bit 15 Temperature lost. SCL/SDA - PullUp 1M: image

SCL/SDA - PullUp 10K: image

Operation is possible only in the "Clock Stretching mode disabled" for the sensor and deep sleep by timer.

pvvx avatar Dec 17 '20 05:12 pvvx

Test version with Sensirion SHTC3 humidity sensor working in deep sleep. Timer wake-up. image Source - https://github.com/pvvx/ATC_MiThermometer Average consumption 17 μA (ATC - 19). Polling of all sensor every 10..11 sec. Adv.interval 1900 ms.

Connection mode is not finalized. Advertising only.

pvvx avatar Dec 17 '20 11:12 pvvx

Thank you Victor for looking that deep into it!

Need to buid your Power meter so i can meassure such thinks as well, do you have it documented somewhere?

Will definitely adapt your changes to make the power consumption go down, or do you want to create a PR?

atc1441 avatar Dec 18 '20 03:12 atc1441

Current consumption in the optimized version: CR2032 - Start 3.314V 200 mAh. Adv.Interval ~1.9 sec (3000*0.625 = 1875 ms) Measured average consumption (1 h, 3.3V): 17.4 uA 200/0.0174/24/30.5 = 15.7025 months

Deep-sleep 6 uA Impulse (Adv): Min 3.5 ms only adv TX/RX, average 5.14 mA Max 17 ms read sensor, average 1.96 mA most often impulse ~4.5 ms

pvvx avatar Dec 18 '20 07:12 pvvx

Need to buid your Power meter so i can meassure such thinks as well, do you have it documented somewhere?

For debugging I use: https://github.com/pvvx/UBIA/tree/master/PowerProfiler image

pvvx avatar Dec 18 '20 07:12 pvvx

Chrome, USB-COM navigator.serial (experimental-web-platform-features) https://github.com/pvvx/UBIA/blob/master/WebSerialUSB/tst_wso_adcs_GY-169_power_BLE.gif Сan write a USB-COM programmer (com-sws) for Chrome and similar explorer...

pvvx avatar Dec 18 '20 07:12 pvvx

Thats a nice idea !

atc1441 avatar Dec 18 '20 08:12 atc1441

Will definitely adapt your changes to make the power consumption go down, or do you want to create a PR?

I just shared information. I don’t create final custom versions - no time for maintenance.

pvvx avatar Dec 18 '20 08:12 pvvx

Power Consumption my new testing (if 2 sec update LCD, measure 10 sec): Advertising Interval 2 sec - 17..18 uA Connection (16,16, 99, 800 -> real interval 2 sec, 3 notify 10 sec) - 15..16 uA

Advertising use RF TX 3 channel, when connected - 1 channel


An additional reduction in consumption for LCD updating:

void update_lcd(){
	if(memcmp(&display_cmp_buff, &display_buff, sizeof(display_buff)))
		send_to_lcd(display_buff[0],display_buff[1],display_buff[2],display_buff[3],display_buff[4],display_buff[5]);
	memcpy(&display_cmp_buff, &display_buff, sizeof(display_buff));
}

pvvx avatar Dec 20 '20 11:12 pvvx

@pvvx Can you compare your results with a 10 Ohm shunt? For advertising and measure I get some higher values, maybe because of the voltage drop? (8mA * 100 Ohm = 800mV less voltage on sensor)

michapr avatar Dec 20 '20 11:12 michapr

Maybe. But for the test, relative values are used - comparison with the original. And less needs to be done. CR2032 also has internal resistance. And operating voltage range device 2.0..3.3V. Lower voltage will result in higher currents (Internal DC-DC).

CPU 16 or 24 MHz ? rf_set_power_level_index(RF_POWER_P3p01dBm)?

Datasheet for Telink BLE SoC TLSR8251: image

pvvx avatar Dec 20 '20 11:12 pvvx

10 Ohm shunt: image

pvvx avatar Dec 20 '20 12:12 pvvx

CPU 16 or 24 MHz ? rf_set_power_level_index(RF_POWER_P3p01dBm)?

I have used your coder from your repo (from yesterday)

For deep sleep: there will be additional current for LCD and sensor (deep sleep) - not much but something.

I want only know the real (true) needed energy for measurement, advertising - this are the parts we could modify over the time... ;)

Thanks!

michapr avatar Dec 20 '20 12:12 michapr

Calculation of the average consumption on the oscilloscope: image Window 24 ms: Average 1.034 mA, Period (adv.impulse) ~2 sec, Deep-Sleep 6 uA (1.034mA * 24ms + 0.006mA * 2000ms) / 2024ms = 0.0182 mA

pvvx avatar Dec 20 '20 12:12 pvvx

Window 24 ms: Average 1.034 mA, Period (adv.impulse) ~2 sec, Deep-Sleep 6 uA (1.034mA * 24ms + 0.006mA * 2000ms) / 2024ms = 0.0182 mA

plus energy of one advertising impulse, right - or is the first part the impulse (I think so,...)?

michapr avatar Dec 20 '20 12:12 michapr

In the last diagram, this is the maximum duration of an Advertisement with readings of battery voltage and temperature sensor with humidity. image The tail also has:

  • I2C SHTV3 sleep command.
  • I2C refreshes the LCD.

0.0182mA - Every 2 seconds (each advertisement) the LCD is updated. Every 10 seconds (5 adv) + measurements of all sensors

I have used your coder from your repo (from yesterday)

Repo updates are frequent. Yesterday it was added: image

I make it possible to configure all parameters with reading. And save to Flash - replacing the battery does not change the settings... In the 'connection' mode, each measurement and notify -> less consumption comes out. It is also necessary to embed a GPIO ("reset" mark on the board) trigger for the assigned temperature / нumidity... + loop recording for a month in flash...

pvvx avatar Dec 20 '20 13:12 pvvx

It is also necessary to embed a GPIO ("reset" mark on the board) trigger for the assigned temperature / нumidity... + loop recording for a month in flash... What do you mean with this, sorry, didn't understand ;)

How to set different frequency in code (16MHz)? (I have checked your TelinkMiFlasher.html (very nice !) but frequency setting is not there, right?)

Thank you for your work and sharing your knowledge!

michapr avatar Dec 20 '20 18:12 michapr

"Connection" mode. image In the "connection" mode, a 10 sec cycle consists of 5 periods (2 sec): image The transmission is carried out over one channel and the total consumption is less by several percent. Due to the shorter duration of the active mode.

pvvx avatar Dec 20 '20 20:12 pvvx

How to set different frequency in code (16MHz)?

Select only in source code. app_config.h: #define CLOCK_SYS_CLOCK_HZ 24000000 / 16000000


And don't confuse CLOCK_16M_SYS_TIMER_CLK_xx with CLOCK_SYS_CLOCK_xx for time settings. System timer always from 16 MHz!

The wrong constant + overflow:

if((clock_time()-last_battery_delay) > 5*60000*CLOCK_SYS_CLOCK_1MS){//Read battery delay

https://github.com/atc1441/ATC_MiThermometer/blob/master/ATC_Thermometer/app.c#L79

5 * 60000 * 1000 * 16 = 4800000000 = 0x1_1E1A3000 (!)

pvvx avatar Dec 20 '20 21:12 pvvx

I have used your repo again ;) Have you tried the OTA firmware update? I have some problems here (using your flasher page) At first flashed from original FW to your current release - all fine. Then have changed the frequency to 16MHz, tried to update via OTA.

...
12:14:13: Detected custom Firmware
12:14:15: Start DFU
12:14:21: Update error: NotSupportedError: GATT operation failed for unknown reason.

After beginning with upload upload is stopped. After that device is "dead". I must use serial update (python) with new compiled FW, then is all again ok. Tried two times, same result. Any idea? ;)

michapr avatar Dec 21 '20 11:12 michapr

I have used your repo again ;)

Write there... Reload 'cstartup_825x.S' (there was a previously changed header)

pvvx avatar Dec 21 '20 13:12 pvvx

image

image

In different devices and SDKs, the maximum advertising interval is no more than 10 seconds. For a longer interval, alternate deep-sleep...

pvvx avatar Dec 21 '20 13:12 pvvx

Write there... Reload 'cstartup_825x.S' (there was a previously changed header)

There are no issues enabled in the repo ;)

michapr avatar Dec 21 '20 13:12 michapr