Lesen und Beschreiben des EEPROM und des FLASH


zurück zu PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage

Allgemeines zum EEPROM
EEPROM lesen
EEPROM beschreiben
Allgenmeines zum FLASH
FLASH lesen
FLASH beschreiben
 

zurück: zu PIC-Grundlagen


Allgemeines zum EEPROM

Viele PICs besitzen EEPROM-Zellen, in denen jeweils 1 Byte gespeichert werden kann. Im Unterschied zu den normalen Daten-Speicherzellen vergessen die EEPROM-Speicherzellen die in ihnen gespeicherten Informationen nicht beim Ausschalten der Stromversorgung. Hier lassen sich also Werte speichern, die immer wieder benötigt werden - z.B. Kalibrierdaten.

Der EEPROM-Speicherbereich liegt nicht im normalen Adressbereich des PIC. Er kann nur indirekt adressiert werden, was vergleichsweise umständlich ist. Da kein PIC mehr als 256 Byte EEPROM-Speicher hat, reicht eine 8 Bit Adresse aus um eine EEPROM-Zelle eindeutig zu adressieren.

Das Beschreiben des EEPROMS kann während des Brennens durch entsprechende Einstellung der Konfiguration des PIC verboten werden (Codeprotection).

Wie man schon im Assembler-Programm EEPROM-Daten festlegen kann, ist hier erläutert.

nach oben

EEPROM lesen

In einem PIC findet man die folgenden 6 Register, die zur Arbeit mit dem EEPROM und FLASH dienen:

Ärgerlich ist, das diese Zellen über alle Speicher-Banken verteilt liegen. Außerdem liegen die Zellen bei jeder PIC-Familie (16F84 / 16F87x / 16F62x) an anderen Adressen und in anderen Banken. Um eine EEPROM Zelle auszulesen benötigen wir aber nur die Register EEADR, EECON1 und EEDATA. In meinem Beispiel verwende ich die Adressen-/Banken-Einstellungen für den 16F87x.

Um Daten aus einer EEPROM-Zelle zu lesen schreibt man zuerst die Adresse der betroffenen EEPROM-Zelle in das Register EEADR. Danach löscht man im EECON1-Register das Bit 7 (EEPGD-Bit) und setzt das Bit 0 (RD-Bit). Daraufhin schreibt der PIC das Datenbyte aus der EEPROM-Zelle in das Register EEDATA, wo man es nun auslesen kann. Im folgenden Beispiel wird die EEPROM-Zelle 10h gelesen:
 
 

    BSF    STATUS, RP1     ;
    BCF    STATUS, RP0     ; EEADR liegt in der Bank 2
    MOVLW  0x10            ; ich möchte die EEPROM-Zelle Nr. 10h auslesen
    MOVWF  EEADR           ; dazu schreibe ich die Adresse 10h in EEADR

    BSF    STATUS, RP0     ; EECON1 liegt in der Bank 3
    BCF    EECON1, EEPGD   ; ich möchte aus dem Daten-Speicher lesen
    BSF    EECON1, RD      ; EEPROM Leseprozess starten

    BCF    STATUS, RP0     ; EEDATA liegt in der Bank 2
    MOVF   EEDATA, W       ; Die Daten der EEPROM Zelle nach W kopieren
 


 

nach oben


EEPROM beschreiben

Das Beschreiben eines EEPROM ist ein komplizierter Prozess, bei dem ein isolierter Bereich des Chips schrittweise mit Elektronen gefüllt wird. Dieser Prozess ist beim PIC automatisiert. Wir müssen dem PIC nur sagen welche Daten wir wo gespeichert haben wollen, und den Schreibprozess starten. Dieser Schreibprozess läuft dann im Hintergrund ab, er dauert allerdings einige Millisekunden (4 bis 8 ms beim 16F87x), was im Vergleich zum Beschreiben einer normalen Speicherzelle eine Ewigkeit ist.

Auch ist jedes Beschreiben für den EEPROM Stress. Der Hersteller gibt eine garantierte Lebensdauer von 100 000 Schreibzyklen an. Schon beim Brennen des PIC können EEPROM-Daten gleich mitgebrannt werden. Oft muss man aber im laufenden Programm Werte in den EEPROM schreiben.

Um ein versehentliches Überschreiben von EEPROM-Daten zu verhindern, hat man den Schreibprozess kompliziert gestaltet.

Zuerst muss die Adresse der zu beschreibenden EEPROM-Zelle in das EEADR-Register sowie das zu schreibende Datenwort in das EEDATA-Register geschrieben werden. Nach dem vorbereitenden Setzen/Löschen einiger Bits folgt diese festgelegte Folge von 5 Befehlen, die genau einzuhalten ist:
 
 

    MOVLW  0x55               ;
    MOVWF  EECON2             ; schreibe 55h
    MOVLW  0xAA               ;
    MOVWF  EECON2             ; schreibe AAh
    BSF    EECON1, WR         ; starte den Schreibzyklus
 

Hält man sich nicht genau an diese Befehlsfolge, dann werden keine Daten geschrieben. Das gilt natürlich auch, wenn diese Befehlsfolge durch einen Interrupt unterbrochen wird. Deshalb sollte man für diese Befehlsfolge alle Interrupts verbieten.

Im folgenden Beispiel schreiben wir den Wert 4 in die EEPROM-Zelle 10h
 
 

    BSF    STATUS, RP1        ;
    BCF    STATUS, RP0        ; EEADR und EEDATA liegen in der Bank 2
    MOVLW  0x10               ;
    MOVWF  EEADR              ; Die Zelle 10h soll beschrieben werden
    MOVLW  4                  ;
    MOVWF  EEDATA             ; eine 4 wollen wir schreiben

    BSF    STATUS, RP0        ; EECON1 liegt in der Bank 3
    BCF    EECON1, EEPGD      ; wir wollen Datenspeicher beschreiben
    BSF    EECON1, WREN       ; nun ist Schreiben erlaubt
    BCF    INTCON, GIE        ; verbieten aller Interrupts

; Die folgenden 5 Zeilen müssen genau so im Code stehen!!!
    MOVLW  0x55               ;
    MOVWF  EECON2             ; schreibe 55h nach EECON2
    MOVLW  0xAA               ;
    MOVWF  EECON2             ; schreibe AAh nach EECON2
    BSF    EECON1, WR         ; starte den Schreibzyklus

    BSF    INTCON, GIE        ; Interrupts wieder erlauben
 

So, das wäre geschafft. Der PIC schreibt nun intern das Byte in den EEPROM, während unser Programm weiterläuft. Solange der Schreibprozess läuft, darf man allerdings nicht auf den EEPROM zugreifen um z.B. weitere Daten zu schreiben. Deshalb muss man vor einem weiteren Zugriff testen, ob der Schreibprozess beendet ist. Im einfachsten Fall schickt man das Programm in eine 10ms lange Warteschleife, innerhalb dieser Zeit wird der PIC schon fertig werden. Es geht aber auch eleganter. Am Ende des Schreibprozesses setzt der PIC das Bit EEIF im Register PIR2. Hat man dieses Bit vor dem Beginn des Schreibens gelöscht, so kann man es nun in einer Schleife so lange Abfragen, bis es wieder gesetzt ist.

Wurde vor Beginn des Schreibens das EEIE-Bit im Register PIE2 gesetzt, so kann das Setzen von EEIF einen Interrupt auslösen. Legt man den PIC nach dem Start des Schreibzyklus schlafen (sleep) so wacht er durch das Setzen von EEIF wieder auf.
 

nach oben


Allgemeines zum FLASH (nur für 16F87x(A), PIC16F818/819 und 16F7x)

Vollen Schreib- und Lesezugriff auf den FLASH erlauben nur wenige PIC-Typen. Das sind insbesondere PIC16F87x,  PIC16F87xA und PIC16F818/819.
Einen Nur-Lesezugriff erlauben die PIC16F7x

Der Flash-Speicher ist der Programmspeicher des PIC. In ihm wird beim 'Brennen' das Arbeitsprogramm des PIC abgelegt. Flash-Speicher ist eigentlich nichts weiter als eine verbesserte EEPROM-Technologie, die sich schneller beschreiben lässt als normaler EEPROM. Deshalb kann das Programm auch wieder gelöscht und neu geschrieben werden.

Wenn man sich einmal die technischen Daten von Flash-PICs ansieht, dann fällt auf, das der Flash-Speiche viel größer ist, als der Daten oder EEPROM-Speicher. Deshalb ist man versucht, große Datenfelder im Programmcode abzulegen, um nicht den knappen EEPROM-Speicher zu verschwenden. mit Hilfe des Befehls 'addwf PCL, f ' und vieler  darauf folgender 'retlw' Befehle lassen sich so im Programmcode Datenblöcke von bis zu 128 Byte ablegen. Größere Datenfelder sind auf diese Weise aber nur kompliziert zu verwalten.

In einigen PICs (insbesondere den 16F87x-Typen) besteht deshalb die Möglichkeit, mittels spezieller Befehle den FLASH-Speicher ähnlich wie den EEPROM-Speicher zu lesen und zu beschreiben.

Das Beschreiben des FLASH kann beim Brennen durch entsprechende Einstellung der Konfiguration des PIC verboten werden (Codeprotection).
Der Hersteller garantiert für den Flash-Speicher eine Lebensdauer von 1000 Schreibzyklen (PIC16F87x) bzw. 100000 Schreibzyklen (PIC16F87xA). EEPROM-Zellen sind deutlich robusterer und überleben 100000 Schreibzyklen (PIC16F87x) bzw. 1000000 Schreibzyklen (PIC16F87xA). Für viele Zwecke reicht aber auch eine Lebensdauer von 1000 Schreibzyklen aus.
 

nach oben


FLASH lesen

Wollen wir eine Flash-Zelle auslesen, so müssen wir dem PIC zunächst einmal die Adresse dieser Zelle mitteilen. Wären sich eine EEPROM-Zelle mit einem 8-Bit-Wert eindeutig adressieren lässt, braucht man für den deutlich größeren Adressbereich des Flash-Programmspeichers 13 Bit. Da so eine Adresse nicht in eine Speicherzelle passt, wird sie in zwei Teile zerschnitten und in zwei Speicherzellen geschrieben. Die unteren 8 Bit kommen nach EEADR und der Rest (5 Bit) nach EEADRH.
Danach setzt man im EECON1-Register das Bit 7 (EEPGD-Bit) und danach das Bit 0 (RD-Bit).  Daraufhin liest der PIC die Flash-Zelle, wozu er aber zwei Arbeitszyklen braucht. Deshalb müssen nun im Progammcode zwei NOP-Befehle folgen, um auf die Beendigung des Lesezyklusses zu warten.

Währenddessen schreibt der PIC das 14-Bit-Datenwort aus der FLASH-Zelle in die Register EEDATA und EEDATH. Die unteren 8 Bit kann man nun aus EEDATA auslesen, wären man die oberen 6 Bit in EEDATH findet. Im folgenden Beispiel wird die Programmspeicher-Zelle 120h gelesen:
 
 

    BSF    STATUS, RP1     ;
    BCF    STATUS, RP0     ; EEADR liegt in der Bank 2
    MOVLW  0x01            ; High Teil der Adresse 120h ist 1h
    MOVWF  EEADRH          ; den schreibe ich in EEADRH
    MOVLW  0x20            ; Low-Teil der Adresse 120h ist 20h auslesen
    MOVWF  EEADR           ; den schreibe ich in EEADR

    BSF    STATUS, RP0     ; EECON1 liegt in der Bank 3
    BSF    EECON1, EEPGD   ; ich möchte aus dem Programm-Speicher lesen
    BSF    EECON1, RD      ; EEPROM Leseprozess starten
    NOP
    NOP

    BCF    STATUS, RP0     ; EEDATA liegt in der Bank 2
    MOVF   EEDATA, W       ; die unteren 8 Bit nach W kopieren
    MOVWF  .....           ; und irgentwohin retten
    MOVF   EEDATH, W       ; die oberen 6 Bit nach W kopieren
 


 

nach oben


FLASH beschreiben (nur für PIC16F87x / PIC16F87xA / PIC16F818/819)

Der folgende Abschnitt bezieht sich auf die 16F87x-Familie. Das Schreibverfahren für die 16F87xA sowie die 16F818/819 weicht etwas ab, da hier immer eine Gruppe von 4 Worten auf einmal geschrieben werden muss.

Ähnlich wie EEPROM-Zellen kann man auch FLASH-Zellen beschreiben. Das soll wohl nicht der Schaffung selbstveränderlichen Programmcodes dienen, wohl aber dem Speichern von Daten im reichlich vorhandenen Programmspeicher. Der Schreibprozess ähnelt dem EEPROM-Schreiben mit folgenden Unterschieden:

Um ein versehentliches Überschreiben von EEPROM-Daten zu verhindern, hat man den Schreibprozess kompliziert gestaltet.

Zuerst muss die Adresse der zu beschreibenden EEPROM-Zelle in die Register EEADR  (untere 8 Bit) und EEADRH (oberer 5 Bit) geschrieben werden. Dann schreibt man das 14-Bit Datenwort in die Register EEDATA (untere 8 Bit) und EEDATH (obere 6 Bit). Nach dem vorbereitenden Setzen/Löschen einiger Bits folgt diese festgelegte Folge von 7 Befehlen, die genau einzuhalten ist:
 
 

    MOVLW  0x55               ;
    MOVWF  EECON2             ; schreibe 55h
    MOVLW  0xAA               ;
    MOVWF  EECON2             ; schreibe AAh
    BSF    EECON1, WR         ; starte den Schreibzyklus
    NOP
    NOP
 

Hält man sich nicht genau an diese Befehlsfolge, dann werden keine Daten geschrieben. Das gilt natürlich auch, wenn diese Befehlsfolge durch einen Interrupt unterbrochen wird. Deshalb sollte man für diese Befehlsfolge alle Interrupts verbieten.

Im folgenden Beispiel schreiben wir den Wert 204h in die Programmspeicher-Zelle 120h:
 
 

    BSF    STATUS, RP1        ;
    BCF    STATUS, RP0        ; EEADR und EEDATA liegen in der Bank 2

    MOVLW  0x01               ;
    MOVWF  EEADRH             ; High Teil der Adresse 120h ist 1h
    MOVLW  0x20               ;
    MOVWF  EEADR              ; Low Teil der Adresse 120h ist 20h

    MOVLW  2                  ;
    MOVWF  EEDATH             ; High Teil des Datenworts 204h ist 2h
    MOVLW  4                  ;
    MOVWF  EEDATA             ; Low Teil des Datenworts 204h ist 4h

    BSF    STATUS, RP0        ; EECON1 liegt in der Bank 3
    BSF    EECON1, EEPGD      ; wir wollen Programmspeicher beschreiben
    BSF    EECON1, WREN       ; nun ist Schreiben erlaubt
    BCF    INTCON, GIE        ; verbieten aller Interrupts

; Die folgenden 7 Zeilen müssen genau so im Code stehen!!!
    MOVLW  0x55               ;
    MOVWF  EECON2             ; schreibe 55h nach EECON2
    MOVLW  0xAA               ;
    MOVWF  EECON2             ; schreibe AAh nach EECON2
    BSF    EECON1, WR         ; starte den Schreibzyklus
    NOP
    NOP

    BSF    INTCON, GIE        ; Interrupts wieder erlauben
 

So, das wäre geschafft. Bei 'BSF    EECON1, WR' beginnt der PIC das Datenwort  in den Programmspeicher zu schreiben. Bis er damit fertig ist steht das Programm still. Danach überspringt der PIC die beiden NOP-Befehle und arbeitet weiter.
 

nach oben

zurück: zu PIC-Grundlagen


zurück zu PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage
Autor: sprut
erstellt: 12.11.2001
letzte Änderung: 02.11.2008