Loading...
 

Zephyr project on STM32

   Zephyr Workbench, a VSCode extension to manage Zephyr on STM32.
It enables users to easily create, develop, and debug Zephyr applications.
Main features:
  • Install host dependencies.
  • Import toolchain and SDK.
  • Create, configure, build and manage apps.
  • Debug STM32.
You can directly download it from the VSCode marketplace
For more details, visit the Zephyr Workbench

System Workbench for STM32


How to calculate the period and prescaler values when using input capture

Hi

I want to be able to capture a 50Hz signal attached to timer 3 of a STM32072 discovery board. However I dont understand how the PERIOD and PRECALER values are calculated. I have looked at the example design in the CUBEMX and they have set the period as 0xFFFF and the prescaler to 0. As I see it the prescaler will just adjust the granularity of the clock which would allow slower input frequencies to be captured. But I dont really see what the period is doing. Can someone explain how these parameters are used for input capture?

Thanks

Jon

I have not used the CubeMX HAL very much but I did recently work on a project that made use of the timer input capture function. Based on this experience, I think I can make a good guess as to what the “PERIOD” and “PRESCALER” values do.

Generally speaking, the STM32 timers are fed by the system core clock (sometimes, depending on the timer, it can be core clock *2 or /2). For sake of this discussion, I’ll assume it’s the SystemCoreClock.

If you want to do an input capture on a signal with a nominal 50 Hz period (sounds like a AC line frequency application, something I’ve had some past experience with :-) ) then you’ll want to set PRESCALER to a value 1 larger than the integer result of:

SystemCoreClock / (Input capture signal nominal frequency) / (PERIOD + 1)

It is important that you set PRESCALER to a value that will divide the timer’s base clock by enough so the timer’s counter is not clocked at a rate less than 0x10000 times (assuming it’s a 16-bit timer) over the worst-case (longest) period of the signal you want to measure the frequency/period of. So, assuming you’re dealing with a AC line frequency application with a nominal line frequency of 50 Hz, you should probably plan on a worst-case line frequency of 47 Hz. I’ll assume this application is running on a F0 series device with a 48 MHz SystemCoreClock:

PRESCALER = 48000000U / 47 / 0x10000 = 15.58 = (round to lowest integer) 15

Note that the PRESCALER value (or, at least, the value that gets loaded into TIMx->PSC) is actually 1 less than the actual
division factor. If TIMx->PSC is set to 15, the clock will be divided by 16 (15 + 1).

I’m assuming that PERIOD is the value that is programmed into the timer’s ARR (Auto Reload Register). This represents the terminal value of the timer’s CNT register if counting up - that is, the CNT register is reset to 0 when reaching this value - or the value that CNT is reset to when it underflows if counting down. I’d recommend leaving this at 0xFFFF.

To measure period, configure the timer channel(s) that you’re feeding your input signal to for input capture mode, set their edge sensitivity as needed/desired, and set up a timer interrupt to be generated on an input capture event.

Inside the timer ISR, you’ll need to allocate a static variable to hold the ‘previous capture’ value. Then, to get the period of your signal, do the following:

static uint16_t previous;
capture = TIMx->CCRx;
period = capture - previous;
previous = capture;

If the timer you’re working with is 32 bits wide (e.g. TIM2), make all varaibles uint32_t instead of uint16_t

To convert the (period) value to frequency, do this:

extern uint32_t SystemCoreClock; // defined in system_stm32xxxx.c
frequency = SystemCoreClock / (TIMx->PSC + 1) / period

If you want more resolution; i.e. if you’d like the measurement in 1/100 Hz units, you could do this:

frequency = SystemCoreClock * 10U / ((uint32_t) period * 10U) / (TIMx->PSC + 1)

The order of operations and reason for doing two *10’s instead of one *100 is to get the best possible resolution and minimum rounding loss while avoiding 32-bit unsigned integer overflow in intermediate results.


 

Newest Forum Posts

  1. SPI on Nucleo_STMH533RE by royjamil, 2025-05-04 20:13
  2. SPI on Nucleo_STMH533RE by higginsa1, 2025-03-25 07:37
  3. SPI on Nucleo_STMH533RE by royjamil, 2025-03-23 11:31
  4. SPI on Nucleo_STMH533RE by higginsa1, 2025-03-23 09:33
  5. Configuring DMA for ADC in SW? by sam.hodgson, 2025-03-04 12:58
  6. Build a project in "release" mode by info@creosrl.it, 2025-02-20 18:12
  7. Build a project in "release" mode by info@creosrl.it, 2025-02-20 17:05
  8. Build a project in "release" mode by tang, 2025-02-20 10:36
  9. Build a project in "release" mode by info@creosrl.it, 2025-02-19 17:35
  10. Fail to debug in Win 11 C/C++ by mortenlund, 2024-12-26 20:27

Last-Modified Blogs