NCS2.3.0, NRF52833
I use a button to wake my product. The same button is used to turn off. The button is tied low with a 100K resistor and pulled high when pressed.
I found that very occasionally, when I turn the device off, it later fails to wake up when I press the button. I copied the code to EnterSystemOff() from one of the examples.
I read the product spec again and concluded that I must ensure the button is not pressed when I call pm_stat_force or the SENSE wont work. (please correct me if I'm wrong)
So I use this code
void EnterSystemOff(void)
{
LOG_INF("Entering system off; press BUTTON to restart");
// #ifdef thread0_id
common.run_button_thread = false;
// k_msleep(100);
// k_thread_abort(thread0_id);
// k_thread_abort(thread1_id);
// #endif
LIS2DW12_power_down();
ClearRGBLEDs();
nrf_pwm_play_shutdown();
nrf_pwm_stop();
all_gpios_off();
do
{
//We MUST not call pm_state_force if the button is pressed.
// So lets wait for the button to be continuously released for at least half a second
// This is still a bit risky because the button could be pressed again before we call pm_state_force
uint32_t button_unpressed_counter = 0;
while(button_unpressed_counter < 500)
{
k_sleep(K_MSEC(1));
if(nrf_gpio_pin_read(MY_BUTTON_PIN))
{
button_unpressed_counter = 0;
}
else
{
button_unpressed_counter++;
}
}
pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
/* Now we need to go to sleep. This will let the idle thread run and
* the pm subsystem will use the forced state. To confirm that the
* forced state is used, lets set the same timeout used previously.
*/
k_sleep(K_SECONDS(2));
LOG_INF("ERROR: System off failed - resetting");
// We should never get here because the button should cause a reset which restarts the system.
// Something serious has gone wrong. so lets try to reset the system.
sys_reboot(SYS_REBOOT_COLD);
k_sleep(K_SECONDS(2));
// If we're still here then the reset failed. Try to call pm_state_force again.
} while (true);
}
As you can see there's a loop that waits for at least 500ms without a button press to *try* to ensure it doesn't go to sleep when the pin is high.
Obviously there's still a race condition which I don't like. I wanted to ask if there's a better way to do this. And to check if I've understood properly.
I need to ensure SENSE is always configured on the pin, so the first line of main() is
nrf_gpio_cfg(
MY_BUTTON_PIN,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_SENSE_HIGH);
I can't see how to configure SENSE on the gpio in the zephyr .dts file, so I use the nrf_gpio functions instead and I don't configure any of my gpios in the .dts file.