Hi,
I am getting started building a project for a nRF54L05, for which I am building my code emulating that target, and flashing it on a nRF54L15dk board.
My current goal is to write an easy code that changes its state between awake and asleep turning off some peripherals and stops its advertising functionality while asleep. In order to change between those states I am using the Common Application Framework (abbreviated as CAF from now on), for which I wrote the following declaration:
static bool app_event_handler(const struct app_event_header *aeh) { if (is_power_down_event(aeh)) { sleep_state = STATE_ASLEEP; LOG_INF("power down event was called\n"); LOG_INF("Entering Constant Latency Sleep for %d seconds\n", CONFIG_SLEEP_DURATION); stop_advertising(); k_timer_start(&wake_up_timer, K_SECONDS(CONFIG_SLEEP_DURATION), K_SECONDS(CONFIG_SLEEP_DURATION)); return false; } return false; }
A reaction to is_wake_up_event was present, but I removed it to simplify the output and the program while analyzing this problem. When an interpretation of the wake up event was present in the app_event_handler, its functionality was correctly ran, and then broke one second after.
If I never call the wake up event, the program never breaks.
This target is built using the toolchain 2.8.0 with west and sysbuild.
The amount of events that can be handled is set as:
The number has been changed up and down to no avail.
The stack size has also been modified up and down without any clear result. Highest I have tried was 4096.
The subscription and listeners are also added:
APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
The power_down_event and the wake_up_event are sent by myself. The power_down_event is called as soon as the initialization is finished, and is sent like:
void sleep_trigger(void){ sleep_state = STATE_ASLEEP; struct power_down_event *event = new_power_down_event(); APP_EVENT_SUBMIT(event); }
The wake_up_event is called from the wake_up_timer triggered when the power_down_event comes from its callback function:
static void sleep_wake_up(struct k_timer *timer_id) { LOG_INF("Timer callback starting"); if (sleep_state != STATE_ASLEEP) { LOG_WRN("Timer callback called but not in ASLEEP state (state=%d)", sleep_state); return; } struct wake_up_event *wake_event = new_wake_up_event(); if (wake_event == NULL) { LOG_ERR("Failed to allocate wake up event"); return; } LOG_INF("Submitting wake up event"); APP_EVENT_SUBMIT(wake_event); LOG_INF("Timer callback completed"); }
The program breaks one second after the wake up event is sent. Whether there is a reaction to the wake up event in the app_event_handler or not is irrelevant, the outcome is the same one.
The KConfigs set for this case are the following:
#CAF - Common Application Framework for BLE CONFIG_CAF=y CONFIG_BT_SMP=n CONFIG_CAF_BLE_STATE=n CONFIG_CAF_BLE_STATE_PM=n CONFIG_CAF_POWER_MANAGER=y CONFIG_CAF_POWER_MANAGER_TIMEOUT=20
I have not observed any differences in behavior if the configs set as 'no' are set as 'yes'.
The output I see in my serial terminal is the following one:
[00:00:00.111,593] <inf> app_event_manager: e: power_down_event [00:00:00.111,599] <inf> sleep: power down event was called [00:00:00.111,604] <inf> sleep: Entering Constant Latency Sleep for 30 seconds [00:00:00.111,731] <inf> main: Advertising successfully stopped [00:00:02.109,924] <inf> main: Still in the main loop [00:00:04.109,985] <inf> main: Still in the main loop [00:00:06.110,050] <inf> main: Still in the main loop [00:00:08.110,113] <inf> main: Still in the main loop [00:00:10.110,178] <inf> main: Still in the main loop [00:00:12.110,241] <inf> main: Still in the main loop [00:00:14.110,306] <inf> main: Still in the main loop [00:00:16.110,369] <inf> main: Still in the main loop [00:00:18.110,434] <inf> main: Still in the main loop [00:00:20.110,497] <inf> main: Still in the main loop [00:00:22.110,562] <inf> main: Still in the main loop [00:00:24.110,625] <inf> main: Still in the main loop [00:00:26.110,690] <inf> main: Still in the main loop [00:00:28.110,753] <inf> main: Still in the main loop [00:00:30.110,818] <inf> main: Still in the main loop [00:00:30.111,731] <inf> sleep: Timer callback starting [00:00:30.111,749] <inf> sleep: Event pointer: 0x20006af0 [00:00:30.111,754] <inf> sleep: Submitting wake up event [00:00:30.111,764] <inf> sleep: Timer callback completed [00:00:30.111,791] <inf> app_event_manager: e: wake_up_event [00:00:30.111,797] <inf> power_manager: debug POWER MANAGER C [00:00:30.111,801] <inf> power_manager: Wake up the board [00:00:30.111,811] <inf> power_manager: debug power manager c power down counter reset is finished [00:00:30.111,815] <inf> power_manager: debug power manager c is done [00:00:31.111,841] <err> os: ***** USAGE FAULT ***** [00:00:31.111,851] <err> os: Illegal use of the EPSR [00:00:31.111,861] <err> os: r0/a1: 0x20002e88 r1/a2: 0xe000ed00 r2/a3: 0x20002e88 [00:00:31.111,868] <err> os: r3/a4: 0x00000000 r12/ip: 0x200005d8 r14/lr: 0x0001f359 [00:00:31.111,872] <err> os: xpsr: 0x60000000 [00:00:31.111,876] <err> os: Faulting instruction address (r15/pc): 0x00000000 [00:00:31.111,895] <err> os: >>> ZEPHYR FATAL ERROR 35: Unknown error on CPU 0 [00:00:31.111,912] <err> os: Current thread: 0x20003130 (sysworkq) [00:00:31.140,825] <err> os: Halting system
I added a print from the main function in a while(1) loop every two seconds to see if the program is still running. I also checked other functions of the program where the wake up event was being used ad added prints to check if they were being called (in this case, they are called in the power manager).
Is there any specific way the wake up event should be handled to avoid these cases?