How do you handle timer overflow (update events) correctly?
Timer overflow occurs when the counter reaches ARR and wraps to 0 (in up-counting mode) or reaches 0 from ARR (in down-counting mode). The hardware sets the Update Event Flag (UIF) in the status register, and if the Update Interrupt Enable (UIE) bit is set, an interrupt request fires. Inside the ISR, you must clear the UIF flag before returning — failing to do so causes the interrupt to fire continuously, locking up the CPU in an infinite ISR loop. On STM32, this means TIMx->SR &= ~TIM_SR_UIF; as the first line of the handler (not the last, to avoid a race with the NVIC tail-chaining).
For counting events or measuring time beyond the timer's 16-bit range (0-65535), maintain a software overflow counter that increments in the update ISR. The total count is overflow_count * (ARR + 1) + current_counter. However, a subtle race condition exists: if you read the overflow count and the counter register non-atomically, an overflow that occurs between the two reads corrupts the result. The safe pattern is to read the overflow count, read the counter, then check UIF — if UIF is set and the counter value is small (meaning it just wrapped), add one to your overflow copy before computing the total.
uint32_t get_extended_count(void) {uint32_t ovf = overflow_count;uint32_t cnt = TIM2->CNT;if ((TIM2->SR & TIM_SR_UIF) && cnt < (TIM2->ARR >> 1)) {ovf++; // Overflow occurred between reads}return ovf * (TIM2->ARR + 1) + cnt;}
Source: Timers & PWM Q&A
