Bluepill: 2 different timers to read 2 different FREQS

Post here first, or if you can't find a relevant section!
julian_lp
Posts: 8
Joined: Sun Jul 09, 2023 10:23 pm

Bluepill: 2 different timers to read 2 different FREQS

Post by julian_lp »

Hello,
I need to be able to read 2 different frequencies (digital pulses) that comes through 2 different pins
(note that the capture registers must be independent, I mean, if one signal makes the proccessor saves "n" value, the other signal should not count FROM "n", it should count independently)

I'm a little confused about what a "Channel" means, dunno if different channels in the same timer object counts in the same register or not...

I just found an example of hardware timer, in which I see:

Code: Select all

  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM);
  channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM));
  // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.
  MyTim = new HardwareTimer(Instance);
As I understand from the code comments, the Instance object just retrieves automatically the timer object related to the pin,
now, how do I know available timers and pins related to them?
Im using the bluepill board, and again, I need to get 2 different frequencies,
Hope I explained clear enough the problem,

regards
julian
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by dannyf »

What is the best approach to a particular application depends on that application.

Many ways to measure a pulse trains frequency. For example, you can count pulses in a given period of time, or to read a known tick generator during rising edges of a pulse train...

A channel in an input capture is nothing but a mechanism to look in the timer value on a timer input pin. Often edge triggered.
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by Bakisha »

julian_lp wrote: Mon Jul 10, 2023 12:40 am now, how do I know available timers and pins related to them?
One way of figuring out which pin is related to which timer/channel is from Arduino core:

https://github.com/stm32duino/Arduino_C ... c#L86-L132


julian_lp wrote: Mon Jul 10, 2023 12:40 am I'm a little confused about what a "Channel" means, dunno if different channels in the same timer object counts in the same register or not...
Channel is bound to a timer. One timer have common prescaler and overflow, but can have more channels. Some of them are advanced with tons of futures, some of them are basic, with minimum set of futures. Each channel can be routed to a one pin (but some of them have a multiple choices).

For bluepill, search reference manual named RM0008.
julian_lp
Posts: 8
Joined: Sun Jul 09, 2023 10:23 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by julian_lp »

I'm still confused about the whole channel topic....
Let me put it in an example,
I've 2 digital signals to read/measure:
A: car tachometer data (typically 2pulses/Revolution in 4 cylinder engines)
B: car speedometer data (lets say 1000pulses/KM)
Both of them are not strictly releated each other...
I want the average cpu cycles lenght of each pulses, to calculate its freqs, and update the dashboard ...... now, should I use the same timer with 2 channels, or different timers ?
regards
julian
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by dannyf »

Fairly simple. A capture pin is a channel. If you code one pin to capture one pulse train, it is easy to expand it to two, or upto 4 channels on most timers .

You just need to get it started.
julian_lp
Posts: 8
Joined: Sun Jul 09, 2023 10:23 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by julian_lp »

dannyf wrote: Fri Jul 21, 2023 4:34 pm You just need to get it started.
I'm having hard time to get started :lol: :lol: :lol:

Well, I found this code to implement a frequency meter, but I made a modification to being able to measure lower freqs, what do you think?

Original (just a piece of it to get the idea):

Code: Select all


volatile uint32_t FrequencyMeasured, LastCapture = 0, CurrentCapture;
uint32_t input_freq = 0;
volatile uint32_t rolloverCompareCount = 0;

 input_freq = MyTim->getTimerClkFreq() / MyTim->getPrescaleFactor();


void InputCapture_IT_callback(void){
    CurrentCapture = MyTim->getCaptureCompare(channel);
    /* frequency computation */
   
    if (CurrentCapture > LastCapture) {
        FrequencyMeasured = input_freq / (CurrentCapture - LastCapture);
    }else if (CurrentCapture <= LastCapture) {
        // 0x1000 is max overflow value 
        FrequencyMeasured = input_freq / ((0x10000 + CurrentCapture - LastCapture);
    }
    */
    LastCapture = CurrentCapture;
    rolloverCompareCount = 0;
}


/* In case of timer rollover, frequency is to low to be measured set value to 0
   To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. */
void Rollover_IT_callback(void){
    rolloverCompareCount++;

    if (rolloverCompareCount > 1){
        FrequencyMeasured = 0; ///
    }
}
But I just cant understand why the above code didnt take into account when the rolloverCompareCount var is greater than 1,... cant the timer overflows multiple times when there is not a Rising Edge interrupt?

So I modified this way:

Code: Select all


void InputCapture_IT_callback(void){
    CurrentCapture = MyTim->getCaptureCompare(channel);
    /* frequency computation */
    
    if (rolloverCompareCount){
    //>0
        FrequencyMeasured = input_freq / ( (rolloverCompareCount * 0x10000) + CurrentCapture - LastCapture);
    }else{    
     ///if rolloverCompareCount == 0 then CurrentCapture > LastCapture ...
        FrequencyMeasured = input_freq / (CurrentCapture - LastCapture);
    }

    LastCapture = CurrentCapture;
    rolloverCompareCount = 0;
}

/* In case of timer rollover, frequency is to low to be measured set value to 0
   To reduce minimum frequency, it is possible to increase prescaler. But this is at a cost of precision. */
void Rollover_IT_callback(void){
    rolloverCompareCount++;

    ///esto no sè por què se hace, se podrìan tener en cuenta mas rollovers, paara calcular frecuencias mas bajas....
    if (rolloverCompareCount > 1){
        ///FrequencyMeasured = 0; ///@@@esto lo comenté del codigo original...
    }
}

will it work? What do you think ? I guess there could be a problem when the "(rolloverCompareCount * 0x10000)" value is too big that doesnt fit in an unsigned int probably....
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by ozcar »

julian_lp wrote: Fri Jul 21, 2023 4:07 am I've 2 digital signals to read/measure:
A: car tachometer data (typically 2pulses/Revolution in 4 cylinder engines)
B: car speedometer data (lets say 1000pulses/KM)
Both of them are not strictly releated each other...
I want the average cpu cycles lenght of each pulses, to calculate its freqs, and update the dashboard ...... now, should I use the same timer with 2 channels, or different timers ?
So what is the minimum time between pulses then? Not knowing much about cars, I guess say 10,000RPM *2 and come up with 3ms for the tachometer, and say 200km/h * 1000 and come up with 18ms for the odometer. Those are not vastly different, so maybe you could use 2 channels on one timer, but it would depend on what resolution you hope to achieve. Otherwise if the two channels you used are on two different timers, you could set the pre-scalers different to get best use of the 16-bit counters.

Extending a timer by counting the overflows may be possible, provided you are careful about how you join (concatenate) the overflow count and the count from the timer register. There is some discussion of doing that here: https://www.eevblog.com/forum/microcont ... ure-timer/. That is specifically for AVR processors, but you may be able to do the same.

Section 2 of ST application note AN2592, talks about doing 32-bit input capture by effectively concatenating two 16-bit timers, but that is an advanced topic. BTW, some other STM32 processors have 32-bit timers.

Given the relatively low frequencies, maybe it would be good enough to use attachInterrupt() for rising or falling edge, and then just use micros() to get the time in the interrupt routine.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by dannyf »

You will need to figure out if you want to runs one code or you want to learn to code.

1. Set up the timer to run freely. Whether you should have overflow free determines how low of a frequency you want to measure.
2. Configure a capture channel.
3.in the IC ISR, calculate the ticks elapsed and set a flag.
4. In the user code, perform the calculation.
julian_lp
Posts: 8
Joined: Sun Jul 09, 2023 10:23 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by julian_lp »

dannyf wrote: Fri Jul 28, 2023 4:49 pm You will need to figure out if you want to runs one code or you want to learn to code.
Definately I want to do my own code. In fact I've my own speedometer and tachometer doing quite a decent job (atmel328=>vid6606=>x27 stepper ), the problem is that both of them are based on the atmel 328 that has only one Capture capable timer, and I need to simplify the hardware, integrating more gauges in one chip...
Sadly all the isr /timer stuff is done manipulating avr registers and that's when things got complicated to migrate to stm. (I guess I'll take te approach of using HardwareTimer class even thoug I did use direct register manipulation in the atmel version)

julian_lp wrote: Wed Jul 26, 2023 5:09 am will it work? What do you think ? I guess there could be a problem when the "(rolloverCompareCount * 0x10000)" value is too big that doesnt fit in an unsigned int probably....
That question wasnt well expressed (im not native speaker), It was not strictly related to the project itself, but was intended as a general question:
"can I keep the overflow count increasing indefinately to read low frequencies"? (note that the original code only let the overflow = 1)

And as soon as I post my previous message, I realized that I didnt include this line which can be important for your answers:

MyTim->setOverflow(0x10000);

Now, what does it mean if the timer suposedly can only count up to (0xFFFF) ?


Finally, I really appreciate you both taking the time to help and guide stm newbees like me :D
dannyf wrote: Fri Jul 28, 2023 4:49 pm 1. Set up the timer to run freely. Whether you should have overflow free determines how low of a frequency you want to measure.
2. Configure a capture channel.
3.in the IC ISR, calculate the ticks elapsed and set a flag.
4. In the user code, perform the calculation.
More or less what I've done in the atmel vesion, great.
(only difference is that I take an average of cpu pulses rather than only one capture reading, trying to avoid strange noises and small changes)
I used one library called FreqMeasure, that it's not ported to stm proccessor
julian_lp
Posts: 8
Joined: Sun Jul 09, 2023 10:23 pm

Re: Bluepill: 2 different timers to read 2 different FREQS

Post by julian_lp »

ozcar wrote: Thu Jul 27, 2023 5:51 am So what is the minimum time between pulses then? Not knowing much about cars, I guess say 10,000RPM *2 and come up with 3ms for the tachometer, and say 200km/h * 1000 and come up with 18ms for the odometer. Those are not vastly different, so maybe you could use 2 channels on one timer, but it would depend on what resolution you hope to achieve. Otherwise if the two channels you used are on two different timers, you could set the pre-scalers different to get best use of the 16-bit counters.
Well the first thing that confused me was the whole channel thing (cause there are no "channel" in atmega328 world)
Now I'm starting to think about a channel, and the starting point is that all the frequencies should be "related" or "not too different" to share the same timer... I'll have to read much more yet about that topic
ozcar wrote: Thu Jul 27, 2023 5:51 am Extending a timer by counting the overflows may be possible, provided you are careful about how you join (concatenate) the overflow count and the count from the timer register. There is some discussion of doing that here: https://www.eevblog.com/forum/microcont ... ure-timer/. That is specifically for AVR processors, but you may be able to do the same.
that's what I was trying to achieve with this: (unsure if it would work and with no hardware to test till next week)

Code: Select all

 FrequencyMeasured = input_freq / ( (rolloverCompareCount * 0x10000) + CurrentCapture - LastCapture);
ozcar wrote: Thu Jul 27, 2023 5:51 am Given the relatively low frequencies, maybe it would be good enough to use attachInterrupt() for rising or falling edge, and then just use micros() to get the time in the interrupt routine.
Interesting option given the stm32 cpu clock. Not very doable/recommended in the 328 version tough

regards,
julian
Post Reply

Return to “General discussion”