mirror of
https://github.com/apache/nuttx.git
synced 2026-09-28 18:13:53 +00:00
espressif/esp_pm.c: restore GPIO config after using it as a wake source
Arming a pin as a light-sleep wake source destroyed whatever it was
configured as, permanently.
esp_pm_gpio_wakeup_prepare() has to reconfigure each masked pin to plain
INPUT and hand it to gpio_wakeup_enable(), because the wakeup path only
supports level triggering. It then never put anything back. A pin that
was also a normal peripheral interrupt -- a sensor's data-ready line, say
-- came out of the first light sleep with its trigger mode gone and never
interrupted again. Nothing failed loudly; the device just went silent.
Fixed generically rather than per-board:
- esp_configgpio() now remembers the last attr applied to each pin, and
a new esp_getconfiggpio() hands it back. This is what lets the PM
code restore a pin without having to know what the pin is for.
- esp_pm_gpio_wakeup_prepare() saves each masked pin's attr before
overwriting it, and a new esp_pm_gpio_wakeup_restore() puts it back
as soon as esp_pm_light_sleep_start() returns.
Tied to the physical sleep/wake cycle deliberately, not to PM state
transitions. An earlier attempt used a board-level pm_register()/notify()
callback and never fired at all, because the board sits in PM_STANDBY
without transitioning back to PM_NORMAL -- there is no state change to
hang the restore on. The return from esp_pm_light_sleep_start() is the
one event that always happens exactly once per sleep.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
This commit is contained in:
parent
4818198a0d
commit
3c3afd04bd
3 changed files with 90 additions and 0 deletions
|
|
@ -72,6 +72,13 @@ static gpio_hal_context_t g_gpio_hal =
|
|||
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
|
||||
};
|
||||
|
||||
/* Mirrors the attr last applied to each pin via esp_configgpio(), so a
|
||||
* caller that has to temporarily reconfigure a pin (e.g. PM wake-source
|
||||
* setup) can read it back and restore it afterward.
|
||||
*/
|
||||
|
||||
static gpio_pinattr_t g_gpio_lastattr[SOC_GPIO_PIN_COUNT];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
|
@ -138,6 +145,8 @@ int esp_configgpio(int pin, gpio_pinattr_t attr)
|
|||
{
|
||||
DEBUGASSERT(pin >= 0 && pin < SOC_GPIO_PIN_COUNT);
|
||||
|
||||
g_gpio_lastattr[pin] = attr;
|
||||
|
||||
/* Handle input pins */
|
||||
|
||||
if ((attr & INPUT) != 0)
|
||||
|
|
@ -191,6 +200,7 @@ int esp_configgpio(int pin, gpio_pinattr_t attr)
|
|||
if ((attr & DRIVE_MASK) != 0)
|
||||
{
|
||||
uint32_t val = ((attr & DRIVE_MASK) >> DRIVE_SHIFT) - 1;
|
||||
|
||||
gpio_hal_set_drive_capability(&g_gpio_hal, pin, val);
|
||||
}
|
||||
else
|
||||
|
|
@ -202,6 +212,7 @@ int esp_configgpio(int pin, gpio_pinattr_t attr)
|
|||
if ((attr & FUNCTION_MASK) != 0)
|
||||
{
|
||||
uint32_t val = ((attr & FUNCTION_MASK) >> FUNCTION_SHIFT) - 1;
|
||||
|
||||
gpio_hal_func_sel(&g_gpio_hal, pin, val);
|
||||
}
|
||||
else
|
||||
|
|
@ -212,6 +223,27 @@ int esp_configgpio(int pin, gpio_pinattr_t attr)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_getconfiggpio
|
||||
*
|
||||
* Description:
|
||||
* Return the attr last passed to esp_configgpio() for this pin.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pin - GPIO pin to query.
|
||||
*
|
||||
* Returned Value:
|
||||
* The attr last passed to esp_configgpio() for this pin.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
gpio_pinattr_t esp_getconfiggpio(int pin)
|
||||
{
|
||||
DEBUGASSERT(pin >= 0 && pin < SOC_GPIO_PIN_COUNT);
|
||||
|
||||
return g_gpio_lastattr[pin];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_gpio_matrix_in
|
||||
*
|
||||
|
|
|
|||
|
|
@ -157,6 +157,25 @@ extern "C"
|
|||
|
||||
int esp_configgpio(int pin, gpio_pinattr_t attr);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_getconfiggpio
|
||||
*
|
||||
* Description:
|
||||
* Return the attr last passed to esp_configgpio() for this pin, so a
|
||||
* caller that has to temporarily reconfigure a pin (e.g. PM wake-source
|
||||
* setup) can restore it afterward without needing its own knowledge of
|
||||
* what the pin is normally used for.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pin - GPIO pin to query.
|
||||
*
|
||||
* Returned Value:
|
||||
* The attr last passed to esp_configgpio() for this pin.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
gpio_pinattr_t esp_getconfiggpio(int pin);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_gpio_matrix_in
|
||||
*
|
||||
|
|
|
|||
|
|
@ -446,6 +446,8 @@ static uint64_t IRAM_ATTR esp_pm_get_gpio_mask(void)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static gpio_pinattr_t g_gpio_wakeup_saved[CONFIG_SOC_GPIO_PIN_COUNT];
|
||||
|
||||
static void IRAM_ATTR esp_pm_gpio_wakeup_prepare(void)
|
||||
{
|
||||
uint64_t mask_value = esp_pm_get_gpio_mask();
|
||||
|
|
@ -461,6 +463,14 @@ static void IRAM_ATTR esp_pm_gpio_wakeup_prepare(void)
|
|||
pin_mask = BIT(i);
|
||||
if ((mask_value & pin_mask) != 0)
|
||||
{
|
||||
/* This pin may also be a normal edge-triggered peripheral IRQ
|
||||
* (e.g. a sensor's data-ready line) -- gpio_wakeup_enable()
|
||||
* below only supports level triggering, so remember whatever
|
||||
* esp_configgpio() had last set here and put it back in
|
||||
* esp_pm_gpio_wakeup_restore() once this sleep is over.
|
||||
*/
|
||||
|
||||
g_gpio_wakeup_saved[i] = esp_getconfiggpio(i);
|
||||
esp_configgpio(i, INPUT);
|
||||
gpio_wakeup_enable(i, level_mode);
|
||||
}
|
||||
|
|
@ -468,6 +478,31 @@ static void IRAM_ATTR esp_pm_gpio_wakeup_prepare(void)
|
|||
|
||||
esp_sleep_enable_gpio_wakeup();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp_pm_gpio_wakeup_restore
|
||||
*
|
||||
* Description:
|
||||
* Undo esp_pm_gpio_wakeup_prepare(): restore each wake-source gpio to
|
||||
* whatever esp_configgpio() had it set to before this sleep.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void IRAM_ATTR esp_pm_gpio_wakeup_restore(void)
|
||||
{
|
||||
uint64_t mask_value = esp_pm_get_gpio_mask();
|
||||
int pin_mask = 0;
|
||||
|
||||
for (int i = 0; i < CONFIG_SOC_GPIO_PIN_COUNT; i++)
|
||||
{
|
||||
pin_mask = BIT(i);
|
||||
if ((mask_value & pin_mask) != 0)
|
||||
{
|
||||
gpio_wakeup_disable(i);
|
||||
esp_configgpio(i, g_gpio_wakeup_saved[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PM_GPIO_WAKEUP */
|
||||
|
||||
#ifdef CONFIG_PM_UART_WAKEUP
|
||||
|
|
@ -777,6 +812,10 @@ void esp_pmstandby(uint64_t time_in_us)
|
|||
|
||||
esp_pm_light_sleep_start(&rtc_diff_us);
|
||||
|
||||
#ifdef CONFIG_PM_GPIO_WAKEUP
|
||||
esp_pm_gpio_wakeup_restore();
|
||||
#endif
|
||||
|
||||
/* Only step the clock where the systimer actually stalls during sleep
|
||||
* (SOC_SLEEP_SYSTIMER_STALL_WORKAROUND); elsewhere it keeps counting
|
||||
* through light sleep, so stepping it here would double-count the time.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue