- SPI port tulajdonságai
- SPCR – SPI kontroll regiszter
- SPSR – SPI státus regiszter.
- SPDR – SPI adat regiszter
- Több master kezelése
- Példa programkódok
Az SPI átvitel az egyik leggyorsabb kommunikációs forma a vezérlők illetve SPI porttal rendelkező eszközök között, épp ezért alap felszereltség a mikrovezérlők világában. Az SPI port működése könnyedén megvalósítható szoftveres úton is, ha netán egy vezérlőben kevésnek bizonyul a beépített hardveres SPI portok száma. Azonban szoftveres megoldás esetén az átvitel ideje alatt a program nem nagyon tud más feladattal foglalkozni. Valamint a megszakítások is megzavarhatják a működést, hiszen nem szerencsés ha egy megszakítás érkezésekor az esetleges megszakítást kiszolgáló programrészek hosszú időre félbeszakítják az átvitelt.
Található a weboldalon leírás az SPI port működéséről, ezt feltétlenül érdemes átolvasni, mielőtt belekezdünk a vezérlő belső regisztereinek megismerésébe. Az SPI port működése meglehetősen egyszerű, és nincs igazán nagy jelentősége, hogy a belső regiszterek közvetlen írásával és olvasásával vagy az Arduino környezetben alapból rendelkezésre álló SPI függvényosztály metódusain keresztül használjuk. Azonban az utóbbi megoldás lényegesen könnyebben olvasható programkódot eredményez, és ez nem igazán elhanyagolható szempont. Munkámhoz kapcsolódóan kényszerültem arra, hogy az Atmel Stúdió szoftverrel C nyelven írjak programot, ez kényszerített a belső regiszterek megismerésére. Amit megtanultam, azt szeretném továbbadni!
Foglaljuk most össze, amit az SPI portról tudni kell:
- SPI kommunikációban mindig van egy master, aki az adatátvitelt kezdeményezi. A másik oldalon egy vagy több slave egység található. A master általában csak egy slave-el beszélget egyszerre, de ha a slave-nek nem kell válaszolnia csak kapja az adatokat, akkor elképzelhető más megoldás is.
- A slave csak akkor küldhet adatot, amikor a master éppen neki küld valamit. Vagyis a küldés és fogadás egyszerre zajlik. Ha a masternek nincs mit küldenie, akkor közömbös, hogy mit küld pl. lehet minden küldött bit 0.
- Az SPI átvitel minden mástól független külön hardver egységben lett megvalósítva az ATMEGA328 vezérlőben. A többi vezérlőben is ugyanez a helyzet, csak van amelyikben nem egy, hanem több hardveres SPI portot is kialakítottak. A független működés azt jelenti, hogy egy byte továbbítása illetve fogadása nem igényel külön törődést részükről, nem kell figyelni a folyamatra. Pl. a mester esetében egyszerűen csak beírjuk a küldeni kívánt adatot egy erre a célra szolgáló belső regiszterbe, és megy minden magától. Ennek leginkább a slave egységben van jelentősége, mert nem kell figyelni folyamatosan a mastert, hogy akar-e adatot küldeni. Ha küld adatot, keletkezni fog egy megszakítás annak megérkezésekor a slave vezérlőjében, és a programban gondoskodhatunk az adat felhasználásáról. Természetesen vannak nagyon buta slave egységek is, amiben nincs vezérlő és nincs program. Ott nem igaz az utóbbi megállapítás.
- Az adatcseréhez három vezeték kell. Egyiken a master küld adatot (MOSI azaz Master Output Slave Input), a másikon a slave küldi az adatokat a master felé (MISO azaz Master Input Slave Output). Ezeket a vezetékeket kell egymással összekötni, tehát MISO a MISO-val, MOSI a MOSI-val. A harmadik vezeték az órajel (CLK). Az órajelet mindig a mester állítja elő. Minden slave párhuzamosan van rákötve erre a három vezetékre, tehát minden slave minden információt egyszerre megkap, de csak az foglalkozik vele, akit a master kiválasztott.
- Az órajel fel és lefutó élének is jelentősége van az átvitel során. Az egyik él végzi a jelvezetékekről a jelszint mintavételezését, és az ellentétes él lépteti tovább az adatregiszter bitjeit. Így elegendő idő van arra, hogy a tranziensek ne zavarják meg az átvitelt. Nincs meghatározva hogy melyik műveletet kötjük a felfutóélhez, és melyiket a lefutó élhez, és az sincs, hogy ez az SS jel 0-ba váltását követő első órajel első vagy második élváltozása legyen-e az ami a mintavételt eredményezi. Ez kicsit bonyolultul hangzik, de nem az. Valójában összesen négyféle módot tudunk beállítani, amit később magyarázó idődiagrammokkal könnyen megérthetünk. Fontos azonban, hogy a master és a slave azonos módon legyen beállítva. Még nem találkoztam olyan slave egységgel, ahol ezzel foglalkozni kellett volna, de elképzelhető, hogy valamelyik „buta” slave esetében erre oda kell figyelni.
- Mivel az adatátvitelben nem lehet a slave-et megcímezni, valahogyan jelezni kell neki, hogy az adat neki szól. A negyedik vezeték (SS Slave select) célja tehát az, hogy kiválaszthassuk azt a slave-et, amelyiknek küldeni akarjuk az adatot. Ha pl. három slave is lóg a porton, akkor három kiválasztó jelvezetékre is szükség van. A hardveres SPI port kijelölt SS jelvezetékét a slave használja, ezen keresztül értesül arról, hogy kiválasztotta a master. Az SS vezeték aktív nulla szinttel működik, vagyis le kell húzni a slave SS bemenetét a kiválasztáshoz. Sajnos a szövegszerkesztőben nem találtam felülhúzás lehetőséget, ezért én most aláhúzással jelzem azt a tulajdonságot.
- Az SS slave kiválasztó jelvezetéket a master hardveres SPI portja nem vezérli amikor egy slave-el kommunikál. Természetesen az SS jelvezeték felhasználható a masterben erre a feladatra, de a felhasználói program feladata, hogy rajta a jelszinteket beállítsa. Tehát a salve SS kivezetésére a vezérlő master bármelyik digitális kivezetése ráköthető, és az általunk írt programnak kell vezérelni az adott kivezetést. Ebből következően az adatok átvitele előtt a kiválasztott slave SS jelét le kell húzni LOW szintre, és amikor befejeződött az átvitel, akkor vissza kell emelni HIGH szintre.
- A vezérlőben kialakított hardver megoldás lehetőséget ad arra, hogy egy ugyanazon SPI portra több mestert is felfűzzünk. Erre SS jelvezeték ad lehetőséget, amit adáskor a master nem használ, de ilyen esetben mégis. Erről még később esik szó.
- Mivel a master állítja elő az órajelet, a master-ben kell beállítani annak frekvenciáját. Előfordulhat, hogy egyes slave-ek nem képesek a vezérlő által kiadott maximális órajelet kezelni. Az említett ATMega328 esetében erre még nem láttam példát. Azonban a vezetékek hossza befolyásolhatja az SPI port maximális sebességét, és a tervezők gondoltak erre. Az órajel frekvenciája néhány lépésben csökkenthető egészen 125Khz-ig (feltéve, hogy 16Mhz kvarc kristályt használunk).
A fenti összefoglal alapján azt hiszem nem sok magyarázatot igényel az alábbi ábra, ami az ATMega328 adatlapjáról származik:
Talán még annyi plusz információ derül ki a leírtakon túl, hogy ugyanabba a léptetőregiszterbe írjuk bele a masternél az átvitelre szánt adatot, amibe a slave-ből megérkezik az eredmény.
Mint említettem az Arduino IDE-hez találunk függvényeket, melyek megoldják az SPI kommunikációt. Ehhez természetesen a programban el kell helyeznünk az #include <SPI.h> programsort. Ezt követőn már használhatjuk az SPI.setting(), SPI.begin(), SPI.setClockDivider(), SPI.transfer() stb. függvényeket. Nagyon kényelmes a használatuk, különösen akkor ha az alább található módon akarunk SPI kommunikációt megvalósítani! Az SPI kezelő függvényeket most nem részletezném, mert részletesen megtalálható leírásuk az arduino.cc eboldalon. Ez lenn az egyszerűbb mód, de én szeretem a nehéz és bonyolult dolgokat. Hát lássuk!
Ha nem használjuk az SPI függvényeket, akkor természetesen az átvitelhez a megfelelő regiszterekbe kell adatokat írnunk, illetve kiolvasni az eredményt. Összesen három regisztert kell megismernünk:
- SPCR – SPI kontroll regiszter, ebben állítjuk be a fő üzemmódot (master/slave) órajel frekvenciát stb.
- SPSR – SPI státus regiszter, ebben a regiszterben találjuk az átvitel állapotának jelzőbitjét, illetve a az átvitel befejezését jelző bitet.
- SPDR – SPI adatregiszter, ebbe írjuk az átvinni kívánt adatot, és ebből olvassuk ki a kapott adatokat
Lássuk hát a fenti regiszterek részletes funkcióit:
SPCR – SPI kontroll regiszter.
Ebben a regiszterben állíthatjuk be, hogy hardveres SPI portunk master, vagy slave üzemmódban működjön. Konfigurálhatjuk az órajel értelmezését (fel vagy lefutóél olvassa az adatokat), beállíthatjuk az órajel frekvenciát, és azt, hogy a továbbítás végeztével keletkezzen-e megszakítás. Ja és a legfontosabb, engedélyezhetjük vagy tilthatjuk a hardveres SPI port működést. Ha más feladatra akarjuk használni az SPI port dedikált kivezetéseit, akkor ne felejtsük el tiltani a működéséti.
A regiszter bitjeinek jelentése:
- SPIE – Ez a bit engedélyezi 1 értékkel a megszakítást az adatátvitel során. Nyilván csak akkor keletkezik megszakítás, ha az SPE bit-el magát az SPI port működést is engedélyeztük. Valamint akkor sem történik megszakítás, ha globálisan letiltottuk a megszakításokat az SPSR regiszterben.
- SPE – Ez bit engedélyezi 1 értékkel az SPI port működését.
- DORD – Ez a bit állítja be adatsorrendet. Ha 1-et írunk bele, akkor az LSB bit lép ki először, és a legutoljára az MSB. Ha azonban 0-át írunk bele az MSB lép ki először és legvégül az LSB bit (lásd később az SPDR regiszter tartalma)
- MSTR – Ez a bit mondja meg, hogy master vagy slave módban használjuk az SPI portot. Ha 1-et írunk bele, akkor master-ként fog működni. Ekkor az SS vagy más tetszőleges kivezetés (illetve kimenet) állítgatását nekünk magunknak kell megtenni! Master módban az SS akár ki és bemenet is lehet és bármire használhatjuk. Slave mód esetén az SS automatikusan bemenet lesz, és az SS-en jelzi a mster, hogy épp küldi az adatot. Persze nekünk ezzel nem kell foglalkoznunk, hisz ez magától működik.
- CPOL – Ezzel a bittel állíthatjuk be, hogy az órajel magas vagy alacsony értékénél, illetve annak fel vagy lefutó élénél zajlanak az események, azaz a mintavétel és a bitek shiftelése. Ha értéke 1, akkor az órajel magas szintje, ha 0 akkor alacsony szintje lesz aktív.
- CPHA – Az órafázisbit (CPHA) beállítása határozza meg, hogy az adatok mintavételezése az SCK első (első) vagy záró (utolsó) szélén történik-e. Kimásoltam az adatlap két idődiagrammját, hogy könnyebb legyen követni a két bit által meghatározott négyféle üzemmódot:
- SPR1 – Az a bit az SPR0-val együtt (és az SPSR regiszter SPI2X bitjével) az órajel sebességét határozza meg.
- SPR0 – Az a bit az SPR1-el együtt (és az SPSR regiszter SPI2X bitjével) az órajel sebességét határozza meg.
Órajel sebesség beállítása az SPR1,SPR0 és SPI2X bitekkel:
SPSR – SPI státus regiszter.
Ebből a regiszterből lekérdezhetjük, hogy megtörtént-e az átvitel, egy másik bit jelzi, ha átvitel közben próbáltunk újabb adatot átvinni, valamint van egy harmadik bit is található, ami még az órajel sebességét befolyásolja. A reiszter tartalmának olvasáskor a 7. és 6. bit 0-ba billen, és majd a következő átvitel fogja 1-ba billenteni amelyiket kell.
A regiszter bitjeinek jelentése:
• 7. bit – SPIF: SPI megszakításjelző
Amikor a soros átvitel befejeződött, a SPIF jelző beállításra kerül. Megszakítás jön létre, ha az SPCR SPIE be van állítva (megszakítás engedélyezve), és a globális megszakítások engedélyezve vannak. Ha az SS bemenet, és alacsony lesz, amikor az SPI Master módban van, ez beállítja a SPIF jelzőt is. Az SPIF-et a hardver törli a megfelelő megszakításkezelési vektor végrehajtásakor. Alternatív megoldásként a SPIF bit törléséhez először olvassuk be az SPI állapotregisztert SPIF beállítással, majd olvassuk az SPI adatregisztert (SPDR).
• 6. bit – WCOL: Collision flag írása
A WCOL bit akkor kerül beállításra, ha az SPI adatregiszter (SPDR) adatátvitel közben íródik. A WCOL bit (és a SPIF bit) törléséhez először be kell olvasni az SPI állapotregisztert, és ha a WCOL értéke 1, akkor lehet kiolvasni az SPI adatregisztert.
5:1. Bit – Fenntartva
Ezek a bitek az ATmega48A/PA/88A/PA/168A/PA/328/P fenntartott bitjei, és mindig nullaként jelennek meg.
SPDR – SPI adat regiszter.
Ebbe a regiszterbe kell beleírnunk az átvinni kívánt adatot. Az adatátvitel master üzemmód esetén azonnal automatikusan meg is indul, és ha végzett a master az átvitellel, akkor itt fogjuk megtalálni az érkezett adatbájtot. A master és a slave egységben teljesen azonos ennek a regiszternek a működése. Azonban slave üzemmódban beleírása nem indítja el azonnal az átvitelt, hanem várakozik amíg a master ezt meg nem teszi.
A regiszter bitjeinek jelentése:
A regiszter tartalma írható és olvasható is. Láthatjuk, hogy a 0. bit az LSB, ha LSB sorrendet állítunk be, akkor ez lép ki először és a legutoljára az MSB bit.
Több master kezelése
Ha az SPI masterként lett konfigurálva (az MSTR be van állítva az SPCR-ben), a felhasználó meghatározhatja az SS kivezetés irányát. Ha az SS kimenetként van konfigurálva, akkor a tű egy általános kimeneti tű, amely nincs hatással az SPI rendszerre. Ha az SS bemenetként van konfigurálva, akkor magasan kell tartani a SPI működésének biztosításához. Ha az SS bemenetet a a vezérlőt körülvevő áramkörök lehúzzák LOW szintre miközben az SPI master-ként lett beállítva, az SPI rendszer ezt úgy értelmezi, hogy egy másik master választja ki az SPI-t slave-ként, és elkezdi küldeni az adatokat neki. A buszversengés elkerülése érdekében az SPI rendszer a következő műveleteket hajtja végre:
1. Az MSTR bit az SPCR-ben törlődik, és az SPI rendszer slave lesz. Az SPI slave-é válásának eredményeként a MOSI és SCK tűk bemenetekké válnak.
3. Ha megérkeztek az adatok az SPSR-ben bebillen az SPIF-jelző, és ha az SPI-megszakítás engedélyezve van, a megszakítás rutin végrehajtásra kerül.
4. A megszakításnak mindig ellenőriznie kell (ha fennáll a lehetőség, hogy másik master is van az SPI buszon), hogy az MSTR bit még mindig be van-e állítva. Ha az MSTR bitet törölte egy slave select (1. pont szerint), akkor a felhasználónak újra be kell állítania az SPI Master módot a MSTR bit bebillentésével. Annak eldöntése, hogy a Master mód újra beállítható-e, azt a megszakítás rutinban a felhasználói szoftvernek kell eldöntenie.
Példa programkódok:
Lássunk néhány egyszerű példát az SPI port használatára. Első lépésben természetesen engedélyezni kell az SPI portot, és be kell állítani, hogy master vagy slave üzemmódbon fogjuk használni. Valamint be kell álltanunk a port órajelének frekvenciáját, és hogy keletkezzen-e megszakítás az átvitel befejezésekor. Az alábbi kódrészlet egy master üzemmódot állít be és elindítja az átvitelt (a slave select funkciójú kimenet vezérlését nem tartalmazza a kód):
// SPI engedélyezése , Master üzemmód, órajel beállítása fck/16 és nincs megszakítás SPCR = (1<<SPE)| (1<<MSTR)| (1<<SPR0); // adat megadása és átvitel indítása SPDR = mData; //ahol mData az átvinni kívánt adat // Várakozás az átvitel befejezésére az SPSR regiszter SPIF bitjének vizsgálatával while(!( SPSR & (1<<SPIF))); // A slave által küldött adatot ekkor az SPDR regiszterből lehet kiolvasni
Az alábbi kódrészlet a slave beállításait és általa küldött adat beírását mutatja:
// SPI engedélyezése, Slave üzemmód SPCR = (1<<SPE); // slave által küldött adat beírása adatregiszterbe SPDR =slData // ahol slData a slave által küldött adat // Várakozás az átvitel befejezésére while(!(SPSR & (1<<SPIF))); // a master által küldött adatot ekkor a SPDR regiszterből lehet kiolvasni