Description
Describe the bug
The function HardwareTimer::setOverflow()
allow to set the overflow value as a uint32_t
an then set the value of the STM32 ARR Register to:
has shown in the function implementation below.
Arduino_Core_STM32/libraries/SrcWrapper/src/HardwareTimer.cpp
Lines 521 to 557 in 8ff274a
this works fine with 16 bit counters and 32 bit counters when not used in the full range.
but to set the max value of a 32 bit counter the ARR register value should be set to 0xFFFFFFFF
to do so the function argument should be set to 0x100000000
but since the argument is defined as uint32_t
the value will not fit and overflow as 0
I want to point out that setting the value to the maximum is an important thing, since not only will increase marginally the maximum counter value but more importantly allows to calculate values of thresholds and time elapsed between input capture event easly because
elapsedTicks = capture - oldCapture
if all variables are defined as uint32_t
and the elapsedTicks guaranteed to be under 0x100000000
will work even if an overflow occurs.
and in the same way when generating a square wave updating the ARR value with the next event value can be done as nextVal = lastVal + delta
under the same conditions.
this methods are common practice on timer usage on any
workaround
In the actual state the problem can be solved by either
- compensating for the missing value in the period computation
if(capture < captureOld) elapsedTicks = capture - oldCapture - 1; else elapsedTicks = capture - oldCapture;
- initializing the timer overflow by accessing directly to the STM32 HAL
timerObj_t _timerObj; _timerObj.handle.Instance = TIM2; __HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, 0xFFFFFFFF);
neither of these solution are efficient nor elegant.
Suggested Fixes
to me the easiest way to fix this issue is changing the function definition from
void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format)
to
void HardwareTimer::setOverflow(uint64_t overflow, TimerFormat_t format)
by using this approach the fix should not cause any compatibility issues with existing code
Constatation
here you can see the serial output of the STM32 when measuring a 1hz pulse over an 80Mhz timebase
both generated by the same oscilltor so they are perfectly coherent.
all the readings are perfect except for when the overflow occurs in that case you sistematically get one count more that is due to the missing code.
captureOld capture difference
4059789198 4139789198 80000000
4139789198 4219789198 80000000
4219789198 4821903 80000001
4821903 84821903 80000000
84821903 164821903 80000000
164821903 244821903 80000000
after applying one of the above workaround the error never appears again
captureOld capture difference
4106049847 4186049847 80000000
4186049847 4266049847 80000000
4266049847 51082551 80000000
51082551 131082551 80000000
131082551 211082551 80000000
211082551 291082551 80000000
here there is a the code on witch i've found the bug:
#include <Arduino.h>
HardwareTimer *FCT; //FCT Frequency Counter Timer
volatile uint32_t captureOld = 0, capture;
volatile uint32_t period;
volatile bool newMeas = false;
void IC_Callback(){
capture = FCT->getCaptureCompare(LL_TIM_CHANNEL_CH1);
Serial.print(captureOld); //print inside an interrupt, bad practice but accettable for debugging
Serial.print(" ");
Serial.print(capture);
Serial.print(" ");
period = capture - captureOld;
Serial.println(period);
captureOld = capture;
newMeas = true;
}
void setup()
{
Serial.begin(115200);
FCT = new HardwareTimer(TIM2);
FCT->setMode(LL_TIM_CHANNEL_CH1,TIMER_INPUT_CAPTURE_RISING,PA_0);
FCT->setPrescaleFactor(1);
FCT->setOverflow(0xFFFFFFFF);//max value on 32 bit // invert the comment on these line to passs
//timerObj_t _timerObj; //from the bug to the workaround
//_timerObj.handle.Instance = TIM2; //
//__HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, 0xFFFFFFFF); //
FCT->updateRegistersIfNotRunning(_timerObj.handle.Instance);
FCT->attachInterrupt(LL_TIM_CHANNEL_CH1,IC_Callback);
FCT->resume();
}
void loop()
{
if (newMeas){
//Serial.println(period);
newMeas = false;
}
}
// unrelated to the issue
// this was the clock configuration to use a 10Mhz extenal oscillator
// that was important to have the 1pps signal exactly coherent to the clock
// otherwise the problem can be hard to spot
// this may be replicable using a wave generated by another timer
extern "C" void SystemClock_Config(void){...}
Desktop :
- OS: Windows 10
- Platformio version: core 6.1.7 on clion
- STM32 core version: 2.6.0
- Upload method: Default
Board:
- Name: Nucleo L476RG
- Extra hardware used if any: squarewave generator
Activity
fpistm commentedon Jul 15, 2023
Hi @GianfrancoIU1JSU
Thanks for the detailed issue. You can provide a PR then we will review it.
overflow value uint32_t -> uint64_t fix stm32duino#2071
PeriodTicks uint32_t -> uint64_t fix stm32duino#2071
add fix stm32duino#2071 modification also to getter
[-]Setting 32 bit timers overflow value to maximum is not possible[/-][+]HardwareTimer: support 32 bit timers[/+]fpistm commentedon Jul 21, 2023
Hi @GianfrancoIU1JSU
As stated in your PR, the implementation to support 32 bits timers required more works. I've changed the title to support 32 bits timers instance.
The
IS_TIM_32B_COUNTER_INSTANCE
could be used to deal with.Ex of limitation
Arduino_Core_STM32/libraries/SrcWrapper/src/HardwareTimer.cpp
Line 33 in 987519a