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.