2025-08-01 3:51 PM
Hello there!
I am on my first foray away from HAL and into bare-metal programming, and am trying to configure LPTIM1 and LPTIM2 on my stm32u031 to periodically trigger interrupts. I am experiencing bizarre behavior that I'm struggling to understand how to troubleshoot.
I have two config functions for these timers, one of them looks like:
static void configure_lptimer2() {
RCC->APBENR1 |= RCC_APBENR1_LPTIM2EN;
if ((RCC->CSR & RCC_CSR_LSION) == 0) {
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
}
RCC->CCIPR &= ~(RCC_CCIPR_LPTIM2SEL);
RCC->CCIPR |= RCC_CCIPR_LPTIM2SEL_0;
LPTIM2->CR &= ~LPTIM_CR_ENABLE;
LPTIM2->CFGR &= ~LPTIM_CFGR_PRESC_Msk;
LPTIM2->CFGR |= (0x0 << LPTIM_CFGR_PRESC_Pos);
LPTIM2->ICR = 0xFFFFFFFF;
LPTIM2->DIER |= LPTIM_DIER_ARRMIE;
NVIC_EnableIRQ(TIM7_LPTIM2_IRQn);
NVIC_SetPriority(TIM7_LPTIM2_IRQn, 0);
LPTIM2->CR |= LPTIM_CR_ENABLE;
LPTIM2->ARR = 1333;
LPTIM2->CR |= LPTIM_CR_CNTSTRT;
}
The other is identical, for LPTIM1.
I notice that when both functions run, I get interrupts on both timers. And, if I run this code to config LPTIM1, it behaves as expected. However, when I run the code only for LPTIM2, my interrupt handler fails to get called.
Further, I notice that when I set my prescalar value to >0, I do see the interrupt handler called, but for a prescalar of 0, no interrupt handler is called.
// Works
LPTIM1->CFGR &= ~LPTIM_CFGR_PRESC_Msk;
LPTIM1->CFGR |= (0x5 << LPTIM_CFGR_PRESC_Pos);
// Doesn't work
LPTIM1->CFGR &= ~LPTIM_CFGR_PRESC_Msk;
LPTIM1->CFGR |= (0x0 << LPTIM_CFGR_PRESC_Pos);
I'm a little lost as to what I might be doing wrong here. Can anyone offer some advice?
Thank you!
2025-08-01 4:14 PM
How are you detecting that the interrupt handler is called?
Is LPTIM2->CNT changing values? CPU isn't being swamped with interrupts? Increasing prescaler causing it to "work" suggests this might be the case.
2025-08-01 7:19 PM
Hi! Thanks for responding!
For interrupt handlers, I have these:
void TIM6_DAC_LPTIM1_IRQHandler(void)
{
if (LPTIM1->ISR & LPTIM_ISR_ARRM) {
LPTIM1->ICR |= LPTIM_ICR_ARRMCF;
}
}
void TIM7_LPTIM2_IRQHandler(void)
{
if (LPTIM2->ISR & LPTIM_ISR_ARRM) {
LPTIM2->ICR |= LPTIM_ICR_ARRMCF;
}
}
I have breakpoints inside the if() statements. Here's the entirety of my own code within a cube-mx-generated project:
/* USER CODE BEGIN 2 */
// --- LPTIMER 2
RCC->APBENR1 |= RCC_APBENR1_LPTIM2EN;
if ((RCC->CSR & RCC_CSR_LSION) == 0) {
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
}
RCC->CCIPR &= ~(RCC_CCIPR_LPTIM2SEL);
RCC->CCIPR |= RCC_CCIPR_LPTIM2SEL_0;
LPTIM2->CR &= ~LPTIM_CR_ENABLE;
LPTIM2->CFGR &= ~LPTIM_CFGR_PRESC_Msk;
LPTIM2->CFGR |= (0x0 << LPTIM_CFGR_PRESC_Pos);
LPTIM2->ICR = 0xFFFFFFFF;
LPTIM2->DIER |= LPTIM_DIER_ARRMIE;
NVIC_EnableIRQ(TIM7_LPTIM2_IRQn);
NVIC_SetPriority(TIM7_LPTIM2_IRQn, 0);
LPTIM2->CR |= LPTIM_CR_ENABLE;
LPTIM2->ARR = 1333;
LPTIM2->CR |= LPTIM_CR_CNTSTRT;
// --- LPTIMER 1
RCC->APBENR1 |= RCC_APBENR1_LPTIM1EN;
if ((RCC->CSR & RCC_CSR_LSION) == 0) {
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
}
RCC->CCIPR &= ~(RCC_CCIPR_LPTIM1SEL);
RCC->CCIPR |= RCC_CCIPR_LPTIM1SEL_0;
LPTIM1->CR &= ~LPTIM_CR_ENABLE;
LPTIM1->CFGR &= ~LPTIM_CFGR_PRESC_Msk;
LPTIM1->CFGR |= (0x5 << LPTIM_CFGR_PRESC_Pos);
LPTIM1->ICR = 0xFFFFFFFF;
LPTIM1->DIER |= LPTIM_DIER_ARRMIE;
NVIC_EnableIRQ(TIM6_DAC_LPTIM1_IRQn);
NVIC_SetPriority(TIM6_DAC_LPTIM1_IRQn, 0);
LPTIM1->CR |= LPTIM_CR_ENABLE;
LPTIM1->ARR = 999;
LPTIM1->CR |= LPTIM_CR_CNTSTRT;
/* USER CODE END 2 */
I can confirm that both counters are running. I can also confirm that if I do this for EITHER timer:
LPTIMx->CFGR |= (0x0 << LPTIM_CFGR_PRESC_Pos);
then that timer's interrupt handler no longer is called.
As I understand it, these timers are configured to use LSI, which is running at 32KHz.
My MCU is configured to run at 1MHz. I'm unsure how to calculate whether this is 'too slow' (such that it's being flooded with interrupts? I don't fully understand this). But, I do find that if I increase the main clock speed to 4MHz, the interrupts DO begin catching with lptimer prescalars of 0.
I suppose this is a silly question, but would you be able to help me understand why this might be the case? I'm hoping to keep the MCU speed as low as possible to be able to run it in lower power modes (which, as I understand it, means keeping it at 2MHz or lower).
2025-08-01 8:17 PM - edited 2025-08-01 8:18 PM
So you only use breakpoints in the ISR to determine if they're getting hit? Timers run while the chip is stopped for debugging unless you freeze them in DBGMCU_APB1FZR. With frequent stops, these interrupts will always fire, and the highest priority one will always hit.
Toggle an LED or pin, set the timers to 1 Hz, or something slow, so you can verify they are in fact functioning as intended.
End of the day, these ISRs "not running" is just an artifact of how you're monitoring them, and there's no useful functionality within them.