Zephyr: Last software timer expiration does not cause immediate transition into low power sleep

I've noticed weird behavior in the software timer scheduling. I my case, there is one timer handling LED blinking. It is used in single shot mode and rescheduled to time the lit up time and blank time. Once the blinking sequence is finished, the timer is not rescheduled and SoC keeps consuming way too much power (~500 uA).
There is something running with 60 s period since the app start, that resolves this increased power consumption.

If I time the LED blinking by sleeping the thread, the issue is not present - it is specific to software timer scheduling and power management tied to it.

Steps to reproduce

  1. Have a minimal application with power management enabled and SoC current measurement.
  2. make the main task sleep for some duration
  3. observer low power consumption (OK)
  4. Start software times with expiration before 60 s of uptime
  5. Observe power consumption after the timer expires -> elevated
  6. Wait for nearest future N*60 s uptime
  7. Observer power consumption drop to expected low power sleep levels

Environment

  • host OS: Archlinux (up to date)
  • toolchain: 16.2.0
  • NRF connect SDK: 3.4.0
  • Zephyr version: ncs-v3.4.0
  • hardware: custom NRF54L15 based board
  • measured with Joulescope JS-220

Appliction task body to get the idea about sequencing.

auto main() -> int {
	AbsTime::sleep(10_s);
	leds[0].blink(50_ms, 50_ms, 3);
	AbsTime::sleep(10_s);
	leds[0].blink(50_ms, 1_s, 3); // starts timer
	AbsTime::sleep(60_s);
	leds[0].blink(50_ms, 50_ms, 3); // starts timer
	return 0;
}

Timer callback

void GpioPulsed::timerExpiredHandler(const std::size_t id) {
	utils::RaiiExecutor flipper([&]{
		config.on = not config.on;
	});
	if (config.on) {
		gpio.setInactive();
		if (config.infinite) {
			Timer::start(config.offTime);
		} else if (config.remains > 0) { // bot the last blink
			Timer::start(config.offTime);
			--config.remains;
		} // else: end of sequence, no timer rescheduling
	} else {
		gpio.setActive();
		Timer::start(config.onTime);
	}
}
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_MAX_CONN=4
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
CONFIG_BT_BONDABLE=n
CONFIG_BT_PRIVACY=n
CONFIG_BT_RECV_WORKQ_SYS=y
CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL=y

CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
CONFIG_BT_AUTO_PHY_UPDATE=n


CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_COUNT=6
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

CONFIG_BT_PERIPHERAL_PREF_MIN_INT=10


CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_GATT_DYNAMIC_DB=y

CONFIG_BT_ATT_PREPARE_COUNT=6

CONFIG_BT_CHANNEL_SOUNDING=y
CONFIG_BT_CTLR_PHY_2M=y
CONFIG_BT_CTLR_SDC_CS_MAX_ANTENNA_PATHS=1
CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS=1
CONFIG_BT_CTLR_SDC_CS_STEP_MODE3=n
CONFIG_BT_CTLR_CHANNEL_SOUNDING_TEST=n
CONFIG_BT_CTLR_SDC_CS_ROLE_REFLECTOR_ONLY=y

CONFIG_BT_CTLR_EXTENDED_FEAT_SET=y

CONFIG_BT_CTLR_CHANNEL_SOUNDING_TEST=n

CONFIG_BT_TRANSMIT_POWER_CONTROL=y

CONFIG_BT_SMP=y


CONFIG_BT_TRANSMIT_POWER_CONTROL=y

CONFIG_FPU=y
CONFIG_FPU_SHARING=y


CONFIG_MPSL_ASSERT_HANDLER=y
CONFIG_ASSERT=y
CONFIG_ASSERT_NO_MSG_INFO=y
CONFIG_ASSERT_NO_FILE_INFO=y

CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=2

CONFIG_CPP=y
CONFIG_STD_CPP2B=y
CONFIG_REQUIRES_FULL_LIBCPP=y

CONFIG_BOOTLOADER_MCUBOOT=n

CONFIG_DEBUG=y
CONFIG_DEBUG_THREAD_INFO=y

CONFIG_MULTITHREADING=y

CONFIG_SYS_HEAP_RUNTIME_STATS=y
CONFIG_SYS_HEAP_LISTENER=y
CONFIG_HEAP_MEM_POOL_SIZE=32768
CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=4096
CONFIG_NEWLIB_LIBC_HEAP_LISTENER=y
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096


CONFIG_PWM=y
CONFIG_FP16=n
CONFIG_CBPRINTF_NANO=y
CONFIG_ASSERT_VERBOSE=n
CONFIG_ASSERT_NO_MSG_INFO=y
CONFIG_BOOT_BANNER=n
CONFIG_NCS_BOOT_BANNER=n

CONFIG_HWINFO=y

CONFIG_LOG=n
CONFIG_CONSOLE=n
CONFIG_PRINTK=n

CONFIG_LOG_MODE_DEFERRED=n
CONFIG_RTT_CONSOLE=n
CONFIG_USE_SEGGER_RTT=n
CONFIG_LOG_BACKEND_RTT=n
CONFIG_LOG_BACKEND_RTT_MODE_OVERWRITE=n
CONFIG_FAULT_DUMP=0


CONFIG_BT_CTLR_CONN_RSSI=y
CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y

CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y


CONFIG_MAIN_STACK_SIZE=1024

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_SPI=y
CONFIG_SPI_ASYNC=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_SFDP_RUNTIME=y
CONFIG_FLASH_JESD216_API=y
Initially opened issues at upstream zepyhr rtos GH repo, but closed due to using NCS (downstream) fork.
After disabling bluetooth and some other stuff, to make the test minimal, the 60 s "recovery tick" does not occur anymore and power consumption never drops back to expected levels. It still drops during 1s LED off times, when the timer runs.
Parents
  • Hello, 

    Sorry, I can see you are using C++ but I do not recognise the function and classes you are using. Have you implemented your own timer or is it a wrapper around the Zephyr timer (https://nrfconnectdocs.nordicsemi.com/ncs/latest/zephyr/kernel/services/timing/timers.html#timers-v2)? Can you provide a minimal version of your project that would allow me to reproduce the problem here?

    Best regards,

    Vidar

  • So this was interesting adventure, it looks like (some?) float operations in the timer expiry callback cause increased power draw.

    I've also attached disassembly of each handler.

    4048.main.cpp

    13457.prj.conf

    my_timer_expiry_handler_float(k_timer*)(struct k_timer *timer);
    ; arg struct k_timer *timer @ r0
    0x000014e8      push    {r4, r5, lr} ; main.cpp:34  ; my_timer_expiry_handler_float(k_timer*)
    0x000014ea      sub     sp, 0xc
    0x000014ec      mov     r5, r0     ; arg1
    0x000014ee      ldr     r3, [ledConfig] ; main.cpp:36 } ; 0x20000060
                                       ; loc.__data_start
    0x000014f0      ldrb    r3, [r3]   ; 0x20000060
                                       ; loc.__data_start
    0x000014f2      cbz     r3, 0x1536
    0x000014f4      movs    r2, 0      ; main.cpp:37  ; int value
    0x000014f6      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x000014f8      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x000014fc      mov     r4, r3
    0x000014fe      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x00001500      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x00001504      ldr     r3, [r4, 0x20] ; main.cpp:38 // works as expected
    0x00001506      cbz     r3, 0x156c
    0x00001508      vldr    s14, [r4, 0x10] ; main.cpp:39 void my_timer_expiry_handler_raw(k_timer *timer) {
    0x0000150c      vldr    s15, [my_timer_expiry_handler_raw(k_timer*)]
    0x00001510      vmul.f32 s15, s14, s15
    0x00001514      vmov    r0, s15    ; int16_t arg1
    0x00001518      bl      dbg.__fixsfdi ; dbg.__fixsfdi ; DItype __fixsfdi(SFtype a)
    0x0000151c      mov     r2, r0     ; k_timeout_t period
    0x0000151e      mov     r3, r1
    0x00001520      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x00001522      movs    r1, 0      ; k_timeout_t duration
    0x00001524      strd    r0, r1, [sp]
    0x00001528      mov     r0, r5     ; struct k_timer *timer
    0x0000152a      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x0000152e      ldr     r3, [r4, 0x20] ; main.cpp:40 
    0x00001530      subs    r3, 1
    0x00001532      str     r3, [r4, 0x20]
    0x00001534      b       0x156c
    0x00001536      movs    r2, 1      ; main.cpp:43 if (ledConfig.blinks_remain > 0) { ; int value
    0x00001538      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x0000153a      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x0000153e      mov     r4, r3
    0x00001540      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x00001542      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x00001546      vldr    s14, [r4, 4] ; main.cpp:44 k_timer_start(timer, {ledConfig.off_time_raw}, K_NO_WAIT);
    0x0000154a      vldr    s15, [my_timer_expiry_handler_raw(k_timer*)]
    0x0000154e      vmul.f32 s15, s14, s15
    0x00001552      vmov    r0, s15    ; int16_t arg1
    0x00001556      bl      dbg.__fixsfdi ; dbg.__fixsfdi ; DItype __fixsfdi(SFtype a)
    0x0000155a      mov     r2, r0     ; k_timeout_t period
    0x0000155c      mov     r3, r1
    0x0000155e      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x00001560      movs    r1, 0      ; k_timeout_t duration
    0x00001562      strd    r0, r1, [sp]
    0x00001566      mov     r0, r5     ; struct k_timer *timer
    0x00001568      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x0000156c      ldr     r2, [ledConfig] ; main.cpp:47 } else { ; 0x20000060
                                       ; loc.__data_start
    0x0000156e      ldrb    r3, [r2]   ; 0x20000060
                                       ; loc.__data_start
    0x00001570      eor     r3, r3, 1
    0x00001574      strb    r3, [r2]
    0x00001576      add     sp, 0xc    ; main.cpp:48 gpio_pin_set_dt(&led_gpio_raw, 1);
    0x00001578      pop     {r4, r5, pc}
    0x0000157a      nop
    0x0000157c      lsls    r0, r4, 1
    0x0000157e      movs    r0, 0
    0x00001580      movs    r4, 0
    0x00001582      mov     ip, lr
    my_timer_expiry_handler_raw(k_timer*)(struct k_timer *timer);
    ; arg struct k_timer *timer @ r0
    0x00001584      push    {r4, r5, lr} ; main.cpp:51  ; my_timer_expiry_handler_raw(k_timer*)
    0x00001586      sub     sp, 0xc
    0x00001588      mov     r5, r0     ; arg1
    0x0000158a      ldr     r3, [ledConfig] ; main.cpp:53 } ; 0x20000060
                                       ; loc.__data_start
    0x0000158c      ldrb    r3, [r3]   ; 0x20000060
                                       ; loc.__data_start
    0x0000158e      cbz     r3, 0x15be
    0x00001590      movs    r2, 0      ; main.cpp:54  ; int value
    0x00001592      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x00001594      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x00001598      mov     r4, r3
    0x0000159a      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x0000159c      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x000015a0      ldr     r3, [r4, 0x20] ; main.cpp:55 K_TIMER_DEFINE(my_timer_float, my_timer_expiry_handler_float, NULL);
    0x000015a2      cbz     r3, 0x15e0
    0x000015a4      ldrd    r2, r3, [r4, 0x18] ; main.cpp:56  ; k_timeout_t period
    0x000015a8      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x000015aa      movs    r1, 0      ; k_timeout_t duration
    0x000015ac      strd    r0, r1, [sp]
    0x000015b0      mov     r0, r5     ; struct k_timer *timer
    0x000015b2      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x000015b6      ldr     r3, [r4, 0x20] ; main.cpp:57 K_TIMER_DEFINE(my_timer_raw, my_timer_expiry_handler_raw, NULL);
    0x000015b8      subs    r3, 1
    0x000015ba      str     r3, [r4, 0x20]
    0x000015bc      b       0x15e0
    0x000015be      movs    r2, 1      ; main.cpp:60 .on {}, ; int value
    0x000015c0      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x000015c2      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x000015c6      mov     r4, r3
    0x000015c8      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x000015ca      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x000015ce      ldrd    r2, r3, [r4, 8] ; main.cpp:61 .on_time = 0.1F, ; k_timeout_t period
    0x000015d2      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x000015d4      movs    r1, 0      ; k_timeout_t duration
    0x000015d6      strd    r0, r1, [sp]
    0x000015da      mov     r0, r5     ; struct k_timer *timer
    0x000015dc      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x000015e0      ldr     r2, [ledConfig] ; main.cpp:64 .off_time_raw = k_ticks_t(ledConfig.off_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1), ; 0x20000060
                                       ; loc.__data_start
    0x000015e2      ldrb    r3, [r2]   ; 0x20000060
                                       ; loc.__data_start
    0x000015e4      eor     r3, r3, 1
    0x000015e8      strb    r3, [r2]
    0x000015ea      add     sp, 0xc    ; main.cpp:65 .blinks_remain {},
    0x000015ec      pop     {r4, r5, pc}
    0x000015ee      nop
    0x000015f0      lsls    r0, r4, 1

Reply
  • So this was interesting adventure, it looks like (some?) float operations in the timer expiry callback cause increased power draw.

    I've also attached disassembly of each handler.

    4048.main.cpp

    13457.prj.conf

    my_timer_expiry_handler_float(k_timer*)(struct k_timer *timer);
    ; arg struct k_timer *timer @ r0
    0x000014e8      push    {r4, r5, lr} ; main.cpp:34  ; my_timer_expiry_handler_float(k_timer*)
    0x000014ea      sub     sp, 0xc
    0x000014ec      mov     r5, r0     ; arg1
    0x000014ee      ldr     r3, [ledConfig] ; main.cpp:36 } ; 0x20000060
                                       ; loc.__data_start
    0x000014f0      ldrb    r3, [r3]   ; 0x20000060
                                       ; loc.__data_start
    0x000014f2      cbz     r3, 0x1536
    0x000014f4      movs    r2, 0      ; main.cpp:37  ; int value
    0x000014f6      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x000014f8      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x000014fc      mov     r4, r3
    0x000014fe      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x00001500      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x00001504      ldr     r3, [r4, 0x20] ; main.cpp:38 // works as expected
    0x00001506      cbz     r3, 0x156c
    0x00001508      vldr    s14, [r4, 0x10] ; main.cpp:39 void my_timer_expiry_handler_raw(k_timer *timer) {
    0x0000150c      vldr    s15, [my_timer_expiry_handler_raw(k_timer*)]
    0x00001510      vmul.f32 s15, s14, s15
    0x00001514      vmov    r0, s15    ; int16_t arg1
    0x00001518      bl      dbg.__fixsfdi ; dbg.__fixsfdi ; DItype __fixsfdi(SFtype a)
    0x0000151c      mov     r2, r0     ; k_timeout_t period
    0x0000151e      mov     r3, r1
    0x00001520      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x00001522      movs    r1, 0      ; k_timeout_t duration
    0x00001524      strd    r0, r1, [sp]
    0x00001528      mov     r0, r5     ; struct k_timer *timer
    0x0000152a      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x0000152e      ldr     r3, [r4, 0x20] ; main.cpp:40 
    0x00001530      subs    r3, 1
    0x00001532      str     r3, [r4, 0x20]
    0x00001534      b       0x156c
    0x00001536      movs    r2, 1      ; main.cpp:43 if (ledConfig.blinks_remain > 0) { ; int value
    0x00001538      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x0000153a      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x0000153e      mov     r4, r3
    0x00001540      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x00001542      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x00001546      vldr    s14, [r4, 4] ; main.cpp:44 k_timer_start(timer, {ledConfig.off_time_raw}, K_NO_WAIT);
    0x0000154a      vldr    s15, [my_timer_expiry_handler_raw(k_timer*)]
    0x0000154e      vmul.f32 s15, s14, s15
    0x00001552      vmov    r0, s15    ; int16_t arg1
    0x00001556      bl      dbg.__fixsfdi ; dbg.__fixsfdi ; DItype __fixsfdi(SFtype a)
    0x0000155a      mov     r2, r0     ; k_timeout_t period
    0x0000155c      mov     r3, r1
    0x0000155e      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x00001560      movs    r1, 0      ; k_timeout_t duration
    0x00001562      strd    r0, r1, [sp]
    0x00001566      mov     r0, r5     ; struct k_timer *timer
    0x00001568      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x0000156c      ldr     r2, [ledConfig] ; main.cpp:47 } else { ; 0x20000060
                                       ; loc.__data_start
    0x0000156e      ldrb    r3, [r2]   ; 0x20000060
                                       ; loc.__data_start
    0x00001570      eor     r3, r3, 1
    0x00001574      strb    r3, [r2]
    0x00001576      add     sp, 0xc    ; main.cpp:48 gpio_pin_set_dt(&led_gpio_raw, 1);
    0x00001578      pop     {r4, r5, pc}
    0x0000157a      nop
    0x0000157c      lsls    r0, r4, 1
    0x0000157e      movs    r0, 0
    0x00001580      movs    r4, 0
    0x00001582      mov     ip, lr
    my_timer_expiry_handler_raw(k_timer*)(struct k_timer *timer);
    ; arg struct k_timer *timer @ r0
    0x00001584      push    {r4, r5, lr} ; main.cpp:51  ; my_timer_expiry_handler_raw(k_timer*)
    0x00001586      sub     sp, 0xc
    0x00001588      mov     r5, r0     ; arg1
    0x0000158a      ldr     r3, [ledConfig] ; main.cpp:53 } ; 0x20000060
                                       ; loc.__data_start
    0x0000158c      ldrb    r3, [r3]   ; 0x20000060
                                       ; loc.__data_start
    0x0000158e      cbz     r3, 0x15be
    0x00001590      movs    r2, 0      ; main.cpp:54  ; int value
    0x00001592      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x00001594      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x00001598      mov     r4, r3
    0x0000159a      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x0000159c      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x000015a0      ldr     r3, [r4, 0x20] ; main.cpp:55 K_TIMER_DEFINE(my_timer_float, my_timer_expiry_handler_float, NULL);
    0x000015a2      cbz     r3, 0x15e0
    0x000015a4      ldrd    r2, r3, [r4, 0x18] ; main.cpp:56  ; k_timeout_t period
    0x000015a8      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x000015aa      movs    r1, 0      ; k_timeout_t duration
    0x000015ac      strd    r0, r1, [sp]
    0x000015b0      mov     r0, r5     ; struct k_timer *timer
    0x000015b2      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x000015b6      ldr     r3, [r4, 0x20] ; main.cpp:57 K_TIMER_DEFINE(my_timer_raw, my_timer_expiry_handler_raw, NULL);
    0x000015b8      subs    r3, 1
    0x000015ba      str     r3, [r4, 0x20]
    0x000015bc      b       0x15e0
    0x000015be      movs    r2, 1      ; main.cpp:60 .on {}, ; int value
    0x000015c0      ldr     r3, [ledConfig] ; 0x20000060
                                       ; loc.__data_start
    0x000015c2      ldrb.w  r1, [r3, 0x50] ; gpio_pin_t pin
    0x000015c6      mov     r4, r3
    0x000015c8      ldr     r0, [r3, 0x4c] ; 0x200000ac
                                       ; obj.led_gpio_raw ; const struct device *port
    0x000015ca      bl      gpio_pin_set ; gpio.h:1721 return gpio_pin_set(spec->port, spec->pin, value); ; sym.gpio_pin_set ; int gpio_pin_set(const struct device *port, gpio_pin_t pin, int value)
    0x000015ce      ldrd    r2, r3, [r4, 8] ; main.cpp:61 .on_time = 0.1F, ; k_timeout_t period
    0x000015d2      movs    r0, 0      ; kernel.h:528 static inline void k_timer_start(struct k_timer * timer, k_timeout_t duration, k_timeout_t period)
    0x000015d4      movs    r1, 0      ; k_timeout_t duration
    0x000015d6      strd    r0, r1, [sp]
    0x000015da      mov     r0, r5     ; struct k_timer *timer
    0x000015dc      bl      dbg.z_impl_k_timer_start ; dbg.z_impl_k_timer_start ;  z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period)
    0x000015e0      ldr     r2, [ledConfig] ; main.cpp:64 .off_time_raw = k_ticks_t(ledConfig.off_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1), ; 0x20000060
                                       ; loc.__data_start
    0x000015e2      ldrb    r3, [r2]   ; 0x20000060
                                       ; loc.__data_start
    0x000015e4      eor     r3, r3, 1
    0x000015e8      strb    r3, [r2]
    0x000015ea      add     sp, 0xc    ; main.cpp:65 .blinks_remain {},
    0x000015ec      pop     {r4, r5, pc}
    0x000015ee      nop
    0x000015f0      lsls    r0, r4, 1

Children
  • Thanks for sharing the code and config. This is an interesting find. I was able to reproduce this on my end as well, and it seems like the elevated sleep current may potentially be related to the FPU. I assume you are also not seeing the issue if you don't enable CONFIG_FPU in your project config?

    Not related to this specific issue, but the Zephyr also documentation states that use of FPU instructions inside interrupts is not supported: 

    https://nrfconnectdocs.nordicsemi.com/ncs/latest/zephyr/kernel/services/other/float.html 

    I will continue to investigate this on my end. 

  • Not related to this specific issue, but the Zephyr also documentation states that use of FPU instructions inside interrupts is not supported: 

    This is the most important info for me! I completely missed this fact in the docs.

    I tried to create global volatile float sink variable and write it from timer expiry callback (ISR) and that went fine. Increased power draw in sleep is probably caused by some heavier FPU use in ISR, not just load/store.

    My opinion:

    Zephyr should assert in such cases. There are flags in Cortex M cores indicating FPU activity on current stack, so ti is doable. I have the impression, that Zephyr uses asserts mostly for user input validation and not even that extensively. Advanced assumptions like this one are rarely guarded by an assert.

    Thank you for looking into this!
    Your answer resolves the issue for me, but if you find out anything interesting or manage to improve Zephyr quality in this aspect, let me know!

  • Thanks for the update and feedback. I agree, having an assert to catch invalid FPU usage inside ISRs sounds like a good idea given the current limitation . I am still trying to understand why the current consumption increases after a FPU exception. Will update the ticket when I know more.

Related