From 86af4e6680b6a3607c76ef7c944897fce85e3a3d Mon Sep 17 00:00:00 2001 From: 94xhn <87560781+94xhn@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:28:02 +0800 Subject: [PATCH] fix(HardwareTimer): use ARR+1 in getCaptureCompare percent/resolution getCaptureCompare() divided by LL_TIM_GetAutoReload() (ARR) for PERCENT_COMPARE_FORMAT and all RESOLUTION_xB_COMPARE_FORMAT cases, while its counterpart setCaptureCompare() multiplies by ARR+1, per the code's own comment: "PWM reach 100% with CCRx value strictly greater than ARR (So ARR+1 in our case)". This makes get/set inconsistent: reading back a duty cycle written via setCaptureCompare(ch, 100, PERCENT_COMPARE_FORMAT) does not return 100, and overshoots more as ARR gets smaller (e.g. ARR=9 reads back 111, ARR=1 reads back 200). When ARR is 0 (a reachable state, e.g. after setOverflow(1, TICK_FORMAT)), the getter performs a division by zero. Use ARR+1 in the getter too, matching the setter and its own documented rationale. Signed-off-by: 94xhn <87560781+94xhn@users.noreply.github.com> --- libraries/SrcWrapper/src/HardwareTimer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/SrcWrapper/src/HardwareTimer.cpp b/libraries/SrcWrapper/src/HardwareTimer.cpp index 5c88223e21..8c4fe21f45 100644 --- a/libraries/SrcWrapper/src/HardwareTimer.cpp +++ b/libraries/SrcWrapper/src/HardwareTimer.cpp @@ -1188,8 +1188,11 @@ uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_ case HERTZ_COMPARE_FORMAT: return_value = (uint32_t)(getTimerClkFreq() / (CCR_RegisterValue * Prescalerfactor)); break; + // As per Reference Manual PWM reach 100% with CCRx value strictly greater than ARR + // (So ARR+1 in our case). Use the same ARR+1 "full scale" as setCaptureCompare() + // so that get/set are consistent, and to avoid a divide by zero when ARR is 0. case PERCENT_COMPARE_FORMAT: - return_value = (CCR_RegisterValue * 100) / LL_TIM_GetAutoReload(_timerObj.instance); + return_value = (CCR_RegisterValue * 100) / (LL_TIM_GetAutoReload(_timerObj.instance) + 1); break; case RESOLUTION_1B_COMPARE_FORMAT: case RESOLUTION_2B_COMPARE_FORMAT: @@ -1207,7 +1210,7 @@ uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_ case RESOLUTION_14B_COMPARE_FORMAT: case RESOLUTION_15B_COMPARE_FORMAT: case RESOLUTION_16B_COMPARE_FORMAT: - return_value = (CCR_RegisterValue * ((1 << format) - 1)) / LL_TIM_GetAutoReload(_timerObj.instance); + return_value = (CCR_RegisterValue * ((1 << format) - 1)) / (LL_TIM_GetAutoReload(_timerObj.instance) + 1); break; case TICK_COMPARE_FORMAT: default :