Fórum témák

» Több friss téma
Cikkek » HMC6352 iránytűmodul - I2C (TWI) használata AVR-rel
HMC6352 iránytűmodul - I2C (TWI) használata AVR-rel
Szerző: Fizikus, idő: Nov 27, 2010, Olvasva: 23821, Oldal olvasási idő: kb. 11 perc
Lapozás: OK   3 / 9

I2C AVR-rel (TWI)

Az Atmel hogy elkerülje az I2C szabadalom használata miatt a Philips-nek történő jogdíjfizetést, egy saját fejlesztésű, az I2C-vel teljes mértékben kompatibilis soros kommunikációt használ a mikrovezérlőiben. Ez az ún. TWI (Two Wire Interface).

I2C Busz órajelének beállítása (SCL)

Amint azt már korábban is említettem, az I2C csak 2 vezetéket használ a buszon lévő eszközök közötti kommunikációhoz. Mivel ez a módszer soros adatátvitelt használ, ezért az I2C protokoll az eszközök közötti kommunikáció szinkronizálására órajelimpulzusokat (SCL) is küld az adatbitekkel együtt (SDA). A buszon minden egyes adatbitet egy órajelimpulzus kísér.

A legtöbb I2C eszköz 100 kHz-es SCL frekvenciával működhet, de bizonyos eszközök (mint pl a Microchip 24AA128 soros EEPROM) 400 kHz-es frekvenciával is kommunikálhatnak. Ezért ha az SCL frekvenciát 100 kHz-körüli értékre állítjuk; akkor az a legtöbb I2C eszközzel működni fog.

Az I2C-busz órajelfrekvenciáját a TWI státuszregiszterben (TWSR) lévő 2 TWPS bittel (TWI előosztás bitek) és a TWI Bit Ráta Generátor regiszterrel (TWBR) tudjuk beállítani. Ezekkel a regiszterekkel az I2C busz órajel-generátorának a leosztását adhatjuk meg. Ezzel a frekvenciaosztóval állítjuk elő az SCL vonal órajelének a frekvenciáját.

Az SCL órajel-frekvencia az alábbi képlettel számítható:

Ebből az egyenletből átrendezéssel kiszámolható TWBR értéke.

Az alábbi C kóddal állíthatjuk be az SCL frekvenciát:

  1. TWSR = 0; /* előosztas = 1 */
  2. TWBR = ((F_CPU/SCL_CLOCK)-16)/2;

AVR TWI Regiszterek

TWI Kontrol Regiszter (TWCR)

Amint a neve is mutatja, ez a regiszter vezérli a TWI periféria működését (engedélyezi/bekapcsolja a perifériát, Start jelet küld, “vettem” jelet küld (Ack), Stop jelet küld stb…).

TWINT: TWI megszakítás jelzőbit

Miután a TWI periféria befejezte az I2C kommunikáció egy lépését, A TWINT bitet a hardver frissíti (értékét 1-re állítja) és az alkalmazás (szoftver) beavatkozására vár. Amíg a TWINT jelzőbit nincs törölve, az SCL órajel alacsony állapotban marad és a TWI periféria várakozik. A TWINT jelzőbitet nem törli a hardver automatikusan a TWI-hez tartozó megszakítás kiszolgáló rutin lefutása után, ezért ezt szoftveresen nekünk kell törölni, úgy hogy értékének logikai "1"-et adunk.

TWEA: TWI nyugtázó bit engedélyezése

A TWEA bit vezérli a "vettem" nyugtázó bitek küldését amikor adatbájt érkezett a Slave eszközről.

TWSTA: TWI Start állapot bit

A mikrovézerlő egy Start jelet küld az I2C buszra, ha a TWSTA bit értékének logikai egyet adunk. A TWI hardver megvizsgálja hogy az I2C busz szabad-e, és ha igen egy Start jelet küld. Ha a busz foglalt, akkor vár a Stop jelre és utána küldi el a Start jelet. A TWSTA bitet a Start jel elküldése után szoftveresen kell törölni.

TWSTO: TWI Stop állapot bit

A mikrovezérlő egy Stop jelet küld az I2C buszra, ha a TWSTO bit értékének logikai egyet adunk. A Stop jel elküldése után a TWSTO bit automatikusan törlődik

TWEN: TWI Engedélyező bit

A TWEN bit engedélyezi a TWI működését és bekapcsolja a perifériát. Ha a TWIEN bit értékének logikai egyet adunk, akkor a TWI átveszi az irányítást az SCL és az SDA I/O lábak felett.

TWIE: TWI megszakítás engedélyezés

Ha a TWIE bit értékének logikai egyet adunk, és az SREG regiszterben az általános megszakításokat engedélyező I-bit értéke is egy, akkor a TWI megszakításkérések aktiválva lesznek amíg a TWINT jelzőbit értéke logikai egy.

TWS3..7: TWI állapotjelző bitek

Az 5 TWS bit jelzi a TWI(I2C) soros busz állapotát (a különböző állapotokhoz tartozó kódok megtalálhatóak az ATMega8 adatlap 178-184. oldalán). Vegyük figyelembe, hogy ha kiolvassuk a TWSR regiszter értékét, akkor az tartalmazza az állapotot jelző 5 TWS bitet, de az SCL órajel előosztását beállító 2 TWPS bitet is. Ezért az állapotjelző bitek ellenőrzése előtt az előosztást beállító TWPS biteket ki kell maszkolni.

TWDR: TWI adat regiszter

A Slave-re történő írás (adatküldés) esetén a TWDR a következő küldendő adatot tartalmazza. Olvasás (adatfogadás) esetén pedig a legutolsó Slave-ről fogadott adatot tartalmazza.

TWAR: TWI(Slave) cim regiszter

Ha a mikrovezérlőt mint másik Slave eszközt szeretnénk használni, akkor ebben a regiszterben tudjuk az I2C címet beállítani (a cikkben a mikrovezérlőt csak mint Master használom, ezért ezt a lehetőséget nem tárgyalom).

A TWI használata

A TWDR regiszter (TWI Adat Regiszter) végzi az ATMega8-as I2C perifériájára történő adat küldést és fogadást. Ezért egyszerűen, ezen regiszter értékének kiolvasásával vagy a regiszterbe történő írással az I2C buszon keresztül adatokat küldhetünk vagy fogadhatunk. Az ATMega8-as I2C perifériájának működését pedig a TWI Kontrol Regiszter (TWCR) és a TWI Státusz Regiszter szabályozza (TWSR).

Az ATMega8-as I2C perifériájának használatához, először engedélyezni kell azt a TWCR regiszterben a TWEN (TWI Engedélyezés) bit értékének logikai "1"-re állításával.

Az AVR-en a TWI kommunikáció bájtonként, és megszakításos alapon történik . Ez azt jelenti, hogy minden busz esemény után (pl. bájt vétele, Start jel küldése stb...) egy megszakításkérés történik. Minden alkalommal, amikor az AVR kommunikál a Slave eszközzel, és a TWI periféria befejezte az I2C kommunikáció egyik lépését, a TWSR státuszregiszter értéke frissítődik egy státuszkóddal és a TWINT megszakítás jelzőbit értékét a hardver logikai "1"-re állítja. A TWI-hez tartozó megszakítás kiszolgáló rutin lefutása után a TWINT jelzőbitet nem törli a hardver automatikusan. Amíg a TWINT jelzőbit nincs törölve, az SCL órajel alacsony állapotban marad,  a TWI periféria várakozik, és az alkalmazás (szoftver) beavatkozására vár. Ezért a szoftvernek a TWINT jelzőbitet kell figyelnie (polling) hogy a TWI buszon történő eseményeket detektálja.

A TWSR állapotregiszter értéke jelzi a TWI periféria pillanatnyi állapotát. Ezt az értéket megvizsgálva a program leellenőrizheti, hogy az adott I2C kommunikációs lépés sikeresen lezajlott-e vagy sem, és ennek függvényében dönthet arról, hogy a TWI periféria mit csináljon a következő lépésben (pl. sikeres adatküldés esetén továbblép, hiba esetén újraküldi az adatot stb...)

Ezután a szoftvernek frissítenie kell a megfelelő értékkel az összes TWI regisztert ami a következő I2C lépéshez kell (pl. adatküldés előtt a TWDR regiszterbe kell tölteni a küldendő adatbájtot). Miután minden szükséges TWI regiszter értékét frissítettük, és minden futó szoftveres feladat befejeződött, utoljára a TWCR regiszter értékét kell megadni.

A TWINT jelzőbitet szoftveresen kell törölni, mielőtt a következő I2C műveletet elkezdenénk.  Szoftveresen a TWINT jelzőbit úgy törölhető hogy értékének logikai “1”-et adunk. A TWI periféria ezután végrehajtja azt a feladatot ami a TWCR regiszterben meg lett adva.

Ez elég kuszának tűnhet első olvasásra, de egy példán keresztül talán érthetőbb lesz.

TWI (I2C) Adat Írási Művelet

Amint azt korábban láttuk, az I2C-t használó eszközökre történő írás elég bonyolult művelet, ha mindent magunknak kellene csinálni. Szerencsére az I2C kommunikációt az Atmel TWI periféria hardveresen lekezeli, ezért nekünk csak annyit kell csinálni, hogy utasítjuk a TWI perifériát és lekérdezzük az állapotát. Az egész komplex Master és Slave között lejátszódó kézfogási műveleteket (ACK/NACK stb..) a TWI periféria lebonyolítja helyettünk. Az alábbi időrendi ábra egy I2C soros EEPROM-ra történő adattárolás (írás) folyamatát mutatja:

1) A fenti ábrán látható, hogy a kapcsolatot egy START jel küldésével kezdjük. A TWCR regiszterbe írt megfelelő érték esetén a START jelet az AVR mikrovezérlő TWI perifériája automatikusan generálja.

Ha a TWCR regiszterben a TWINT=1 (megszakításjelző bit), a TWSTA=1 (start kondíció bit) és a TWEN=1 (TWI perifériát engedélyező bit) értékek beállításakor, a TWI periféria egy START jelet küld az I2C buszon, amint az szabaddá válik. Ezután addig várunk amíg a TWI periféria vissza nem jelzi, hogy sikeresen elküldte a START jelet a buszon. Ez a TWCR regiszterben lévő TWINT bit értékének a figyelésével tehető meg. (A TWI periféria ezen bit értékét logikai "1"-nek állítja be, ha a START jel elküldésre került )

  1. // START jel kuldese
  2. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
  3. // varakozas amig a jel kuldese be nem fejezodik
  4. while(!(TWCR & (1<<TWINT)));

Ez a TWI beállítás egy kicsit zavaró lehet, aktiváljuk a TWI perifériát a TWINT bit értékének logikai "1“-re történő állításával (TWINT=1), majd arra kell várnunk hogy ennek a megszakítás jelzőbitnek az értéke logikai “1“ legyen. Valójában a következő történik: amint a TWI perifériát aktiváljuk, az automatikusan reseteli ezt a megszakítás jelzőbitet (az értékét logikai "0”-ra változtatja). És amint végzett egy feladattal a TWI periféria, a megszakításjelző bitnek az értékét újra logikai “1"-re állítja. Ezért a TWCR regiszterben lévő TWINT jelzőbitet kimaszkolva és a C kódban a while feltételt használva tudunk várni addig amíg a TWI periféria végez egy feladattal, és  a TWINT bitet logikai "1"-re nem állítja.

2) A Start jel elküldése után a TWINT jelzőbit törlésre kerül és a TWSR státuszregiszterben lévő státuszkód frissítve lesz egy olyan értékkel, ami jelzi hogy a Start jel sikeresen el lett küldve.

3) Az AVR-en futó szoftvernek meg kell vizsgálnia a TWPS1 és TWPS0 bitekkel kimaszkolt TWSR regiszter állapotát, hogy megbizonyosodjon róla, hogy a Start jel sikeresen el lett-e küldve. A TWSR regiszter állapotát figyelő makró a compat/twi.h include fájlban van definiálva. Ezért ezt az előre megadott makrót használva eldönthetjük, hogy folytassuk az adatküldést, újraküldjük az utolsó adatbájtot vagy hibaüzenettel kilépjünk az I2C adatküldő rutinból (a TWI állapotregiszter teljes leírása megtalálható az ATMega8 adatlapjában).

  1. // TWI Statusz Regiszter ertekenek ellenorzese,  eloosztast beallito bitek kimaszkolasa
  2. twst = TW_STATUS & 0xF8;
  3. if ( (twst != TW_START) && (twst != TW_REP_START)) continue;

A következő feladat annak a kiválasztása, hogy melyik I2C eszközzel akarunk kommunikálni. Ez a Slave I2C címének (4 bit eszköz azonosító + 3 bit fizikai cím ) és az írást/olvasást jelző adatirány bit elküldésével tehető meg. Ehhez a szoftvernek a Slave eszköz I2C címét és az adatirányt jelző bitet bele kell írnia a TWDR regiszterbe. Ezután a TWCR regiszterben beállítjuk a megfelelő vezérlő biteket, majd töröljük a TWINT jelzőbitet, ezzel utasítjuk a TWI hardvert hogy küldje el a TWDR regiszterben lévő címet.

  1. // I2C eszkozazonosito cim elkuldese
  2. TWDR = address;
  3. TWCR = (1<<TWINT) | (1<<TWEN);

 

4) Ezután várunk a Slave eszköz válaszára.

  1. //  varakozas a kommunkacio vegezteig (a ACK/NACK nyugtazas veteleig)
  2. while(!(TWCR & (1<<TWINT)));


5) Az I2C cím elküldése után várunk a függvény által visszaadott állapotjelzésre (a TWINT jelzőbit törlésre kerül és a TWSR státuszregiszterben lévő státuszkód frissítve lesz egy olyan értékkel, ami jelzi hogy a cím sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e a cím vételét).

6) Az AVR-en futó szoftvernek meg kell vizsgálnia a TWSR regiszter értékét, hogy megbizonyosodjon róla, hogy a Slave cím sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e a cím vételét. Ha a kiválasztott Slave eszköz egy vettem jellel válaszol (ACK - acknowledge); az azt jelzi hogy az I2C Slave eszköz vette a Master által küldött címet és az megkezdheti az adatok küldését.

  1. //  TWI Statusz Regiszter ertekenek ellenorzese,  eloosztast beallito bitek kimaszkolasa
  2. twst = TW_STATUS & 0xF8;
  3. if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
  4. return 0;

Ezután a szoftvernek a Slave eszköz memóriacím felső bájtját kell beírnia a TWDR regiszterbe. Ezután a TWCR regiszterben beállítjuk a megfelelő vezérlő biteket és töröljük a TWINT jelzőbitet, ezzel utasíthatjuk a TWI hardvert hogy küldje el a TWDR regiszterben lévő adatot.

  1. TWDR = data;
  2. TWCR = (1<<TWINT) | (1<<TWEN);
  3. // varakozas amig az adatkuldes be nem fejezodik
  4. while(!(TWCR & (1<<TWINT)));

7) A memóriacím felső bájtjának elküldése után a TWINT jelzőbit törlésre kerül és a TWSR státuszregiszterben lévő státuszkód frissítve lesz egy olyan értékkel, ami jelzi hogy az adatcsomag sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e a memóriacím vételét.

8) Az AVR-en futó szoftvernek ismét meg kell vizsgálnia a TWSR regiszter értékét, hogy megbizonyosodjon róla, hogy a hogy a Slave memóriacím első fele sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e a cím vételét.

  1. // TWI Statusz Regiszter ertekenek ellenorzese,  eloosztast beallito bitek kimaszkolasa
  2. twst = TW_STATUS & 0xF8;
  3. if( twst != TW_MT_DATA_ACK) return 1;
  4. return 0;

A fentiekhez hasonlóan el kell küldeni az Slave eszköz memóriacímének alsó bájtját is.

9) Ezután a szoftvernek a Slave eszközbe írandó adatot kell beírnia a TWDR regiszterbe. Ezután a TWCR regiszterben beállítjuk a megfelelő vezérlő biteket és töröljük a TWINT jelzőbitet, ezzel utasíthatjuk a TWI hardvert hogy küldje el a TWDR regiszterben lévő adatot.

10) Az adatcsomag elküldése után a TWINT jelzőbit törlésre kerül és a TWSR státuszregiszterben lévő státuszkód frissítve lesz egy olyan értékkel, ami jelzi hogy az adatcsomag sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e az adat vételét.

11) Az AVR-en futó szoftvernek meg kell vizsgálnia a TWSR regiszter értékét, hogy megbizonyosodjon róla, hogy a hogy az adatcsomag sikeresen el lett-e küldve és hogy a Slave eszköz nyugtázta-e az adat vételét. Ha miden rendben, akkor a TWCR regiszterben a megfelelő bitekbe írt értékekkel utasítjuk a TWI hardvert hogy egy az I2C buszon küldött STOP jellel fejezze be a kommunikációt és tegye szabaddá az I2C buszt (12).

  1. /* STOP jel kuldese*/
  2. TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
  3. // varakozas amig a STOP utasitas vegre nem hajtodik es a busz szabad nem lesz
  4. while(TWCR & (1<<TWSTO));

 TWI (I2C) Adat Olvasási Művelet

Az I2C-busszal történő olvasási folyamat kicsit bonyolultabb, mert amint az alábbi ábráról látható az I2C eszközre történő írási művelet az eszközről történő olvasási műveletet is magában foglalja.

Az írási folyamatnál megmondjuk a soros EEPROM-nak, hogy melyik memóriacímről akarunk adatokat kiolvasni. Ez a folyamat az előbbiekben tárgyalt írási folyamathoz hasonló. Majd a  START jel ismételt elküldésével (RESTART) lépünk be az olvasási szakaszba. Ezután a Slave eszköz 7 bites I2C címét az olvasást jelző READ adatiránybit-tel együtt küldjük el (I2C_READ = 1). Amint a Slave eszköz visszaigazolta a vételt, a Master adatfogadási módba kapcsol. A Slave eszköz átveszi az SDA adatvonal feletti irányítást és elküldi az adatokat a kért regiszterből a Masternek. Ezután a Master beolvassa a kívánt mennyiségű adatbájtot. A Master minden bájt vételét nyugtázza egy ACK vagy NACK jellel. Az ACK-val azt jelzi, hogy az adatbeolvasás még nem ért véget és kíván még a céleszközről adatot olvasni. Amint a Master megkapta a kért adatokat, egy no acknowledge (NACK) jelet küld vissza, ezzel jelzi a slave eszköznek, hogy nem vár több adatot, az olvasási folyamat befejeződött. Végül a Master a kommunikációt egy STOP jel küldésével zárja le és teszi szabaddá az I2C buszt.

Peter Fleury TWI (I2C) könyvtára

Én a könnyebbik fejlesztési utat választottam, mert ahelyett hogy a fent vázolt lépéseket és az egész TWI-t kezelő algoritmusokat magam programoztam volna le, inkább Peter Fleury TWI (I2C) könyvtárát használtam fel (i2cMaster.zip, weboldal). Ebben a könyvtárban az a nagyszerű, hogy használatával olyan AVR-ekkel is használható lesz az I2C, amelyek nem rendelkeznek hardveres TWI perifériával. A könyvtár az alábbi fontosabb fájlokat tartalmazza:

i2cmaster.S
Az I2C assembly implementációja olyan AVR-ekre, amelyek nem rendelkeznek hardveres TWI perifériával (pl. ATTiny 24/44/84).

twimaster.c
Az I2C C nyelvű implementációja implementációja olyan AVR-ekre, amelyek rendelkeznek hardveres TWI perifériával (mint pl. az általam ebben a cikkben is használt ATMega8 is).

i2cmaster.h
I2C függvénydefiníciókat tartalmazó fejlécfájl

A könyvtár az alábbi I2C függvénydefiníciókat tartalmazza:
#define I2C_READ 1
#define I2C_WRITE 0

i2c_init()
I2C periféria inicializálása

i2c_stop()
Lezárja az adatküldést és felszabadítja az I2C buszt.

i2c_start(cím)
Startjel kiadása, majd az eszközazonosító cím és az adatirány elküldése.
Ha a függvény által visszaadott érték 0 = eszköz elérhető, 1= eszköz elérése sikertelen

i2c_rep_start(cím)
A Startjel ismételt kiadasa (Restart), majd az eszközazonosító cím és az adatirány elküldése
Bemeneti paraméter: az eszköz I2C címe és az adatirány
Ha a függvény által visszaadott érték 0 = eszköz elérhető, 1= eszköz elérése sikertelen

i2c_start_wait(cím)
A Startjel kiadasa, majd az eszközazonosító cím és az adatirány elküldése. Ha a Slave eszköz elfoglalt, addig vár amig az eszköz kész nem lesz. Bemeneti paraméter: az eszköz I2C címe és az adatirány

i2c_write(adat)
Egyetlen bájtot elküld az I2C eszköznek
Bemeneti paraméter: küldendő adatbájt
Ha a függvény által visszaadott érték  0 = adatírás sikeres, 1= adatírás sikertelen

i2c_readAck()
Egyetlen bájt beolvasása az I2C eszközről. További adat kérése sz eszközről.
A függvény által visszaadott érték: az eszközről beolvasott adatbájt

i2c_readNak()
Egyetlen bájt beolvasása az I2C eszközről. Az olvasás után a kommunikáció lezárása egy Stop jel-lel.
A függvény által visszaadott érték: az eszközről beolvasott adatbájt

Ezekkel a fügvényekkel már könnyedén megadhatóak az I2C adatírási és olvasási műveletek:

Írási műveletsor (az i2c_start_wait függvény addig vár amig nem sikerül kapcsolatba lépnie a slave eszközzel):
i2c_init();
i2c_start_wait(I2C cím+I2C_WRITE);
i2c_write(regisztercím);
i2c_write(adat);
i2c_stop();

Olvasási műveletsor:
unsigned char ertek;
i2c_init();
i2c_start_wait(I2C cím+I2C_WRITE);
i2c_write(regisztercím);
i2c_rep_start(I2C cím+I2C_READ);
ertek = i2c_readNak();
i2c_stop();

(A readNak azt jelenti, hogy csak egyetlen adatbájtot olvasunk ki, ha több adatot akaruk kiolvasni akkor az i2c_readAck() függvényt kell használni, az i2c_readNak() függvényt pedig csak az utolsó adat kiolvasásánál kell használni.)
 


A cikk még nem ért véget, lapozz!
Következő: »»   3 / 9
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem