cancel
Showing results for 
Search instead for 
Did you mean: 

Nano second Precision using a hardware timer on STM32L4S5ZI

SJant.1
Associate III

Hi,

I am working with STM32L4S5ZI MCU and I have a custom board with the same.

I am evaluating the hardware timer and as part of my project I need time in nano seconds for some time constrained work. Right now I am using Timer3 and below is my sample code with which I am able to get the counter value between a start and stop of the timer.

Can I derive the time with nano second precision using these timers on the chip? And I need to do this specifically with a timer and not using any other means like a DWT.

Please let me know if there is a way to do this. Thanks a lot.

int i =1;
regValue = TIM3->CNT; 
printf("Timer value %d\n", regValue);
HAL_TIM_Base_Start(&htim3);
 
printf("Timer cycle %d\n", i);
i++; 
 
HAL_TIM_Base_Stop(&htim3);
regValue = TIM3->CNT;
printf("Timer value %d\n\n", regValue);

17 REPLIES 17
Nikita91
Lead II

You want a nanosecond precision and you use the HAL and callback?

You will get more precision using timer registers directly, and put your code for timer overflow in the interrupt handler (and not use the callback).

What is the maximum time you want to measure? If it is less than 35 sec you can use TIM2 which is 32 bits.

Don't use start/stop time base. Use a free running counter: reading the current counter value is much faster, and you only have to subtract the start value from the stop value to get the duration (only with unsigned ints).

For your callback question: what did you put in the TIM interrupt handler?

Hi Nikita,

As you can see in the code snippet attached above, I registered HAL_GetTimerOverflow_count as the callback function for period elapsed interrupt. I did not make any changes in interrupt handler function.

Regarding writing to registers, I can do that and yeah I am aware of the delay that the HAL functions can create.

Instead of callback function are you suggesting to use TIMx_IRQ​Handler() function directly?

To start and stop the timer can I set some bits in registers which should do the same thing as the HAL functions but with much less consumption of time?

Please explain how this can be done directly with writing to registers.

Thanks a lot ​

Nikita91
Lead II

Yes put your code in the TIMx_IRQ​Handler() function directly.

You can start the timer, then never stop it. use something like:

uint32_t  start, stop, delay ;
 
 
start = TIMx->CNT ;
 
...
 
stop = TIMx->CNT ;
delay = stop - start ;
// Then add the overflow counter * 65536

This is OK if the delay is less than 65536 on a 16 bit counter.

Else it's a bit more complicated: on start set CNT to 0, and reset your overflow counter, ideally this must be atomic.

Another thought : what happens if the overflow interrupt comes right after the 'stop = TIMx->CNT ;'? The value will be off by +1 overflow count.

For the stop value you must get the timer counter and the overflow counter atomically (Disabling interrupts for this very short time ?).

Uwe Bonnes
Principal III

Better use the capture unit to capture start and stop events.

Nikita91
Lead II

Start the time base and never stop it. You can use use something like:

uint32_t   start, stop, delay ;
 
start = TIMx->CNT ;
....
stop = TIMx->CNT ;
delay = stpo - cnt ; 
// Then add de overflow count * 65536

This is ok if the delay is less then 65536

Else it's a bit more complicated: On start clear the CNT and the overflow counter.

On stop read the CNT and the overflow counter

Beware: what happens if the overflow interrupt is between the CNT reading and the overflow counter reading ? The delay will be off by 1 overflow count.

So the two reads must be atomic (disable the interrupts for this very short time?)

To use a critical section on bare metal Cortex (Very rude, probably better to use BASEPRI on M3, M4, M7):

uint32_t	status ;
 
status =  __get_PRIMASK() ;
__set_PRIMASK (1) ;
__ASM volatile ("" : : : "memory") ; // Compiler barrier : avoid the compiler to move instructions across this barrier
 
... Critical section
 
__ASM volatile ("" : : : "memory") ; // Compiler barrier : avoid the compiler to move instructions across this barrier
__set_PRIMASK (status) ;

Ideally the same thing for start: You must clear the 2 counters atomically

Yes put your code directly in TIMx_IRQ​Handler() 

How to manage overflow counter?

Can this be done reliably with timer chaining?

Nikita91
Lead II

In reality a free counteris too complicated.

You were right, starting and stopping the counter is easier and more reliable.

Perhaps use only the timer CR1_CEN bit to start/stop the timer.

SJant.1
Associate III

Thank you Nikita for you detailed explanations and your time.