Der I²C-Bus als Verbindung zwischen Linux und HeimelektronikBits im Gänsemarschvon Simon G. Vogl |
Der I²C-Bus wurde ursprünglich von Philips zur digitalen Steuerung
von Fernsehern entwickelt. Seither jedoch hat sich dieser Bus in allen
möglichen Anwendungsgebieten breitgemacht, und ist in fast jeder Nische
zu Hause.
Die Anbindung von IC's erfolgt über zwei Leitungen, namentlich eine
Daten- und eine Steuerleitung (SDA & SCL), Informationen werden synchron
zum Takt mit maximal 100 kHz übertragen (in Erweiterungen sind bis
zu 400 kHz möglich). Dadurch daß keine fixe Übertragungsfrequenz
eingehalten werden muß, kann man im Zweifel Daten nur dann übertragen,
wenn man gerade dazu Zeit hat.

Abbildung 1: Übertragung - Beispiel (Start + Adresse)
Um nun Daten an ein IC über den Bus zu schicken, geht man wie
folgt vor:
Ist der Bus frei, erzeugt der Master eine sogenannte Start-Bedingung, die
die Interfaces aller am Bus befindlichen IC's initialisiert und empfangsbereit
macht.
Dann sendet der Master die Adresse des Chips, mit dem er kommunizieren
will. Diese besteht aus 7 Bits und wird zuerst übertragen, gefolgt
von einem Richtungsindikator, der angibt, ob der Master auf das IC schreiben,
oder von ihm lesen will. Da wir schreiben wollen, bleibt es auf Null.
Fühlt sich ein Slave angesprochen, d.h. seine Adresse stimmt mit der
gesendeten überein, so zieht er im darauffolgenden Takt die Datenleitung
auf low, um anzuzeigen, daß er gespprächsbereit ist. Manche
Schaltungen sind so ausgelegt, daß sie ihren Bus-Teil abschalten,
solange sie mit internen Verarbeitungsaufgaben beschfätigt sind. Es
kann sich also lohnen, öfter mal nachzufragen.
Da wir senden wollten, übertragen wir jetzt die Daten Byte für
Byte. Nach jeweils 8 Bit mit Daten muß, wie nach der Adresse auch,
ein Acknowledge-Bit gelesen werden, das anzeigt, ob die Aktion erfolgreich
war.
Um den Transfer dann zu beenden, erzeugt der Master schließlich auf
dem Bus eine Stop-Bedingung, wonach der Bus wieder frei ist.
Will der Master hingegen von einem Chip lesen, liegt die Sache etwas
anders:
Zum ersten muß das Schreib-Lese Bit auf 1 gesetzt werden. Zweitens
ändert sich die Übertragungsrichtung der Daten: Zwar gibt der
Master immer noch den Takt vor, nach der Adresse ist aber sein Leitungstreiber
inaktiv, und er liest den jeweiligen Zustand der Leitung in sein Datenregister.
Auch das Acknowledge-Bit wird nun anders herum verwendet: Solange man weitere
Daten einlesen will, legt man ein low auf die Datenleitung. Hat man das
letzte benötigte Byte gelesen, beläßt man die Leitung auf
high.
Wie aber, stellt sich hier nun die Frage, weiß man ob der Bus frei
ist? Nun, in den meisten Fällen gibt es nur einen Master am Bus, nämlich
den Computer, daher ist der Bus immer frei, außer er ist selbst gerade
mit Datenübertragung beschäftigt.
Es können jedoch durchaus mehrere Master am Bus hängen, wie etwa ein Mikrocontroller im Fernseher, die die Sachlage etwas verkomplizieren. Korrekterweise muß man hier immer ein Ohr am Bus haben und die Start- und Stop-Bedingungen mitzählen, um sicher zu sein, daß der Bus frei ist. Bei derartigen Applikationen wird man meist einen eigenen Interface-Adapter wie den PCF 8584 oder einen billigen Mikrocontroller für diesen Zweck abstellen. Diese können den Computer dann auch noch zusätzlich entlasten, indem sie Teile des Protokolls selbstständig abwickeln.
Nun bleibt nur noch ein Sonderfall zu behandeln, um die volle multi-master Fähigkeit des Busses zu erreichen: Es kann passieren, daß der Bus zwar frei ist, jedoch zwei Master gleichzeitig eine Start-Bedingung generieren. Man braucht also man einen Mechanismus, der in einem solchen Fall einen Datenverlust verhindert. Möglich wird das durch die `wired and` Schaltung der Bus-Leitungen: Beginnen zwei Master gleichzeitig zu übertragen, so verliert der das Rennen, der den Bus auf high beläßt, während der andere den Bus auf low zieht, und muß den Bus sofort ohne weiteren Zugriff freigeben. Ermöglicht wird dies durch die Open-Collector-Ausgänge der Bus-Pins.
Zusätzlich ist der Bus multi-master fähig, d.h. es lassen sich mehrere Mikrocontroller oder Computer an einen Bus hängen. Möglich wird das durch eine `wired and` Schaltung: Beginnen zwei Master gleichzeitig zu übertragen, so verliert der das Rennen, der den Bus auf high beläßt, während der andere den Bus auf low zieht. Ermöglicht wird dies durch die Open-Collector-Ausgänge der Bus-Pins.
Damit man nicht nur ein IC eines Typs am Bus haben kann, sondern bei Bedarf mehrere, liegen bei den meisten die unteren Bits ihrer Adresse auf freien Pins am Gehäuse an. Dadurch kann man mit ein paar Jumpern bis zu acht oder noch mehr IC's der selben Bauart an den Bus hängen.
Daraus, und der Tatsache, daß die Adressen nur sieben Bit lang sind, ergibt sich ein ziemliches Gedränge im Adressraum. Tatsächlich gibt es kaum eine der 112 möglichen Nummern - zwei Achterblöcke sind reserviert - die nicht doppelt oder dreifach belegt sind.
Aus diesem Grund wurde ein erweiterter Addressierungsmodus eingeführt,
der 10 Bit breite Adresssen erlaubt. Jedoch sind noch nicht viele ICs mit
einer solchen Adresse gesichtet worden, bedeutet dies doch einen erheblichen
Mehraufwand in der Dekoderhardware.
Zur Anbindung des I²C-Busses benötigt man nur einen freien
Druckerport, ein TTL IC, ein paar Widerstände und ein kleines Stück
einer alten Lochrasterplatine. Das IC trennt den bidirektionalen Bus in
zwei Eingangs- und zwei Ausgangsleitungen, und wird am besten auf einen
billigen IC-Sockel gesetzt.
Abbildung 2: Schaltplan des Adapters
Als letzte Frage bleibt nur noch offen: Woher 5 Volt nehmen und nicht stehlen?
Wer sich kein eigenes Netzgerät leisten will, kann ja mal in seinem
Computer Ausschau halten. Meist pendelt da an der Stromversorgung einer
Floppy oder Festplatte ein Kabel, das 5 Volt für LED-Anzeigen oder
ähnliches Zubehör bereithält. Im Zweifel schafft ein Multimeter
Gewißheit, bevor man Chips grillt. Hat man hier kein Glück,
kann man sich noch am Joystick-Port bedienen, oder die Tastatur anzapfen.
Hiebei wirkt eine DIN-Audio Verlängerung oft Wunder.
Ist der Adapter aufgebaut, kann man im Makefile des Treibers auswählen,
welche Hardware man möchte, und ihn schließlich compilieren.
Wenn man ihn zum ersten Mal installiert, wird auch noch ein mknod /dev/i2c0
c 63 0 notwendig, und schließlich muß man das Modul mit
insmod i2c noch laden.
Anfänglich suchte ich mir einen möglichst einfachen character-device
Treiber im Linux-Kernel heraus, den ich dann für meine eigenen Zwecke
umschrieb. Dadurch hatte ich sofort ein grundgerüst, daa das Laden
zur Laufzeit ermoglichte.
Am Anfang war ich natürlich in erster Linie daran interessiert, meine
Installation zum Laufen zu bringen, danach erst machte ich mir Gedanken
darüber, wie wohl verschiedene Adapter zu berücksichtigen seien.
In der jetzigen Form teilt sich das Modul in mehrere Schichten, wie aus
untenstehender Abbildung zu ersehen ist.
Abbildung 3: Architektur des Treibers
Das Kernel Interface stellt die Schnittstelle zwischen Anwendung und Treiber
dar. Sie wird über die Device-Dateien angesprochen. Ihre Aufgabe besteht
im wesentlichen darin, Anfragen an die unteren Schichten weiterzuleiten,
globale Informationen zu verwalten, und den Treiber zu initialisieren.
Die Algorithmus-Schicht entstand aus der Notwendigkeit, verschiedene Arten
von Adaptern unterstützen zu müssen, für die man aber unterschiedliche
Zugriffs-Algorithmen braucht. Bei den meisten Karten, die über den
Bus angesprochen werden, wird direkt der Zustand der Leitungen verbogen,
wie auch unser Adapter das macht. Professionelle Lösungen jedoch verwenden
eigene Port-Bausteine, die einen Großteil des Protokolls automatisieren.
Die HAL (Hardware Abstraction Layer)-Schicht schließlich
implementiert die geräteabhängigen Befehle, die notwendig sind,
um eine konkrete Zustandsänderung am Bus zu erreichen, da es einen
Unterschied macht, ob auf ein Register am ISA-Bus zugegriffen werden soll,
oder ob eine Leitung an der Druckerschnittstelle verändert werden
soll.
Diese Aufteilung mag zwar allzu akademisch erscheinen, sie erlaubt allerdings
die größtmögliche Flexibilität beim Einbinden neuer
Hardware. Meist ist eine so vielschichtige Betrachtungsweise nicht notwendig,
da man oft nicht mehr als einen Adapter hat. Deshalb habe ich die Funktionen
der untersten Schicht, je nach Anzahl der im Makefile definierten Interfaces,
automatisch inline definiert, sodaß fast immer auf einen extra Funktionsaufruf
verzichtet werden kann. Auch wenn die Geschwindigkeitsanforderungen eine
solche Optimierung nicht unbedingt erforderlich machen, ist es doch ein
ganz angenehmer Nebeneffekt, denn schließlich möchten ja auch
noch mal andere Prozesse an den Prozessor.
Will man nun beispielsweise wissen, wie kühl das Bier (Limo, resp.)
ist, das im Kühlschrank auf einen wartet, so braucht man nur einen
kleinen Temparatursensor an den I²C-Bus hängen.
Für so einfache Meßaufgaben genügt ein unkomplizierter
Sensor wie der LM 75 von National Semiconductors, auf den ich hier kurz
eingehen möchte. Der Chip kommt ohne externe Beschaltung aus, und
erreicht mit einem 9-Bit A/D-Wandler auf eine Auflösung von 0.5°
Celsius.
Abbildung 4: Pin Layout des LM 75
Die einzige Herausforderung besteht darin, daß es den Sensor nur
in SMD - Ausführung gibt, man muß also beim Löten etwas
genauer schauen und relativ zügig sein. Um eine ausreichende mechanische
Stabilität zu erreichen, sollte man den Chip am Kabel mechanisch fixieren.
Ansonsten kann es passieren, daß ein unvermuteter Zug an einem Kabel
das zugehörige Bein im Nu abreißt. Gießt man das Ganze
wasserdicht ein, kann man den Sensor auch unter Wasser verwenden.
Ähnliche Sensoren werden unter anderem auch von Dallas angeboten. Sie sind vom Beschaltungsaufwand her ähnlich einfach, wenn auch die Auflösung - i.e. Anzahl der Bits/Temparatur - variiert. Dies ist jedoch meist nicht von allzugroßer Bedeutung, da die Hersteller für die meisten Wandler eine Genauigkeit von +/- 2 Grad garantieren.
| Listing 1: temp.c |
#include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <stdio.h> #include "i2c.h" #define LM75 144 int main(int argc,char** argv) {
int f = open("/dev/i2c0",O_RDWR);
char buf[2];
if (f>0) {
ioctl(f,I2C_SLAVE,LM75);
if (-1 == read(f,buf,2)) {
printf("read error.\n");
} else { /* calc. temparature*/
int temp = buf[0]*256+buf[1];
temp >>=7;
if (temp>512)
temp &= -1;
printf("%g Grad Celsius\n", (float)temp/2.0);
}
}
return close(f);
}
|
Zum Auslesen der aktuellen Temparatur braucht man nur ein kleines Programm,
wie im Kasten temp.c angeführt. Die Daten werden in den oberen
9 Bits der ersten beiden Bytes übertragen, man muß also ein
wenig herumschieben, bis man das Endergebnis hat.
Wer das Ganze in einer Schleife machen will, sollte bedenken, daß
der LM 75 nur 10 Mal in der Sekunde wandelt. Wenn man seine Register vorher
ausliest, bekommt man die alten Werte, und er fängt wieder von Neuem
zu rechnen an.
Neben dieser reinen Akquisitionsfunktion bietet der LM 75 auch noch die
Möglichkeit, als Thermostat zu funktionieren. Dazu besitzt er einen
Open-Kollektor Ausgang, der normalerweise high ist. Dieser kann in zwei
Modi angesteuert werden:
Entweder man setzt ihn als temparaturgesteuerten Schalter ein, der sich
ab dem Überschreiten einer gewissen Mindesttemparatur aktiviert, und
erst unterhalb einer zweiten Temparaturschranke wieder ausschaltet; so
lassen sich beispielsweise Lüfter oder Heizelemente steuern.
Oder aber man betreibt ihn in einem Interrupt-Modus betreiben, wobei bei
jedem Über- bzw. Unterschreiten der gesetzten Schranken ein Low-Impuls
am Ausgang erzeugt wird. Den könnte man etwa an den Ack-Eingang des
Parallelports hängen, der ja bekanntlich Interrupts generieren kann.
Will man aber nun mehr als ein Gerät steuern, oder bloß ein paar LED's zur Anzeige verschiedener Zustände ansteuern, so kommt man um einen PCF 8574 nicht herum. Dises IC erlaubt die Ansteuerung von acht Ausgängen, die stark genug sind, um direkt ein LED treiben zu können.
Da man sowieso nicht zu lange vor seiner Kiste sitzen sollte, und Entspannung
allgemein positiv für Geist und Körper ist, möchte ich hier
noch ein eher esoterisches Abschlußprojekt vorstellen: Eine einfache,
aber dennoch effektive, Mind-Machine. Im Vergleich zu im Handel erhältlichen
Geräten hat diese zwei Vorteile: Einerseits beträgt der Preis
einen Bruchteil, andererseits ist der Tragekomfort höher, da meist
ein vergleichsweise breites Flachbandkabel verwendet wird.
| Mind-Machines & Co. |
Mind- oder auch Brain-Machines sind Geräte, die im Benutzer eine tiefe Entspannung oder einen Meditationszustand im Benutzer hervorrufen können. Diese wird durch die sogenannte Frequenz-Folge-Reaktion (FFR) hervorgerufen, der Fähigkeit des Gehirns, sich auf eine, von außen einwirkende Frequenz einzustellen. Dieser Effekt ist seit alters her bekannt und wird in den unterschiedlichsten Kulturen verwendet, von Schamanentrommeln bis zu den Stroboskopen in den Techno-Tempeln. Wie EEG-Messungen zeigen, arbeitet das Gehirn bei normalem Wachzustand hauptsächlich im sogenannten beta-Bereich (von ca. 12-30 Hz), bei Entspannung mit alpha-Wellen (8-12 Hz), bei Schalf mit delta-Wellen ( - 4 Hz ). Dazwischen liegt noch eine Übergangsphase, die man im Halbschlaf mit 4-8 Hz erlebt, und die mit theta bezeichnet wird. Es werden verschiedene Techmiken eingesetzt, die das Gehirn dazu anregen sollen, auf einer bestimmten Frequenz zu arbeiten. Die wohl am weitesten Verbreitete ist eine Kombination aus optischen und akustischen Signalen. Es sind allerdings auch Geräte am Markt, die mit elektrischen Reizen arbeiten, und über Elektroden, beispielsweise in Ohrclips, die Nerven direkt reizen. Daneben gibt es natürlich auch noch eine Reihe anderer Methoden, die benutzt werden, wie der Einsatz von Magnetfeldern, und ähnlichem. Ob sich dieser Aufwand allerdings lohnt, sei dahingestellt. Eines haben aber alle diese Systeme gemeinsam: Sie können den Benutzer zwar darin unterstützen, sich zu entspannen, dies aber nicht erzwingen. Wenn man nicht will, dann funktioniert´s auch nicht. |
Epileptikern sei allerdings von der Benützung dringend abgeraten! Da die flackernden Lichter einen Anfall auslösen könnten, ist Epileptikern dringend davon abzuraten, dieses oder ähnliche Geräte zu benutzen. Ansonsten sind jedoch keine negativen Auswirkungen auf Leib oder Seele bekannt.
Alles was dazu nötig ist, ist eine alte Brille (ich verwende eine
ausrangierte Sonnenbrille mit großem Visier), ein PCF8574, acht LED's,
ebensoviele Widerstände ( a 330 Ohm), und schließlich noch genug
vierpoliges Kabel, um vom Computer bequem bis zu einem Sessel oder Bett
zu kommen. Die einzige Anforderung, die der Sehbehelf erfüllen sollte,
ist, daß er bequem sitzen sollte - Ziel soll ja Entspannung sein.

Abbildung 5: Pin Layout des PCF 8574
Als erstes ersetzt man die Gläser der Brille durch dünnen
Karton, oder ein ähnlich leicht bearbeitbares Material. Am einfachsten
ist es, ihn an der Oberkante mit Klebestreifen zu fixieren, dann die Kontur
der Brille mit einer Schere nachzuschneiden, und schließlich auch
noch die anderen Seiten anzukleben.
An dieser Stelle sollte man sich nun Gedanken über die Posititon der
vier LED's pro Seite machen. Je nach Geschmack können diese weiter
außen oder innen liegen, im Quadrat oder als Karo; der Experimentierfreude
sind hier keine Grenzen gesetzt. Sie sollten nur in etwa symmetrisch um
das Auge angeordnet sein.
Zur Fixierung der LEDs eignen sich die im Handel erhältlichen Einbauhülsen
am Besten, da man sie im Zweifelsfall auch wieder abmontieren kann, wenn
die Position nicht paßt.
Um den Chip beim Einlöten zu schonen, ist es ratsam ihn zu sockeln.
So kann man den Sockel beruhigt im Karton mit umgeknickten Kontakten verankern,
ohne viel zu verlieren, wenn man später auf ein anderes Design umstiegen
möchte. Wer versehentlich verbogene Füßchen vermeiden will,
der drücke erst den Sockel so auf den Karton, daß leichte Vertiefungen
entstehen, welche man dann mit einer dickeren Nadel durchstoße. Wer's
ganz nach Norm haben will, kann auch ein Stück Lochrasterplatine als
"Bohrmaske" verwenden. Dabei kann man dann nebenn dem eigentlichen
IC gleich noch Löcher für die Kabel bohren.
Beim Anlöten der LED's sollte man unbedingt auf die richtige Polarität
achten, da das LED sonst dunkel bleibt. Im Zweifel kann man sich darüber
Gewissheit verschaffen, indem man es, bei nicht aktivem Bus, zwischen SDA
oder SCL und Masse hält. Die Anode der LED's werden mit dem Widerstand
an die Versorgungsspannung gelegt, die Kathode an den jeweiligen Ausgang
des Chips. Ist man mit dem Einsetzen der Beleuchtung fertig, kann man sich
noch vergewissern ob alles richtig ist, indem man einsteckt und jede der
Steuerleitungen an Masse legt.
Damit das Versorgungskabel beim Tragen nicht stört, und gleichzeitig
als Zugentlastung, befestigt man es am Besten entlang eines der Bügel
der Brille.
| Listing 2: shades.c |
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/mc146818rtc.h>
#include <sys/ioctl.h>
#include "i2c.h"
#define L_UP 0x80 /* ____________ ____________ */
#define L_DN 0x40 /* / ~--~ \ */
#define L_LT 0x20 /* | L_UP R_UP | */
#define L_RT 0x10 /* | L_LT L_RT __ R_LT R_RT | */
#define R_UP 0x08 /* \ L_DN / \ R_DN / */
#define R_DN 0x04 /* \__________/ \__________/ */
#define R_LT 0x02
#define R_RT 0x01
typedef struct _Pattern {
int length;
char bits[0];
} Pattern;
Pattern pattern1= { 4,
{ L_UP|L_DN|R_DN|R_UP, 0,
L_LT|L_RT|R_LT|R_RT, 0, } };
Pattern pattern2 = { 4,
{ L_UP|R_UP, L_LT|R_RT,
L_DN|R_DN, L_RT|R_LT, } };
int i2c, rtc;
int blinky (int times, int count, Pattern p)
{
int i,j=0,idx=0;
unsigned long data;
char buf[1];
for (i=0;i<times;i+=j,j=0) {
while (j < count) {
read(fd, data, sizeof(unsigned long));
j += data >> 8;
}
buf[0] = 0xff - p.bits[idx++];
idx %= p.length;
write(i2c,buf,1);
}
}
int main(void)
{
int count;
i2c = open("/dev/i2c0",O_RDWR);
rtc = open("/dev/rtc" ,O_RDWR);
if ( i2c > 0 && rtc >0 ) {
ioctl(i2c,I2C_SLAVE, 0x40); /* PCF 8574A: 0x70*/
ioctl(rtc, RTC_PIE_ON, 0);
ioctl(rtc, RTC_IRQP_SET, (unsigned long)512);
blinky(512*30,20,pattern1); /* Zeit für Brille */
for (count=20;count<=64;count++)
blinky(512*15,count,pattern1);
blinky(512*120,72,pattern2);
for (count=64;count>=20;count--)
blinky(512*10,count,pattern1);
return 0;
ioctl(rtc, RTC_PIE_OFF, 0);
}
return 1;
}
|
Damit das Programm funktioniert, muß der Kernel mit der Echtzeituhr-Option
compiliert worden sein, sie ermöglicht eine Erzeugung von regelmäßigen
Interrupts im 2- bis 8192 Hertz - Rythmus. Bei mehr als 64 Hertz muß
man das Programm als Super-User starten.
Dann bleibt nur noch den Raum zu verdunkeln, störende Geräusche
zu beseitigen ( eventuell durch Meeresrauschen - CD), das Programm zu starten
und sich zurückzulehnen. Wer zu dem Ganzen noch Ton haben will, dem
steht es natürlich frei, den Midi-Chip der Soundkarte zu belästigen.
Die wahre Stärke des Busses liegt allerdings weniger im Regeltechnik-Bereich, sondern in der Steuerung von Multimediageräten. Es ist kaum eine TV- oder Radiokarte am Markt, die nicht auf I²C-Bus gesteuerten Hardwarelösungen basiert.
Als weiterführende Literatur mit vielen Projekten sei an dieser Stelle noch auf ein Buch von Elektor hingewiesen: I²C-BUS angewandt, Elektor Verlag Aachen, ISBN 3-928051-71-7.
Den I²C-Bus Treiber gibt es in der aktuellen Version gibt's an der
Uni Linz unter ftp://ftp.tk.uni-linz.ac.at/pub/simon/i2c/
oder auf jedem guten ftp Server, der ftp.funet.fi (in .../linux/kernel/i2c)
oder sunsite (.../Linux/kernel/misc-cards) spiegelt. Weitere Infos und
Updates liegen auf meiner Hompage,
| Der Autor |
Simon
Vogl studiert Informatik an der J. Kepler Univ. Linz (Österreich)
und ist ein absoluter Linux-Freak seit 0.99.4. Sitzt er nicht mit rauchendem
Lötkolben vor seiner Kiste, ist er meist mit seiner Freundin in Europa
unterwegs. Zu erreichen ist er unter simon@tk.uni-linz.ac.at.
Diverse Info's, sowie das Treiberpaket gibt es auf seiner Homepage unter
http://www.tk.uni-linz.ac.at/~simon/private.Der Schreiber dieses Artikels rät jedem, die Finger von Lötkolben und anderen Werkzeugen zu lassen, die mit Strom, Feuer oder Wasser betrieben werden, und fühlt sich in keiner Weise für irgendwelche Brände, Kurzschlüsse und andere Naturkatastrophen verantwortlich :) |