Write EEPROM

Liebe/-r Experte/-in,
ich beschäftige mich seit mehreren Monaten mit PICs, speziell PIC16F690 von MICROCHIP. Mein Problem ist die Kontrolle des Laufes der R-Achse eines astronomischen Fernrohres. Dazu habe ich eine Vorrichtung mit einer Codierscheibe angebaut, über die ich etwa alle 6 sekunden einen elektrischen Impuls erhalte. Diese Impulse erzeugen externe Interrupts im PIC-Programm. Mit Hilfe von Timer-Interrupts wird der Abstand der externen Interrupts in Einheiten von Millisekunden gemessen und auf einem 4-stelligen 7-Segment-Display als Hexadezimalzahl ausgegeben.
Bisher habe ich immer während einer Messung alle 6 Sekunden (etwa) die 4 Stellen der LED-Anzeige aufgeschrieben. Nach der Messung habe ich die (meist) 48 Zahlen in meinen PC von Hand eingegeben, um sie dort einer statistischen Analyse zu unterziehen.
Dieses Verfahren ist nervig - und fehleranfällig.
Meine Idee war nun, die Hexadezimalzahlen, evtl. in 2 Bytes komprimiert, im PIC-EEPROM-Speicher abzulegen.
Dann könnte man sie nach der Messung mit dem PICkit2-
Programmer auslesen und in den PC übertragen.
Ich habe mir dazu in den Datasheets DS41262E, Seite 122,
das EXAMPLE 10-2: DATA EEPROM WRITE angesehen und ein Testprogramm diesem Beispiel „nachempfunden“. Aber leider kann ich in dem EEPROM-Speicher die eingeschriebenen Daten nicht wiederfinden.
Meine Frage an Sie: Was mache ich beim EEPROM-Beschreiben falsch? Ich könnte noch mein Beispielprogramm per email nachliefern.
Vielen Dank und freundliche Grüße!
enricoernesto

Sehr geehrter Herr Ernesto,

Ihr Beispielprogramm wäre schon nötig. Da es sehr kurz sein müsste, können Sie den Code doch einfach in die Antwort auf diese Antwort kopieren.

Vorher möchte ich Sie allerdings bitten folgendes zu prüfen: Ist Ihr Controller vielleicht geschützt? Denn dann wäre ein externes Auslesen nicht möglich. (Datenbuch Seite 119, linke Spalte, letzter Absatz, und Seite 125, Abschnitt 10.4)

Mit freundlichen Grüßen

Thomas Klingbeil

> Sehr geehrter Herr Klingbeil,
> > Ihr Hinweis auf den Data-Schutz war sehr nützlich; bisher hatte ich über
> > diese Stelle immer hinweggelesen, da ich es nicht verstanden hatte. Ich
> > habe das beigefügte Programm inzwischen sowohl mit der Ergänzung _CDP_ON
> > als auch mit der Ergänzung
> > _CPD_OFF in der _CONFIG-Direktive getestet, in beiden Fällen enthielt
> > der EEPROM-Speicher nicht den eingespeicherten Inhalt:
> > H’17’ in Zelle 0 und H’28’ in Zelle 1.
Ich hatte diese Antwort falsch adressiert.
Mit freundlichen Grüßen
Heinz Hahn
PS.: Ich verstehe das Programm nicht
wirklich.Vermutlich habe ich die Adresse
des EEPROM-Speichers nicht richtig angegeben.
*******************************************************

Das Testprogramm:

list p=16f690
; Includedatei für den 16F690 einbinden

#include
; Configuration festlegen
; bis 4 MHz: Power on Timer, kein Watchdog, Interner Oscillator

__CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC

;******************************************************
; Variablennamen vergeben

w_copy Equ 0x20 ; Backup für Akkuregister
s_copy Equ 0x21 ; Backup für Statusregister
;******************************************************
; los gehts mit dem Programm

org 0
goto Init
;******************************************************
; die Interuptserviceroutine

org 4
intvec
bcf INTCON, GIE ; disable Interupt
movwf w_copy ; w retten
swapf STATUS, w ; STATUS retten
movwf s_copy ;
banksel EEADR
movf H’01’, w
movwf EEADR
movf H’28’, w
movwf EEDAT
banksel EECON1
bcf EECON1, EEPGD
bsf EECON1, WREN
bcf INTCON, GIE
btfsc INTCON, GIE
goto $-2
movlw H’55’
movwf EECON2
movlw H’AA’
movwf EECON2
bsf EECON1, WR

Int_end
swapf s_copy, w ; STATUS zurück
movwf STATUS
swapf w_copy, f ; w zurück mit flags
swapf w_copy, w
goto exit

Init
banksel EEADR
movf 0, w
movwf EEADR
movf H’17’, w
movwf EEDAT
banksel EECON1
bcf EECON1, EEPGD
bsf EECON1, WREN
bcf INTCON, GIE
btfsc INTCON, GIE
goto $-2
movlw H’55’
movwf EECON2
movlw H’AA’
movwf EECON2
bsf EECON1, WR
Init_ende
bsf INTCON, GIE ; generellen Interrupt erlauben
banksel H’00’
loop goto loop ; eine Endlosschleife

;******************************************************

exit
end

Sehr geehrter Herr Hahn,

ich denke, Sie haben einen Adressierungsfehler im Programm und Sie verwenden die Interruptserviceroutine (ISR) etwas unkonventionell.
Zunächst zur ISR:
Die ISR ist wie ein Unterprogramm, das durch einen Interrupt aufgerufen wird. Der Interrupt löscht das GIE-Flag, sodass weitere Interrupts gesperrt werden. Insofern ist auch die Zeile „bcf INTCON, GIE“ überflüssig. Damit das Hauptprogramm nach Beendiung der ISR dort weitermachen kann, wo es unterbrochen wurde, müssen Sie mit einem Return-Befehl zurück, wobei für die ISR der Befehl retfie vorgesehen ist, der das GIE-Flag beim Rücksprung automatisch wieder setzt. Bitte schauen Sie sich hierzu das Kapitel 14.3 an.
Ferner haben Sie vergessen, dass Sie bei der Kontextsicherung sicherstellen müssen, dass die Speicherbank für die Variablen w_copy und s_copy gewählt ist. Schauen Sie sich hierzu im Datenbuch nochmal das Beispiel 14.1 auf der Seite 211 an. Dort finden Sie den Befehl clrf STATUS, der die Speicherbank 0 für die Kontextsicherung erzwingen soll.
Dann beenden Sie die ISR anstatt mit retfie mit „goto exit“, was einem Sprung ins Nirwana gleichkommt, denn exit steht für eine Adresse, an der kein Programmcode mehr kommt. Sollte der Controller tatsächlich „goto exit“ ausführen, dann tritt ein nicht definiertes Verhalten auf. Letztendlich ist mir aber nicht klar, warum Sie die ISR überhaupt programmiert haben, denn es ist nicht ersichtlich, dass ein Interrupt aufgerufen wird. Um das EEPROM zu testen, sollten Sie die ISR zunächst einfach weglassen und sich später mit der Interruptprogrammierung beschäftigen, denn das wäre ein Kapitel für sich.

Kommen wir nun zur eigentlichen EEPROM-Programmierung.
Im Beispielprogramm taucht zunächst die Variable „DATA_EE_ADDR“ auf, die aber nirgends definiert ist. Also benutzen Sie diese auch bitte nicht oder definieren Sie sie. Im unten stehenden Testprogramm haben Sie sie nicht benutzt, sondern Sie haben anscheinend versucht, die EEPROM-Speicherzelle 0 unmittelbar mit dem Wert 0x17 zu laden. Das ist Ihnen deshalb nicht gelungen, weil Sie die Befehle movf verwendet haben. „movf H’17’, w“ schreibt nicht den Wert 0x17 nach w, sondern der Inhalt des Registers mit der Adresse 0x17 wird nach w geschrieben. Wenn Sie 0x17 nach w schreiben wollen, so müssen Sie movlw 0x17 benutzen.

Die korrigierte und um den Ballast der ISR befreite Routine sieht also so aus:

*******************************************************

Das Testprogramm:

list p=16f690
; Includedatei für den 16F690 einbinden

#include
; Configuration festlegen
; bis 4 MHz: Power on Timer, kein Watchdog, Interner Oscillator

__CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC

;******************************************************
; Variablennamen vergeben

w_copy Equ 0x20 ; Backup für Akkuregister
s_copy Equ 0x21 ; Backup für Statusregister
;******************************************************
; los gehts mit dem Programm

org 0
goto Init
;******************************************************
; die Interuptserviceroutine

org 4

retfie

Init
banksel EEADR
movlw 0
movwf EEADR
movlw H’17’
movwf EEDAT
banksel EECON1
bcf EECON1, EEPGD
bsf EECON1, WREN
bcf INTCON, GIE
btfsc INTCON, GIE
goto $-2
movlw H’55’
movwf EECON2
movlw H’AA’
movwf EECON2
bsf EECON1, WR
Init_ende

loop goto loop ; eine Endlosschleife

;******************************************************

end

Probieren Sie es mal aus, es müsste klappen.

Mit freundlichen Grüßen

Thomas Klingbeil

Hallo,

die Fehleranalyse in fremden Programmcodes ist erfahrungsgemäß eine langwierige Angelegenheit und es wird wohl meine (frei)zeitlichen Kapazitäten sprengen. Ich kann aber nur empfehlen, die Beispielprogramme erstmal unverändert auszuprobieren und evtl. Anmerkungen im Text genau zu beachten. Die vorgeschriebenen Programmiersequenzen müssen exakt befolgt werden. Dies dient als Schutz vor unbeabsichtigten Schreibzugriffen.

MfG
Jörg Rehrmann

ich beschäftige mich seit mehreren Monaten mit PICs, speziell
PIC16F690 von MICROCHIP. Mein Problem ist die Kontrolle des
Laufes der R-Achse eines astronomischen Fernrohres. Dazu habe
ich eine Vorrichtung mit einer Codierscheibe angebaut, über
die ich etwa alle 6 sekunden einen elektrischen Impuls
erhalte. Diese Impulse erzeugen externe Interrupts im
PIC-Programm. Mit Hilfe von Timer-Interrupts wird der Abstand
der externen Interrupts in Einheiten von Millisekunden
gemessen und auf einem 4-stelligen 7-Segment-Display als
Hexadezimalzahl ausgegeben.
Bisher habe ich immer während einer Messung alle 6 Sekunden
(etwa) die 4 Stellen der LED-Anzeige aufgeschrieben. Nach der
Messung habe ich die (meist) 48 Zahlen in meinen PC von Hand
eingegeben, um sie dort einer statistischen Analyse zu
unterziehen.
Dieses Verfahren ist nervig - und fehleranfällig.
Meine Idee war nun, die Hexadezimalzahlen, evtl. in 2 Bytes
komprimiert, im PIC-EEPROM-Speicher abzulegen.
Dann könnte man sie nach der Messung mit dem PICkit2-
Programmer auslesen und in den PC übertragen.
Ich habe mir dazu in den Datasheets DS41262E, Seite 122,
das EXAMPLE 10-2: DATA EEPROM WRITE angesehen und ein
Testprogramm diesem Beispiel „nachempfunden“. Aber leider kann
ich in dem EEPROM-Speicher die eingeschriebenen Daten nicht
wiederfinden.
Meine Frage an Sie: Was mache ich beim EEPROM-Beschreiben
falsch? Ich könnte noch mein Beispielprogramm per email
nachliefern.
Vielen Dank und freundliche Grüße!
enricoernesto

Sehr geehrter Herr Klingbeil,
um es vorweg zu nehmen: Ich kann jetzt, dank Ihrer Hilfe, Daten aus dem PIC in meinen PC in eine Datei schreiben und dort wiederfinden!
Ich habe Ihr Programmbeispiel verdreifacht; im ersten Teil schreibe ich H’17’ nach Adresse 0, im zweiten H’28’ nach Adresse 1 und im dritten H’39’ nach Adresse 2 im EEPROM. Zwischen den Teilen warte ich, bis der Schreibvorgang beendet ist, angezeigt durch Bit EEIF in PIR2 = 1. Anschließend lösche ich das Bit.
Dass ich dieses Schreibproblem durch eine ISR verkompliziert habe, verstehe ich jetzt auch nicht mehr. Es ist wohl so zu erklären: In meinem Anwendungsprogramm stehen die beiden zu rettenden Bytes (4-stellige Hexadezimalzahl) in der ISR für den externen Interrupt zur Verfügung und müssen innerhalb der ISR verarbeitet werden. Mit dem EE-Write hat das nichts zu tun.
Ein Problem kommt noch auf mich zu: Die Adresse im EEPROM muss ich in einer Zelle hochzählen, beginnend mit 0; diese Zelle ist in Bank0, ebenso wie die zu rettenden Bytes. Ich muss also beim EEWRITE mehrmals zwischen Bank0 und Bank(EEADR) mit banksel umschalten.
Ich hoffe, dass der von banksel generierte Code nicht den Inhalt von w-Register zerstört!
Nochmal vielen Dank für Ihre Arbeit, die Sie mit mir hatten!
Mit freundlichen Grüßen
Heinz Hahn

Sehr geehrter Herr Rehrmann,
ich danke Ihnen für Ihre Antwort auf meine Anfrage. Ich würde nie von jemandem erwarten, dass er sich durch meinen Spaghetticode quält. In diesem Fall handelte es sich um eine vergleichsweise simple Codesequenz, die in dem Beispiel aus dem PIC-Datasheet leider nicht ganz zweifelsfrei wiedergegeben war.
Herr Klingbeil von wer-weiß-was hatte die entscheidenden Tips bereit, und so ist mein Problem jetzt gelöst.
Nochmal vielen Dank!
Mit freundlichen Grüßen
Heinz Hahn