Új fejezet
A fejezet tartalma:Az SPI kommunikációs csatorna
Az SPI (soros periféria illesztő = Serial Peripheral Interface) busz kétirányú szinkron soros kommunikációt valósít meg két eszköz között. A kommunikációban résztvevő eszközök között master/slave (mester/szolga) viszony áll fenn. Az SPI buszt "négyvezetékes" busznak is szokták nevezni, bár az SPI kommunikáció egyes változatai 3, 5, vagy ötnél is több vezetéket használnak. Az SPI busz kiterjeszthető: egy master több slave eszközhöz is kapcsolódhat, ám a kommunikációra kiválasztott slave eszközt egyedi választó vonallal (Slave Select) hardveresen kell kijelölni.5. ábra: Több SPI eszköz kezelése külön választó vonalakkal
Az SPI busz kiterjesztésének egy másik módja az eszközök soros felfűzése (daisy chain). Ezt a módszert csak azoknál az eszközöknél használhatjuk, amelyek támogatják a felfűzést. Ilyen SPI eszközök például az AD5204 digitális potenciométerek, a MAX7219 LED vezérlő IC-k, MAX5233 dual 10-bites DAC-ok.
6. ábra: Felfűzött SPI eszközök vezérlése
Az SPI órajel polaritása és fázisa
Az SPI buszon az adatátvitel szinkronizálását a busz vezérlő eszköze (SPI master) által keltett szinkron órajel (SCK) biztosítja. Azon túlmenően, hogy a master megszabja az órajel frekvenciáját, a megszólított slave eszközhöz illeszkedően biztosítani kell az órajel megfelelő polaritását és fázisát. Az adatlapok tartalmazzák azt az információt, hogy az adott SPI eszköz milyen üzemmódban vagy üzemmódokban képes működni. Az alábbi ábrán az SPI busz jeleinek a különböző üzemmódokhoz tartozó jelalakjait szemléltetjük.SCK - Az SPI busz szinkronizálást biztosító órajele. A master eszköz állítja elő.
SS - Slave select, azaz a slave eszköz kiválasztására szolgáló jel, melynek '0' állapota aktivizál. A master eszköz állítja elő. Slave eszköz esetében az SPI modul speciális kivezetését kell használnunk az eszköz kiválasztásához, de Master eszköznél elvileg bármilyen GPIO lábat használhatunk a slave eszköz megszólítására.
MOSI - A master eszköz kimeneti adatvonala (Master out, Slave in). A master eszköz állítja elő.
MISO - A slave eszköz kimeneti adatvonala, melyet a master olvas (Master in, Slave out). A slave eszköz állítja elő.
A két, szeparált adatvezeték lehetővé teszi, hogy szinkronizáltan kétirányú kommunikáció folyjon, tehát amíg a master bitenként kiléptet egy adatbájtot a MOSI vonalon, ugyanakkor bitenként beolvas egy másik bájtot, amit a slave eszköz küldött (egy előzőleg kapott parancsra válaszul).
7. ábra: Az SPI busz jelalakjai a különböző üzemmódokban
A lehetséges üzemmódok az órajel polaritásának és fázisának kombinációjaként állnak elő. Az órajel polaritását (CPOL) egyszerű megérteni: CPOL = 0 azt jelenti, hogy inaktív állapotban SCK alacsony szintű, CPOL = 1 esetén pedig az SCK órajel inaktív állapotban magas szinten van.
A fázis (CPHA) esete valamivel bonyolultabb: CPHA = 0 esetén az adatvonalak bekapuzása az órajel páratlan számú átmenetein történik (az ábrán rózsaszín vonalakkal jelölt időpontokban). CPHA = 1 esetén pedig a páros számú átmeneteknél (kék vonalakkal jelölt időpontokban) történik az adatvonalak bekapuzása.
Fentiek alapján az órajel polaritás és fázisa az alábbi négy üzemmódot jelenti:
Üzemmód |
CPOL |
CPHA |
---|---|---|
0 |
0 |
0 |
1 |
0 |
1 |
2 |
1 |
0 |
3 |
1 |
1 |
A FRDM-KL25Z
kártya SPI perifériái
Az MKL25Z128VLK4
mikrovezérlő
két SPI modult
tartalmaz (SPI0 és SPI1), amelyek az alábbi
tulajdonságokkal rendelkeznek:- Az SPI modulok 8 bites adatformátumot támogatnak
- Az SPI0 modul órajel forrása a busz órajel, az SPI1 modulé pedig a CPU órajel.
- Az SPI modulok támogatják a DMA adatátvitelt és VLPS energiatakarékos módban is működnek (ez esetben természetesen csak slave módban). Az SPI modulok VLPS módból történő ébresztésre is képesek, amikor slave módban adatot kapnak.
- Master vagy slave módú működés
- Full-duplex vagy egyvezetékes kétirányú mód
- Programozható adatküldési sebesség (bitráta)
- Kettős pufferelésű adó és vevő adatregiszterek
- Órajel polaritása és fázisa konfigurálható (mind a négy mód beállítható)
- Automatikusan kiküldött "Slave select" jel (opcionális)
- Hibás mód jelzés fogadás és megszakításkérés (a slave jelezhet, ha nem megfelelő üzemmód lett beállítva).
- Választható bitsorrend: MSB-first vagy LSB-first kiléptetés
- Vett adat egyezésének hardveres figyelése megadott értékkel
Az SPI portok konfigurálása
A konfigurálás egyik fontos eleme, hogy kivezetéseket rendeljünk az adott perifériához. Az alábbi táblázatban láthatjuk az SPI modulokhoz rendelhető kivezetéseket. A MOSI és MISO oszlop azért közös, mert lényegében megegyeznek, a benne felsorolt kivezetések bármelyike konfigurálható MOSI vagy MISO kivezetésként.1. táblázat: Az SPI modulokhoz rendelhető kivezetések
SPI
modul |
SCLK |
MOSI/MISO |
SS |
---|---|---|---|
SPI0 |
PTA15, PTC5, PTD1 |
PTA16, PTA17, PTC6, PTC7,
PTD2, PTD3 |
PTC4, PTD0 |
SPI1 |
PTB11, PTD5, PTE2 |
PTB16, PTB17, PTD6, PTD7,
PTE1,
PTE3 |
PTB10, PTD4, PTE4 |
Azt a FRDM-KL25Z Pinouts dokumentumban találjuk meg, hogy az adott funkció kiválasztásához milyen kódot kell megadni a megfelelő portvezérlő regiszter MUX bitcsoportjába.
Az SPI modulok engedélyezése
Az SPI modulok működését a többi soros perifériához hasonlóan a Rendszer-integrációs Modul SIM_SCGC4 regiszterében lehet engedélyezni, a megfelelő bit '1'-be állításával. Az ábrán csak a regiszter második felét mutatjuk.
Az SPI modulok regiszterkészlete
Az SPI modulok azonos regiszterkészlettel rendelkeznek. Az SPI0 modul báziscíme 0x4007 6000, az SPI1 modulé pedig 0x4007 7000. Az alábbi táblázatban az SPIx regisztereknek (ahol x = 0, vagy 1) csak a báziscímekhez képesti eltolási címét (ofszet cím) adtuk meg.Ofszet cím |
Regiszter neve, funkciója |
Méret |
Elérés |
Reset |
---|---|---|---|---|
0x0000 |
SPIx_C1 control register (1. vezérlő
regiszter) |
8 bit |
R/W |
0x04 |
0x0001 |
SPIx_C2 control register (2. vezérlő regiszter) | 8 bit |
R/W |
0x00 |
0x0002 |
SPIx_BR baud rate register (adatsebesség regiszter) | 8 bit |
R/W |
0x00 |
0x0003 |
SPIx_S status register (állapotjelző regiszter) | 8 bit |
R |
0x20 |
0x0005 |
SPIx_D data register (adatregiszter) | 8 bit | R/W | 0x00 |
0x0007 |
SPIx_M match register (adategyezés regiszter) | 8 bit | R/W | 0x00 |
A konfigurációs regiszterek közül ez a legfontosabb, mivel ebben engedélyeznünk kell a modult (SPE), itt állítjuk be a master vagy slave módot (MSTR), s az órajel polaritását és fázisát (CPOL, CPHA). A konfiguráció tartamára célszerű letiltani a modult, s csak a konfiguráció legvégén állítsuk '1'-be az SPE bitet!
SPE - Az SPI modul működésének engedélyezése (0: tiltás, 1: engedélyezés)
SPTIE - Megszakítás engedélyezése ha az SPI adatküldő puffere üres (SPTEF) eseménykor (0: megszakítás tiltás - lekérdezéses mód 1: megszakítás engedélyezés)
MSTR - Master / Slave mód választása (0: slave mód, 1: master mód)
CPOL - Órajel polaritása (0: nyugalmi szint alacsony, 1: nyugalmi szint magas)
CPHA - Órajel fázisa (0: első átmenet a bitidő felénél, 1: első átmenet az első bitidő elejénél)
SSOE - Ez a bit csak master módban és a MODFEN bit '1' állapotában hatásos (0: az SS kivezetés MODFAULT bemenet legyen, 1: az SS kivezetés automatikusan kezelt SS kimenet legyen).
LSBFE - Bitsorrend választása (0: a legmagasabb helyiértékű bit megy ki először - MSB-first mód, 1: a legalacsonyabb helyiértékű bit megy ki először - LSB-first mód)
Az SPIx_C2 regiszter
A konfigurációs regiszterek közül ez kevésbé fontos számunkra, hagyjuk a RÉSET során beállított 0x00 értéken!
SPMIE - Megszakítás engedélyezése adategyezés esetén (0: megszakítás tiltás, 1: megszakítás engedélyezés)
TXDMAE - DMA adatküldés engedélyezése (0: tiltás, 1: engedélyezés)
MODFEN - Master módban "módbeállítás hiba" fogadásának engedélyezése
BIDIROE - Kétirányú mód esetén (amikor SPC0 = 1) az adatáramlás irányát állítja be (0: bemenet, 1: kimenet)
RXDMAE - Adatfogadás DMA támogatással. Ha ez a bit '1', akkor DMA átvitel történik, ha SPRF és SPE egyaránt '1'.
SPISWAI - SPI leállítása Stop módban (0: az SPI WAIT módban is működik, 1: az SPI leáll, amikor az MCU leáll)
SPCO - Kétirányú adatvonal engedélyezése (0: szétválasztott adatvonalak, 1: közös, kétirányú adatvonal)
Az SPIx_BR regiszter
Ebben a regiszterben állíthatjuk be az SPI modul órajelét (az SCK jel frekvenciáját). A 8 bites regiszter két felében egy előosztási és egy osztási arányt állíthatunk be.
SPPR - Előosztási arány (0 - 7 közötti értéket írhatunk bele)
SPR - Frekvenciaosztási arányt írhatunk bele (csak a 0 - 8 közötti értékek érvényesek!)
Például 48 MHz-es CPU frekvencia és 24 MHz-es buszfrekvencia esetén az 0x53 érték beírása az alábbi adatsebességeket eredményezi:
SPI0->BR = 0x53; // fspi = 24 MHz / (6 * 2^4) = 24 MHz/ (6*16) = 0.25 MHz = 250 kHz
SPI1->BR = 0x53; // fspi = 48 MHz / (6 * 2^4) = 48 MHz/ (6*16) = 0.50 MHz = 500 kHz
Az SPIx_S regiszter
Az állapotjelző regiszter az alábbi négy bit beállításával jelzi az SPI modulhoz kapcsolódó események bekövetkezését:
SPMF - Adategyezés jelzése. Ez a bit akkor áll '1'-be, ha beérkezett egy bájt (SPRF = 1) és a beérkezett adat megegyezik azzal, amit az SPIx_M match regiszterbe írtunk. (0: nincs egyezés, 1: egyezés van)
SPTEF - Az SPI adatküldő puffere üres, újabb írásra kész (0: az adatküldő regiszter foglalt 1: az adatregiszter felszabadult)
MODF - Üzemmód beállítási hibajelzés érkezésének jelzése (0: nem érkezett hibajelzés, 1: hibajelzés érkezett)
Az SPIx_D regiszter
Az adatregiszter íráskor és olvasáskor valójában fizikailag két, különálló regisztert ír vagy olvas. Küldéskor ebbe írjuk a kiküldendő bájtot, olvasáskor pedig ezen a címen olvashatjuk ki a beérkezett adatot. Az adat kiolvasása egyúttal automatikusan törli az SPRF jelzőbitet is.
Az SPIx_M regiszter
Ebbe a regiszterbe írhatjuk bele azt a számot, ami a hardveres adategyezés figyelésének az alapja. Ha az SPI modul által vett adat megegyezik az itt beállított értékkel, akkor az SPIx_S állapotjelző regiszter SPMF bitje '1'-be áll. Az SPIx_C2 vezérlőregiszter SPMIE bitjének '1'-be állításával megszakítást is engedélyezhetünk az adategyezési eseményhez.
Mintaprogramok
Program8_1: Adatküldés az SPI0 csatornán
Ezen az egyszerű mintapéldán keresztül bemutatjuk az SPI0 csatorna konfigurálását és az adatküldést. Hogy láthassuk is az eredményt, két 74HC595 shift regiszterből (léptetőregiszter) építettünk egy SPI perifériát, amellyel 2 db. HD1131R típusú 7 szegmenses LED számkijelzőt vezérelünk.A bemutatott kapcsolás közös anódú kijelzőkhöz készült, de könnyen átalakítható közös katódú kijelzőkhöz is.
A kapcsolást hevenyészett kivitelben egy 3x7 cm-es próbapanelon is megépíthetjük. Kicsit sok és csúnya a vezetékezés, de a hátoldalon senkit nem zavar...
Bekötések
- A 74HC595 shift regiszter soros bemenete a 14. láb (SER), kimenete pedig a 9. láb (QH*). A shift regiszterek tetszőleges hosszúságban felfűzhetők. Arra kell csak ügyelnünk, hogy n db. IC felfűzése esetén n db. adatbájtot küldjünk ki, s a küldést a láncban a legtávolabb eső IC-be küldeni kívánt bájttal kezdjük. A láncban ez első IC SER bemenetére vezetjük ki a mikrovezérlő SPI0 moduljának MOSI kimenő adatvezetékét (PTD2 kivezetés)
- A shift regiszter léptetését az SCK jel végzi, s mivel a léptetés szinkronban történik, ezt a jelet a felfűzött lánc minden tagjához el kell vinni. Ide kötjük a mikrovezérlő SPI0 moduljának órajelét (PTD1 kivezetés). Sok IC felfűzése esetén a közösített órajel miatt ezt a vonalat pufferelni kell. Esetünkben a két IC meghajtása nem okoz gondot a mikrovezérlőnek.
- Az SS (Slave Select) eszközkiválasztó jel, amit itt az RCK bemenetekre kötöttünk rá, valójában nem az eszköz kiválasztására szolgál, hanem a kiválasztó jel visszaállásakor (felfutó él) a kettős pufferelésű 74HC595 shift regiszter párhozamos kimeneti adattároló regiszterébe kapuzzuk át az adatokat. A soros regiszteren átáramló adatok tehát mindaddig nem befolyásolják a kimenetek állapotát, amíg az SS jel alaphelyzetbe nem áll (nyugalmi szintje magas). A kettős pufferelés helyes működéséhez tehát fontos követelmény, hogy csak a felfűzött regiszterek számának megfelelő adatmennyiség kiküldése után állhat vissza az SS jel alaphelyzetbe, amikor minden bit a megfelelő helyiértékre került. Ezért az ilyen, több-bájtos tranzakcióknál nem használhatjuk az SS jel automatikus vezérlését, mert az minden bájt után alaphelyzetbe állítaná azt, ami esetünkben a kijelzőn zavaró villózásokhoz vezetne.
- A 74HC595 IC 13. lába a kimenetek engedélyezésére szolgál, alacsony szintre kell húzni (mi fixen a GND-re kötöttük).
- A 74HC595 IC 10. lába (SCL) alacsony szintre húzásával az adatregisztereket törölhetnénk. Ezt a lehetőséget sem használjuk, az SCL lábakat fixen magas (VCC) szintre kötöttük.
A hétszegmenses kijelzők meghajtásához a a számjegyeket kódolni kell. A kódolást most szoftveresen oldjuk meg, egy 10 elemű táblázat segítségével. A kódolandó számjegyet indexként használjuk, s a táblázatból kiolvasott tömbelem egyes bitjei a kijelző szegmensek vezérlésére szolgálnak (a, b, c, d , e, f, g és tizedespont). például az 1-es kódja 0b01100000, tehát csak a b és c szegmens világít.
1. lista: Program8_1/main.c listája
/* program8_1: Adatküldés az SPI0 csatornán
* A program 0-tól 99-ig írja ki a számokat egy kétjegyű kijelzőre.
*
* Hardver követelmények:
* Két sorbakötött 74HC595 shift regiszter felhasználásával
* két darab hetszegmenses LED kijelzőt vezérlünk. Az általunk használt
* közös anódú kijelzők miatt a kimenő adatokat komplementálva kell kiküldeni.
*
* Arduino kompatibilis lábkiosztást használunk:
* D13 (PTD1): SPI SCK
* D12 (PTD3): SPI MISO (ebben a programban nem használjuk)
* D11 (PTD2): SPI MOSI
* D10 (PTD0): SPI SS
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Freescale_ARM_codes.htm
*
* A tankönyvi programot alaposan átdolgoztuk, csak távolról hasonlít az eredetire...
* A rendszer órajelek beállítása: CPU 48 MHz, Bus 24 MHz
*/
#include "MKL25Z4.h"
// Számjegy kódok 7-szegmenses kijelzöhöz
const unsigned char digit [10] = {
0xFC, // 0b11111100 - 0
0x60, // 0b01100000 - 1
0xDA, // 0b11011010 - 2
0xF2, // 0b11110010 - 3
0x66, // 0b01100110 - 4
0xB6, // 0b10110110 - 5
0xBE, // 0b10111110 - 6
0xE0, // 0b11100000 - 7
0xFE, // 0b11111110 - 8
0xF6}; // 0b11110110 - 9
void SPI0_init(void);
void SPI0_write(unsigned char data);
//---------------------------------------
// Késlelteto függvény 48 MHz órajelhez
//---------------------------------------
void delayMs(int n) {
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 8010; j++);
}
int main(void) {
unsigned char n, d0, d1;
SPI0_init(); // Az SPI0 modul konfigurálása
while(1) {
for(n=0; n<100; n++) {
d1 = ~digit[n/10]; // Elso számjegy szegmensei
d0 = ~digit[n%10]; // Második számjegy szegmensei
PTD->PCOR = 1; // SS aktiválása
SPI0_write(d0); // Egyesek kiküldése
SPI0_write(d1); // Tízesek kiküldése
PTD->PSOR = 1; // SS deaktiválása
delayMs(500);
}
}
}
void SPI0_init(void) {
SIM->SCGC5 |= 0x1000; // Port D engedélyezése
PORTD->PCR[1] = 0x200; // PTD1 legyen SPI SCK */
PORTD->PCR[2] = 0x200; // PTD2 legyen SPI MOSI */
PORTD->PCR[0] = 0x100; // PTD0 legyen GPIO módban
PTD->PDDR |= 0x01; // PTD0 kimenet legyen (SPI SS)
PTD->PSOR = 0x01; // Kezdetben '1' legyen
SIM->SCGC4 |= 0x400000; // Az SPI0 modul engedélyezése
SPI0->C1 = 0x10; // SPI letiltása, master mód
SPI0->C1 |= 0x01; // LSBFE = 1 (elöször LSB-t küldjük)
SPI0->C2 = 0; // Alapértelmezett beállítások
SPI0->BR = 0x54; // Baud rate = 125 kHz (/6 és /32 osztók)
SPI0->C1 |= 0x40; // Az SPI modul engedélyezése
}
void SPI0_write(unsigned char data) {
volatile char dummy;
while(!(SPI0->S & 0x20)) { } /* wait until tx ready */
SPI0->D = data; /* send data byte */
while(!(SPI0->S & 0x80)) { } /* wait until tx complete */
dummy = SPI0->D; /* clear SPRF */
}
A program által generált SPI jeleket egy logikai analizátorral is
megvizsgálhatjuk. Az egyik lehetőség erre egy PICkit2 programozó
készülék használata, ha van kéznél egy. Ennek logikai analizátor
funkciója elég korlátozott (max 1 MHz mintavételi frekvencia), de
cserébe könnyen használható. Az alábbi ábrán azt a pillanatot kaptuk el, amikor a kiküldött szám 41 volt, az ezekhez tartozó szegmensvezérlő kódok 0b01100110, illetve 0b01100000. Az SPI0 MOSI kimenentén ezt komplementálva és fordított bitsorrendben kellett kiküldeni (a kapcsolás kialakítása diktálta így). A kiküldött adatsor binárisan felírva 11111001_10011001, s ezt látjuk a logikai analizátoron is. A jelek felcímkézését és a kiolvasott adatok értelmezését (1, vagy 0) utólag szerkesztettük bele az ábrába, a jobb érthetőség kedvéért.
Program8_2: számkijelző vezérlése MAX7219 IC-vel
Ebben a programban egy Maxim Integrated MAX7219típusú LED vezérlővel ellátott, 8-digites, hétszegmenses számkijelző modult használunk, ami SPI illesztőfelülettel rendelkezik. Az előző programban használt kijelző csupán két számjegyű volt, mégis alkatrész temetőnek bizonyult, mert minden számjegyhez kellett egy-egy shift regiszter, s minden szegmenshez egy-egy áramkorlátozó ellenállás. Többjegyű (4-8 digites) kijelzők megvalósítása ilyen módon nem hatékony. Ilyen esetekben célszerű speciális LED vezérlő IC-ket használni.Az általunk használt MAX7219 IC 2x8 kimenettel rendelkezik, melyek közül SEGA, SEGB,..SEG_DP szegmensvezérlő lábak áramforrásként, a DIG0, DIG1..DIG6 számjegyvezérlő kimenetek pedig áramnyelőként működnek. Fentiekből következően közös katódú 7-szegmenses kijelzők meghajtására alkalmas. A kijelzett számjegyek, illetve képpontok száma természetesen tovább növelhető, ha több MAX7219 meghajtót felfűzünk az SPI buszra (daisy chain).
9. ábra: A MAX7219 LED vezérlő IC tokrajza és tipikus alkalmazása
A MAX7219 IC további kellemes tulajdonságai közé tartozik, hogy:
- Automatikusan korlátozza a LED szegmensek vagy képpontok áramát. Az áram értéke a 18. lábra kötött ellenállással állítható be.
- Automatikusan és hardveresen megoldja a kijelzés multiplexelését (16 lábbal nyilvánvalóan csak időosztásos rendszerben valósítható meg 56 kijelző szegmens és 8 tizedespontvezérlése)
- A kijelző fényereje 32 lépésben programozottan változtatható
- Beépített hétszegmensű kódolóval rendelkezik, ennek bekapcsolásával elegendő csak a számjegyek BCD kódját kiküldeni, a szegmensek vezérlével nem kell bajlódnunk.
- Beépített teszt mód (teszt módban minden szegmens kigyullad) és kijelző letiltási lehetőség
- FRDM-KL25Z kártya
- MAX7219 IC-vel vezérelt 8 jegyű számkijelző modul
- Dekódolás mód bekapcsolása minden számjegyre
- Multiplex vezérlés 8 számjegyre
- Közepes fényerő (17/32 kitöltés)
A főprogram végtelen ciklusában először sorra megjelenítjük a számjegyeket 0-tól 7-ig, majd egyenként kitöröljük azokat ("szóköz" beírásával).
2. lista: Program8_2/main.c listája
/* program8_2: Számkijelző vezérlése MAX7219 IC-vel
*
* A egy nyolc jegyű hétszegmenses számlálót vezérel
* MAX7219 IC-vel, ami SPI buszon kommunikál
*
* Hardver követelmények:
* MAX7219 IC, nyolcjegyű (pl. 2x4) kijelzővel
*
* Arduino kompatibilis lábkiosztást használunk:
* D13 (PTD1): SPI SCK
* D12 (PTD3): SPI MISO (ebben a programban nem használjuk)
* D11 (PTD2): SPI MOSI
* D10 (PTD0): SPI SS
*
* A program forrása: Mazidi et al., Freescale ARM Cortex-M Embedded Programming
* http://www.microdigitaled.com/ARM/Freescale_ARM/Code/Freescale_ARM_codes.htm
*
* A tankönyvi programot kibővítettük (több számjegy, dinamikus kiírás)
* A rendszer órajelek beállítása: CPU 48 MHz, Bus 24 MHz
*/
#include "MKL25Z4.h"
void SPI0_init(void);
void max7219_write(unsigned char command, unsigned char data);
void delayMs(int n);
// MAX7219 parancskódok:
#define NO_OP 0
#define DECODE 9
#define INTENSITY 10
#define SCANLIMIT 11
#define SHUTDOWN 12
#define TESTMODE 15
int main(void) {
unsigned char i;
SPI0_init(); // SPI0 konfigurálása
max7219_write(DECODE, 0xFF); // dekódolás 8 számjegyre
max7219_write(SCANLIMIT, 7); // pásztázás 8 jegyre
max7219_write(INTENSITY, 8); // Kitöltési arány = 17/32
max7219_write(TESTMODE, 1); // Teszt mód engedélyezése
max7219_write(SHUTDOWN, 1); // Megjelenítés engedélyezése
for(i=1; i<9; i++) { // Számjegyek törlése
max7219_write(i,0x0F); // Blank karakter
}
delayMs(1000);
max7219_write(TESTMODE, 0); // Teszt mód letiltása
delayMs(1000);
while(1) {
for(i=1; i<9; i++) { // Számjegyek kiírása
max7219_write(i,i-1);
delayMs(500);
}
delayMs(1000);
for(i=1; i<9; i++) { // Számjegyek törlése
max7219_write(i,0x0F); // Blank karakter
delayMs(500);
}
}
}
void max7219_write(unsigned char command, unsigned char data) {
volatile char dummy;
PTD->PCOR = 1; // SS aktiválás
while(!(SPI0->S & 0x20)) { } // TX kész jelre vár
SPI0->D = command; // Parancs küldése
while(!(SPI0->S & 0x80)) { } // Átvitel végére vár
dummy = SPI0->D; // SPRF törlése
while(!(SPI0->S & 0x20)) { } // TX kész jelre vár
SPI0->D = data; // Adat küldése
while(!(SPI0->S & 0x80)) { } // Átvitel végére vár
dummy = SPI0->D; // SPRF törlése
PTD->PSOR = 1; // SS deaktiválása
}
//---------------------------------------
// Késleltető függvény 48 MHz órajelhez
//---------------------------------------
void delayMs(int n) {
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 8010; j++);
}
//---------------------------------------
// SPI0 modul konfigurálása
//---------------------------------------
void SPI0_init(void) {
SIM->SCGC5 |= 0x1000; // Port D engedélyezése
PORTD->PCR[1] = 0x200; // PTD1 legyen SPI SCK */
PORTD->PCR[2] = 0x200; // PTD2 legyen SPI MOSI */
PORTD->PCR[0] = 0x100; // PTD0 legyen GPIO módban
PTD->PDDR |= 0x01; // PTD0 kimenet legyen (SPI SS)
PTD->PSOR = 0x01; // Kezdetben '1' legyen
SIM->SCGC4 |= 0x400000; // Az SPI0 modul engedélyezése
SPI0->C1 = 0x10; // SPI letiltása, master mód, MSB elöször
SPI0->C2 = 0; // Alapértelmezett beállítások
SPI0->BR = 0x51; // Baud rate = 1 MHz (/6 és /4 osztók)
SPI0->C1 |= 0x40; // Az SPI modul engedélyezése
}
Program8_3: 8x8 LED mátrix vezérlése MAX7219 IC-vel
Az alábbi egyszerű mintapéldában egy 8x8-as LED mátrixot vezérlünk MAX7219 IC-vel. A program az SPI periféria konfigurálásával és a MAX7219 LED vezérlő inicializálásával kezdődik. Inicializáláskor a LED vezérlő teszt üzemmódját is engedélyezzük. Ekkor minden LED kigyullad. Egy másodperc eltelte után letiltjuk a teszt üzemmódot, és nullára törölt adatregiszterekkel normál megjelenítési módba kapcsolunk (minden LED elalszik). Ezután végtelen ciklusban felváltva két karakter (H és W) jelenítünk meg.8. ábra: 8x8 LED mátrix MAX7219 vezérléssel, mint SPI periféria
Hardver követelmények:
- FRDM-KL25Z kártya
- MAX7219 IC-vel vezérelt 8x8-as LED mátrix modul
MAX7219 |
FRDM-KL25Z |
Megjegyzés |
---|---|---|
VCC |
3V3 |
Tápfeszültség (3,3 V) |
GND |
GND |
Tápegység közös pontja ("föld") |
DIN |
D11 (PTD2) |
MOSI adatkimenet |
CS |
D10 (PTD0) |
Chip select jel |
CLK |
D13 (PTD1) |
SCLK szinkron órajel |
3. lista: Program8_3/main.c listája
/* program8_2: 8x8 LED mátrix vezérlése MAX7219 IC-vel
*
* A program egy 8x8-as LED mátrix kijelzőt vezérel
* MAX7219 IC-vel, ami SPI buszon kommunikál
*
* Hardver követelmények:
* 8x8 LED mátrix MAX7219 vezérlővel
*
* Arduino kompatibilis lábkiosztást használunk:
* D13 (PTD1): SPI SCK
* D12 (PTD3): SPI MISO (ebben a programban nem használjuk)
* D11 (PTD2): SPI MOSI
* D10 (PTD0): SPI SS
*
* A rendszer órajelek beállítása: CPU 48 MHz, Bus 24 MHz
*/
#include "MKL25Z4.h"
void SPI0_init(void);
void max7219_write(unsigned char command, unsigned char data);
void delayMs(int n);
// MAX7219 parancskódok:
#define NO_OP 0
#define DECODE 9
#define INTENSITY 10
#define SCANLIMIT 11
#define SHUTDOWN 12
#define TESTMODE 15
const unsigned char minta1[]= {
0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0xFF
}; //H
const unsigned char minta2[]= {
0x1F,0x60,0x80,0x40,0x40,0x80,0x60,0x1F
}; //W
int main(void) {
unsigned char i;
SPI0_init(); // SPI0 konfigurálása
max7219_write(DECODE, 0); // Nincs dekódolás
max7219_write(SCANLIMIT, 7); // pásztázás 8 sorra/oszlopra
max7219_write(INTENSITY, 8); // Kitöltési arány = 17/32
max7219_write(TESTMODE, 1); // Teszt mód engedélyezése
max7219_write(SHUTDOWN, 1); // Megjelenítés engedélyezése
for(i=1; i<9; i++) {
max7219_write(i,0); // képpontok törlése
}
delayMs(1000);
max7219_write(TESTMODE, 0); // Teszt mód letiltása
delayMs(1000);
while(1) {
for(i=1; i<9; i++) { // 1. minta kirajzolása
max7219_write(i,minta1[i-1]);
}
delayMs(1000);
for(i=1; i<9; i++) { // 2. minta kirajzolása
max7219_write(i,minta2[i-1]);
}
delayMs(1000);
}
}
//---------------------------------------
// Adatküldés (16 bit) a MAX7219 IC-re
//---------------------------------------
void max7219_write(unsigned char command, unsigned char data) {
volatile char dummy;
PTD->PCOR = 1; // SS aktiválás
while(!(SPI0->S & 0x20)) { } // TX kész jelre vár
SPI0->D = command; // Parancs küldése
while(!(SPI0->S & 0x80)) { } // Átvitel végére vár
dummy = SPI0->D; // SPRF törlése
while(!(SPI0->S & 0x20)) { } // TX kész jelre vár
SPI0->D = data; // Adat küldése
while(!(SPI0->S & 0x80)) { } // Átvitel végére vár
dummy = SPI0->D; // SPRF törlése
PTD->PSOR = 1; // SS deaktiválása
}
//---------------------------------------
// Késlelteto függvény 48 MHz órajelhez
//---------------------------------------
void delayMs(int n) {
int i, j;
for(i = 0 ; i < n; i++)
for (j = 0; j < 8010; j++);
}
//---------------------------------------
// SPI0 modul konfigurálása
//---------------------------------------
void SPI0_init(void) {
SIM->SCGC5 |= 0x1000; // Port D engedélyezése
PORTD->PCR[1] = 0x200; // PTD1 legyen SPI SCK */
PORTD->PCR[2] = 0x200; // PTD2 legyen SPI MOSI */
PORTD->PCR[0] = 0x100; // PTD0 legyen GPIO módban
PTD->PDDR |= 0x01; // PTD0 kimenet legyen (SPI SS)
PTD->PSOR = 0x01; // Kezdetben '1' legyen
SIM->SCGC4 |= 0x400000; // Az SPI0 modul engedélyezése
SPI0->C1 = 0x10; // SPI letiltása, master mód, MSB elöször
SPI0->C2 = 0; // Alapértelmezett beállítások
SPI0->BR = 0x51; // Baud rate = 1 MHz (/6 és /4 osztók)
SPI0->C1 |= 0x40; // Az SPI modul engedélyezése
}
A max7219_write() függvény egy
kétbájtos tranzakciót haj végre: aktiválja az SS kimenetet, kiküld két bájtot az SPI buszra (regisztercím és
a regiszterbe írandó tartalom), majd inaktív állapotba helyezi az SS kimenetet.Az Init_MAX7219() függvényben adatlap szerint alaphelyzetbe állítjuk a LED vezérlőt (közben egy másodpercig engedélyezzük a teszt módot, amikor minden LED kigyullad). A fényerőt közepes szintre állítjuk be.
A végtelen ciklusban felváltva a minta1[], illetve a minta2[] tömb tartalmával töltjük fel a LED mátrixot vezérlő IC adatregisztereit, ami egy H, illetve egy W betű 8x8 pixeles rajzolatát képviseli.
10. ábra: Pillanatkép a program működéséről