cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L432 LPTIM prescaler behaviour

JordanY
Associate

I have a NUCLEO-L432KC that I am trying to configure such that a LPTIM interrupt fires at a set time period in the future. To simplify calculations, the future time is 2048 low frequency clock ticks away (62.5 ms).

I can achieve this with relative simplicity, using the single shot mode of LPTIM1 and a CMP register value of 2048.
I am measuring the timer period by pulsing a GPIO after the timer is enabled, and inside the the Compare Match interrupt. For a prescaler value of 1x, this works as I expect (I am assuming the slight difference from 62.5 ms is due to the execution overhead of the interrupt)

JordanY_1-1738124750443.png

My problem is that when enabling the prescaler, simply dividing the CMP register by the prescaler ratio does not result in the interrupt occurring with the same period. For example, setting the prescaler ratio to 16x and CMP to 128.

JordanY_2-1738124998826.png

The interrupt period has increase from 62.6 ms up to 64.3 ms. The timer resolution decreases by enabling the prescaler, but that should only account for a change of 480 uS (16 * 30.05 uS). Both tests were run on the same hardware 30 seconds apart, and the trend has been reproduced on several pieces of hardware.

I have attached the `.ioc` file and the minimal reproduction `main.c`, which simply triggers the timer once a second.
Unfortunately my real application needs the prescaler to support longer timeout delays.
I am sure I am missing something to explain the behavior I am seeing, I would appreciate any information on how I can accurately predict the interrupt period given the CMP and prescaler values.

 

 

8 REPLIES 8
JordanY
Associate

I have updated the sample to be a bit more sophisticated (attached), it now rotates through the various prescalers every 500 ms and does the best linear fit I can find (CMP - 5) to get the expected interrupt period. The 1x prescaler is now almost spot on at 62.53 ms, but the 128x prescaler is still significantly off at 63.53 ms.

The time is given by CNT+1, as the match occurs when the counter counts away from CNT. This, for CNT use value one less.

JW

 

Thanks JW, that accounts for one part of the puzzle.
To get a period of approximately 62.5 ms for all prescalers, I needed an offset of -5 (in the second sample).
1 unit is from your suggestion.
2 units are from the timer enable delay (It seems this is 2 prescaled clock cycles, not the raw 32khz input)

JordanY_0-1738134487056.png

2 units are still unknown. Does SNGSTRT perhaps have the same 2 cycle delay?

Once all 5 units are accounted for (which would be nice but not strictly necessary), there is still the question of why the period increases slightly as the prescaler increases. The extra 1ms at 128x prescaling is 32 raw clock ticks, which is a relatively long time.

There may be all sorts of resynchronizations in the way, both from APB interface to LPTIM kernel and vice versa. And although it sounds to me to be a design bug, this synchronization may be dependent on the prescaler. It's not clear how the prescaler is exactly applied; it may be, that it simply divides the kernel clock from RCC, before being input to the LPTIM kernel as a whole (instead of being applied only to the counter itself, which would be the sane thing to do). Btw. remarks in RM requiring the prescaler to be off for sampled clock hints, that the prescaler is applied only to the internal clock.

I have little practical experience with the LPTIM except from a couple of rather frustrating experiments (frustrating in that they quite invariably reveal more and more undocumented properties of that module), and I've never tried to use the prescaler.

Try to post a reproducible example exhibiting the problem. Try to avoid Cube/HAL altogether, as that increases the chance for others to exactly reproduce the issue (I for one don't use Cube/HAL at all) and to have direct 1:1 relationship to the few things which actually are documented in RM.

Btw. what's LPTIM kernel clock source (as set up in RCC_CCIPR.LPTIMxSEL) and what is the system clock/APB clock?

JW

Hi JW, the `main.c` as attached to my first comment after the original post is the reproducible example, the code I added is all direct register access, although the setup is the autogenerated Cube logic.

LPTIM1SEL is 0x3 (LSE clock).
The system clock is the MSI running at 24 MHz with the LFXTAL auto calibration enabled.

From that code, it's not clear to me how exactly do you measure the time you are talking about. You appear to toggle a pin, but not according to LPTIM flags, and you don't appear to be using interrupts.

You can post code directly inline in posts, using the </> icon at top of the editor.

JW

Why do you think interrupts aren't being used?

void LPTIM_Setup(LPTIM_HandleTypeDef *hlptim)
{
	int div = 0;

	/* Clear the current prescaler value */
	hlptim->Instance->CFGR &= ~LPTIM_CFGR_PRESC_Msk;

	/* Set the new prescaler and get the divisor ratio */
	switch(iter) {
	case 0:
		hlptim->Instance->CFGR |= LPTIM_PRESCALER_DIV1;
		div = 1;
		break;
        ....
       }
	hlptim->Instance->ICR |= LPTIM_FLAG_CMPOK;
	/* Enable compare match interrupt */
	hlptim->Instance->IER = LPTIM_IT_CMPM;
	/* Enable LPTIM instance to set CMP */
	hlptim->Instance->CR |= LPTIM_CR_ENABLE;
	/* 2 from the ENABLE delay, 1 due to CMP behaviour, 2 from SNGSTRT? */
	hlptim->Instance->CMP = (2048 / div) - 5;
        /* Wait for CMP to be updated */
        while (!(hlptim->Instance->ISR & LPTIM_FLAG_CMPOK));
        hlptim->Instance->CR &= ~LPTIM_CR_ENABLE;
}

The compare interrupt is being enabled, and the callback below is run by the interrupt handler when it fires.

void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
    GPIOB->BSRR = LD3_Pin;
    GPIOB->BRR = LD3_Pin;
    /* Disable the timer instance */
    hlptim1.Instance->CR &= ~LPTIM_CR_ENABLE;
}

I know that driving the output from software rather than hardware is not going to give HSE cycle accurate results, but the delays due to the software should be consistent (since the MSI frequency isn't changing), and they are consistent for a given prescaler (i.e. a prescaler of 128x is always 63.5 ms, and a prescaler of 1x is always 62.5 ms).

> Why do you think interrupts aren't being used?

Don't see them being enabled in NVIC.

JW