STM32L476 in STOP2 mode
Posted: Mon Mar 30, 2020 1:25 pm
Hello,
I have troubles trying to use the STOP2 sleep mode on a STM32L476.
Its on a custom board: i enter manually in sleep mode. (now with a command under the shell)
And the wakeup will come from 3 different sources: external button, LPUART activity, or timeout on internal timer. (RTC is on LSE)
The consumption i obtain is 70uA when sleeping: not perfect, but it is not the problem.
The problem is that this value is obtained only for the FIRST sleep cycle.
All the next sleep cycles are at min 200uA.
And during wake, everything seems fine.
And i tried a LOT of things without result.
I think its a problem of register reconfiguration.
For that, i tried to backup all PWR_CRx, RCC_CRx, and RCC_Ax registers, then restoring them after wakeup, without success.
Thinking its perhaps an OS related problem, I tried also to stop Chibios before sleepping, also without success.
Its why i put here the code of my sleep function.
This code is called from main() because i read somewhere there is better to go in sleep mode from main(). (if we have many threads)
Its under Chibios 19.1.
The callback for the external button is this simple:
I can post also a relatively small program to show everything. (around 300 lines without ports init/deinit)
But it is designe for my board.
If someone has some ideas, i'm happy to receive it.
Stephane
I have troubles trying to use the STOP2 sleep mode on a STM32L476.
Its on a custom board: i enter manually in sleep mode. (now with a command under the shell)
And the wakeup will come from 3 different sources: external button, LPUART activity, or timeout on internal timer. (RTC is on LSE)
The consumption i obtain is 70uA when sleeping: not perfect, but it is not the problem.
The problem is that this value is obtained only for the FIRST sleep cycle.
All the next sleep cycles are at min 200uA.
And during wake, everything seems fine.
And i tried a LOT of things without result.
I think its a problem of register reconfiguration.
For that, i tried to backup all PWR_CRx, RCC_CRx, and RCC_Ax registers, then restoring them after wakeup, without success.
Thinking its perhaps an OS related problem, I tried also to stop Chibios before sleepping, also without success.
Its why i put here the code of my sleep function.
This code is called from main() because i read somewhere there is better to go in sleep mode from main(). (if we have many threads)
Its under Chibios 19.1.
Code: Select all
/** ****************************************************************************
* \fn void sleep_for_x_sec(uint16_t nb_sec)
* \brief Put the STM32 in the Stop2 mode
* Must be called only from main() To be tested (seen some comments on forums)
* \param[in] (u16) nb_of sec to wait in sleep mode: 1-65535
* \return (u8) wake source: WAKE_SOURCE_TIMER, WAKE_SOURCE_EXTERNAL, WAKE_SOURCE_LPUART
*/
uint8_t sleep_for_x_sec(uint16_t nb_sec)
{
static RTCWakeup wakeupspec;
static uint8_t wakeup_source;
GL_Sleep_Requested = 0; // Reset Flag Sleep_Requested
// Config CB for ext button
GL_Flag_External_WakeUp = 0; // Reset flag that will be set by the CB
palEnableLineEvent(LINE_WakeUp, PAL_EVENT_MODE_FALLING_EDGE); // Falling edge creates event
palSetLineCallback(LINE_WakeUp, cb_external_input_wake_up, NULL); // Active callback
// Config LPUART for wakeup
LPUART1->CR1 &= ~USART_CR1_UE; // Disable LPUART to allow modif
LPUART1->CR1 |= USART_CR1_UESM; // LPUART able to wakeup from Stop
LPUART1->CR3 |= USART_CR3_WUS_1; // Wakeup on Start bit detected
LPUART1->CR3 |= USART_CR3_WUFIE; // Wakeup from Stop IRQ enabled
LPUART1->CR3 |= (0x1U << 23); // LPUART clk enabled during STOP (UCESM)
LPUART1->ICR = USART_ICR_WUCF; // Clear WUF flag
LPUART1->CR1 |= USART_CR1_UE; // Enable LPUART after modif
// Config RTC for wakeup after delay
wakeupspec.wutr = ( (uint32_t)4 ) << 16; // bits 16-18 = WUCKSel : Select 1 Hz clk
wakeupspec.wutr |= nb_sec - 1; // bits 0-15 = WUT : Period = x+1 sec
rtcSTM32SetPeriodicWakeup(&RTCD1, &wakeupspec); // Set RTC wake-up config
ports_set_lowpower(); // Set ports for low power
// DBGMCU->CR = DBGMCU_CR_DBG_STOP; // Allow debug in Stop mode: +130uA !!!
// chSysLock(); // Wakeup in strange mode: 200uA, freezed
chSysDisable(); // No effect
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; // No effect // Disable TickInt Request
chSysEnable(); // No effect
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // Low power mode in deep sleep
PWR->CR1 |= PWR_CR1_LPMS_STOP2; // Deep sleep mode in Stop2
// -----------------------------------------------------
//
__WFI(); // Sleep now !!!
//
// -----------------------------------------------------
LPUART1->CR1 &= ~USART_CR1_UESM; // LPUART not able to wakeup from Stop
if (GL_Flag_External_WakeUp) // Search for the wake-up sources
{
wakeup_source = WAKE_SOURCE_EXTERNAL; // External signal indicated by callback
}
else if ( !(LPUART1->ISR & USART_ISR_IDLE) )
{
wakeup_source = WAKE_SOURCE_LPUART; // LPUART
}
else // Else
{
wakeup_source = WAKE_SOURCE_TIMER; // Its the internal timer
}
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // Clear deep sleep mask
PWR->SCR |= PWR_SCR_CSBF; // Clear standby flag
LPUART1->ICR |= USART_ICR_PECF; // Clear Parity error
// chSysUnlock();
// chSysDisable(); // No effect
ports_set_normal(); // Restore ports states
stm32_clock_init(); // Re-init RCC and power, Important
__enable_irq(); // No effect
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; // No effect // Enable TickInt Request
return wakeup_source;
}
The callback for the external button is this simple:
Code: Select all
void cb_external_input_wake_up(void *arg)
{
(void)arg;
GL_Flag_External_WakeUp = 1; // Set Flag for Wake_Up signal
}
I can post also a relatively small program to show everything. (around 300 lines without ports init/deinit)
But it is designe for my board.
If someone has some ideas, i'm happy to receive it.
Stephane