timer (hardware)
Hardwarový timer je periferie v mikrokontroléru, která odlehčuje CPU od časově kritických a repetitivních úloh (jako je generování PWM signálu, měření časových intervalů atd.).
Základní registry
Timer se skládá z několika klíčových registrů:
- Counter register — počítadlo, které se inkrementuje/dekrementuje s každým tiknutím
- Prescaler register — dělí vstupní clock. Pokud timer dostává 84 MHz a prescaler je 84, counter se inkrementuje s frekvencí 1 MHz
- Autoreload register — definuje periodu counteru. Když counter dosáhne této hodnoty, resetuje se na 0 a začne znovu
- Capture/Compare register (CCR) — používá se pro porovnání s counterem, klíčový pro PWM generování
Kanály
Timer může mít více nezávislých kanálů (typicky 4). Každý kanál má vlastní CCR, takže může generovat nezávislý výstup. Kanály sdílejí prescaler, autoreload a counter (tedy frekvenci), ale duty cycle je pro každý kanál nezávislý.
Režimy
- Output — timer generuje signál ven na pin (např. PWM)
- Input Capture — timer měří příchozí signál (např. délku pulzu)
Frekvence timeru
Vstupní clock timeru závisí na tom, na jaké sběrnici timer sedí (např. APB1, APB2). Timer clock se pak dělí prescalerem a autoreload hodnotou.
Vzorce
Timer clock (frekvence tikání counteru): \(f_{timer} = \frac{f_{vstup}}{prescaler + 1}\)
Prescaler se přičítá 1, protože hodnota 0 = dělení jedničkou (žádné dělení).
Frekvence periody (jak často counter přeteče / jak často se celý cyklus opakuje): \(f_{perioda} = \frac{f_{timer}}{ARR + 1} = \frac{f_{vstup}}{(prescaler + 1) \times (ARR + 1)}\)
ARR (Autoreload) se taky přičítá 1, protože counter počítá od 0 — tedy ARR = 255 znamená 256 kroků (0–255).
Příklad
- Vstupní clock = 84 MHz
- Prescaler = 9 → $f_{timer}$ = 84 MHz / 10 = 8.4 MHz
- ARR = 255 → $f_{perioda}$ = 8.4 MHz / 256 = 32 812 Hz
To znamená, že jedna celá perioda (např. PWM cyklus) trvá přibližně 30 µs.
Důležité
V PWM módu timer negeneruje interrupt (pokud ho explicitně nepovolíš). Hardware sám přepíná pin HIGH/LOW podle CCR registru — CPU se o to nestará. To je celý smysl offloadingu na timer.
Mapování na piny
Výstupy timeru jsou propojené s konkrétními GPIO piny přes alternate function. Toto mapování je nadrátované v křemíku a najdeš ho v datasheetu čipu.
Přerušení timeru
Update Event Flag (UIF)
Když counter přeteče (dosáhne ARR a resetuje se), hardware nastaví flag TIM_FLAG_UPDATE (bit UIF v registru TIM_SR). Pokud je povoleno update interrupt (TIM_IT_UPDATE), vyvolá se ISR. Flag se musí manuálně vyčistit v ISR — pokud to neuděláš, přerušení se vyvolá okamžitě znovu (nekonečná smyčka přerušení).
__HAL_TIM_CLEAR_FLAG(&htim, TIM_FLAG_UPDATE);
Sdílené IRQ vektory (STM32F4)
Na STM32F4 není dostatek IRQ linek pro každý timer zvlášť, takže některé timery sdílejí IRQ vektor. Název vektoru popisuje, které eventy kterých timerů sdílejí daný vektor:
| IRQ Handler | Zdroj 1 | Zdroj 2 |
|---|---|---|
TIM8_UP_TIM13_IRQHandler |
TIM8 update event | TIM13 |
TIM1_BRK_TIM9_IRQHandler |
TIM1 break event | TIM9 |
TIM1_UP_TIM10_IRQHandler |
TIM1 update event | TIM10 |
TIM1_TRG_COM_TIM11_IRQHandler |
TIM1 trigger/commut. | TIM11 |
UP = update event, ne “counting up”. Přerušení TIM1 jsou rozdělena podle typu eventu do více vektorů, a ke každému je připojen menší timer.
Pokud jsou oba timery na jednom vektoru aktivní, musíš v ISR zkontrolovat flagy obou:
void TIM8_UP_TIM13_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_UPDATE)) {
__HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_UPDATE);
// handle TIM8
}
if (__HAL_TIM_GET_FLAG(&htim13, TIM_FLAG_UPDATE)) {
__HAL_TIM_CLEAR_FLAG(&htim13, TIM_FLAG_UPDATE);
// handle TIM13
}
}
Pokud druhý timer nepoužíváš, stačí ošetřit jen ten svůj — ale kontrola flagu je dobrá praxe proti spurious interruptům.