Přeskočit na hlavní obsah

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:

  1. smažou se staré bity, které říkají, kudy je vyvedený USART0,
  2. 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 bitů pro USART0
jinájinájinájinájinájináUSART0USART0
význam
00000011

Skupina pro USART0 jsou u ATtiny1626 bity 1 a 0. Maska skupiny může vypadat takto:

Maska skupiny USART0
76543210
USART0_gm
00000011

Když ji obrátíme pomocí ~, dostaneme nuly jen v místě skupiny USART0:

Obrácená maska skupiny
76543210
~USART0_gm
11111100

Příklad:

Vyčištění staré volby a vložení ALT1
76543210
původní
10101011
~USART0_gm
11111100
po &
10101000
ALT1
00000001
výsledek
10101001

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ázkapříklad registruvýznam
Co je na pinu připojené?PORTMUX.USARTROUTEAtřeba UART místo běžného GPIO
Je GPIO vstup nebo výstup?PORTA.DIRsměr obyčejného digitálního pinu
Jaká je hodnota výstupu?PORTA.OUTlogická 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á:

  1. V datasheetu najít, na kterých pinech může periferie být.
  2. Vybrat variantu, která sedí zapojení desky.
  3. Nastavit pinmux registr.
  4. Nastavit směr pinů, pokud to daná periferie vyžaduje.
  5. 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.