Přeskočit na hlavní obsah

Hodiny

Hodiny určují, jak rychle mikrokontrolér běží. Nejsou to hodiny na zdi, ale pravidelné tikání uvnitř čipu. Procesor, časovače, UART, ADC i další periferie z nich odvozují svůj čas.

Když jsou hodiny nastavené jinak, než si program myslí, začnou se dít divné věci:

  • funkce delay čeká moc dlouho nebo moc krátce,
  • UART posílá data špatnou rychlostí,
  • ADC převodník měří v jiném tempu,
  • časovač přeruší program jindy, než čekáme.

Proto se v embedded projektech často objevuje hodnota F_CPU. Ta říká překladači, na jaké frekvenci má program běžet.

#ifndef F_CPU
#define F_CPU 3333333UL
#endif

Tento zápis říká: pokud F_CPU ještě nikdo nenastavil, použij hodnotu 3333333. To je přibližně 3.33 MHz.

Hodinová mapa

V datasheetu nebo referenčním manuálu bývá pro hodiny často obrázek, kterému se říká clock tree, clock diagram nebo prostě hodinová mapa. Je to schéma, které ukazuje, odkud hodiny přicházejí, přes jaké přepínače, děličky a někdy i násobičky jdou dál, a které části čipu z nich nakonec žijí.

U některých ARM mikrokontrolérů se potkáte s názvy jako HSI a HSE:

  • HSI bývá high-speed internal clock, tedy rychlý vnitřní oscilátor,
  • HSE bývá high-speed external clock, tedy vnější zdroj hodin, často krystal nebo externí oscilátor.

AVR a ATtiny nemusí používat stejné názvy, ale princip je podobný: čip má nějaký vnitřní zdroj hodin a někdy může používat i vnější zdroj. Konkrétní názvy vždycky hledejte v manuálu konkrétního čipu.

Vnitřní a vnější hodiny

Vnitřní oscilátor je pohodlný. Nemusíte k čipu připojit další součástku a pro mnoho jednoduchých úloh úplně stačí: blikání LED, čtení tlačítek, jednoduché měření nebo pomalejší komunikace.

Vnější zdroj hodin je obvykle přesnější. Často je to krystal, keramický rezonátor nebo hotový oscilátor připojený k pinu čipu. Nevýhoda je jasná: musí být na desce opravdu osazený a zabere piny nebo místo.

Přesnost hodin začne být důležitá hlavně u komunikace. Například UART neposílá zvláštní hodinový signál. Obě strany si musí samy odměřit, kdy číst jednotlivé bity. Když mají hodiny příliš velkou chybu, začne se příjem rozjíždět a místo dat přijdou nesmysly.

Rychlá komunikace potřebuje přesné hodiny

U vyšších rychlostí UARTu už vnitřní oscilátor nemusí stačit. Pak je potřeba zkontrolovat přesnost hodin v datasheetu a podle čipu nebo desky použít přesnější zdroj, typicky vnější krystal nebo oscilátor.

Děličky a násobičky

Mikrokontrolér často nemá jen jednu pevnou rychlost. Uvnitř může být oscilátor, který běží třeba rychleji, a pak dělička, která z něj udělá pomalejší takt pro procesor. Některé čipy mají také PLL, tedy obvod, který umí z jednoho zdroje vyrobit vyšší frekvenci.

Zjednodušeně:

  • dělička frekvenci snižuje,
  • násobička nebo PLL frekvenci zvyšuje,
  • přepínač zdroje vybírá, odkud se hodiny vezmou,
  • další děličky mohou zvlášť nastavit CPU, periferie, časovače nebo sběrnice.

Proto jsou hodiny samostatná kapitola. Nejde jen o jedno číslo. Je to malá distribuční síť uvnitř čipu. Když se nastaví špatně, chyba se může projevit úplně jinde: v UARTu, časovači, ADC nebo ve funkci pro čekání.

Na ATtiny může nastavení hodin vypadat například takto:

static void clock_init(void)
{
ccp_write_io((volatile uint8_t *)&CLKCTRL.MCLKCTRLB,
CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm);
}

Registr CLKCTRL.MCLKCTRLB nastavuje děličku hlavních hodin. Hodnota CLKCTRL_PDIV_6X_gc vybírá dělení šesti. Hodnota CLKCTRL_PEN_bm zapíná použití prescaleru, tedy děličky.

Operátor | tady spojí dvě volby dohromady:

CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm
Dělička 6 a povolení prescaleru v jednom registru
765PDIVPDIVPDIVPDIVPEN
PDIV_6X
00010000
PEN
00000001
spolu
00010001

Je to stejné jako říct: "chci děličku 6 a zároveň ji chci zapnout".

Podrobně je práce s bity rozebraná v kapitole Ovládání registrů.

Proč je tam ccp_write_io

Některé registry jsou chráněné. Výrobce nechce, aby je program omylem změnil náhodným zápisem. Hodiny patří mezi citlivé nastavení: když je pokazíme, celý čip může běžet špatně.

Proto se na ATtiny používá pomocná funkce:

ccp_write_io((volatile uint8_t *)&CLKCTRL.MCLKCTRLB, hodnota);

ccp znamená configuration change protection. Je to krátké časové okno, ve kterém je povolen zápis do chráněného registru. Mimo toto okno se zápis ignoruje.

Pro začátek stačí vědět: některé důležité registry se nepíšou obyčejným =, ale přes speciální ochranný postup.

Hodiny a UART

UART musí vědět, jak rychle čip běží, aby správně spočítal rychlost komunikace. Typický výpočet hodnoty pro UART může vypadat takto:

#define UART_BAUD_REGISTER ((uint16_t)((4UL * F_CPU + (UART_BAUD / 2UL)) / UART_BAUD))

Tento výpočet používá F_CPU. Když F_CPU nesedí s reálným nastavením hodin, UART bude posílat bity špatným tempem. Počítač pak místo textu uvidí nesmysly.

F_CPU není kouzelný knoflík

F_CPU samo o sobě nezmění rychlost čipu. Je to informace pro překladač a výpočty v programu.

Skutečnou rychlost mění nastavení hodin v registrech, třeba CLKCTRL.MCLKCTRLB. Obě věci musí souhlasit.

Obecný postup

U většiny mikrokontrolérů je nastavení hodin podobná práce:

  1. Vybere se zdroj hodin.
  2. Nastaví se dělička.
  3. Počká se, až se zdroj hodin ustálí.
  4. Nastaví se frekvence používaná v projektu.
  5. Podle ní se dopočítají periferie, třeba UART nebo časovače.

Konkrétní názvy registrů se liší podle čipu. Princip je ale stejný: hodiny jsou základní rytmus celého programu.