PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Externes EEPROM am PIC16F877A Codeproblem



Enrock
09.01.2008, 10:39
Servus,

also auf meinem Testboard ist ein externes EEPROM 24LC256 und dieses würde ich gerne absprechen(PIC16F877A). Also ich würde gerne Daten draufschreiben und diese dann auch wieder auslesen.
Ich habe im Democode auch folgenden Code in asm gefunden.

write_eeprom
banksel SSPCON2 ;write to EEPROM
bsf SSPCON2,SEN ;start bit
btfsc SSPCON2,SEN
goto $-1
movlw B'10100000' ;send control byte (write)
banksel SSPBUF
movwf SSPBUF
call ssprw
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ;ack?
goto $-1

movlw 0x00 ;send slave address HIGH byte
banksel SSPBUF
movwf SSPBUF
call ssprw
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ;ack?
goto $-1

movlw 0x05 ;send slave address LOW byte(0x0005)
banksel SSPBUF
movwf SSPBUF
call ssprw
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ;ack?
goto $-1

banksel temperature
movf temperature,w ;send slave DATA = temperature
movwf SSPBUF
call ssprw
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ;ack?
goto $-1

bsf SSPCON2,PEN ;stop bit
btfsc SSPCON2,PEN
goto $-1

banksel TMR1L
bcf PIR1,TMR1IF ;clear TIMER1 overflow flag
clrf TMR1L ;clear registers for next overflow
clrf TMR1H

return
;------------------------ IDLE MODULE -------------------------------------
ssprw ;check for idle SSP module
movlw 0x00
banksel SSPCON2
andwf SSPCON2,w
sublw 0x00
btfss STATUS,Z
goto $-4

btfsc SSPSTAT,R_W
goto $-1
return



Aber leider funktioniert die ganze Geschichte nicht. Und da ich davon nicht all zu viel Ahnung habe, brauche ich nun Hilfe.
Hat irgendwer einen Beispielcode, der funzt?

Danke

Gruß

Enrock
09.01.2008, 12:01
Noch eine weitere Frage, wie lese ich das ganze wieder aus?

MichaelM
09.01.2008, 19:20
Hallo,
wenn du nicht weist wie man das ausliest, woher weist du dann das das Schreiben nicht geht? Das Auslesen geht folgendermaßen: Du sendest das Controlbyte mit Bit 0 = 0 (Bit 0 = 1 bedeutet lesen, Bit 0 = 0 bedeutet schreiben), anschließend die Adresse (High- und Lowteil), daraufhin ein Restart (gibts beim MSSP-Modul ein Bit; SSPCON2,RSEN), dann wieder das Controlbyte mit Bit 0 = 1 (=lesen) und dann liest du die Daten Byte für Byte (mit SSPCON2,RCEN wird ein Byte eingelesen, nach jedem Byte Acknowledge senden bcf SSPCON2,ACKDT und dann bsf SSPCON2,ACKEN), wenn du keine weiteren Daten mehr einlesen möchtest sendest du statt Acknowlede ein NotAcknowledge (bsf SSPCON2,ACKDT und dann bsf SSPCON2,ACKEN).
Gruß,
Michael

PS: Entschuldigt den Schreibstil aber ich habe heute 11h gelötet.

Enrock
10.01.2008, 06:40
Guten Morgen,

also ich mein Oszi wahlweise an an der Daten und Wahlweise an der Clock Leitung. Aber ich sehe einfach kein Signal. Selbst, wenn ich die Frequenz runter schraube.... also ich habe einen 4 MHz Quarz dran, was ja bedeutet, dass diese intern mit 1Mhz arbeitet, was wiederum die oberste Grenze für den EEPROM ist. Aber es tut net...

MichaelM
10.01.2008, 19:28
Hallo,
wie hast du das MSSP-Modul initialisiert? Bei mir läuft der Bus mit 100kHz. Dazu schreibe ich ins Register SSPCON 28h und in SSPADD 31h für 100kHz bei 20MHz. Außerdem müssen PORTC.3 und .4 auf Eingang stehen.
Gruß,
Michael

Enrock
11.01.2008, 08:56
Servus,

also irgendwie ist der Bereich der PIC schwach frequentiert. Ich habe nach wie vor das Problem mit dem EEPROM.

Ich habe mich jetzt noch mal im Detail mit I2C Programmierung auseinander gesetzt und bin bei sprut fündig geworden und versuche das Beispiel mit dem EEPROM umzusetzen, doch auch das mag nicht so recht klappen!


EPPROM_INIT
; einstellen von RC3 & RC4 auf input
bsf STATUS, RP0 ; Bank 1
movlw B'00011000' ; RC3,4 inputs
iorwf TRISC, f ; + RC2=CCP1 output
bcf STATUS, RP0 ; Bank 0
;bcf PORTC,3
;bcf PORTC,4


; einstellen des I2C-Taktes auf knapp 400 kHz
bsf STATUS, RP0 ; Bank 1
movlw d'9' ; clock = 4MHz/(4*(9+1)) = 100kHz
movwf SSPADD ; für I2C
bcf STATUS, RP0 ; Bank 0

movlw B'00001000' ; master mode, clock=Fosc/(4*(SSPADD+1))
movwf SSPCON ;
bsf SSPCON, SSPEN ; MSSP-Modul enable



EEPROM_SCHREIBEN
;**Schreibe Wert 5 auf Speicher-Adresse 3 in 24C04*************
call i2c_on ; Bus aktiv
movlw H'A0' ; 1010 0000
call i2c_tx ; 24C04 zum Schreiben adressieren

movlw 0x00 ; high Teil der Adresse (Page)
call i2c_tx
movlw 0x03 ; low Teil der Adresse
call i2c_tx

movlw 0x05 ; Wert der auf Adresse 3 soll
call i2c_tx

call i2c_off ; Bus freigeben
; Fertig. Nun beginnt im EEPROM ein Lösch-Schreib-Zyklus
; mit dem der Wert 5 in die EEPROM-Zelle 3 geschrieben wird.
; Das wird etwa 10 ms dauern. Solange ist der 24C04 nicht ansprechbar.
;
; .... ; das Programm geht dann irgentwie weiter
EEPROM_LESEN
;**Stelle EEPROM auf Speicher-Adresse 3 ein*************
call i2c_on ; Bus aktiv
movlw H'A0' ; 1010 0000
call i2c_tx ; 24C04 zum Schreiben adressieren

movlw 0x00 ; high Teil der Adresse
call i2c_tx
movlw 0x03 ; low Teil der Adresse
call i2c_tx

call i2c_off ; Bus freigeben

;Nun steht der Adress-Pointer im 24C04 auf dem Wert 3.
;Nun können wir den I2C-Bus erneut aktivieren, um ein Byte aus dem 24C04 zu lesen. Das ist unser Datenbyte.

;**Lesen des aktuellen Bytes aus 24C04*************
call i2c_on ; Bus aktiv

movlw H'A0' ; 1010 0001
call i2c_tx ; 24C04 zum lesen adressieren

call i2c_rx
movfw SSPBUF ; I2C Empfangsregister auslesen
movwf DATENPUFFER ; Byte in Speicherzelle Datenpuffer retten

call i2c_off ; Bus freigeben


;***I2C UNTERPROGRAMME************************************ ************************
;
; I2C-Bus im Master-Mode übernehmen
i2c_on bcf PIR1, SSPIF ; SSPIF Bit löschen
bsf STATUS, RP0
bsf SSPCON2, SEN ; Bus Übernahme anweisen
bcf STATUS, RP0
goto i2c_warte

; ein Byte aus W senden
i2c_tx
movwf SSPBUF ; -> zum I2C-Slave übertragen
goto i2c_warte

;ein Byte vom Slave empfangen (nach SSPBUF)
i2c_rx
bsf STATUS, RP0
bsf SSPCON2, RCEN ; Daten Empfang einschalten
bcf STATUS, RP0
goto i2c_warte

; I2C-Bus wieder freigeben
i2c_off
bsf STATUS, RP0
bsf SSPCON2, PEN ; Bus Freigabe anweisen
bcf STATUS, RP0

i2c_warte
btfss PIR1, SSPIF ; fertig?
goto i2c_warte ; nein, noch nicht
bcf PIR1, SSPIF ; ja, alles fertig, nun noch SSPIF zurücksetzen
return

;***ENDE UNTERPROGRAMME************************************ **********************






; End of I2C routines

Das ist der Code von der Seite, den ich versuche zum laufen zu bekommen. Dort wird die Initialisierung genauso gemacht, wie ich das in meinem Code mache.
Mein Problem ist, dass ich gleich bei der Aktivierung des Busses im Unterprogramm (voriger durchlauf von i2c_on) i2c_warte hängen bleibe und sich der PIC dann totläuft, wenn er das setzen von SSPIF wartet.
Jemand ne Idee?

Gruß und Danke

MichaelM
11.01.2008, 09:56
Hallo,
ja die PICs sind hier in der Minderheit. Dein Problem klingt nach vergessenen Pullup-Widerständen. Können die EEPROMs wirklich 400kHz? Ich bin mir momentan nicht sicher. Mess einfach mal die Spannung an PortC.3 und .4, dort müssten eigentlich 5V anliegen. Wenn dem nicht so ist könnte ein Reset (Power-On-Reset) des Speicherbausteins nicht schaden.
Gruß,
Michael

Enrock
11.01.2008, 11:48
Servus,

ja der 24LC256 kann 400 kHz aber ich Takte mit nur 100kHz

Enrock
11.01.2008, 12:22
Achja und die Widerstände sind selbstverständlich auch vorhanden

MichaelM
11.01.2008, 17:24
Hallo,
ich habe mir jetzt mal den Code (von Sprut) im Detail angesehen. Das Einzige was mir auffällt ist ein Fehelr in der Zeile

movlw H'A0' ; 1010 0001

beim Lesen des aktuellen Bytes. Im Kommentar steht der Wert richtig drin, vorne aber nicht (H'A1' statt H'A0').

Wenn der PIC den Bus garnicht erst übernehmen kann stimmt normalerweise was mit den Pegeln an den Busleitungen nicht. Mess also bitte mal mit einem Multimeter die 5V nach. Wenn man den Bus nämlich abschießt kann es vorkommen dass eine oder beide Leitungen dauerhaft auf LOW liegen.

Ich habe soeben das Programm in einen 16F877 geladen, es läuft einwandfrei. Ich habe nur zwei Wartezeiten und ein paar nops zum Debuggen eingefügt. Die Adresse des EEPROMS (24C512) ist bei mir 0A4h.

Gruß,
Michael

Enrock
12.01.2008, 15:31
Servus Michael,

vielen Dank für die Hilfe. Ich bin leider immer noch nicht weiter mit dem Problem. Also ich habe die Pegel nachgemessen und die Datenleitung ist dauerhaft auf LOW gezogen... Habe bisher leider keine Idee wo da der Fehler liegt.
Trotzdem Danke!

Gruß Daniel

Enrock
14.01.2008, 08:07
Guten Morgen,

also ich habe gerade eine heiße Konstruktion entworfen um mir die Pins RC3+RC4 vom Kontroller abzugreifen. Und siehe da, das Schreiben auf den EEPROM funktioniert.
Ich weiß jetzt nicht ob ich mich freuen soll, da das nun bedeutet, dass ein Bauteil auf meinem Board kaputt ist.
Ich benutze das PICDEM 2 Plus Board... tja und irgendwas zieht den Pegel von RC4 auf Low. Hat jemand dasselbe Board und könnte mal die Pegel an U5 dem Temperaturfühler messen. Also an der Datenleitung.
Ich nehme nicht an, dass der Fehler am EEPROM liegt, da diese auf meiner Zusatzplatine funktioniert.

Danke
Gruß Daniel

marcemich
14.01.2008, 09:29
Hi, Hier mal der code, den ich mit dem 24AA1025 verwendet habe:




#define ADR_EEPROM1_TX b'10100000'
#define ADR_EEPROM1_RX b'10100001'






eeprom Lesen

DATEN_LESEN_B2
; bcf INTCON,GIE
call I2C_WAIT_EEPROM_NOT_BUSY_B2 ; Weiter, wenn eeprom nicht busy
call I2C_ON_B2
movlw ADR_EEPROM1_TX ; EEPROM zum Schreiben Adressieren
call I2C_TX_B2
movfw EEPROM_ADR_HBYTE ; Speicheradresse Senden
call I2C_TX_B2
movfw EEPROM_ADR_LBYTE
call I2C_TX_B2


call I2C_RESTART_B2 ; Restart
movlw ADR_EEPROM1_RX ; EEPROM zum Lesen Adressieren
call I2C_TX_B2

call I2C_RX_B2 ; Datenbyte Empfangen
movfw SSPBUF ; speichern
movwf STARTBYTE;1
call I2C_ACK_B2 ; ACK Senden

.
.hier lese ich eigentlich noch ca.30 weitere bytes ein
.
.

call I2C_RX_B2 ; Datenbyte Empfangen
movfw SSPBUF ; speichern
movwf KRAFT_BCD_Z;32
call I2C_ACK_B2 ; ACK Senden
call I2C_RX_B2 ; Datenbyte Empfangen
movfw SSPBUF ; speichern
movwf KRAFT_BCD_E;33
call I2C_NACK_B2 ; NOT- ACK Senden
call I2C_OFF_B2 ; Bus freigeben

return
;************************************************* ************************************************** *******




; eeprom beschreiben


;Datensatz Speichern
call I2C_WAIT_EEPROM_NOT_BUSY_B2 ; Weiter, wenn eeprom nicht busy
call I2C_ON_B2
movlw ADR_EEPROM1_TX ; EEPROM zum Schreiben Adressieren
call I2C_TX_B2
movfw EEPROM_ADR_HBYTE ; Speicheradresse Senden
call I2C_TX_B2
movfw EEPROM_ADR_LBYTE
call I2C_TX_B2 ;datensatz senden


movfw DATUM_BCD_Z
call I2C_TX_B2
movfw DATUM_BCD_E
call I2C_TX_B2
movfw MONAT_BCD_Z
call I2C_TX_B2
movfw MONAT_BCD_E
call I2C_TX_B2
movfw JAHR_BCD_Z
call I2C_TX_B2
movfw JAHR_BCD_E
call I2C_TX_B2
.
.
.
.


movfw KRAFT_BCD_ZT
call I2C_TX_B2
movfw KRAFT_BCD_T
call I2C_TX_B2
movfw KRAFT_BCD_H
call I2C_TX_B2
movfw KRAFT_BCD_Z
call I2C_TX_B2
movfw KRAFT_BCD_E
call I2C_TX_B2
call I2C_OFF_B2 ; Busfreigabe
call I2C_WAIT_EEPROM_NOT_BUSY_B2 ; Warten, bis speichervorgang abgeschlossen ist
return
;************************************************* ************************************************** *******


;************************************************* ************************************************** *******
; I2C Unterprogramme
;
; I2C Bus im Master Mode Übernehmen
I2C_ON_B2
bcf PIR1, SSPIF ; Interrupt flag löschen
bsf STATUS, RP0
bsf SSPCON2, SEN ; Bus übernahme anweisen
bcf STATUS, RP0
goto I2C_WARTE_B2
; I2C Bus Restart
I2C_RESTART_B2
bcf PIR1, SSPIF ; Interrupt flag löschen
bsf STATUS, RP0
bsf SSPCON2, RSEN ; Bus Restart anweisen
bcf STATUS, RP0
goto I2C_WARTE_B2
; ein Byte aus W senden
I2C_TX_B2
movwf SSPBUF ; -> zum I2C-Slave übertragen
goto I2C_WARTE_B2

;ein Byte vom Slave empfangen (nach SSPBUF)
I2C_RX_B2
bsf STATUS, RP0
bsf SSPCON2, RCEN ; Daten Empfang einschalten
bcf STATUS, RP0
goto I2C_WARTE_B2


; Warte, bis eeprom nicht busy
I2C_WAIT_EEPROM_NOT_BUSY_B2
bcf STATUS,RP0


call I2C_RESTART_B2
movlw ADR_EEPROM1_TX
call I2C_TX_B2
bsf STATUS,RP0
btfsc SSPCON2,ACKSTAT ; Wenn ACK empfangen: BEENDEN
goto I2C_WAIT_EEPROM_NOT_BUSY_B2
bcf STATUS,RP0
call I2C_OFF_B2
nop
nop
nop
nop
return
;ein Byte vom Slave empfangen (nach SSPBUF)
I2C_ACK_B2
bsf STATUS, RP0
bcf SSPCON2, ACKDT
bsf SSPCON2, ACKEN ; ACK senden
bcf STATUS, RP0
goto I2C_WARTE_B2
;ein Byte vom Slave empfangen (nach SSPBUF)
I2C_NACK_B2
bsf STATUS, RP0
bsf SSPCON2, ACKDT ; NOTACK senden
bsf SSPCON2, ACKEN
I2C_NACK1_B2
btfsc SSPSTAT,R_W
goto I2C_NACK1_B2
bcf STATUS, RP0
goto I2C_WARTE_B2
; I2C-Bus wieder freigeben
I2C_OFF_B2
bsf STATUS, RP0
bsf SSPCON2, PEN ; Bus Freigabe anweisen
bcf STATUS, RP0

I2C_WARTE_B2
btfss PIR1, SSPIF ; SSPIF == 1 ?
goto I2C_WARTE_B2 ; nein->sprung
bcf PIR1, SSPIF ; SSPIF =0
return

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

wichtig ist, dass du beim lesen nach dem senden der Speicheradresse einen RESTART sendest das ist zwar prinzipiell das gleiche wie ein STOP gefolgt von einem START aber der zeitliche ablauf ist dabei einzuhalten. also: restart verwenden.

ausserdem verwende ich vor jedem Zugriff eine funktion, die das ACHNOWLEDGE Polling durchführt und damit sicherstellt, dass das eeprom nicht noch mit schreiben beschäftigt ist.

Ich dachte auch erst, dass mein eeprom def ist, lag aber dann doch an der ansteuerung meinerseits.... so wie das doch meistens ist...

habe auch noch ein PDF von microchip angehängt, in dem der umgang mit pic und eeprom über I2C erklärt anschaulich mit code-beispielen weklärt wird. -- doch nicht. das pdf ist mit ~650kb zu gross aber ich sende es dir per e-mail, wenn du mir deine Adresse zukommen lässt...

Hartwig
25.01.2008, 22:04
Hallo Marcemich,
welches Dokument genau meintest Du denn?
magst Du mir das auch zuschicken, oder vielleicht den Link dazu?
Viele Grüße,
Hartwig

marcemich
26.01.2008, 08:44
Hallo Hartwig,

es handelt sich bei dem Dokument um einen Microchip Vortrag zum Thema I2C. es besteht aus den Vortrags-Folien und den jeweiligen Erklärungen dazu.
Einen Link dazu habe ich nicht. ich kann es dir aber gerne senden, wenn du mir deine e-mail adresse zukommen lässt.

gruss, ME

Enrock
26.01.2008, 16:44
Servus,

ich kann das nur empfehlen! Nochmal danke!

Gruß

Enrock
04.02.2008, 14:17
Servus,

ich bräuchte noch mal Hilfe.
Und zwar beschäftige ich mich mal wieder mit dem EEPROM 24LC256. Bisher schreibe ich alle Daten einzeln, also Byteweise ins EEPROM. Nun habe ich irgendwo gelesen, dass es geschickter sei, wenn man immer die gleiche Anzahl an zu schreibenden Bytes hat, das Ganze Page-Weise zu machen.
Im Datenblatt habe ich gelesen, dass ich bis zu 64 Byte gleichzeitig übertragen kann. Bedeutet das, dass ich auch weniger also beispielsweise bloß 7 Byte übertragen kann? Oder wird immer erst die komplette Page, wenn diese mit 64 Byte voll ist, geschrieben? Falls das so ist und ich vorher den Stecker ziehe, gehen dann ja meine Daten verloren?!
Wie ist denn das mit den Pages? Ich habe absichtlich eine ungerade Zahl als Beispiel gewählt. Wenn ich nun das neunte Mal 7 Byte geschrieben habe, fehlt ja noch ein Byte um die Page voll zu machen. Wenn ich nun aber erneut die 7 Bytes sende, wird dann eine neue Page begonnen oder wie funktioniert das?
Das Auslesen kann ich ja wieder Byteweise machen oder?
Des Weiter habe ich gelesen, dass diese Schreibart weniger belastend für den EEPROM sei und die Lebensdauer verlängert. Wieso? Weil die Anzahl des Schreibzyklus geringer ist?!
Gibt es sonst noch Vor- oder Nachteile?

Danke
Gruß

MichaelM
04.02.2008, 20:50
Hallo,
du kannst maximal 64 Bytes auf einmal schreiben. Der Baustein hat intern ein RAM mit 64 Byte. Wenn jetzt ein Schreibbefehl kommt werden die ankommenden Bytes erstmal in das RAM geschrieben. Wenn die Datenübertragung abgeschlossen ist werden die Bytes ins EEPROM geschrieben, das dauert etwa 1 bis 10 ms. Wenn du nun immer 7 Bytes schreibst werden diese 7 Bytes immer im RAM an die gleiche Adresse gelegt (was dir eigentlich egal sein kann ...) und anschließend diese 7 Bytes ab der angegebenen Adresse ins EEPROM geschrieben. Wenn du also in deinem Schreibbefehl die Adresse 50 angibst werden die 7 Bytes zunächst im RAM an Adresse 0 bis 6 und anschließend im EEPROM an Adresse 50 bis 56 geschrieben. Wenn du nun 15 Bytes schreibst landen die eben an Adresse 0 bis 14 im RAM und 50 bis 64 im EEPROM. Für das EEPROM ist es egal ob ein oder 64 Bytes geschrieben werden, es hält etwa 100000 dieser Prozeduren aus.

Gruß,
Michael

Die Zahlen habe ich jetzt nicht nachgeprüft, ich vertraue dir voll und ganz ;-)

Enrock
05.02.2008, 06:40
Guten Morgen,

na das nenn ich mal ne Antwort auf meine Fragen!
Noch eine Frage...
Habe ich das richtig verstanden, dass ich mich um die Adresse im RAM nicht zu kümmen brauche? Für mich ist nur die Adressierung der EEPROM-Zellen interessant, ja?
Hm alles klar, dann ist es, wie erwartet, besser mit Blöcken zu arbeiten. Na dann leg ich gleich mal los.

Gruß und DANKE!

MichaelM
05.02.2008, 15:31
Hallo,
jawoll das RAM ist für dich völlig belanglos. Das einzig interessante daran ist die Größe, also wieviele Bytes man auf einmal schreiben kann.
Gruß,
Michael