Pinmux
Jeden pin mikrokontroléru často neumí jen jednu věc. Může být obyčejný GPIO, ale také UART, SPI, I2C, ADC vstup, výstup časovače nebo jiná speciální funkce.
Pinmux je zkratka pro pin multiplexing.
Znamená to,
že jeden fyzický pin může být připojený k různým vnitřním částem čipu.
Program musí vybrat,
která funkce se má na pin dostat.
Je to podobné jako přepínač kolejí. Kolej je pořád jedna, ale můžeme rozhodnout, odkud na ni vlak přijede.
Proč pinmux existuje
Malý čip má málo nožiček. Kdyby každá periferie měla vlastní piny, ATtiny by rychle přestala být "tiny".
Proto výrobce dovolí, aby se některé funkce daly vyvést na různé piny. Je to praktické:
- návrh desky může být jednodušší,
- UART může být na pinech, které se lépe zapojují,
- jeden pin může být v jednom projektu GPIO a v jiném ADC,
- některé funkce se dají přesunout mimo obsazené piny.
Cena za to je, že pinmux musíme správně nastavit.
Příklad z ATtiny: přesunutí UARTu
Na ATtiny může přesunutí UARTu na alternativní piny vypadat například takto:
PORTMUX.USARTROUTEA =
(uint8_t)((PORTMUX.USARTROUTEA & (uint8_t)~PORTMUX_USART0_gm) |
PORTMUX_USART0_ALT1_gc);
Na první pohled to vypadá dlouze. Ve skutečnosti se dějí dvě věci:
- smažou se staré bity,
které říkají,
kudy je vyvedený
USART0, - zapíše se nová volba
PORTMUX_USART0_ALT1_gc.
Rozložené na kroky:
uint8_t puvodni = PORTMUX.USARTROUTEA;
uint8_t vycistene = puvodni & (uint8_t)~PORTMUX_USART0_gm;
uint8_t nove = vycistene | PORTMUX_USART0_ALT1_gc;
PORTMUX.USARTROUTEA = nove;
Proč nestačí prosté =
Mohlo by lákat napsat jen:
PORTMUX.USARTROUTEA = PORTMUX_USART0_ALT1_gc;
To ale může přepsat i jiné části registru.
V jednom registru totiž nemusí být jen nastavení pro USART0.
Mohou tam být i další volby pro jiné periferie.
Proto se používá postup:
PORTMUX.USARTROUTEA =
(PORTMUX.USARTROUTEA & ~MASKA_SKUPINY) | NOVA_VOLBA;
Tento vzor znamená:
- vezmi aktuální hodnotu registru,
- vyčisti jen bity, které patří danému nastavení,
- vlož novou volbu,
- ostatní bity nech tak, jak byly.
Podrobné vysvětlení masek,
|=,
&= a ~ je v kapitole
Ovládání registrů.
Názorně po bitech
Představme si,
že registr PORTMUX.USARTROUTEA vypadá zjednodušeně takto:
Skupina pro USART0 jsou u ATtiny1626 bity 1 a 0.
Maska skupiny může vypadat takto:
Když ji obrátíme pomocí ~,
dostaneme nuly jen v místě skupiny USART0:
Příklad:
Změnily se jen bity 1 a 0. Ostatní nastavení v registru přežilo.
Pinmux není totéž co směr pinu
Pinmux vybírá funkci pinu. GPIO registr směru vybírá, jestli je GPIO pin vstup nebo výstup.
To jsou dvě různé otázky:
| otázka | příklad registru | význam |
|---|---|---|
| Co je na pinu připojené? | PORTMUX.USARTROUTEA | třeba UART místo běžného GPIO |
| Je GPIO vstup nebo výstup? | PORTA.DIR | směr obyčejného digitálního pinu |
| Jaká je hodnota výstupu? | PORTA.OUT | logická 0 nebo 1 |
Když pin používá UART,
program typicky nastaví pinmux
a potom ještě nastaví samotnou periferii USART0.
Když pin používá jen jako LED,
pinmux často vůbec řešit nemusí
a stačí nastavit GPIO.
Obecný postup
Když používáme periferii, která může být na více pinech, postup bývá:
- V datasheetu najít, na kterých pinech může periferie být.
- Vybrat variantu, která sedí zapojení desky.
- Nastavit pinmux registr.
- Nastavit směr pinů, pokud to daná periferie vyžaduje.
- Nastavit samotnou periferii.
U ATtiny je to dobře vidět na UARTu:
nejdřív se přes PORTMUX vybere trasa,
pak se nastaví piny PA1 a PA2,
a nakonec se nastaví registry USART0.