Skip to content

Commit 0b38f85

Browse files
committed
HardwareTimer: Fix ARR and CCRx computation
* protect setOverflow against underflow. * remove -1 for MICROSEC_COMPARE_FORMAT, HERTZ_COMPARE_FORMAT and TICK_COMPARE_FORMAT. * remove -1 in setCount() too * Manage special case where ARR = MAX_RELOAD and 100% expected. Fixes #897
1 parent cc05df9 commit 0b38f85

File tree

1 file changed

+19
-7
lines changed

1 file changed

+19
-7
lines changed

cores/arduino/HardwareTimer.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ HardwareTimer::HardwareTimer(TIM_TypeDef *instance)
8787

8888
/* Configure timer with some default values */
8989
_timerObj.handle.Init.Prescaler = 0;
90-
_timerObj.handle.Init.Period = 0xFFFF; // 16bit max value
90+
_timerObj.handle.Init.Period = MAX_RELOAD;
9191
_timerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP;
9292
_timerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
9393
#if defined(TIM_RCR_REP)
@@ -474,6 +474,10 @@ void HardwareTimer::setOverflow(uint32_t overflow, TimerFormat_t format)
474474
break;
475475
}
476476

477+
// In case ARR computation give 0xFFFFFFFF (equal (0 - 1) ) set ARR register to 0 (the smallest achievable period)
478+
if (ARR_RegisterValue == 0xFFFFFFFF) {
479+
ARR_RegisterValue = 0;
480+
}
477481
__HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, ARR_RegisterValue);
478482
}
479483

@@ -520,14 +524,14 @@ void HardwareTimer::setCount(uint32_t counter, TimerFormat_t format)
520524
uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
521525
switch (format) {
522526
case MICROSEC_FORMAT:
523-
CNT_RegisterValue = ((counter * (getTimerClkFreq() / 1000000)) / Prescalerfactor) - 1 ;
527+
CNT_RegisterValue = ((counter * (getTimerClkFreq() / 1000000)) / Prescalerfactor);
524528
break;
525529
case HERTZ_FORMAT:
526-
CNT_RegisterValue = (uint32_t)((getTimerClkFreq() / (counter * Prescalerfactor)) - 1);
530+
CNT_RegisterValue = (uint32_t)(getTimerClkFreq() / (counter * Prescalerfactor));
527531
break;
528532
case TICK_FORMAT:
529533
default :
530-
CNT_RegisterValue = counter - 1;
534+
CNT_RegisterValue = counter;
531535
break;
532536
}
533537
__HAL_TIM_SET_COUNTER(&(_timerObj.handle), CNT_RegisterValue);
@@ -699,11 +703,12 @@ void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerC
699703

700704
switch (format) {
701705
case MICROSEC_COMPARE_FORMAT:
702-
CCR_RegisterValue = ((compare * (getTimerClkFreq() / 1000000)) / Prescalerfactor) - 1 ;
706+
CCR_RegisterValue = ((compare * (getTimerClkFreq() / 1000000)) / Prescalerfactor);
703707
break;
704708
case HERTZ_COMPARE_FORMAT:
705-
CCR_RegisterValue = (getTimerClkFreq() / (compare * Prescalerfactor)) - 1;
709+
CCR_RegisterValue = getTimerClkFreq() / (compare * Prescalerfactor);
706710
break;
711+
// As per Reference Manual PWM reach 100% with CCRx value strictly greater than ARR (So ARR+1 in our case)
707712
case PERCENT_COMPARE_FORMAT:
708713
CCR_RegisterValue = ((__HAL_TIM_GET_AUTORELOAD(&(_timerObj.handle)) + 1) * compare) / 100;
709714
break;
@@ -727,10 +732,17 @@ void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerC
727732
break;
728733
case TICK_COMPARE_FORMAT:
729734
default :
730-
CCR_RegisterValue = compare - 1;
735+
CCR_RegisterValue = compare;
731736
break;
732737
}
733738

739+
// Special case when ARR is set to the max value, it is not possible to set CCRx to ARR+1 to reach 100%
740+
// Then set CCRx to max value. PWM is then 1/0xFFFF = 99.998..%
741+
if ((__HAL_TIM_GET_AUTORELOAD(&(_timerObj.handle)) == MAX_RELOAD)
742+
&& (CCR_RegisterValue == MAX_RELOAD + 1)) {
743+
CCR_RegisterValue = MAX_RELOAD;
744+
}
745+
734746
__HAL_TIM_SET_COMPARE(&(_timerObj.handle), timChannel, CCR_RegisterValue);
735747
}
736748

0 commit comments

Comments
 (0)