Hallo Zusammen,
Ich befasse mich die letzten Tage zum ersten Mal mit dem I²C Interface
des MSP430f2617. Als Basis für meine Software dient mir eine Appnote von
TI (SLAA382). Ich führe in einem bestimmten Intervall (Timer) eine
Messung durch. Nun beobachte ich folgendes Verhalten:
So lange der Sensor nicht angeschlossen ist, sendet der MSP die korrekte
Adresse des Sensors + Schreibbefehl, bekommt aber natürlich kein ACK
(siehe Bild, leider schlechte Quali) vom Sensor. Sobald ich den Sensor
jedoch an den MSP hänge, bleibt das Programm an folgender Funktion
hängen:
1
unsignedcharI2C_notready(){
2
return(UCB0STAT&UCBBUSY);
3
}
Der Takt ist das auf HIGH und die Datenleitung auf LOW und nüscht tut
sich mehr.
Vorher wird ein transmitinit ausgeführt (von TI übernommen):
1
P3SEL|=SDA_PIN+SCL_PIN;// Assign I2C pins to USCI_B0
Vielleicht hat jemand von euch ein Idee wo das Problem liegen könnte. Da
ich schon den ganzen Tag dran hänge, kann es sein, dass ich mich ein
wenig kryptisch ausgedrückt habe. Für Fragen haben ich also ein offenes
Ohr ;)
Grüße
Seb
Kann ich mal versuchen. Hatte laut Hersteller 10k genommen.
Kann man den Hänger im Programm denn darauf zurückführen? Bis dahin
findet ja noch gar keine Kommunikation statt.
Gruß
Seb
Ich verstehe vom dem Prozessor nix, aber vielleicht sollte es ja statt:
return (UCB0STAT & UCBBUSY); (Bitweises UND)
eher
return (UCB0STAT && UCBBUSY); (Nur wenn beide wahr, dann alles wahr)
heissen?
A. K. schrieb:
> Der Ablauf kommt mit etwas seltsam vor. Ich habe in Erinnerung, dass bei> I2C üblicherweise SCL und SDA nicht gleichzeitig auf 0 gehen.
Mir ist nicht bekannt das das eine Rolle spielen sollte. Ausserdem
dürfte der Hardware I2C vom MSP das wohl richtig machen :)
Seb schrieb:
>So lange der Sensor nicht angeschlossen ist, sendet der MSP die korrekte>Adresse des Sensors + Schreibbefehl, bekommt aber natürlich kein ACK>(siehe Bild, leider schlechte Quali) vom Sensor.
Wäre ein Bild der Kommunikation die nicht geht nicht vielleicht besser?
>Der Takt ist das auf HIGH und die Datenleitung auf LOW und nüscht tut>sich mehr.
Bitte genauer erklären.
Pete K. schrieb:
> Ich verstehe vom dem Prozessor nix, aber vielleicht sollte es ja statt:> return (UCB0STAT & UCBBUSY); (Bitweises UND)>> eher> return (UCB0STAT && UCBBUSY); (Nur wenn beide wahr, dann alles wahr)>> heissen?
Nö, das ist schon richtig so. UCB0STAT ist das Register, UCBBUSY das Bit
im Register.
A. K. schrieb:
> Der Ablauf kommt mit etwas seltsam vor. Ich habe in Erinnerung, dass bei> I2C üblicherweise SCL und SDA nicht gleichzeitig auf 0 gehen.
Tun sie ja auch nicht. Der MSP generiert jeweils eine
Start/Stop-Bedingung, welche die Kommunikation mit dem Slave einrahmen.
Bei der Start-Bedingung geht der Datenleitung auf low während Takt noch
high ist. Bei stop ists läuft es andersrum ab.
Jörg S. schrieb:
> Wäre ein Bild der Kommunikation die nicht geht nicht vielleicht besser?
Tja, genau da gibt es ja nicht viel zu sehen, da gar keine Kommunikation
zustande kommt. Der Leitung wird als "busy" erkannt und das Programm
bleibt in der Schleife bei der Statusabfrage hängen. Wenn ich das Oszi
an den Takt halte ist dieser high und die Datenleitung liegt auf low.
Den anderen Beitrag werde ich mir direkt mal reinziehen. Schonam Danke
für die Hilfe.
Das Abziehen des Programmier-Interfaces hat bei mir genauso wenig
gebracht wie der vorgeschlagene zyklische Reset (UCB0CTL1 |= UCSWRST;),
falls das busy-bit gesetzt ist.
Nun verfolge ich diese Lösung:
"Die Lösung lag darin, nach Power-On des Mikrocontrollers einfach einige
zig Takte auf SCL manuell zu erzeugen, während SDA=1 bleibt. Dadurch kam
die State-Machine im EEPROM wieder in den Tritt und der I2C Controller
im Mikrocontroller fand bei Erzeugung der Start-Bedingung den korrekten
Zustand SDA=1 vor!
"
Bin mir aber noch nicht sicher wie ichdas bewerkstelligen soll. Einfach
den SCL-PIN mit der Erstfunktion (I/O) hoch- und runterziehen?
Das Gewackel mit dem SCL-PIN habe ich nun auch hinter mir. Habe zu
Beginn der main() 50 Takte auf die SCL-Leitung gegeben während SDA high
war. Also eigentlich so wie es in dem anderen Forenbeitrag beschrieben
wurde. Danach läuft das Programm trotzdem in die busy-Schleife.
Ich versuche jetzt mal kleinere Pullups. Vielleicht liegt es ja wirklich
an den runden Flanken.
Busy auf dem I2C-Bus bedeutet eigentlich nichts anderes, als dass der
Master SDA auf Low sieht, obwohl er High erwartet. Jedoch tritt diese
Bedingung normalerweise nur im Multimasterbetrieb auf.
Den MSP kenne ich nicht, und du schreibst nicht, mit welchem Sensor du
getestet hast. - Hm.
Pullups 1,8k - 4,7k?
Welcher Sensor?
Konntest du Verdrahtungsfehler auschließen?
Test mit einem anderen I2C-Slave?
Welche Busgeschwindigkeit?
Wurde vor dem Busy-Zustand eine Startcondition gesendet?
Wenn ja, wie viele Takte wurden ausgegeben?
Michael L. schrieb:
> Pullups 1,8k - 4,7k?> Welcher Sensor?> Konntest du Verdrahtungsfehler auschließen?> Test mit einem anderen I2C-Slave?> Welche Busgeschwindigkeit?> Wurde vor dem Busy-Zustand eine Startcondition gesendet?> Wenn ja, wie viele Takte wurden ausgegeben?
Hi Michael,
Danke dir jetzt schonmal für deine Hilfe. Nun zu deinen (berechtigten)
Fragen:
1. Pullups hatte ich, wie weiter oben erwähnt, 10k. Seit ein paar
Minuten sind erstmmals 4k7 drin gelandet. Die Flanken sehen nun etwas
steiler als auf dem Bild da oben aus. An dem Problem hat sich jedoch
nichts geändert.
2. Sensirion LG16 (Flusssensor)
3. Verdrahtungsfehler, da gerne begangen, konnte ich erstmal
ausschließen. Habe die Durchkontaktierungen vom Sensor bis zum µC
geprüft und außerdem auch sichergestellt, dass sich kein leitendes
Material zwischen Daten-/Taktleitung und Masse verirrt hat.
4. Ich habe momentan nur baugleiche Sensoren, die ich über I²C testen
könnte und bei denen ergibt sich das gleich Bild. Wie es mit anderen
Slaves läuft weiß ich nicht.
5. Die Busgeschwindigkeit habe ich von den im Datenblatt als typisch
angegebenen 100 kHz bis runter auf 20kHz und hoch auf 200 kHz variiert.
6+7. Weiter oben habe ich ja den Quelltext gepostet, welcher vor der
Abfrage des Busy-Flags ausgeführt wird. Soweit ich das sehe, wird in der
"transmitinit" keine Start-Condition gesetzt.
Pete K. schrieb:
> Du hast aber schon einen digitalen Sensor mit Endung -D ?
Jupp.
Problem ist einfach, dass mir der Sensor die SDA-Leitung auf low zieht.
Wenn du den MSP vom I2C-Bus abtrennst, nur den LG16 und die Pullups
dran, wie sind dann die Pegel von SCL und SDA? Falls SDA auf Low liegt,
versuchsweise ein paar Takte auf SCL geben und beobachten.
Kannst du evtl. doch ein Bild auf den Oszi bringen? (Mal die
Busy-Abfrage auskommentieren oder ein kleines Testprogramm)
Versuche ggf. einen TCN75 als Alternative zu testen.
Seb schrieb:
> 6+7. Weiter oben habe ich ja den Quelltext gepostet, welcher vor der> Abfrage des Busy-Flags ausgeführt wird. Soweit ich das sehe, wird in der> "transmitinit" keine Start-Condition gesetzt.
Ach so, der Fehler kommt nach dem transmitinit und nicht nach einem
Zugriffsversuch?
So, vielleicht bin ich schon ein wenig weitergekommen.
Zu Beginn der Main gebe ich dem Sensor ein paar Takte auf die Leitung
(siehe Bild). Dabei wird die SDA-Leitung hochgezogen.
Danach mache ich folgendes, um eine Messung zu starten:
1
SENSIRION_transmitinit(SENSIRION_ADRESS);// init transmitting the measurement start sequence
2
3
while(SENSIRION_notready());// wait for bus to be free
SENSIRION_receiveinit(SENSIRION_ADRESS);// init receiving the measurement data
11
while(SENSIRION_notready());// wait for bus to be free
12
SENSIRION_receive(0x03,meas_data);// start receiving the measurement data
13
while(SENSIRION_notready());// wait for bus to be free
Nach dem ersten Slave Present erscheint das zweite Bild. Heißt also
schonmal, dass er nicht mehr in der ersten Busy-Schleife hängen bleibt.
Der ACK sieht jedoch etwas verzögert aus (kleiner Peak).
Wenn ich nun schrittweise durchsteppe läuft das Programm. Sobal ich
jedoch meine Breakpoints entferne, bleibt das die Sache schnell wieder
in der busy-Schleife hängen. Vielleicht muss ich dem Sensor noch ein
bisschen mehr Zeit zwischen den einzelnen Aktionen geben. Halte euch auf
dem laufenden.
Gruß
Seb
Was machen eigentlich deine Funktionen SENSIRION_transmitinit,
SENSIRION_transmit usw.? Es sieht m.E. nämlich so aus, dass du einzelne
Bytes auf den Bus wirfst, aber keinen Daten-Transfer im eigentlichen
Sinne der Spezifikation machst.
Wie im Eingangspost erwähnt verwende ich die Appnote SLAA832 von TI.
Soweit ich diese verstanden habe, kann man im Sinne von I2C Bytes
verschicken und empfangen.
Na gut, die App-Note kenne ich nicht, wollte nur andeuten, dass Adress-
und Datenbyte "in einem Rutsch" zu übertragen sind. Dazwischen darf
keine Stop-Condition kommen.
@Michael: Jupp, da habe ich ein Auge drauf. Ich nähere mich so langsam
dem Problem. Ich habe da an zwei Stellen Datentypen "missverstanden",
welche in der Appnote übergeben werden.
...
Ich glaube ich habs! Nun zappeln die Daten über die Leitung und auf den
ersten Blick sieht das sinnvoll aus. Die Messfunktion sieht nun so aus:
1
SENSIRION_transmitinit(SENSIRION_ADRESS);// init transmitting the measurement start sequence
2
3
while(SENSIRION_notready());// wait for bus to be free
while(SENSIRION_notready());// wait for bus to be free
10
SENSIRION_receiveinit(SENSIRION_ADRESS);// init receiving the measurement data
11
while(SENSIRION_notready());// wait for bus to be free
12
SENSIRION_receive(3,meas_data);// start receiving the measurement data
13
while(SENSIRION_notready());// wait for bus to be free
14
}
Punkte, welche zur Lösung beigetragen haben:
1. Sensor erstmal mit ein paar Takten füttern bevor etwas anderes
gemacht wird.
2. Ich habe bei transmit und receive keine Felder übergeben. So war es
jedoch in der Appnote gewollt.
3. Vor dem Receiveinit muss nochmal der Bus abgefragt werden, weil die
Initialisierung zu flott kommt.
Jetzt muss ich das Bitgewackel noch in physikalische Werte umrechnen und
dann bin ich hoffentlich glücklich.
Danke nochmal für all die Anregungen.
Gruß
Seb