Forum: Mikrocontroller und Digitale Elektronik MSP430 und ADXL345 Sensor via i2c - Probleme


von Markus D. (daubsi)


Angehängte Dateien:

Lesenswert?

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!

von Jörg S. (joerg-s)


Lesenswert?

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.

von Markus D. (daubsi)


Lesenswert?

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.

von Markus D. (daubsi)


Lesenswert?

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?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Beide Widerstände müssen Pullups sein, gegen GND dürfen diese nicht 
geschaltet werden.

von Markus D. (daubsi)


Lesenswert?

Die Widerstände stecken in der VCC Rail. Sorry, falls das aus meiner 
Zeichnung nicht klar hervor ging.

von Jörg S. (joerg-s)


Lesenswert?

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?

von Markus D. (daubsi)


Lesenswert?

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)
1
P3SEL |= 0x06; // P3.1 + P3.2 USBI_B0 option select  
2
UCB0CTL1 |= UCSWRST;                      // Enable SW reset
3
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
4
UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
5
UCB0BR0 = 0x0b;                             // fSCL = SMCLK/11 = 95.3kHz  
6
UCB0BR1 = 0;
7
UCB0I2CSA = 0x1d;             // Set slave address (translates to 0x3a for write and 0x3b for a read
8
UCB0CTL1 &= ~UCSWRST;
Ich habe mit diesem Prescaler auch schon gespielt (/63 usw.) Die Takte
wurden entsprechend länger, aber am Verhalten hat sich nichts
geändert...

von Markus D. (daubsi)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

Noch mal zusammengefasst: Die Kommunikation usw. geht alles problemlos, 
nur ab und zu bleibt der MSP hängen?

von Markus D. (daubsi)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.