Overflow del Timer: Meccanismo, Conseguenze e Gestione nei Sistemi Embedded
Overflow del Timer: Meccanismo, Conseguenze e Gestione nei Sistemi Embedded
Un **overflow del timer** si verifica quando un registro contatore/timer hardware raggiunge il suo valore massimo ($2^N - 1$ per N-bit) e riparte da zero al tick di orologio successivo. È un evento fondamentale e periodico in praticamente tutti i microcontrollori (MCU), SoC e kernel RTOS.
Il Meccanismo
- Contatore: Registro a libera esecuzione incrementato da sorgente di orologio ($f_{clk}$ o $f_{clk}$/Prescaler).
- Larghezza: 8-bit (256), 16-bit (65.536), 32-bit (4,29 miliardi), 64-bit.
- Periodo ($T_{ovf}$): $T_{ovf} = \frac{2^N}{f_{count}}$.
- Esempio: 16-bit, orologio 1 MHz $\rightarrow$ $T_{ovf} = 65,536 \text{ ms}$.
- Esempio: 32-bit, 100 MHz $\rightarrow$ $T_{ovf} = 42,9 \text{ s}$.
- Flag/Interrupt: L'hardware imposta l'**Overflow Flag (TOV / UIF)**. Genera una **Richiesta di Interrupt (IRQ)** se abilitata (TOIE).
Conseguenze di Overflow Non Gestito
| Dominio | Modalità di Guasto |
|---|---|
| Misurazione Tempo (RTC / SysTick) | Il tempo salta all'indietro / si avvolge. `millis()` si avvolge (Arduino: 49,7 giorni). Corruzione di `gettimeofday()` se ISR perso. |
| PWM / Output Compare | Glitch se il valore TOP non aggiornato atomicamente con buffer. Errore ciclo di lavoro per un periodo. |
| Input Capture / Larghezza Impulso | Periodo misurato > $T_{ovf}$ $\rightarrow$ Ambiguità (conteggio overflow perso). Richiede estensione contatore overflow software. |
| Scheduler RTOS (SysTick) | Perdita di tick $\rightarrow$ Deriva temporale task, scadenze mancate, inversione di priorità. |
| Sicurezza / Crypto | Malfunzionamento sorgente entropia. Perdite temporali side-channel se overflow prevedibile. |
| Y2K38 / `time_t` 32-bit | Overflow epoca Unix 19 gennaio 2038. Non timer HW, stessa matematica. |
Strategie di Gestione (Firmware)
1. Estendi Larghezza in Software (Pratica Standard)
// Timer HW 16-bit $\rightarrow$ Tempo di Sistema 32/64-bit
volatile uint32_t overflow_count = 0;
ISR(TIMER_OVF_vect) {
overflow_count++;
}
uint64_t get_time_us() {
uint8_t sreg = SREG; cli();
uint16_t hw = TCNT1;
uint32_t ovf = overflow_count;
SREG = sreg;
// Gestisci race: if (TIFR & TOV) ovf++; hw = TCNT1;
return ((uint64_t)ovf << 16) | hw;
}
volatile uint32_t overflow_count = 0;
ISR(TIMER_OVF_vect) {
overflow_count++;
}
uint64_t get_time_us() {
uint8_t sreg = SREG; cli();
uint16_t hw = TCNT1;
uint32_t ovf = overflow_count;
SREG = sreg;
// Gestisci race: if (TIFR & TOV) ovf++; hw = TCNT1;
return ((uint64_t)ovf << 16) | hw;
}
2. Reset/Ricarica Periodica (Modalità Auto-Ricarica / Periodica)
- Imposta **Registro Auto-Ricarica (ARR / TOP / PRD)** = Periodo Desiderato - 1.
- Il timer conta 0 $\rightarrow$ ARR $\rightarrow$ 0. **Nessun flag di overflow** (o flag = Periodo Corrispondente).
- Elimina ambiguità overflow; definisce periodo esatto.
3. Input Capture con Conteggio Overflow
- Su Evento di Cattura: Leggi Timer ($T_{cap}$) + Leggi/Incrementa Contatore Overflow ($N_{ovf}$).
- Tempo Totale = $(N_{ovf} \times 2^N + T_{cap}) / f_{count}$.
- Lettura atomica di (Contatore + Overflow) critica (Supporto HW: registro di cattura 32-bit inclusi bit overflow, o doppia lettura con controllo flag).
4. Contatori Liberi ad Alta Risoluzione / 64-bit
- ARM Cortex-M **DWT CYCCNT** (32-bit @ frequenza CPU).
- RISC-V **`mtime` / `mtimeh`** (64-bit mappato in memoria).
- x86 **TSC (Time Stamp Counter)** (64-bit, invariante).
- Periodo di overflow = Secoli. Effettivamente "nessun overflow" per la vita del sistema.
5. Compensazione Drift Orologio (Calibrazione)
- Tolleranza oscillatore ($\pm 50$ ppm quarzo, $\pm 1-2\%$ RC).
- Sincronizzazione periodica a riferimento esterno (PPS GPS, NTP, PTP IEEE 1588, Passaggio Zero Rete Elettrica).
- Regola `ARR` o fattore di scalamento software dinamicamente.
Best Practice
- Usa Modalità Auto-Ricarica per task periodici (SysTick, PWM, Loop di Controllo). Evita overflow a libera esecuzione a meno che non misuri intervalli lunghi.
- Letture Atomiche: Disabilita interrupt / Usa LDREX/STREX / Leggi due volte con controllo flag per valori multi-registro.
- Volatile + Barriere di Memoria: Variabili condivise ISR/Main.
- Test Avvolgimento: Simula overflow (imposta contatore vicino a MAX) in CI/HIL. Verifica gestione avvolgimento `millis()` (storia bug avvolgimento `millis()` Arduino).
- Watchdog: Watchdog finestra indipendente (IWDT/WWDT) — dominio orologio separato — cattura guasto timer principale.
Conclusione
L'overflow del timer non è un errore—è un **vincolo di progettazione**. I moderni contatori liberi 32/64-bit lo rendono trascurabile per la misurazione del tempo. Per timer 8/16-bit, **estensione software (contatore overflow) + accesso atomico** è lo schema standard. Per task periodici, la **modalità Auto-Ricarica elimina il concetto interamente.**