Forum: Mikrocontroller und Digitale Elektronik I²C Sensor antwortet nicht


von Seb (Gast)


Angehängte Dateien:

Lesenswert?

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
unsigned char I2C_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
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 = prescale;                         // set prescaler
6
  UCB0BR1 = 0;
7
  UCB0I2CSA = slave_address;                  // set slave address
8
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
9
  UCB0I2CIE = UCNACKIE;
10
  IE2 = UCB0RXIE;                            // Enable RX interrupt


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

von GastXIV (Gast)


Lesenswert?

Mach mal die Pullups auf 1k2 die Flanken sind alles andere als 
berauschend.

von Seb (Gast)


Lesenswert?

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

von Pete K. (pete77)


Lesenswert?

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?

von (prx) A. K. (prx)


Lesenswert?

Der Ablauf kommt mit etwas seltsam vor. Ich habe in Erinnerung, dass bei 
I2C üblicherweise SCL und SDA nicht gleichzeitig auf 0 gehen.

von Jörg S. (joerg-s)


Lesenswert?

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.

von Jörg S. (joerg-s)


Lesenswert?

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.

von Jörg S. (joerg-s)


Lesenswert?


von Seb (Gast)


Lesenswert?

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.

von Seb (Gast)


Lesenswert?

Ai ai, die Links klingen interessant. Werde ich morgen direkt mal 
ausprobieren.

von Seb (Gast)


Lesenswert?

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?

von Seb (Gast)


Lesenswert?

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.

von Michael L. (michaelx)


Lesenswert?

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?

von Seb (Gast)


Lesenswert?

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.

von Pete K. (pete77)


Lesenswert?

Du hast aber schon einen digitalen Sensor mit Endung -D ?

von Seb (Gast)


Lesenswert?

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.

von Michael L. (michaelx)


Lesenswert?

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.

von Jörg S. (joerg-s)


Lesenswert?

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?

von Seb (Gast)


Angehängte Dateien:

Lesenswert?

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
4
  if ( SENSIRION_slave_present(SENSIRION_ADRESS) )    // flow sensor present?    
5
  { 
6
    SENSIRION_transmitinit(SENSIRION_ADRESS);           // init transmitting the measurement start sequence
7
    while ( SENSIRION_notready() );    
8
    SENSIRION_transmit(0x01,(unsigned char*)SENSIRION_flowMeas);      // Send start measurement command         
9
                            
10
    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

von Michael L. (michaelx)


Lesenswert?

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.

von Seb (Gast)


Lesenswert?

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.

von Seb (Gast)


Lesenswert?

PS: Die Funktionen sind auch aus der Appnote. In meinem Projekt tragen 
die nur den Namen des Sensors vorweg.

von Michael L. (michaelx)


Lesenswert?

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.

von Seb (Gast)


Lesenswert?

@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
4
  if ( SENSIRION_slave_present(SENSIRION_ADRESS) )    // flow sensor present?    
5
  { 
6
    SENSIRION_transmitinit(SENSIRION_ADRESS);         // init transmitting the measurement start sequence
7
    while ( SENSIRION_notready() );    
8
    SENSIRION_transmit(1,flowMeas);                   // Send start measurement command         
9
    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

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.