Buttons module stops working if button is pressed during power off

When a button is pressed during power off, the buttons module disables the wakeup interrupt but the button scan never happens, leaving the module in an invalid state and preventing any wakeup from system off.

I modified the buttons.c CAF module to log when it changes the interrupt configuration:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static int setup_pin_wakeup(void)
{
uint32_t wakeup_cols = get_wakeup_mask(col, ARRAY_SIZE(col));
uint32_t wakeup_rows = get_wakeup_mask(row, ARRAY_SIZE(row));
LOG_DBG("Setting pin wakeup: 0x%08x 0x%08x", wakeup_cols, wakeup_rows);
/* Disable callbacks (and cancel the work) to ensure it will not be scheduled by an
* invalid button in the idle state.
*/
int err = callback_ctrl(0);
if (!err) {
/* Setup callbacks and columns for the idle state. */
err = set_cols(wakeup_cols);
if (!err) {
err = callback_ctrl(wakeup_rows);
}
}
LOG_DBG("Completed setting pin wakeup: %d", err);
return err;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Here are the logs when pressing the button during power off:

Fullscreen
1
2
3
4
5
6
7
8
9
10
[00:00:00.309,814] <inf> app_event_manager: e: force_power_down_event
[00:00:00.309,814] <inf> power_manager: Force power down processing
[00:00:00.309,906] <inf> app_event_manager: e: power_down_event
[00:00:00.310,058] <dbg> buttons: setup_pin_wakeup: Setting pin wakeup: 0xffffffff 0xffffffe4
[00:00:00.310,150] <dbg> buttons: setup_pin_wakeup: Completed setting pin wakeup: 0
[00:00:00.310,607] <inf> power_manager: Power down the board
[00:00:00.310,913] <inf> app_event_manager: e:module_state_event module:buttons state:STANDBY
[00:00:00.311,035] <inf> app_event_manager: e:module_state_event module:board state:OFF
[00:00:00.317,413] <wrn> power_manager: System turned off
[00:00:00.357,299] <dbg> buttons: button_pressed_isr: Disabled callbacks: 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Although the k_work_reschedule call in button_pressed_isr succeeds, the work is never performed. It seems that the button module should somehow check if work can be scheduled, but I'm not sure what is preventing it from firing. Is the RTC stopped? Is the work cancelled on power down? Should k_work_reschedule even succeed in this situation?