2024-01-10 07:45 PM
I have the low power timer LPTIM1 working on a STM32H7A3 but the way I have to clear the IRQs is a little confusing. Here's my IRQHandler:
void LPTIM1_IRQHandler(void)
{
//Disable LPTIM1
CLEAR_BIT(LPTIM1->CR, 0x01);
//Clear IRQs
LL_LPTIM_ClearFlag_ARRM(LPTIM1);
LL_LPTIM_ClearFlag_CMPM(LPTIM1);
//Enable LPTIM1
SET_BIT(LPTIM1->CR, 0x01);
LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
lptim1TestTimerCallBack();
}
I don't understand why I have to disable LPTIM1 before clearing the ARRM and CMPM IRQ flags. Nothing I've found in the reference manual says I need to do this. But if I don't, LPTIM1_IRQHandler keeps getting called with no delay. If I do the enable/disable dance, LPTIM1 function as I expect. If I understand correctly, disabling LPTIM1 stops the counter while I clear the IRQs. In this case, that little bit of added delay isn't a big issue but it doesn't seem right and I'd like to understand what I'm doing wrong.
Right now my lptim1TestTimerCallBack() doesn't do anything significant but it will in the future. Here it is anyway.
void lptim1TestTimerCallBack()
{
std::cout << "Hit LPTIM1Test lptim1TestTimerCallBack at systick: " << std::to_string(systickCtr) << std::endl;
timerCallBackCounter++;
hitTimerCallback = true;
};
Here's my test program where I initialize the timer and start it up.
TEST(CPFTestGroup, LPTIM1Test)
{
SystemClock::configSystemClock();
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE);
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
/* LPTIM1 interrupt Init */
NVIC_SetPriority(LPTIM1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(LPTIM1_IRQn);
LL_LPTIM_Disable(LPTIM1);
LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL);
LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV128);
LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_INTERNAL);
LL_LPTIM_TrigSw(LPTIM1);
LL_LPTIM_SetInput1Src(LPTIM1, LL_LPTIM_INPUT1_SRC_GPIO);
LL_LPTIM_SetInput2Src(LPTIM1, LL_LPTIM_INPUT2_SRC_GPIO);
LL_LPTIM_ClearFlag_ARRM(LPTIM1);
LL_LPTIM_EnableIT_ARRM(LPTIM1);
LL_LPTIM_ClearFlag_CMPM(LPTIM1);
LL_LPTIM_EnableIT_CMPM(LPTIM1);
LL_LPTIM_Enable(LPTIM1);
LL_LPTIM_SetAutoReload(LPTIM1, 1024);
LL_LPTIM_SetCompare(LPTIM1, 1024);
LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
std::cout << "LPTIM1Test started at systick: " << std::to_string(systickCtr) << std::endl;
for (int i = 0; i < 1000000; i++)
{
LL_mDelay(1);
}
}
For completeness, here's my configSystemClock function
void SystemClock::configSystemClock()
{
SystemClock_Config();
}
void SystemClock_Config(void)
{
/*AXI clock gating */
RCC->CKGAENR = 0xFFFFFFFF;
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
{
}
LL_PWR_ConfigSupply(LL_PWR_DIRECT_SMPS_SUPPLY);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0);
while (LL_PWR_IsActiveFlag_VOS() == 0)
{
}
LL_RCC_HSE_Enable();
/* Wait till HSE is ready */
while (LL_RCC_HSE_IsReady() != 1)
{
}
LL_PWR_EnableBkUpAccess();
LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_LOW);
LL_RCC_LSE_Enable();
/* Wait till LSE is ready */
while (LL_RCC_LSE_IsReady() != 1)
{
}
LL_RCC_HSE_EnableCSS();
LL_RCC_LSE_EnableCSS();
LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE);
LL_RCC_PLL1P_Enable();
LL_RCC_PLL1Q_Enable();
LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_8_16);
LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL1_SetM(3);
LL_RCC_PLL1_SetN(70);
LL_RCC_PLL1_SetP(2);
LL_RCC_PLL1_SetQ(35);
LL_RCC_PLL1_SetR(2);
LL_RCC_PLL1_Enable();
/* Wait till PLL is ready */
while (LL_RCC_PLL1_IsReady() != 1)
{
}
/* Intermediate AHB prescaler 2 when target frequency clock is higher than 80 MHz */
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1);
/* Wait till System clock is ready */
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_16);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16);
LL_RCC_SetAPB3Prescaler(LL_RCC_APB3_DIV_1);
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_1);
LL_SetSystemCoreClock(280000000);
/* Update the time base */
if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
{
SystemClock_Error_Handler();
}
LL_RCC_HSE_EnableCSS();
LL_RCC_LSE_EnableCSS();
}
Thanks
Solved! Go to Solution.
2024-01-10 08:09 PM
ARR must be greater than CMP. Looks like you have them equal. Not sure if that's the reason, but could be.
2024-01-10 08:09 PM
ARR must be greater than CMP. Looks like you have them equal. Not sure if that's the reason, but could be.
2024-01-10 11:05 PM
@TDK thanks a tonne, that was most of my problem. I just need a really simple timer that calls the LPTIM1_IRQHandler and my specific call back once every 4 seconds (in this case). Somewhere along the way I thought I had to load the CMP and the ARR register and enable the CMPM and ARRM IRQs. Based on your input, i load the CMP register with 0 and don't enable the CMPM IQR at all and it seems to be working the way I expect.
I'm always amazed and grateful at how often I get the right answer really quickly on this forum. Thanks again.
Here's the new, working code if anyone in the future is interested.
void LPTIM1_IRQHandler(void)
{
//Clear IRQs
LL_LPTIM_ClearFlag_ARRM(LPTIM1);
lptim1TestTimerCallBack();
}
TEST(CPFTestGroup, LPTIM1Test)
{
SystemClock::configSystemClock();
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE);
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
/* LPTIM1 interrupt Init */
NVIC_SetPriority(LPTIM1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(LPTIM1_IRQn);
//Actual call back frequency seems to be (LPTIM1 freq) / (prescaler * (ARR + 1))
// 32767 / (128 * (1023+1)) = .2502367 Hz = 3.9962157 sec
LL_LPTIM_Disable(LPTIM1);
LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL);
LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV128);
LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_INTERNAL);
LL_LPTIM_TrigSw(LPTIM1);
LL_LPTIM_SetInput1Src(LPTIM1, LL_LPTIM_INPUT1_SRC_GPIO);
LL_LPTIM_SetInput2Src(LPTIM1, LL_LPTIM_INPUT2_SRC_GPIO);
LL_LPTIM_ClearFlag_ARRM(LPTIM1);
LL_LPTIM_ClearFlag_CMPM(LPTIM1);
LL_LPTIM_EnableIT_ARRM(LPTIM1);
LL_LPTIM_Enable(LPTIM1);
LL_LPTIM_SetAutoReload(LPTIM1, 1023);
LL_LPTIM_SetCompare(LPTIM1, 0);
LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
std::cout << "LPTIM1Test started at systick: " << std::to_string(systickCtr) << std::endl;
for (int i = 0; i < 1000000; i++)
{
LL_mDelay(1);
}
}
2024-01-11 06:21 AM
Very surprised that was the cause. I wonder what the internal hardware does when ARR=CMP. Glad it worked, thanks for following up.