Skip to main content
peterka
Associate II
August 4, 2022
Question

Count external pulses

  • August 4, 2022
  • 13 replies
  • 7361 views

I want to count external pulses for one second.

On STM32F030 / HAL-Lib I did not find

  • atomic read/reset counter
  • capture by a second timer did not work, thoug I studied well and tested a lot how to config it by STM32CubeIDE

Is there any example for a highly accurate count of external pulses by a tim (timers/capture/compare/pwm)?

Thanx, Peter

This topic has been closed for replies.

13 replies

waclawek.jan
Super User
August 4, 2022

> On STM32F030 / HAL-Lib I did not find

If you *want* to do something, then don't look at some random library, read the real manual.

> atomic read/reset counter

Are you talking about the Timers?

There is no such operation (there is something resembling that, but I don't recommend to use it). But you don't need that: simply subtract values of consecutive readout (taking into account the registers' width, a.k.a. modulo arithmetics) in software.

> Is there any example for a highly accurate count of external pulses by a tim (timers/capture/compare/pwm)?

What do you mean by "highly accurate"?

Do you want run one timer as counter of external pulses, and sample its count by an other timer serving as a regular timebase?

If yes, at this point, I assume you know how to enable clocks in RCC and how to set pins in GPIO.

You need to use TIMx_ETR pin in the first timer (only a few timers have it) and set it count from that input, i.e. External clock mode 2, by setting TIMx_SMCR.ECE and enable counting by setting TIMx_CR1.CEN (at that point, you can check if it counts appropriately, in debugger; there's no point in changing TIMx_PSC/TIMx_ARR from their defaults here). Steer the second timer's TRGO (described below) as TRGI in this timer, by selecting appropriate ITRx in TIMx_SMCR.TS. Set input capture on the trigger, for example on CH1, by setting TIMx_CCMR1.CC1S to 0b11. Enable capture by setting TIMx_CCER.CC1E. Optionally, set interrupt on capture by setting TIMx_DIER.CC1IE and enable the given interrupt in NVIC, writing an ISR with appropriate name. (As a "higher level", you can use DMA to pull captured values).

Set TIMy_ARR/TIMy_PSC of second timer to provide the required timebase and set it to generate TRGO from Update by setting TIMy_CR2.MMS=0b010. Enable it by setting TIMy_CR1.CEN.

Then, in runtime, for polled operation, poll the first timer's TIMx_SR.CC1IF, and if set, read out TIMx_CCR1 and store. You don't need to clear TIMx_SR.CC1IF, it's cleared automatically by reading out TIMx_CCR1 (although you can if you know how to). Subtract two consecutive readouts for the difference.

When using interrupts, the procedure is the same, but I recommend to start with polling.

JW

S.Ma
Principal
August 4, 2022

As JW wrote, there are different hw methods that can be used around timers. Are you going next measure duty cycle? What frequency range? Are there time periods without pulses? What precision? Should it work in any low pwer modes?

Slh
Senior
August 4, 2022

I think using PA12 in TIM1 with ETR2 mode as External Timer Clock Input could be suitable for your work.

peterka
peterkaAuthor
Associate II
August 4, 2022

Thank You. This is what I did / tried and I did read the original manuals.

I thought that these tims are so advanced, that they support counting in a very flexible way, saving CPU performance a lot ... and found out that they can do very well advanced ways of capture / compare / pwm ... but counting does not seem to be their favorite.

I want to do simple counting pulses during a periode of 60 seconds, with a resolution from 0.1 Hz to 100kHz.

Accurate in meaning of not loosing any pulse while counting.

It would be nice to use one timer to control a second counter (timer) to read the counted external pulses into the capture-register, reset the counter (timer), send an interrupt for the reading of the counts. But this was not possible.

Thank for Your hint. I will implement a read of the counter (timer) every second and calculate the difference regarding the wrap-around. That is a good solution as well, costing a bit more CPU-cycles.

Thanx, Peter

waclawek.jan
Super User
August 4, 2022

> It would be nice to use one timer to control a second counter (timer) to read the counted external

> pulses into the capture-register, reset the counter (timer), send an interrupt for the reading of the counts. But this was not possible.

This is exactly what I described above, except the "reset the counter (timer)".

Even that is possible, but I don't recommend it, as there's an inevitable and undocumented lag between the capture and reset. Most users ignore that lag and its consequences, and for most applications it's OK indeed, but my personal notion of "precise" is different than that. And subtracting two values is not that expensive in a 32-bit multimegahertz processor.

Here's how: set TIMx_SMCR.SMS to 0b100 for Reset mode. Done.

Do things one at a time. Learn to walk, before trying to run.

Read the TIM chapter in RM. Read it again and again. And ditch Cube, now.

JW

peterka
peterkaAuthor
Associate II
August 4, 2022

I have been trying and reading for two entire days, tried the reset-mode as well ... and gave up. I never was able to generate a capture-interrupt.

But when there is a glitch, then anyway I`ll implement it with a bit more software.

waclawek.jan
Super User
August 4, 2022

> I have been trying and reading for two entire days,

I have been trying and reading for 25 entire years. Keep trying and reading. Do one thing at a time. Do you have a timer which counts the external pulses, yet? That's the first step.

JW

peterka
peterkaAuthor
Associate II
August 4, 2022

Yes shure.

Counting on external pulses by a timer/counter and generating interrupts by a second timer did work quickly. I successfully tested a lot of other stuff as well , just by curiosity. But triggering capture by a second timer and generating interrupt on capture did not work in my test-projects.

peterka
peterkaAuthor
Associate II
August 4, 2022

For the timers on stm32I412kb I did not find any overrun- and/or underrun-flags, nor interrupt-flags for this purpose.

waclawek.jan
Super User
August 4, 2022

In STM32 timers, what you'd refer to as under/overrun, is called Update.

0693W00000QMxwWQAT.png 

Didn't you say that you are using 'F030?

JW

peterka
peterkaAuthor
Associate II
August 4, 2022

I use stm32l412kb because I have an eval board with it, but I want to unse stm32f030 in my final design.

Quote from page 780 of RM0394:

" Bit1 UDIS: Update disable

This bit is set and cleared by software to enable/disable UEV event generation.

0: UEV enabled. The Update (UEV) event is generated by one of the following events:

  • – Counter overflow/underflow
  • – Setting the UG bit
  • – Update generation through the slave mode controller

Buffered registers are then loaded with their preload values.

1: UEV disabled. The Update event is not generated, shadow registers keep their value

(ARR, PSC, CCRx). However the counter and the prescaler are reinitialized if the UG bit is set or if a hardware reset is received from the slave mode controller.

"