cancel
Showing results for 
Search instead for 
Did you mean: 

Help with STM32H7A3 low power timer

magene
Senior II

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

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

ARR must be greater than CMP. Looks like you have them equal. Not sure if that's the reason, but could be.

 

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

3 REPLIES 3
TDK
Guru

ARR must be greater than CMP. Looks like you have them equal. Not sure if that's the reason, but could be.

 

If you feel a post has answered your question, please click "Accept as Solution".
magene
Senior II

@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);
	}
}

 

Very surprised that was the cause. I wonder what the internal hardware does when ARR=CMP. Glad it worked, thanks for following up.

If you feel a post has answered your question, please click "Accept as Solution".