RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
7) De I2C interface.
De firma Philips implementeerde de Inter IC of I2C bus ongeveer 20 jaar geleden voor het eerst op een aantal van hun componenten. Het is een seriëel bus protocol dat werd ontwikkeld voor de communicatie tussen geïntegreerde schakelingen. De werking en de specificaties van de I2C bus kunnen geraadpleegd worden op de website van Philips. Nu is de I2C bus wereldwijd een de-facto standaard geworden die veelvuldig toegepast wordt in embedded systemen. De I2C bus wordt voornamelijk gebruikt in embedded toepassingen waar een microcontroller met verschillende periferie componenten moet communiceren Het wordt veel gebruikt in een waaier van industriële, consumer en telecom toepassingen, als controle-, diagnose- en power management-bus. Het feit dat de I2C bus gevormd wordt door een eenvoudige tweedraads seriële bus, is de hoofdreden voor het grote succes van deze standaard. De data-overdracht snelheid was lang gespecifieerd op 100Kbits/sec. maar is nu in “fast-mode” opgedreven tot 400Kbits/sec. en in de “high speed mode” tot 3.4Mbits/sec. Philips heeft ondertussen meer dan 150 producten die voorzien zijn van een I2C bus en de standaard is ondertussen overgenomen door een 50-tal verschillende fabrikanten met meer dan 1000 verschillende I2C bus-compatibele componenten die op de markt zijn. Het brede assortiment omvat oa: A/D en D/A converters, clock/calenders, general pupose I/O chips, display drivers/controllers, EEPROM/RAM geheugens, temperatuursensoren en temperatuur/ voltage monitors, tuners, RF synthesizers, stereo decoders/sound processors, enz… Deze populaire I2C bus wordt ook toegepast op het RIOT bord, dat toelaat dat de gebruiker vanuit de IPC@CHIP SC12, verschillende I2C bus compatibele componenten aanspreekt . On board is de PCF 8583, een I2C bus compatibele Real Time Clock voorzien. De I2C bus is verder ook op CONN2 beschikbaar zodat de gebruiker ook externe I2C bus compatibele systemen kan aanspreken. Deze interface wordt ondersteund door de IIC-API vanuit het OS. We verwijzen dan ook naar de betreffende documentatie voor verdere informatie. Enkele belangrijke kenmerken van deze bus zijn: • • • • •
•
Versie 1.0
De I2C bus bestaat uit twee signalen: de seriële clock (SCL) en de seriële datalijn (SDA). De bus is bidirectioneel, en maakt gebruik van pull-up weerstanden. I2C componenten trekken de bus naar een logisch '0' niveau of staan toe dat ze naar een logisch '1' niveau wordt getrokken door de weerstanden. Data uitwisseling is gebaseerd op 8-bit woorden. Iedere component heeft een uniek adres, dat ofwel 7 bits ofwel 10 bits breed is. De bus werkt volgens het master/slave principe. Componenten kunnen master of slave zijn of beide. De bus kan ook meer dan één master hebben en voorziet arbitrage om conflicten op te lossen wanneer twee of meer masters tegelijk de bus willen controleren. Het aantal componenten dat met de I2C bus wordt verbonden is beperkt door de maximale capaciteit (lager dan 400pF) waarmee de bus wordt belast.
97
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
Meer details over de I2C bus.
We hebben de kenmerken van de I2C bus reeds even aangehaald, we gaan nu dieper in op de werking ervan. Het master/slave principe bij de I2C bus. Bij de I2C bus kunnen componenten soms master of soms slave zijn of soms kunnen ze met meerdere masters zijn die de bus willen controleren. Voor we verder gaan met de bespreking van de werking van de bus, willen we eerst nog de terminologie van de I2C bus specificatie aangeven.
Term Transmitter Receiver Master Slave Multi-master Arbitrage Synchronisatie
Tabel 7.1: Definitie van de basis I2C termen. Beschrijving De component die data op de bus zet. De component die data ontvangt op de bus. De component die de datatransfer opzet, de clock genereert en de transfer stopzet. De component die geadresseerd wordt door de master. Meer dan één master kan proberen de bus te controleren op hetzelfde moment zonder de boodschap te verminken. Een procedure om te verzekeren dat indien meer dan één master gelijktijdig de bus wil controleren, er maar één toegestaan wordt zonder de boodschap te vervormen. Een procedure om de clock signalen van twee of meer componenten te synchroniseren.
Een belangrijke eigenschap van de I2C bus is het multimaster concept waarbij verschillende componenten mogen proberen om tegelijk master te worden van de bus. Het I2C bus protocol vangt dit op door 'synchronisatie' en 'arbitrage'. Synchronisatie is het proces waardoor alle masters dezelfde clock gebruiken. Het is gebaseerd op het feit dat de clocklijn (SCL) door een pull-up weerstand wordt omhoog getrokken. Het gevolg hiervan wordt aangegeven in figuur 7.1. Het logisch SCL-lijn niveau is een 'wired-AND' functie van alle SCL signalen van de verschillende I2C componenten op de bus.
Figuur 7.1: De I2C bus is een open drain bus met wired-AND SDA en SCL lijnen. Masters genereren hun eigen clock gedurende de datatransfers. Als twee of meer masters een datatransfer proberen op hetzelfde ogenblik, zullen ze allen proberen hun clock op de SCL-lijn te plaatsen. Elke component die master wil worden en een clock genereert zal de SCL-lijn laag
Versie 1.0
98
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
trekken voor een bepaalde periode en dan de pull-up's de SCL-lijn laten hoog trekken voor een bepaalde periode. De timing hiervoor wordt door interne timers in de component afgepast. De verschillende componenten kunnen een lichtjes verschillende timing hebben voor de lage en de hoge periodes. De eerste clock die van een hoge naar een lage toestand gaat reset de clockcircuits van al de andere componenten die ook master willen worden, en laat ze beginnen met het afpassen van de tijd van hun eigen laag niveau van de clock. De component met de langste laag periode zal de SCL-lijn nog laag trekken terwijl de andere componenten de SCL-lijn reeds hebben 'vrijgegeven'. Deze component zal dus de tijdsduur van de lage periode bepalen. Wanneer de laatste component de SCL-lijn vrijgeeft en ze naar een hoog niveau wordt getrokken starten alle componenten het afpassen van de tijd van hun eigen hoog niveau. De eerste component die de SCL-lijn laag trekt laat het hele proces opnieuw beginnen. De resulterende golfvorm op de SCL-lijn is wat we noemen de gesynchroniseerde clock. Het SCL signaal wordt dus bepaald door de component met de langste laag tijd, en de component met de kleinste hoog tijd, voor het clocksignaal. Dit principe wordt verduidelijkt met figuur 7.2.
Figuur 7.2: Clock synchronisatie procedure bij de I2C bus. Het proces van arbitrage verloopt op een vergelijkbare manier. Het synchronisatieproces heeft niet uitgemaakt wie er nu master wordt van de bus, er werd enkel een eenduidige clock gedefinieerd. De SDA-lijn is op dezelfde manier (zie figuur 7.1) een wired-AND van alle individuele SDA lijnen. Net zoals elke component die master wil worden de clocklijn aanstuurt, zal deze ook data in de vorm van individuele bits op de SDA-lijn plaatsen.
Figuur 7.3: arbitrageprocedure bij twee masters.
Versie 1.0
99
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal .
Gebruikers handleiding v1.0 Indien een component een logisch hoog niveau op de SDA-lijn zet en een anders component een logisch laag niveau, zal het logisch hoog niveau geëlimineerd worden door de wired-AND configuratie. De componenten waarvan het logisch hoog niveau wordt geëlimineerd door de wired-AND verliest de arbitrage en zal geen master worden van de bus gedurende deze datatransfer. Dit wordt aangegeven in figuur 7.3. De component die als laatste een logisch hoog niveau op de SDAlijn stuurt wint dus de arbitrage, wordt de master, en kan zijn datatransfer die reeds begonnen was afmaken. Het I2C data formaat.
Bij de communicatie over de I2C bus onderscheiden we een aantal verschillende elementen.
Zo zij er: • • • • • •
De startconditie. Het adres. De read/write bit. De acknowledge of de not acknowledge bit. De data. De stopconditie.
De startconditie. De startconditie geeft het begin aan van de communicatie door de master, en ze komt steeds van de master. De startconditie bestaat uit het laag trekken van de SDA-lijn terwijl de SCL-lijn hoog is. Het adres. Het adres bestaat uit een reeks bits (7 bits in deze uiteenzetting) die een geldige waarde moeten hebben voor de stijgende flank van het SCL signaal, en nog geldig moeten zijn tijdens de dalende flank van SCL. De adresbits komen steeds van de master. De read/write bit. De read/write bit komt onmiddellijk na de adresbits en heeft dezelfde timing eigenschappen als de adresbits. De read/write bit komt steeds van de master. De read/write bit met waarde '1' geeft aan dat de master data wil lezen, de waarde '0'geeft aan dat de master data wil schrijven. De acknowledge bit. De acknowledge bit wordt gebruikt door de master en de slaves om aan te geven dat ze verder zullen communiceren. Net zoals de adresbits en de R/W bit moet deze bit de clocklijn 'overlappen'. De exacte betekenis zal aangegeven worden wanneer we het hebben over de communicatie tussen een master en een slave. Data bits. Data wordt steeds in groepen van 8 bits over de bus gestuurd, en na iedere groep wordt er een acknowledge bit voorzien. Databits moeten de clocklijn overlappen net zoals de adres, R/W en acknowledge bits. De stopconditie. De stopconditie beëindigt de communicatie en geeft aan dat de bus vrij is. Om een stopconditie te genereren laat de master de databus hoog trekken terwijl de clocklijn hoog is. De stopconditie wordt altijd door de master gegeven.
Versie 1.0
100
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
Bit transfers met 'overlapping' ( adres, data, R/W, ackn) op de I2C bus.
Start- en stopcondities op de I2C bus. Figuur 7.4: Timingdiagramma dat de start, stop en de data aangeeft in relatie met de clock. Het dataformaat voor communicatie over de I2C bus komt voor in drie vrij gelijkaardige configuraties (zie figuur 7.5), die corresponderen met drie mogelijke acties: •
De master schrijft data naar een slave. Het proces van een busmaster die schrijft naar een slave gaat als volgt: De master geeft een start conditie. De master schrijft de 7 adresbits op de bus. De master geeft de R/W bit op de bus de waarde '0'. De slave geeft een acknowledge bit (logisch 1). De master stuurt info in groepjes van 8 databits, elk gevolgd door een acknowledge bit van de slave. Dit gaat door tot de master een stop conditie aangeeft.
•
De master leest data van een slave. Het proces van een busmaster die leest van een slave gaat bijna op dezelfde manier als bij het schrijven naar een slave: De master geeft een start conditie. De master schrijft de 7 adresbits op de bus. De master geeft de R/W bit op de bus de waarde '1'. De slave geeft een acknowledge bit (logisch 1). De slave stuurt de data op de bus in groepjes van 8 bits,elk gevolgd door een acknowledge bit van de master. Wanneer de master wil stoppen met data te lezen geeft hij een 'notacknowledge' bit door op de bus (logisch 0) De master geeft een stop conditie.
•
De master schrijft eerst data naar en leest dan data van een slave. Wanneer de master zowel leest als schrijft naar een slave, is dit wat men noemt een gecombineerd formaat. Zoals de naam het zegt is dit een combinatie van de twee vorige voorbeelden (zie figuur 7.6). Als we eerst data schrijven en daarna lezen gaat het proces als volgt:
Versie 1.0
101
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
-
De master geeft een start conditie. De master schrijft de 7 ( of 10) adresbits op de bus, gevolgt door de R/Wbit (0). De slave geeft een acknowledge bit (logisch 1). De master stuurt info in groepjes van 8 databits, elk gevolgd door een acknowledge bit van de slave. Wanneer de master klaar is met schrijven, en nu wil lezen, geeft hij opnieuw de start conditie, geeft opnieuw het adres nu gevolgd door de R/W bit met de waarde '1'. De slave geeft een acknowledge bit (logisch 1), gevolgd door de data in groepjes van 8 bits. Na iedere 8 bits geeft de master een acknowledge bit (1). Wanneer de master klaar is met lezen, geeft hij een not-acknowledge (0) en stop conditie.
Figuur 7.5: Een voorbeeld van een complete datatransfer.
Figuur 7.6: Gecombineerd formaat. Een master adresseert eenslave met een 10 bit adres, stuurt data naar deze slave en leest vervolgens data van de slave. Enkele beschouwingen aangaande adressering. Eerder hebben we reeds vermeld dat elke component op de bus een uniek adres heeft. Een I2C bus product zoals de PCF8583 Clock/calender met 240 bytes RAM heeft een 7bit adres, waarvan 6 bits gelijk zijn voor elke PCF8583 component en waar één adresbit door de gebruiker kan worden ingesteld. Deze component is aanwezig op ons RIOT bord. Daar er maar één adresbit instelbaar is kunnen we maximum 21=2 dergelijke componenten op de bus plaatsen. De instelbare adresbit wordt verbonden met de voedingsspanning ('1') of de massapotentiaal ('0'). Zie figuur 7.7. Op het RIOT bord is deze adresbit op '0' geplaatst.
Versie 1.0
102
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
Figuur 7.7: Adres instelling van de PCF8583 Andere types van I2C bus producten kunnen meerdere instelbare adresbits bezitten. Indien het adres uit 10 i.p.v. 7 bits bestaat, zal een vaste bitcombinatie '11110' in het adres aangeven dat het om 10bit adressering gaat, de twee volgende adresbits geven twee MS van de tien adresbits weer. De resterende 8 LS adresbits worden in de volgende byte doorgegeven zoals wordt aangegeven in figuur 7.8.
Figuur 7.8: Een master adresseert een slave met een 10bit adres. Voor een verdere gedetailleerde bespreking verwijzen we naar de I2C bus specificatie van Philips semiconductors.
RIOT en I2C: Software. //************************************************************************** // Example of using the iic bus of the IPC@CHIP at the RIOT board. // // Created by [dp] Danny Pauwels on 01/05/2002. // This program reads the on board PCF 8583 iic RTC of the RIOT board, and // displays it on stdio. // The address of the device is hardwired to:0x1010000. // The bit following the address is the r/w bit, it should be '0' for writing // tot the device and '1' for reading it. // The internal registermap of the RTC is as follows: // 00h Control/status // 01h Hundredths of a sec. // 02h Seconds // 03h Minutes // 04h Hours // 05h Year/Date // 06h Weekday/Month // All data stored in these registers are in BCD format. // //************************************************************************** #include <stdio.h> #include <string.h> Versie 1.0
103
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
#include <dos.h> #define I2C_INT #define TCPIP_int #define RTC8583
0xAA 0xAC 0xA0
// Register structures static union REGS inregs; static union REGS outregs; static struct SREGS sregs; // TCPIP bios calls void sleep (unsigned int sleeptime) { // Give the low priority tasks a break(web server).... inregs.x.ax = 0x0900; inregs.x.bx = sleeptime; //time in msec. int86 (TCPIP_int,&inregs,&outregs); } //iic functions for the RIOT board. //I2C bus initialisatie void I2C_init (char speed) // 0-3 { inregs.h.ah = 0x80; if ((speed<0)||(speed>3)) {inregs.h.al = 0; } else {inregs.h.al =speed; } int86 (I2C_INT,&inregs,&outregs); } //I2C bus stop condition void I2C_release (void) { inregs.x.ax = 0x8400; int86 (I2C_INT,&inregs,&outregs); }
Versie 1.0
104
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal .
Gebruikers handleiding v1.0 //Scan all I2C addresses untill acknowledge detected, and return ackn. address int I2C_scan (unsigned char start_addr, unsigned char end_addr) { inregs.h.ah =0x81; inregs.h.al =start_addr; inregs.h.cl =end_addr; int86 (I2C_INT,&inregs,&outregs); return outregs.h.al; } //Transmit datablock to specified I2C address int I2C_transmit_block (unsigned char slave, unsigned char *buffer, int lenght) { inregs.h.ah =0x83; inregs.h.al =slave &0xfe; //lsb=0 for write inregs.x.cx =lenght; sregs.es =FP_SEG (buffer); inregs.x.bx =FP_OFF (buffer); int86x (I2C_INT,&inregs,&outregs,&sregs); if (outregs.x.flags & 0x01) //failure if carry is set! {return outregs.h.al; //Error code comes back } return 0; // ok code } //Receive block from specified I2C address int I2C_receive_block (unsigned char slave, unsigned char *buffer, int lenght) { inregs.h.ah =0x83; inregs.h.al =slave |0x01; //lsb=1 for read inregs.x.cx =lenght; sregs.es =FP_SEG (buffer); inregs.x.bx =FP_OFF (buffer); int86x (I2C_INT,&inregs,&outregs,&sregs); if (outregs.x.flags & 0x01) //failure if carry is set! {return outregs.h.al; //Error code comes back } return 0; // ok code } //Transmit one char to specified addres int I2C_transmit_char (unsigned char slave, char c) { inregs.h.ah =0x82; inregs.h.al =slave & 0xfe; // lsb=0 for write inregs.h.cl =c; int86 (I2C_INT,&inregs,&outregs); if (outregs.x.flags &0x01) {return (int) outregs.h.al &0x00ff; } return 0; }
Versie 1.0
105
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
//Receive one char to specified addres int I2C_receive_char (unsigned char slave,unsigned char *c,unsigned char lastchar) { inregs.h.ah =0x82; inregs.h.al =slave | 0x01; // lsb=1 for read if (lastchar) {inregs.h.cl =1; //want more char. } else {inregs.h.cl =0; //only one char. } int86 (I2C_INT,&inregs,&outregs); if (outregs.x.flags &0x01) {*c =0; return (int) outregs.h.al &0x00ff; } *c =(char) outregs.h.ch; return 0; } //Main program void main (void) { unsigned int result; unsigned char s[10]={0x00,0x80,0x00,0x00,0x00,0x00,0x83,0x85};//sendbuffer unsigned char r[10]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//receive buf unsigned char status=0x01; printf ("\n RIOT I2C bus test...\n"); printf ("\n Initialising I2C bus...\n"); I2C_init (0); printf ("Scanning for on board PCF8583 RTC...\n"); result =I2C_scan (2,0xfe); // 00,01and ff are unused addresses if (result != RTC8583) {printf ("\I2C scan error: non RTC devive found at %03xh\n",result); return; } printf ("\n RTC device found at 0x%02x\n",outregs.h.al); printf ("\n Initialising regiters to default 00:00:00 at 03/05/2002\n"); I2C_transmit_block (RTC8583,s,8); I2C_release (); s[1] =0x00; I2C_transmit_block (RTC8583,s,2); I2C_release (); printf ("\n Reading the device...\n");
Versie 1.0
106
[dp] D. Pauwels
RIOT
Remote Internet Operated Terminal . Gebruikers handleiding v1.0
while (1) { sleep (1000); //Give the low priority tasks a break... I2C_transmit_char (RTC8583,0x01); status = I2C_receive_block (RTC8583,r,6); I2C_release (); if (status==0) {printf ("RTC8583 reads: %02x/%02x/20%02x %02x:%02x:%02x r[4]&0x3f,r[5]&0x1f,(r[4]&0xc0)>>6,r[3],r[2],r[1]); } else {printf ("Error: %u",status); } I2C_release (); } }
\r",
In dit voorbeeld wordt de IIC API van de IPC@CHIP uitvoerig gebruikt met de functies: I2C_init, I2C_release, I2C_scan, I2C_transmit_block, I2C_receive_block, I2C_transmit_char I2C_receive_char. Voor de gedetailleerde informatie over de IIC API verwijzen we graag naar de info van de firma Beck (IPC@CHIP). De functie sleep van de TCPIP API wordt gebruikt om de controle voor een bepaalde tijd terug aan het RTOS te geven, zodat ook andere tasks, zoals de webserver, kunnen uitgevoerd worden. Dit is de gebruikelijke manier van werken in een userprogramma.
Versie 1.0
107
[dp] D. Pauwels