Hallo!
Ich habe folgendes Problem. Es geht um ein Projekt mit dem MSP430,
genauer gesagt dem MSP430F1611. Teil dieses Projektes ist es, Presets in
ein EEPROM zu schreiben und später wieder daraus zu lesen. Genau hier
liegt mein Problem, denn das funktioniert offenbar nicht.
Mein MSP430 läuft mit einem 4MHz-Quarz; sowohl MCLK als auch SMCLK
laufen mit 4MHz. Da ich die beiden UARTs bereits anderweitig in Gebrauch
habe, habe ich das EEPROM an zwei GPIO-Pins angeschlossen und den
I²C-Bus per Software realisiert. Die Pins sind P4.3 (SDA) und P4.4
(SCL). Beide sind mit 10k-Pullup-Widerständen gegen Vcc (+3,3V)
versehen. Ich war davon ausgegangen, daß man hier die freie Wahl der
GPIO-Pins hat, da man ja nicht auf die I²C-Pins der UART0 des MSP430
festgelegt ist.
Hardwaremäßig habe ich keinen Fehler finden können; ich gehe davon aus,
daß in der Software was nicht stimmt. Wie ist es denn z.B. mit dem
I²C-Takt, der ja 100kHz oder 400kHz betragen soll. Kann mir jemand
zeigen, wo das in den Assembler-Routinen eingestellt wird? Sind
vielleicht die Pullup-Widerstände zu groß - laut Datenblatt des 24LC64
sollen es 10k für einen I²C-Takt von 100kHz und 2k für 400kHz sein. Ich
weiß halt nicht, wie hoch mein I²C-Takt überhaupt ist.
Hier mal der Code, den ich hierfür benutzt habe. Im C-Headerfile werden
die Routinen
deklariert. Über diese beiden soll der Schreib- und Lesezugriff auf das
EEPROM von C aus erfolgen. Die Routinen stammen nicht von mir - da sie
in anderen Projekten bereits erfolgreich eingesetzt wurden, habe ich sie
von dort übernommen. Da ich mich mit Assembler-Programmierung nicht
auskenne - was kann ich daran vielleicht noch verändern? Kann der Fehler
darin liegen?
Wie gesagt, ich habe die Routinen nicht selbst erstellt, sondern von
einem anderen Projekt übernommen. Dort hat die Sache mit genau diesem
Code funktioniert. Da der MSP430 in dem anderen Projekt mit dem internen
DCO bei ca. 800kHz betrieben wurde, hatte ich testweise mal die
Initialisierung meines Quarzes auskommentiert, aber auch mit dem DCO
funktioniert es bei mir nicht. Ich habe keine Ahnung, wo der Fehler
liegen könnte - nicht, daß am Ende mein EEPROM defekt ist...
Christian Z. wrote:
> Hat denn keiner eine Idee? Die Pullup-Widerstände kann ich ausschließen;> habe es heute mal mit 2k versucht, aber es hat sich nichts geändert...
ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library
von Peter Fleury an...da ist auch Assembler-Code für eine
Software-Implementierung für i2c dabei. Der ist zwar dafür gedacht, von
c aus aufgerufen zu werden, aber vielleicht hilft es dir ja weiter...
> ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library> von Peter Fleury an...da ist auch Assembler-Code für eine> Software-Implementierung für i2c dabei.
Ich hab grad mal danach gesucht. Was ich gefunden habe, ist aber für AVR
und nicht für den MSP430. Hab ich nicht richtig gesucht, oder meintest
du das? Dann hilft mir das leider nicht, sorry.
> Der ist zwar dafür gedacht, von c aus aufgerufen zu werden
Ist bei mir auch so, die Assemblerroutinen werden von C aus aufgerufen.
Du meinst die slaa330.pdf? Die habe ich schon gelesen. Worüber ich dort
stutzig geworden bin, ist folgendes: Für einen I²C-Takt von 100kHz
werden dort µC-Takte von Minimum 5,22MHz (schreiben) und 6MHz (lesen)
angegeben. Mein MSP430 läuft, wie gesagt, mit externem Quarz an XT2 mit
4MHz. Kann es denn daran liegen? Ich wundere mich nur, da die Routinen
vorher in einem Projekt genutzt wurden, bei dem der MSP430 mit dem DCO
in Standardeinstellung genutzt wurde, also mit ca. 800kHz lief. Kann ich
denn vor dem Aufruf der Lese- oder Schreibroutinen einfach die
Takterzeugung ändern? Also den MSP430 für den normalen Betrieb mit
externem Quarz und 4MHz initialisieren und vor dem Zugriff auf die
I²C-Routinen auf den DCO mit z.B. 6MHz wechseln? Nach dem I²C-Zugriff
müßte ich dann wieder zurückwechseln. Geht das? Könnte das Problem daran
liegen?
Der Takt wird bei I²C erzeugt indem SCL auf 1 und dann wieder auf 0
gesetzt wird.
1
bic.b #SCL,&I2C_PORT_DIR ; SCL=1, Master No Acknowledge
2
nop ; Verzögerung für I²C-
3
; Spezifikation
4
nop ;
5
bis.b #SCL,&I2C_PORT_DIR ; SCL=0
Hast du dir die Kommentare angeschaut? "Verzögerung für
I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen
sie bei 4MHz natürlich deutlich schneller...
Details zu I²C findest du in der Spezifikation von NXP oder Philips:
http://www.jp.nxp.com/acrobat_download/literature/9398/39340011.pdf
Im Datenblatt des EEPROMs findest du normalerweise auch Informationen
wie I²C Signale aussehen.
Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du
die Routinen ausführst? Vielleicht hast du deine Hardware falsch
initialisiert... es gibt so viele Fehlermöglichkeiten... es könnte auch
sein, dass dein C-Compiler die Parameter falsch an die
Assembler-Routinen übergibt.
Wie macht sich denn das Problem denn bemerkbar? Was hast du denn bisher
alles untersucht um den Fehler zu finden? Warum nimmst du nicht I²C
Routinen, die in C implementiert wurden wenn du kein Assembler kannst?
Z.B.
http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#I2C.2FTWI_in_Software
Hallo Kamil!
> Hast du dir die Kommentare angeschaut? "Verzögerung für> I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen> sie bei 4MHz natürlich deutlich schneller...
Natürlich habe ich mir die Kommentare angeschaut. Ich wußte nur nicht,
daß mit "für I²C-Spezifikation" die Takterzeugung gemeint ist. Du meinst
also, mit einer Anpassung an der Stelle könnte es klappen? Werde ich mal
ausprobieren.
> Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du> die Routinen ausführst? Vielleicht hast du deine Hardware falsch> initialisiert...
Ich habe das Oszi schonmal drangehabt und es passiert auch was. Aber ich
konnte die Sequenz noch nicht festhalten, also einfrieren, um sie
auszuwerten. Die Hardware ist, denke ich, richtig initialisiert, denn es
funktioniert ja sonst alles.
> es könnte auch sein, dass dein C-Compiler die Parameter> falsch an die Assembler-Routinen übergibt.
Ich benutze IAR Embedded Workbench, da sollte es eigentlich keine
Probleme geben.
> Wie macht sich denn das Problem denn bemerkbar?
Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht
daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben
und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die
C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und
Lesen stimmen überein.
Hier mal meine Schreib- und Leseroutinen im C:
for(i=0;i<NUMBER_OF_PRESETS;i++)// Presetwerte ins EEPROM schreiben
71
{
72
for(j=0;j<8;j++)
73
{// Schreiben ab Adresse 5001 bis 6600
74
Write_A16_I2C_BYTE(0x50,5001+8*i+j,values[i][j]);
75
WAIT_ms(3);
76
}
77
}
78
}
> Was hast du denn bisher alles untersucht um den Fehler zu finden?
Den Aufbau habe ich auf Kurzschlüsse und Leiterbahnunterbrechungen
untersucht. Die Pullup-Widerstände an SCL und SDA habe ich gegen andere
Werte getauscht. Ich habe nachgesehen, ob bei einem Zugriff an beim
EEPROM ein Signal ankommt, konnte dieses aber wie gesagt noch nicht
auswerten. Die C-Routinen sollten meiner Meinung nach auch ok sein. Mehr
habe ich nicht untersucht, weil mir die Ideen ausgingen, was ich noch
untersuchen könnte...
> Warum nimmst du nicht I²C Routinen, die in C implementiert wurden> wenn du kein Assembler kannst?
Weil ich noch keine gefunden hatte und ich angenommen hatte, daß ich mit
den Assemblerroutinen arbeiten kann, weil sie schon getestet wurden...
> Z.B.> http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#I2C.2FTWI_in_Software
Danke, das habe ich offenbar bisher übersehen! Ich schaus mir mal an.
Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie
siehts mit dem Pin WP aus?
Bist du dir sicher, dass IAR die Parameter richtig an die Assembler
Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den
Registern
> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie> siehts mit dem Pin WP aus?
Die liegen allesamt an Masse.
> Bist du dir sicher, dass IAR die Parameter richtig an die Assembler> Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den> Registern>
Entweder in der Dokumentation vom IAR-Compiler nachlesen wie er das
macht oder Schritt für Schritt debuggen (nicht den C-Code sondern den
Assembler-Code).
Bei MSPGCC sieht es mit der Parameterübergabe so aus: Es wird zuerst R15
dann R14,... bis R12 verwendet (in dieser Reihenfolge) Bei mehr
Parametern wird der Stack verwendet. Wie es IAR macht hab ich allerdings
keine Ahnung... aber irgendwie habe ich das Gefühl, dass es nicht R12,
R14 und dann R13 ist. Man kann jedoch nie wissen...
Hier das dazugehörige Dokument, dass dir die Parameterübergabe erklärt:
http://focus.ti.com/mcu/docs/mcusupporttechdocsc.tsp?sectionId=96&tabId=1502&abstractName=slaa140
Hier ist also definitiv der Fehler. So sollte es sein:
Parameter 1 (SlaveAdresse) aus Register R12 laden
Parameter 2 (PointerAdresse) aus Register R14 laden
Parameter 3 (SendeDaten) vom Stack holen
Das heißt aber nicht, dass das alles war. Das Clock-Signal könnte noch
immer zu kurz sein.
Ic hab gerade nochmal nachgesehen. Eigentlich macht der Code doch, was
er soll.
>Parameter 1 (SlaveAdresse) aus Register R12 laden>Parameter 2 (PointerAdresse) aus Register R14 laden>Parameter 3 (SendeDaten) vom Stack holen
Das letzte passiert doch mit dieser Anweisung unter Write_A16_I2C_BYTE:
1
mov.b2(SP),SendeDaten
Der Parameter 3 wird vom Stackpointer geholt und in R13 abgelegt. Sollte
doch so ok sein?
Kamil P. wrote:
> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie> siehts mit dem Pin WP aus?
Es könnte sein, dass die SlaveAdresse falsch ist. Oder das die
Writeprotection aktiviert ist.
Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt
sein...)
> Es könnte sein, dass die SlaveAdresse falsch ist.
Laut Datenblatt ist 50h richtig.
> Oder das die Writeprotection aktiviert ist.
Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen
sein.
> Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt> sein...)
Das habe ich auch schon überlegt. Probiert habe ich das aber noch nicht,
da ein neues erst bestellt werden müßte.
Christian Z. wrote:
>> Es könnte sein, dass die SlaveAdresse falsch ist.>> Laut Datenblatt ist 50h richtig.>
Die Adresse ist abhängig von den Pins A0 bis A2.
>> Oder das die Writeprotection aktiviert ist.>> Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen> sein.>
Schau im Datenblatt nach.
>Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht>daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben>und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die>C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und>Lesen stimmen überein.
Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu
schreiben)?
Ist das EEPROM 100%ig richtig angeschlossen? Hast du dir die Signale an
SDA und SCL angeschaut und analysiert? Deinen Code schon mal Schritt für
Schritt mit dem Debugger abgearbeitet?
> Die Adresse ist abhängig von den Pins A0 bis A2.
Richtig, sie setzt sich aus dem Control Code 1010 und den Bits für A2,
A1, A0 zusammen. Da A0 bis A2 Null sind (und das sind sie definitiv),
heißt die Adresse 1010000b = 50h.
> Schau im Datenblatt nach.
Daher weiß ich ja, daß das so ist.
> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu> schreiben)?
Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM
geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff
erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben
erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen
wird.
> Ist das EEPROM 100%ig richtig angeschlossen?
Ja, definitiv. Das habe ich mehrfach penibelst überprüft.
> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?
Noch nicht weiter als oben schonmal beschrieben.
>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?
Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen
Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.
> Probier doch mal just4fun 0xA0...
Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann
müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört
eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...
Christian Z. wrote:
>> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu>> schreiben)?>> Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM> geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff> erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben> erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen> wird.
Mit einem Schreibgerät das EEPROM beschreiben und dann mit deiner
Hardware auslesen.
>> Ist das EEPROM 100%ig richtig angeschlossen?>> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?>> Noch nicht weiter als oben schonmal beschrieben.
Unbedingt überprüfen, ob da alles stimmt.
>>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?>> Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen> Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.
Ohne zu wissen wie man einen Debugger verwendet, wirst du sehr viel Zeit
mit Fehlersuche verbringen. Ließ dir also unbedingt Tutorials durch.
Debugger sind normalerweise sehr einfach zu bedienen.
Christian Z. wrote:
>> Probier doch mal just4fun 0xA0...>> Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann> müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört> eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...
aber es gehört zum ersten übertragenen Byte...Bits 7-4 für den Typen,
3-1 für A0..A2 und Bit 0 für R/W..und soweit ich sehe, wird deine
1010000 im Code nicht automatisch geshiftet:
1
mov.bSlaveAdresse,RXTXI2C;Slave-AdresseinsRXTX-
2
;Registerladen
3
bis.b#01h,RXTXI2C
so wie ich das verstehe, wird im Moment deine 7Bit lange Adresse in das
Register kopiert und dann das letzte Bit geändert, was eigentlich noch
deinem A0 entsprechen würde
Die Adresse zu ändern hat nichts gebracht. Ich habe mal den Takt an SCL
(gemessen direkt am EEPROM) mit dem Oszi untersucht; ein Bild davon ist
im Anhang. Die Frequenz bewegt sich mit ca. 160kHz in Bereichen, die
schonmal nicht völlig falsch sind. Ich weiß nicht, wie ich die Form der
High-Pegel deuten soll. Sind derart verschliffene Taktspitzen ok?
Das kommt durch die PullUps, und dadurch, dass der MSP430 den High Pegel
nicht treibt, sondern den Pin auf Eingang schaltet. Eventuell sind die
Widerstände zu hochohmig. Und so asymmetrisch ist das ganze ja auch.
Ich habe jetzt mal versucht, alternativ die Hardware-I²C-Schnittstelle
der UART0 zu benutzen. Ich stehe dabei jedoch schon wieder vor dem
nächsten Problem:
Ich benutze diese Routinen, die TI irgendwo als Beispielcode
vorgeschlagen hat (s.Anhang).
Irgendwo scheint noch was nicht zu stimmen. Wenn ich schreiben will,
rufe ich
1
EEPROM_Write(adresse,daten);
auf, gefolgt von
1
EEPROM_Ack_Polling();
Beim Ack_Polling bleibt er dann bei
1
while(I2CTCTL&I2CSTT);
hängen. Wenn ich zum Lesen
1
EEPROM_Read(adresse);
aufrufe bleibt er bei
1
while((~I2CIFG)&ARDYIFG);
hängen.
Habe ich irgendwo einen Fehler drin? Muß ich beim Aufrufen noch
irgendwas beachten?