Der FKG- Roboter

FORPHYS- Mess- Interfaces

Forschendes Lernen im Physik-UR

Würzburger Quanten- physik- Konzept

Grundfakten der Quanten- physik

Materialien Physik-UR

Physika- lische Analysen

Im- pres- sum

Kommen- tare und Wünsche

© Horst Hübel Würzburg 2005 - 2014

Anschluss eines seriellen EEPROMs vom Typ 24C256 an den I2C-Bus (AVISE 4.3)

NEU Physikalische Schülerversuche mit PC und Mikroprozessor, 2. erweiterte Auflage, im Buchhandel erschienen

.

Die folgenden Informationen sind für ATMEL-Prozessoren, z.B. ATMEGA168 oder ATMEGA32, zusammengestellt, die mit der Programmiersprache AVISE4.3 (vgl. So schön geht AVISE) programmiert sind, einer FORTH-Variante von Herrn W. Schemmert (Fa. CINETIX, Frankfurt). Sie lassen sich mit etwas Mühe auf andere Programmiersprachen übertragen.

Das EEPROM wird über zwei Leitungen angesprochen: SCK mit dem Clock-Signal und SDA, einer Leitung, auf der serielle Adressen, Daten und Kontrollbits übertragen werden. Der Speicherraum ist in $200 = 512(10) Pages mit je $40 = 64(10)Bytes organisiert. Bei der Adressierung muss sowohl die Page-Nr. pbnr (von 0 bis 511(10)) als auch die Adresse adr (von 0 bis 63(10)) übertragen werden. Die Daten werden dann byteweise aus der adressierten Speicherzelle herausgelesen oder in sie hineingeschrieben. Leichter handhabbar erscheint die Adressierung, wenn man eine virtuelle Adressierung (addr) zugrundelegt, bei der die 1-Byte-Speicherzellen der Reihe nach durchnummeriert werden, von 0 bis $7FFF = 32767(10). Bei der Speicherung eines 2-Byte-Wortes muss man dann zwei Speicherzellen mit aufeinanderfolgenden Nummern ansprechen.

Die Pageblock-Nr. und die Adresse innerhalb einer Page (adr) erhält man dann aus der virtuellen Adresse addr wie in der Zeichnung angedeutet.

Zum Glück gibt es in AVISE-FORTH ein Wort, mit dem man beide Adress-Anteile auf einmal auf den Stapel legen kann:

   
                              .         addr 1 40 */MOD DROP

                   

legt zunächst die Page-Nr., dann die Adresse adr innerhalb der Page auf den Stapel. Dabei sind alle Ein- und Ausgaben Hexadezimalzahlen.

2F78 1 40 */MOD DROP . . liefert dann BD 38

Man kann leicht nachrechen, dass wirklich BD*40 + 38 = 2F78 (dezimal:       189*64+ 56 = 12152).

Es gibt aber noch elegantere Varianten.

Es sollen jetzt Worte entwickelt werden, mit denen man 2-Byte-Worte in virtuell adressierte Speicherzellen schreiben bzw. aus ihnen auslesen kann (AVISE-FORTH geht überwiegend mit 2-Byte-Worten um). Dazu ist es nötig, 2-Byte-Worte mittels des Worts ZL in einzelne Bytes zu zerlegen, die auf den Stapel gelegt werden, und einzelne aus dem EEPROM gelesene Bytes wieder mittels FUSE zu einem 2-Byte-Wort zu fusionieren.

.

Konvention für Ein-/Ausgabeparameter:

Beispiel:

: PBADR { ( addr -- pbnr adr )

.wird folgendermaßen aufgerufen:    addr PBADR

Danach liegen die Parameter pbnr adr mit adr als oberstem Element des Stapels (TOS, top of stack) auf dem Stapel (stack).

.
$ Schaltet auf Hexadezimalzahlen um: Alle folgenden Zahlen und Adressen sind Hexadezimalzahlen.
: PBADR { ( addr -- pbnr adr )

1 40 */MOD DROP RET

(Variante 1)

Legt Pageblock-Adresse pbnr auf Stack (TOS), darunter Adresse adr innerhalb des adressierten Blocks

: PBADR { ( addr -- pbnr adr )

DUP 3f AND SWAP 6 ROR 3ff AND RET

(Variante 2)

Bewirkt das gleiche, benötigt aber nur ca. 1/3 der Zeit.

Die virtuelle Adresse wird dupliziert. Mit 3f AND werden die niederwertigsten 6 bits abgetrennt, was dem Rest bei der Division durch 40 entspricht. Die virtuelle Adresse wird noch einmal auf den TOS geholt, die Bits werden um 6 Stellen nach rechts rotiert (nach rechts geschoben, aber die herausfallenden Bits werden links wieder eingefügt), was dem Ergebnis der Integer-Division mit 40 entspricht. Mit ROR werden die rechts herausfallenden Bits links leider wieder eingefügt. Diese überzähligen Bits werden mit 3ff AND entfernt.

: PBADR { ( addr -- pbnr adr )

DUP 3f AND SWAP 6 >> RET

(Variante 3)

Und noch eleganter:

Die virtuelle Adresse wird dupliziert. Mit 3f AND werden die niederwertigsten 6 bits abgetrennt, was dem Rest bei der Division durch 40 entspricht. Die virtuelle Adresse wird noch einmal auf den TOS geholt, die Bits werden mit 6 >> um 6 Stellen nach rechts verschoben, was dem Ergebnis der Integer-Division mit 40 entspricht. Beim Schiebebefehl werden links Nullen nachgezogen.

: ZL { ( w -- lb hb )

DUP ff AND SWAP 8 ROR ff AND

RET

(Variante 1)

Zerlegt Wort x in Highbyte und Lowbyte. Highbyte bildet TOS.

Das 2-Byte-Wort w wird dupliziert. Durch die AND-Verknüfung mit ff entsteht ein 2-Byte-Wort, von dem nur die niedrigsten 8 Bits erhalten blieben. Es bildet jetzt den TOS. Mit SWAP liegt wieder w auf dem TOS. Mit 8 ROR werden die höherwertigen 8 Bits auf die Plätze der früheren niederwertigen Bits rotiert, die früheren niederwertigen Bits nehmen jetzt die höherwertigen Plätze ein. Durch die AND-Verknüpfung mit ff werden die neuen höherwertigen Bits zu 0 gemacht. Den TOS bildet jetzt ein Wort, dass die höherwertigen Bits von w enthält, darunter liegt ein Wort mit den niederwertigen Bits von w.

: ZL { ( w -- lb hb )

DUP ff AND SWAP 8 >> RET

(Variante 2)

Auch das geht eleganter:

Das 2-Byte-Wort w wird dupliziert. Durch die AND-Verknüfung mit ff entsteht ein 2-Byte-Wort, von dem nur die niedrigsten 8 Bits erhalten blieben. Es bildet jetzt den TOS. Mit SWAP liegt wieder w auf dem TOS. Mit 8 >> (>>: Shift-Befehl) werden die höherwertigen 8 Bits auf die Plätze der früheren niederwertigen Bits verschoben, die früheren niederwertigen Bits fallen heraus, an die Stelle der höherwertigen Bits rücken Nullen nach. Den TOS bildet jetzt ein Wort, dass die höherwertigen Bits von w enthält, darunter liegt ein Wort mit den niederwertigen Bits von w.

: FUSE  { ( lb hb -- w )

8 ROR +  RET

Hilfswort zur Fusionierung von lb und hb zu einem 2-Byte-Wort.

Durch 8 ROR wird das 2-Byte-Wort mit dem Highbyte hb um 8 bits nach rechts rotiert. Die rechts herausfallenden Bits werden links wieder in das manipulierte Wort eingeführt, stehen jetzt wirklich an der Position der höherwertigen Bits. Durch + erhalten alle relevanten Bits die zugehörige Position innerhalb des Ergebnisworts w. Beispiel:

Auf dem Stapel liegen die Worte 004F 007A (hb = 007A als TOS). Durch 8  ROR wird daraus 004F 7A00. Die Summe ist 7A4F.

: DEVSEL{ ( x -- flag )

ISTART ISEND IACK RET

Wählt Gerät mit Adresse x aus.

ISTART sendet Startkommando an den I2C-Bus

ISEND sendet TOS an den I2C-Bus

IACK fragt ab, ob Byte angekommen.

Auf dem TOS liegt flag = true, falls angekommen,  flag = false, falls nicht.

: ADDRESS { ( addr -- flag )

A0 DEVSEL

0= IF 45 EMIT DROP 0 EXIT ENDIF

PBADR ISEND IACK

0= IF 45 EMIT DROP 0 EXIT ENDIF

1 MS WAIT ISEND IACK RET

Adressiert Speicherzelle im EEPROM     (  A0 = 1010 0000(2)  )

Wählt Speicher mit Geräte-Adresse A0 (0: für Schreiben) aus. Falls EEPROM nicht bereit, wird CHR(45) = E vom Terminal ausgegeben, die Adresse addr entfernt und eine 0 als Flag auf den Stapel gelegt und abgebrochen. Auf dem TOS bleibt flag = false zurück.

Andernfalls (falls EEPROM bereit) wird mit PBADR die Adresse addr in PageBlock-Nr. und Adresse innerhalb des Speicherblocks umgewandelt und auf den Stapel gelegt.

ISEND sendet die Pageblock-Nr. an den I2C-Bus. IACK fragt ab, ob angekommen.

Falls ja, wird 1 ms gewartet, dann wird mit ISEND die Adresse adr innerhalb des Pageblocks an den I2C-Bus gesendet. IACK fragt wieder ab, ob angekommen, und legt ein entsprechendes Flag auf den TOS.

Den TOS bildet in jedem Fall ein Flag

: CUREAD { ( -- b )

A1 DEVSEL

0= IF 45 EMIT 0 EXIT ENDIF

IRECV ISTOP RET

Liest ein Byte aus vorher adressierter Zelle des EEPROM A1 = 1010 0001 (CurrentRead)

Adressiert Speicher-Device mit Geräte-Adresse A1 (1:  für Lesen). Falls EEPROM nicht bereit, wird CHR(45) = E vom Terminal ausgegeben, eine 0 auf den TOS gelegt und abgebrochen.

Andernfalls wird ein Byte vom I2C-Bus eingelesen und ein Stopkommando gesendet.

: RAREAD{ ( addr -- b )

ADDRESS

0= IF 45 EMIT 0 EXIT ENDIF

CUREAD RET

Adressiert ein EEPROM und eine Zelle darin und liest das entsprechende Byte aus.

ADDRESS sendet Adresse an EEPROM. Wenn das Flag 0 ist wird CHR(45) = E ausgegeben, eine 0 auf den TOS gelegt und abgebrochen. Andernfalls wird das adressierte Byte auf den TOS gelegt.

: WRITE  { ( b addr -- flag )

ADRESS

0= IF 45 EMIT DROP 0 EXIT ENDIF

ISEND IACK DUP

0=  IF 45 EMIT ENDIF

ISTOP RET

Schreibt ein Byte an eine bestimmte Adresse des EEPROM.

ADDRESS sendet Adresse an EEPROM. Wenn das Flag 0 ist wird CHR(45) = E ausgegeben, eine 0 auf den TOS gelegt und abgebrochen.

Falls gelungen wird das Datenbyte b an den I2C-Bus gesendet, und mit IACK abgefragt, ob erfolgreich. Das Flag wird dupliziert, wobei eine Exemplar davon zur eventuellen Erzeugung einer Fehlermeldung genutzt wird.

Auf dem TOS verbleibt ein Flag.

Mit ISTOP wird das Lesevorgang beendet.

: WEEPROM  { ( b addr -- )

REPEAT

SWAP DUP ROT DUP ROT SWAP

WRITE

3 ms wait

NOT UNTIL DROP DROP RET

Versucht immer wieder Byte b an Adresse addr zu schreiben bis es schließlich gelingt. Aber Vorsicht: Andernfalls wird das Wort nie beendet.

SWAP DUP ROT DUP ROT SWAP macht der Reihe nach

a b / a b b / b b a / b b a a / b a a b / b a b a

WRITE schreibt b an Adresse a und legt flag auf TOS

NOT: flag wird invertiert.

Wiederholung bis flag = True auf TOS, dann wird letztes a und letztes b entfernt.

Das Wort WEEPROM kann nicht beendet werden, wenn nicht gleichzeitig in Write das Schreiben der Adresse wie des Bytes gelingt.

: RAWORD { ( addr -- w )

RAREAD CUREAD 8 ROR + RET

Liest Wort aus zwei aufeinanderfolgenden Speicherzellen. Die virtuelle Adresse addr sollte immer geradzahlig sein.

RAREAD liest aus der addressierten Speicherzelle hb auf den TOS. Ohne Zutun des Programmierers wird die Adresse im EEPROM um 1 erhöht. Deshalb wird mit CUREAD an der laufenden Adresse (addr + 1) das lb gelesen. Dann werden, wie bei FUSE beschrieben, beide Bytes zu einem Wort vereinigt.

: WWORD { ( w addr -- )

SWAP ZL ROT DUP ROT SWAP 1 + WRITE DROP 3 MS WAIT WRITE DROP 3 ms wait RET

(WWORD-Variante 1)

Schreibt das 2-Byte-Wort w an die virtuelle Adresse addr.

Zuerst wird w auf den TOS geholt mit SWAP. w wird dann in lb und hb (TOS) zerlegt. Mit ROT erscheint wieder die Adresse auf dem TOS. Sie wird dupliziert. Mit ROT wird hb auf den TOS geholt, mit SWAP dann wieder addr. Die Adresse addr wird um 1 erhöht, dann wird mit WRITE hb in addr+1 geschrieben. Das flag wird mit DROP beseitigt. Auf dem Stack bleiben lb und addr (TOS). Nach 3 ms wird mit WRITE lb an addr geschrieben. Das flag wird beseitigt.

Das zweite 3 ms wait ist erforderlich, wenn man schnell hintereinander WWORD 2 x anwenden möchte.

: WWORD { ( w addr -- )

ADDRESS

0= IF 45 EMIT DROP EXIT ENDIF

ZL SWAP ISEND IACK

0=  IF 45 EMIT ENDIF 

ISEND IACK

0=  IF 45 EMIT ENDIF

ISTOP 3 ms wait RET

(WWORD-Variante 2; ersetzt WWORD-Variante 1)

Schreibt das 2-Byte-Wort w an die virtuelle Adresse addr (schneller als WWORD (Variante 1), da EEPROM selbsttätig Adresse inkrementiert).

ADDRESS sendet die Adresse, aufgespalten nach Pageblock und Adresse im Pageblock an den Slave. Wenn dabei ein Fehler auftritt, wird "E" gesendet, w beseitigt und das Wort beendet.

Andernfalls wird mit ZL das Wort w in Hi-Byte und Low-Byte zerlegt, ihre Reihenfolge auf dem Stack vertauscht. Das erste Byte (lb) wird mit ISEND auf den I2C-Bus gebracht. Mit IACK wird geprüft, ob der Slave empfangen hat. Falls nein, wird "E" ausgegeben. Dann wird das nächste Byte  (hb) an die Adresse addr+1 gesendet, der Empfang geprüft. Wenn alles gut gegangen ist, wird das Stopp-Signal gesendet und das Wort beendet.

3 ms wait ist erforderlich, wenn man schnell hintereinander WWORD 2 x anwenden möchte.

Eine txt-Datei mit den Wort-Definitionen zum Einlesen in den Prozessor mittels des Terminalprogramms ATOOL33 von Herrn Schemmert (Fa. CINETIX, Frankfurt)  finden Sie hier. Das EEPROM 24C256 hat 32 kByte Speicherplatz. Es gibt auch 24C64 mit 8 kByte und 24C1024 mit 128 kByte Speicherplatz.


Schäden werden bei sachgemäßem Umgang nicht erwartet. Dennoch wird keinerlei Haftung übernommen, z.B. bzgl. Gefährdung der Prozessoren, der PCs und vor allem der mit dem System experimentierenden Personen.

Ein Haftungsausschluss von Herrn Schemmert wird hier einkopiert:

[Image] IMPORTANT SAFETY INFORMATION:

'Avise' is not specified for safety-critical, medical or any application else, which ever might cause danger for persons or animals or damage of things. The use of 'Avise' in such applications is strictly forbidden.

(zuletzt aktualisiert 2013)