2024-03-22 08:37 AM
I have implemented a fully working usart keyboard with interrupts in a Nucleo L412Kb. The main code loop checks whether a pending-key flag and no-bouncing flag are set, then scans the rows in the selected keyboard matrix column, and sends the key via usart.
The ISR for the GPIOs (columns) sets the pending flag, selects the column to scan, and starts a debouncing timer TIM2. The ISR for the timer TIM2 interrup is setting the no-bouncing flag.
void TIM2_IRQHandler(void) {
if (TIM2->SR & (1<<0)) {
TIM2->SR &= ~(1<<0); // clear flag
bouncing = 0;
TIM2->CR1 &= ~(1<<0); // Disable timer
}
}
void col_IRQ(uint8_t col) {
if (pendingkey == 0) {
pendingkey = 1;
bouncing = 1;
coln = col;
set_triggers(0);
TIM2->CNT = 0;
TIM2->CR1 |= (1<<0); // Enable timer
set_all_rows(0);
}
}
void EXTI0_IRQHandler(void) {
if (EXTI->PR1 & (1 << 0)) {
EXTI->PR1 |= (1 << 0);
col_IRQ(0);
}
}
Now I want the MCU to go into STOP2 mode and wake up with the EXTI interrupts, but my main code get blocked.
Im using ony GPIOs, a timer (TIM2), the systicks, and one USART. In the stopkbd() function I disable the clocks for the peripherals, call the __WFI() function and restore the clocks. What Im missing?
Im running with the HSI16 oscillator only, and I have the STOPWUCK bit set in order to wake up with the HSI16.
Do I need to clear the SLEEPDEEP bit after? Or do I need to wait for the HSI16 or something else?
From the RM manual, I can not get to understand how the GPIOs EXTI interrupts can work if the clocks are stopped or the peripherals are disabled. Do I need to perhaps enable at least one clock in order for the interrupts to trigger? I see in the manual that the LSI can be enabled in STOP2.
2024-03-22 09:29 AM
I dont see NVIC init part code. Without this interrupts dont works.
2024-03-22 11:20 AM
Interrupts work (for the IO). NVIC init part code is called with the function col_trigger_init(). The code attached is fully working for me, except for the line stopkbd(), responsible of starting the STOP2 mode, and coming back from it. Otherwise, commenting the stopkbd() line the program is ok. The question is What I am missing/needing to come back from STOP2 mode...
2024-03-23 12:44 AM - edited 2024-03-23 12:45 AM
Is your trouble enter STOP2 or exit ? Try inspire
void HAL_PWREx_EnterSTOP2Mode(uint8_t STOPEntry)
{
/* Check the parameter */
assert_param(IS_PWR_STOP_ENTRY(STOPEntry));
/* Set Stop mode 2 */
MODIFY_REG(PWR->CR1, PWR_CR1_LPMS, PWR_CR1_LPMS_STOP2);
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Select Stop mode entry --------------------------------------------------*/
if(STOPEntry == PWR_STOPENTRY_WFI)
{
/* Request Wait For Interrupt */
__WFI();
}
else
{
/* Request Wait For Event */
__SEV();
__WFE();
__WFE();
}
/* Reset SLEEPDEEP bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}
and manage HSI or any clock before enter isnt required, is managed by design.
2024-03-25 02:06 PM
Unfortunately I haven't run any debugger or so...But the MCU stall right after executing the stokbd() function. My guess is my trouble is to come back from the STOP2 mode.
static inline void stopkbd(void) {
RCC->APB1ENR1 &= ~RCC_APB1ENR1_USART2EN; // disable USART2
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // disable SysTicks
RCC->APB1ENR1 &= ~(1UL<<0); // Disable clock for TIM2
RCC->AHB2ENR = 0; // disable all GPIO clock
RCC->CR &= ~RCC_CR_HSION;
__WFI();
clock_init();
RCC->APB1ENR1 |= (1<<0); // Enable clock for TIM2
RCC->AHB2ENR |= 3; // enable GPIO clocks for bit 0 and 1 (A and B banks)
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN; // re-enable USART2
}
static inline void stop2_init(void) {
PWR->CR1 &= ~PWR_CR1_LPMS_STOP2_Msk;
PWR->CR1 |= PWR_CR1_LPMS_STOP2;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // set Cortex SLEEPDEEP bit
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk; // disable re-entering in sleep mode after ISR
RCC->CFGR |= RCC_CFGR_STOPWUCK; // select the HSI16 clock for wakeup
}
The stop2_init() function is executed before the main loop. So far, everything looks like the same as the HAL function you propose HAL_PWREx_EnterSTOP2Mode().
I set the stop2 mode in the PWR_CR1 register, I set the SLEEPDEEP bit in the cortex SCB_SCR register, and then call __WFI.
After returning from WFI, I set back the clocks, enable GPIOs, USART, and Systicks...