Hallo,
ich befasse mich in den letzten Tagen mehr oder weniger erfolgreich mit
der MSP430 Plattform, nachdem ich zunächst nur ATmegas benutzt habe.
Hintergrund ist der, dass ich mit einem µC einen ADXL345 Sensor
ansprechen/testen möchte, der nur 3.3V verträgt, und ich es nicht
hingekriegt habe, mit einem ATmega8 mit diesem zu kommunizieren. Um
auszuschließen, dass es an der 5V->3.3V Konverter-Schaltung lag, die ich
im Internet gefunden hatte, habe ich mir gedacht: Versuche ich das
einfach mal mit dem MSP430FG4016 vom dem Experimenters Board.
Zunächst wollte ich die Ansprache mittels SPI versuchen (Siehe dazu auch
Beitrag "MSP430FG4618/2013 Experimenters Board - Anfängerfrage"). Hat leider nicht so recht
geklappt, weil der Sensor sehr seltsam reagierte. Nun habe ich mich
heute an i2c versucht.
Leider bin ich hier auch nicht sehr erfolgreich gewesen:
Zwar war Erfolg insofern da, dass ich a) Die ID des Sensors erfolgreich
auslesen konnte, b) ich ihn in den Measurement Modus schicken konnte.
Heißt also, der Sensor scheint doch nicht hin zu sein, auch wenn die
Kommunikation via SPI irgendwie gar nicht geklappt hatte.
Aber: Ich habe immer wieder Hänger in der Kommuniation gehabt, die es
nötig machten, dass ich entweder den Sensor power-toggeln mußte oder den
µC, sprich: irgendwas stimmt da noch nicht, aber ich kann nicht mit
Bestimmtheit sagen, ob der Sensor doch wirklich nen Hau hat oder ob mein
USCI Code nicht passt... - ich vermute letzteres.
Den Code um den Sensor via i2c anzusprechen habe ich aus verschiedenen
Quellen:
a) Aus den TI Code samples (msp430xG46x_uscib0_i2c_0x) - keines der
Beispiele scheint sich aber mit dem "Spezialfall" der Ansprache eines
Sensors zu beschäftigen, wo ich ein Write an den Sensor mache um ein
Register zu selektieren und danach davon lese.
b) Aus anderen Artikeln hier im Forum (der Code von dort hat dann
zumindest funktioniert, wenn auch nur R/W mit 1 Byte)
c) Aus der TI "Using the USCI i2c Master" (SLAA382) Doku
(http://focus.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=slaa382)
Ich habe das Verhalten mit einem Oszi an SCL und SDA beobachtet. Mir ist
aufgefallen, dass immer wenn das Programm hängt, dann SCL low bleibt,
anstatt wieder high zu werden. Ob jetzt da die richtigen Stop-Bits auf
der Leitung waren, kann ich anhand der Darstellung im Oszi leider nicht
sehen. Woanders habe ich dann gelesen, dass das mit den
Pullup-Widerständen zu tun haben könnte. Ich habe mich an die
TI-Beispiele gehalten, wo immer die Rede von 10k Widerständen ist, habe
dann aber gelesen, dass bei 3.3V deutlich geringere Werte
möglich/sinnvoll sind. Bin zuletzt über 4.7k bis auf 2.2k runter, aber
auch dies hat keine Verbesserung gebracht.
>> Welche Werte soll ich denn nun konkret einsetzen? Ich habe nur diesen Sensor im
i2c Netz, er ist auf einem Breadboard mit eigener 3.3V Stromversorgung und die
Leitung ist ca. 20cm bis zum µC.
Ich setze keine Interrupts im Code ein, somit sollte auch ein
"zufälliges" Falschverhalten ausgeschlossen werden können, je nach
Timing. Ich habe schon verschiedene Prescaler beim Initialisieren des
i2c USCI getestet um die Taktrate anzupassen, auch dies hat keine
Besserung gebracht.
Ich würde mich freuen, wenn mal jemand einen Blick auf den Code werfen
könnte und mir Hilfestellunge geben könnte.
Nochmal zur Erläuterung was der Code machen soll und wo es Probleme
gibt:
Zeile 66-76: i2c initialisieren. Die 7Bit adresse des Sensors ist 0x1d.
Ein Read ist demnach ein 0x3a und ein Write ein 0x3b. (Soweit ich das
verstanden habe, muß ich die aber nie explizit angeben, sondern da
kümmert sich der USCI Baustein drum, je nachdem ob ich UCTR in UCB0CTL1
setze oder nicht?)
Zeile 81-84: Ein Read auf das Register 0x00. Der Sensor schickt
daraufhin seine ID zurück. Diese muss 0xE5 sein. Klappt in 95% aller
Fälle. Manchmal hängt hier dann einfach alles.
Zeile 93-107: Hier aktiviere ich den Measurement-Mode. Zuerst wird in
das Register 0x2d der Wert 0x28 geschrieben. Danach lese ich den Wert
wieder aus und prüfe ob er wirklich 0x28 ist. Dies ist 1:1 von einem
Codebeispiel von Sparkfun. Anscheinend klappt das nicht immer beim
ersten Mal...
Hier hängt sich der Code oft weg oder er kriegt immer nur 0 zurück
anstatt 0x28. Beim Debuggen ist mir hier aufgefallen, dass "manchmal" in
Zeile 175 sehr wohl in UCB0RXBUF 0x28 steht, beim Verlassen der Routine
*data aber wieder 0x00 hat... Wie kann das sein?
Wenn ich dann die Stromversorgung zum Sensor kappe und wieder anlege,
klappt das Setzen des Wertes meistens sofort danach.
Was mir sonst noch aufgefallen ist:
Wenn sich mal wieder alles so richtig aufgehängt hat ist SCL low und
bleibt low (sehe ich am Oszi). Und das auch wenn ich den Sensor
ausgeschaltet habe. Das ist mir völlig schleierhaft, da die
Stromversorgung noch an ist, und aufgrund des Pullup-Widerstands doch
der Pegel wieder auf High gehen muß, weil er doch mit VCC verbunden
ist??? Nach ein paar Mal Ein-/Ausschalten des Sensros, Restart des µC
via JTAG Interface usw. geht es dann irgendwann wieder und der Bus
initialisiert mit High auf SCL und SDA und ich darf's nochmal
probieren...
Das Datenblatt zum Sensor gibt es übrigens hier:
http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf
Bei Sparkfun kommt der Sensor leider nicht besonders gut weg
(http://www.sparkfun.com/products/9156) und es gibt noch andere die über
Probleme schreiben. Ich würde aber gerne wissen, ob meine Probleme auch
von dem Sensor herrühren können oder ob ich hier einfach einen dummen
Anfängerfehler gemacht habe.
Also, passt mein Code oder springt Euch irgendwas ins Auge?
Vielen Dank für Eure Mühe!
Du könntest ja zunächst mal rausfinden wer denn SCL auf low hält. Ich
würde zwei Jumper einbauen (Einer vom Pull-Up Richtung µc und einer vom
Pull-Up Richtung Sensor) und dann die Jumper ziehen und schauen wann die
Spannung an SCL wieder high wird.
Als es scheint mir so, als würde der Sensor SDA runterziehen... ich sage
"scheint so", weil es gerade ganz seltsam war: Ich habe die Jumper in
beide Richtungen geöffnet, so dass eigentlich auf jeden Fall der Pegel
wieder hoch gehen musste, aber er war immer noch low...
Nachher war es dann reproduzierbar, dass beim Verbinden mit dem Sensor
SDA auf low geht.
Jetzt aber nochmal für Doofe: Ich hab zum ersten Mal so eine i2c
Schaltung aufgebaut. Nur um Auszuschliessen, dass ich das völlig falsch
gemacht habe:
------------------------------ GND Rail des Breadboards
++++++++|+++++++++|+++++++++++ VCC Rail des Breadboards
|R1,4.7k |R2,4.7k
| |
----- | |
SCL |-------------|------> to MC pin
SDA |-------------|------> to MC pin
|
-----
Das ist doch so richtig, oder? Die beiden Rs berühren sich natürlich
nicht und haben nur Kontakt mit ihrer jeweiligen Leitung.
Nachtrag: Es ist also wirklich SDA low, SCL ging wieder hoch. Gerade
habe ich den Fall, dass er sich "verschluckt" hat (Habe gerade oben
gesehen, dass ich mich in meinem Original-Post daher verschrieben hatte.
SCL verhält sich normal).
Was ist denn im Allgemeinen der Grund für so ein Verhalten. Kann das ein
Timing-Problem sein (Bustakt zu schnell?). Oder liegt sowas an falschen
Pullup-Widerständen? Oder ist der Sensor einfach kaputt?
SDA wird runter gezogen wenn er einen ACK auf den Bus legen will. Evt.
bekommt er den nächsten SCL Takt nicht mit und lässt SDA deshalb weiter
unten.
Wie schnell ist denn dein I2C Bus?
So, hatte die Antwort leider im falschen Thread gepostet. Hier nochmal:
--
Ich weißt es nicht 100%, da ich es nicht selbst definiert habe, aber
wenn ich mir die Kommentare zu dem Codeschnippsel ansehe, dass ich zum
Initialisieren des i2c Busses aus den TI Examples genommen habe würde
ich sagen die normalen ca. 100 kHz (siehe UCB0BR0 = 0x0b Anweisung)
Das Thema hat mir keine Ruhe gelassen...
Ich habe heute mal meinen "Bus Pirate" ausgepackt und habe mal versucht
über den mit dem Sensor zu sprechen und siehe da... DeviceID=E5,
Measurement Mode aktiviert, alles ging...
Habe dann auch mit dem Oszi mir die Kommunikation angesehen und war aber
wieder verwundert, da SDA irgendwie um die 0V rumzuckelte und auch im
Leerlauf nur 0V hatte, obwohl SDA über den Pullup direkt mit VCC
verbunden war... Dachte ich mir, "Gibts doch nicht!" und hab dann mal
mit dem Multimeter nachgemessen... aha! 3V!?!?!
Lange Rede, kurzer Sinn: Nach einigen Ausschlusstests hat sich
rausgestellt, dass wohl der Plastik-Aufsatz für den einen Tastkopf bei
meinem Oszi einen Wackelkontakt hat (und zum Glück das Oszi in Ordnung
ist...). "Drückt" man ihn ein bisschen zurecht, hat man auf einmal
wieder ein schönes Signal im Oszi (Merke: Billig-Probes vom C auf den
Müll werfen und noch einen Testec Kopf kaufen...)
Ok, das heißt nun zumindest, dass i2c funktioniert und ich den Fehler
erstmal ganz woanders gesucht hatte. SPI habe ich noch nicht
ausprobiert, wird dann aber vermutlich auch gehen. Nur - in meinem
Programm funktionierts halt deswegen immer noch nicht...
Das bringt mich aber zu meiner ursprünglichen Frage zurück: Offenbar
mache ich ja bei der i2c Kommunikation irgendwas falsch, vergesse ein
ACK oder NACK oder sonstwas.
OK - aber es muss für sowas aber doch fertige Bibliotheken geben, oder
nicht?? Wie setzt Ihr denn i2c Funktionen in Euren Programmen ein? Das
wird doch nicht nur via "Bit banging" gemacht?
Grüße,
Markus
Hmm... lass es mich anders sagen: Anscheinend geht i2c problemlos, da es
mit dem BusPirate (http://dangerousprototypes.com/docs/Bus_Pirate) als
i2c Master ohne Probleme (=Hänger) funktioniert. Ich habe bislang i2c
nur beim Auslesen eines LM75 verwendet, und der ist ja sehr einfach
gestrickt. Insofern möchte ich nicht mit Sicherheit sagen, dass die
Kommunikation (mit dem MSP430) problemlos funktionierte. Ich vermute
halt, dass mein Code ganz oben, "das" nicht ganz richtig gemacht hat,
aber ich weiß halt nicht, wie es gemacht werden muss. Die Konsequenz
davon war dann, dass das Programm dann hing, weil er wahrscheinlich
irgendein IO Flag, dass erwartet wurde, nicht empfangen oder versendet
hatte. Auf dem Oszi stellte sich das ja so da, dass SDA nicht wieder
freigegeben wurde - hier hatte ich aber bis dato noch nicht ermitteln
können, woran das lag.
Grüße,
Markus