Skip to content

Commit 8a81c63

Browse files
94xhnfpistm
authored andcommitted
fix(HardwareTimer): guard HERTZ_FORMAT get* against register==0
getCount(HERTZ_FORMAT) and getCaptureCompare(..., HERTZ_COMPARE_FORMAT) both compute getTimerClkFreq() / (register * Prescalerfactor), dividing directly by the live CNT (counter) or CCR (capture/compare) hardware register with no zero-guard. Both registers legitimately read 0 with no caller error involved: - CNT is 0 right at/after every timer reset or overflow, simply from the timer running (getOverflow()/setOverflow() already special-case this exact situation via the ARR+1 "period" offset; getCount() and getCaptureCompare() do not). - CCR is 0 on reset before the first setCaptureCompare() call, and in Input Capture mode holds whatever was last captured, which is 0 before any edge has been captured or if an edge lands exactly at CNT == 0. Hitting either case triggers an integer divide by zero: undefined behavior in C/C++, verified to crash (SIGFPE-equivalent) on a desktop toolchain. On Cortex-M without DIV_0_TRP configured (the default), UDIV silently returns 0, so on-target this instead silently reports "0 Hz" with no indication anything went wrong. Add an explicit zero-check to both HERTZ_FORMAT branches, returning 0 (no meaningful frequency available) instead of dividing, matching the existing "do not underflow" zero-guard style already used by setOverflow() in this same file. No public API/signature changes. Signed-off-by: 94xhn <87560781+94xhn@users.noreply.github.com>
1 parent 59e2cdd commit 8a81c63

1 file changed

Lines changed: 10 additions & 2 deletions

File tree

‎libraries/SrcWrapper/src/HardwareTimer.cpp‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,10 @@ uint32_t HardwareTimer::getCount(TimerFormat_t format)
746746
return_value = (uint32_t)((CNT_RegisterValue * Prescalerfactor * 1000000.0) / getTimerClkFreq());
747747
break;
748748
case HERTZ_FORMAT:
749-
return_value = (uint32_t)(getTimerClkFreq() / (CNT_RegisterValue * Prescalerfactor));
749+
// CNT_RegisterValue is 0 right at/after every timer reset or overflow,
750+
// which is a normal, reachable state (not a caller error): avoid a
751+
// divide by zero and report 0 (no meaningful frequency available).
752+
return_value = (CNT_RegisterValue == 0) ? 0 : (uint32_t)(getTimerClkFreq() / (CNT_RegisterValue * Prescalerfactor));
750753
break;
751754
case TICK_FORMAT:
752755
default :
@@ -1203,7 +1206,12 @@ uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_
12031206
return_value = (uint32_t)((CCR_RegisterValue * Prescalerfactor * 1000000.0) / getTimerClkFreq());
12041207
break;
12051208
case HERTZ_COMPARE_FORMAT:
1206-
return_value = (uint32_t)(getTimerClkFreq() / (CCR_RegisterValue * Prescalerfactor));
1209+
// CCR_RegisterValue is 0 on reset (before the first setCaptureCompare()
1210+
// call) and, in Input Capture mode, whenever the last captured edge
1211+
// landed exactly at CNT == 0 or before any edge has been captured yet.
1212+
// That is a normal, reachable state (not a caller error): avoid a
1213+
// divide by zero and report 0 (no meaningful frequency available).
1214+
return_value = (CCR_RegisterValue == 0) ? 0 : (uint32_t)(getTimerClkFreq() / (CCR_RegisterValue * Prescalerfactor));
12071215
break;
12081216
// As per Reference Manual PWM reach 100% with CCRx value strictly greater than ARR
12091217
// (So ARR+1 in our case). Use the same ARR+1 "full scale" as setCaptureCompare()

0 commit comments

Comments
 (0)