pondělí 28. června 2010

Rozhraní SPI

Líbí se mi. Je jednoduché a elegantní.

Master se dá velmi jednoduše SW emulovat (např. pokud regulérní spi piny už využíváme k něčemu jinému). Chceme-li vysílat, prostě jen generujeme hodiny a k nim fázově posunutá data, toť vše. Slave dokonce ani nemusí být procesor, postačí posuvný registr. To může být šikovné např. pro buzení LEDek (shift registr s paralelním výstupem) nebo pro snímaní tlačítek (shift registr s paralelním vstupem).




Jedná se o synchronní komunikaci, přenáší se tedy i hodniny. To kromě vodiče navíc přináší samá pozitiva a sociální jistoty. U takového UARTu se totiž nezávisle generují (nastavují) hodiny u vysílače i přijímače. Tyto hodiny musí být zpravidla danné, přesné a neměnné. Už drobné rozhození časování může vést ke zhroucení celé komunikace. Při SPI generuje hodiny jen MASTER a na jejich kmitočtu a přesnosti nezáleží. Rychlé, pomalé, nejdřív rychlé potom pomalé nebo naopak, nic z toho nám neohrozí komunikaci. S pomalými zařízeními komunikujme pomalu, s rychlými rychle.

Narozdíl od I2C, CAN a dalších se SLAVE nevybírá adresou ale zvláštními vodiči SS (slave select) – viz obrázky. Tím SPI dosahuje nejštíhlejšíhpo možného protokolu, přenáší jen data a v tomto ohledu nemá mezi synchroními kolegy konkurenci. Platí za to daň v podobě SS vodičů navíc, jejich počet je roven počtu SLAVE jednotek v síti.

(Na druhou stranou při vývoji slouží tyto vodiče jako výborný pomocník při odhlalovaní problémů a chyb, máme jednoznačnou identifikaci, který SLAVE je právě vybrán. To je určitě pohodlnější než hledat v posílaných datech adresu SLAVE jednotky. Já osobně pokud budu mít na výběr a najdu nějáký ten volný pin procesoru pro SS vodiče, vždy použiji pro komunikaci s periferií SPI rozhraní.)



Realizace SPI v kódu je poměrně jednoduchá, máme k dispozici jeden společný registr pro vysílání i příjem. Vše je patrné z obrázku nahoře, MASTER zapsáním do registru vydá povel, následně se vygeneruje 8 hodinových cyklů a díky obousměrné komunikaci se provádí příjem i vysílání zároveň. Pokud chceme jenom přijímat, vysíláme zpravidla hodnotu (0×FF), kterou
SLAVE zahodí. Pokud naopak chceme jen vysílat, přijmutá data v registru ignorujeme.

U AVR by pro jednotku MASTER vypadal kód nějak takhle…

funkce pro inicializaci
void SPI_MasterInit(void)
{
    // Set MOSI and SCK output, all others input
    DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
    // Enable SPI, Master, set clock rate fck/16
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}

funkce pro vysílání a příjem
unsigned char SPI_MasterTransmit(unsigned char data)
{
    SPDR = data;
    while ((SPSR & (1<<SPIF)) == 0);
    return SPDR;
}

vysílání
SPI_MasterTransmit('A');

příjem
unsigned char data;
data = SPI_MasterTransmit(0xFF);

Žádné komentáře:

Okomentovat