Probleme mit dem TWI

  • Hi Leute,

    wie der Titel schon vermuten lässt, geht es um das TWI oder auch I²C Bus genannt.

    Und zwar sind mein Bruder und ich an den WE's wieder aktiver an unserem Quadrocopter dran, passt also vlt. nicht 100%ig hier rein, aber ich versuche es dennoch erstmal hier! ;)


    Zur ersten Frage: Kennt sich jemand mit dem TWI überhaupt aus??
    Ich habe mich die letzten zwei Wochen intensiv mit dem Thema auseinandergesetzt, (und habe nebenbei eeeendlich das TWI-Protokoll ziemlich gut gerafft! ;) ) aber komme einfach nicht auf die Lösung, bzw. auf keine Erklärung warum das so ist, wie es ist...

    Zum Problem: Wir haben ja den Rasberry Pi, meinen uC, die vier Flugregler und den Gyro im TWI-Bus.
    Der Raspi ist der alleinige Master, alle anderen, unter anderem halt der uC, fungieren als Slave.

    Und nun meint mein uC nach einigen Sekunden, die SDA-Leitung auf Low zu ziehen, und vor allem da zu lassen...
    Das lässt sich auch erst mit einem kompletten Reset des uC's beheben. Dann aber nach ein paar (mal mehr, mal weniger) Sekunden, das gleiche Problem.

    Warum ich so sicher bin das mein Prozessor der Übeltäter ist?
    Ich kann alle Teilnehmer (Hardware- und Softwaremäßig) von dem Bus entfernen, sodass nur noch der Raspi und mein uC mitspielen. Aber keine Veränderung...
    Der Raspi ist auch nicht das Problem, da zum einen auf dem Oszi-Bild zu sehen ist, das dieser versucht, seine Bits weiter zu senden, es aber wegen den Open-Collector-Ausgängen nicht schafft die Leitung nach "oben" zu ziehen.
    Zudem ist es so, das wenn alle Busteilnehmer wieder im Spiel sind, und ich nur meinen TWI deaktiviere, also mein uC virtuell vom Bus getrennt ist, funktioniert alles ganz wunderbar... ;(

    Um die ganze Sache noch etwas zu erschweren gibt es da noch das Detail, das alles bis vor zwei Wochen Tipp-Top funktionierte. Wir haben das Ding bestimmt 0,5-1h am Laufen gehabt und schon ein paar Startversuche gemacht. Das Ding stürzte natürlich aus bis zu 1-1,5m ab. Aber dass das die Ursache sein soll, bezweifle ich. Den Ausleger hat es ein paar mm nach oben verzogen und der Raspi hat zweimal eins auf den Deckel bekommen aber die Platine hat nichts mitgekriegt und sieht optisch absolut iO aus...

    Dann, eine Woche später halt das Problem, das der ganze Bus geschrottet wird und, wie gesagt, nach einem uC-Reset wieder für einige Sekunden tut...

    Ich hab schon alles rausgeschmissen aus dem Programm und schicke dem Pi nur noch eine Konstante rüber...

    Was auch gegen eine Hardwaremäßige Beschädigung spricht: Wenn der Bus verreckt, dann ausschließlich an der selben Stelle! Der Pi (Master) sendet die gewünschte Adresse. In meinem Fall 0100001 -> adr33 und nach der ersten "1" wars das, also quasi 01 00000000000000...
    Hier mal ein Bild wie der Fehler aussieht...


    Wie gesagt, man sieht noch eine leichte Erhebung bei den "high's"auf dem Bildschirm. So erkennt man noch die korrekte Datenübertragung, wenn die SDA-Leitung nicht auf Low gezogen wäre:

    start_condition_0100001_0 _1__00001010 1_repeatet start_0100001_1_1__11001000_1_stop_condition
    ______________Adr33___W_A*_Wert 10_A*______________Adr33___R_A*_Wert 200_A*

    Adr: Meine Adresse im Bus
    W: Write-Anforderung des Masters
    R: Read-Anforderung des Masters
    A*: Acknowledge, eig ist eine 0 ein Ack, aber da mein uC nicht mehr reagiert, gibt es eine 1. Da der Pegel aber so klein ist, erkennt der Pi das als 0 an und sendet munter weiter... ;)
    Wert: Der Wert ist im ersten Fall 10, da der Pi mir erst einmal eine Buffer-Adresse schicken muss, der Wert 200 ist der Wert, der in der Buffer-Adresse 10 zu finden ist. Dort kommt später die gemessene Empfängerpuls-Länge 0-255 (1-2ms) rein.

    Hier als Referenz das richtige Signal, das die ersten Sekunden über die Leitungen geschoben wird:

    Was mir schon aufgefallen ist, ist das zum einen die "high's" der Datenleitung zweistufig zu sein scheinen...
    Sprich erst hoch, dann geht der Pegel etwas runter.
    Als nächstes ist deutlich zu erkennen, das auch die clk-Pegel unterschiedlich hoch sind, wenn auf der Datenleitung ein "high" liegt. So kann man quasi an der SCL-Leitung die Datenleitung ablesen... *lol* ;)


    Der uC bleibt btw. nicht hängen, wenn ich LEDs blinken lasse o.ä. macht der das auch fleißig weiter...

    Für die TWI-Übertragung nutze ist übrigens die Lib von dem Kollegen hier:
    http://www.jtronics.de/avr-projekte/l…-twi-slave.html


    Soo, ich hoffe wirklich seeeehr, das ihr mir da etwas helfen könntet. So langsam ist es frustrierend, nach zwei Wochen lesen, goggeln, denken, Kopfschmerzen_vom_denken_kriegen immer noch keine Lösung gefunden zu haben... ;( ;( ;(

    • Offizieller Beitrag

    Hallo Andreas,

    ich habe Deine technischen Details jetzt nur grob überflogen. Aber ich glaube, ich weis, woran es liegt.... ;)

    Mit meinen PICs hatte ich auch schon einmal ein externes I2C-EEPROM am I2C angehängt und das Ding zunächst nicht zum Laufen gekriegt. Es war in einer Bibliothek ein "Treiber" mit dabei. Aber der funktionierte nicht. Dann aus dem Internet einen Treiber. Funktionierte auch nicht. Also selbst geschrieben. Funktioniert.

    Der Gag bei dem I2C ist, dass es ja eigentlich nur zwei Leitungen sind. Nämlich der Clock und die Datenleitung. Und es muss sowohl vom Master zum Slave als auch vom Slave zum Master funktionieren. => Bidirektional.

    Mein erster Eindruck ist, dass Dein µC die Leitungen nicht freigibt. Somit versuchen zwei Portausgänge gleichzeitig, die TTL-Pegel anzuheben oder abzusenken. Das geht natürlich nicht.

    Zunächst mal: Du hast beide Leitungen jeweils mit einem Widerstand auf +5V gepullt? => Sonst geht's nicht.

    Ich hab' das bei mir so gelöst:
    - Meine beiden Porteingänge sind auch tatsächlich auf "Eingänge" parametriert und nicht auf Ausgänge.
    - Die Ports sind also "hochohmig" über die Wiederstände auf +5V.
    - Egal welches Gerät jetzt was senden will. => Den Portausgang von "Eingang" auf "Ausgang" ändern und mit "0" den Pegel absenken. Nachdem alle anderen I2C-Geräte ihre Ports auch auf "Eingänge" haben, lässt sich der Pegel an der Leitung somit auf "0" senken".
    - Wenn Du eine "1" versenden willst, dann nicht unbedingt eine "1" beim Ausgang hinausschicken, sondern den Ausgang wieder als "Eingang" setzen. Die Pullup-Widerstände ziehen Dir den Pegel dann schon nach oben.

    Am Ende der ganzen Sende-Zermonie sicherstellen, dass Du die Leitungen wieder freigibst und somit der High-Pegel durch die Widerstände wieder wirksam ist. => Wenn am I2C nichts los ist, muss sowohl auf der Clock als auch auf der Datenleitung immer "High" sein. Und jedes Gerät ist auf "Eingang", damit der Pegel von den anderen Geräten bei Bedarf nach unten gezogen werden kann.

    Schau mal.... Ich denke, wenn Du das Datenrichtungsregister bei dem µC (ich weis nicht, wie das bei Deinem Prozessor heißt) entsprechend auf "Eingang" setzt, dann wird's funktionieren. ;)

    Die "gestuften" Pegel, die Du gemessen haben, deuten darauf hin, dass zwei Portausgänge von zwei Geräten gleichzeitig auf "Ausgang" sind und einer dem anderen seinen Pegel aufdrängen will.
    Kannst ja mal versuchsweise zwei 100 Ohm Widerstände in die Leitungen hineinsetzen. Dann den Pegel auf beiden Seiten des Widerstands messen. Dann wirst Du den Übeltäter schnell herausgefunden haben.

    Eine Ferndiagnose ist jetzt schwierig. Aber ich denke, der Fehler könnte bei der Quittierung (ACK) liegen. Dann wird der Port nicht mehr als Eingang zurückgesetzt und die weiteren Signale vom Master krepieren elendig an der "0" von Deinem µC-PortAUSGANG.

  • Hi Reiner,

    aber selbstnatürlich habe ich die Pullups drin, allerdings nach 3,3V. Die gesamte Elektronik muss mit 3,3V betrieben werden, da der Raspi keine anderen Spannungspegel verträgt. ;)
    Allerdings haben die, wenn ich das Multimeter dran halte 1,8k. Ich glaube der Raspi hat auch welche an Bord, somit ist es möglich, das meine parallel zu denen auf dem Raspi hängen. Aber wir haben meine Pullups bei der ersten Inbetriebtnahme des TWIs mal entfernt, nur da klappte der ganze Bus überhaupt nicht. Also kA was da los ist...
    1,8k sind aber nicht zu wenig oder? Ergibt ja bei 3,3V 1,8mA.

    Ich habe die DDR mal auf Eingänge gewechselt, aber ohne Erfolg.
    Dann habe ich mal den DDR-Befehl in das Hauptprogramm gepackt, also das die DDRs bei jedem Programmdurchlauf wieder auf Eingänge gesetzt werden, aber auch da kein Erfolg... ;(
    Die eigendliche TWI-Routine ist wie gesagt mit einer Bibliothek realisiert. Das mache ich ja garnicht selber.
    Ich rufe eine TWI-init-Funktion mit der gewünschten Adresse auf. Und alles weitere wird mittels ISP erledigt.
    Aber zum einen ist das eine Lib, die sehr viele Leute (ohne Probleme) im Netzt nutzen und das erklärt ja nicht, warum das vor zwei Wochen noch klappte. ;(

    Die einzelnen Register, die bei der Lib genutzt werden, habe ich auch schonmal durchgeschaut. Manchmal heißen die Register bei den unterschiedlichen µCs anders, aber auch da scheint alles korrekt zu sein.

    • Offizieller Beitrag
    Zitat

    1,8k sind aber nicht zu wenig oder?


    Nein, daran kann's nicht liegen. Ich hab' bei einem einzigen angeschlossenem Baustein 10k verwendet. Ein Praktikant von mir hatte es gut gemeint und 1k verbaut.... Hat alles funktioniert.

    Hm... Deine Beschreibung ergibt noch keinen Sinn. Kann es sein, dass das verwendete Modul aus der Lib an zwei Stellen geändert werden muss. Also nicht nur an einer Definition des Ports, wo die Datenpulse herauspurzeln, sondern noch eine zweite Stelle, bei dem dann das DRR verändert wird?
    (Vermutung: So ein Modul kann ja im Prinzip für jeden Portausgang des µC verwendet werden. => Dass die Initialisierung nicht ganz mit dem verwendeten Port zusammenpasst.)

    Andere Hinterfragung: Wie ist das mit der Baudrate des Taktgenerators. Zu schnell? Oder unterschiedliche Frequenzen (Raspi und µC) eingestellt?
    Ich frag' deswegen nach, da man ja die Taktfrequenz beim Empfänger wissen muss. Denn beim halben Clock wird dann die Datenleitung abgefragt. Dann die restliche Clock-Halbe abwarten und dann das nächste Bit einlesen. Nach dem letzten Bit auf "Senden" umschalten und das ACK hinausprügeln. Dann wieder auf Eingang schalten.

  • Ich habe heute (in der Pause ;) ) dennoch mal meine Widerstände rausgebaut.
    Der Bus schneint dennoch zu gehen, kA wo früher das Prob war...

    Beim RasPi sitz btw. ein 3k Widerstand auf dem Board. Soll also wohl passen!
    Eine Änderung gab es aber dann dennoch: Diese zweistufigen Signale sind weg! Die Datensignale sind nun ein korrekter Rechteck, und die Pulse haben jetzt eine ganz leichte e-Funktion kurz vom Erreichen der 3,3V-Marke. Also alles gut!

    Aber... nach einem kurzen Augenblick des Optimismus, verreckte mir der Bus aber dennoch wieder...


    Bei Atmel läuft der ganze TWI-Krams über eigene TWI-Register. Es wird nur damit gearbeitet und die Ports werden dann automatisch für den TWI-Betrieb reserviert/angesteuert.

    Wie gesagt, die Register-/Bitnamen können variieren, aber in meinem Fall stimmt das...


    Soweit ich weis erzeugt ausschließlich der Master den Takt. Sobald sich dann am SCL-Eingang des Slaves was tut, springt das Programm in die TWI-ISR und verarbeitet das, was an der SDA reinkommt...
    Mein Takt sollte da nicht von bedeutung sein denke ich.

    Der Takt ist bzw. auf 100kHz eingestellt, was ja als Standart-Frequenz beim TWI gilt. ;(


    Ich habe mal die Lib in den Anhang gesteckt. Vlt. hilft das ja etwas weiter... :/

    • Offizieller Beitrag

    Ah ja,... Du lässt mit Deiner Subroutine die Bits selber gar nicht wackeln, sondern nimmst eine interne Funktion vom Prozessor. Ok,... sollte dann eigentlich gehen. Ich muss aber zugeben, dass ich bisher immer mit meinem eigenen Treiber die I2C betrieben habe, obwohl meine "neueren" Prozessoren auch dazu fähig wären, das standardmäßig zu betreiben.

    Jetzt wird's schwieriger....

    Die Routine habe ich mir angesehen, aber eigentlich geht's da ja nur um Speicherverwaltung für den Datenpuffer.
    Die "Init" von der I2C habe ich vermisst. Oder übersehen?

    Soweit ich das dunkel in Erinnerung habe, muss man die beiden "Takte" schon synchronisieren. Einfach wegen der Übertragungssicherheit. Wenn der Empfänger nicht weis, dass es ein 100kHz-Takt ist und deshalb der Puls 10µs lang ist, wie soll er dann nach 5µs den Data-Puls abfragen?
    Beim Senden gibt dann normalerweise der Slave seinen Takt vor (Darum ist auch die Clock-Leitung gepullt, damit der Slave sie "herunterziehen" kann. Was ich nicht weis: Ob die Slaves einen Erkennungsmechanismus für die verwendete Clock des Masters haben und sich beim Senden dann automatisch auf die gleiche Frequenz aufsynchronisieren.

    Kannst Du beim RasPi die Clock-Frequenz heruntersetzen? Einfach mal probieren, ob's bei 1kHz dann besser funktioniert. ;) Wenn es da geht, dann kommen die beiden Geräte offensichtlich mit der Quittierung durcheinander. (Einer "überholt" den Anderen...Heißt: Der Slave ist noch mit dem Abschluss des ACK beschäftigt und möchte seine Register umstellen, der Master knallt ihm aber schon das nächste Telegramm um die Ohren)

    Schau mal in der I2C-Init nach, ob da irgendein Register für die Clock-Frequenz gesetzt wird. (Normalerweise wird die Clock von einem bestimmten Timer abgeleitet , also mit Prescaler oder Postscaler)

    Hab' jetzt mit dem Datenpuffer nicht mehr weiter geschaut.... Er ist derzeit auf 20 Byte festgelegt. Du holst die Bytes in Atmel ab, um den Puffer wieder leer zu kriegen? (=> Nicht dass der Puffer überläuft und Du suchst an einer ganz anderen Stelle...)

  • Hab mal rumgelesen und bin hierauf gestoßen:


    Bit Rate Generator unit:

    This unit controls the period of SCL when operating in a Master mode. The SCL period is controlled
    by settings in the TWI Bit Rate Register (TWBR) and the Prescaler bits in the TWI Status
    Register (TWSR). Slave operation does not depend on Bit Rate or Prescaler settings, but the
    CPU clock frequency in the Slave must be at least 16 times higher than the SCL frequency. Note
    that slaves may prolong the SCL low period, thereby reducing the average TWI bus clock
    period.


    Wie ich das verstehe, muss ich da nichts machen und meine CPU läuft mit 8MHz. :/


    Nichts desto trotz werde ich morgen mal meinen Bruder anhauen, das der die Frequenz mal herab setzt. Ich glaube nicht, dass das was bringt, (auf dem Oszi-Bild sieht die Puls/Daten-Abfolge i.O. aus) aber einmal versuchen kostet ja nichts... ;)

    Die Buffergröße hab ich in meinem Code auf 11 beschränkt, da ich nicht vorhabe mehr zum RasPi zu schicken (6x EmPu, 1xuBat, 4xMotor-Strom). Im Laufe der ISR wird die Bufferadresse wieder auf null gestellt, wenn ich bei der letzten Adresse angekommen bin. :)
    Mein Bro schickt mir btw. ja auch eine definierte Bufferadresse mit der ersten Write-Operation. Danach liest die ISR den Inhalt dieser Bufferadresse aus und packt die ins TWI-Datenregister, soweit ich verstanden habe.

    • Offizieller Beitrag
    Zitat

    Original von Replikator
    Slave operation does not depend on Bit Rate or Prescaler settings, but the
    CPU clock frequency in the Slave must be at least 16 times higher than the SCL frequency. ... Wie ich das verstehe, muss ich da nichts machen und meine CPU läuft mit 8MHz. :/


    Ich glaube nicht, dass das was bringt,

    Ich bin da jetzt zwar überrascht, dass sich der Slave anhand des Master-Clock seine eigene Clock generieren kann, aber ok.... Mit den "vorkonfigurierten" Modi habe ich bei meinen PICs noch nicht gearbeitet.

    Wenn Du die Inbetriebnahmetests mit einer geringeren Clock machst, dann kannst Du diese Fehlerquelle zumindest schon mal ausschließen. Das erleichtert die Fehlersuche, wenn statt 5 Möglichkeiten nur noch 4 da sind. ;)

    Du schickst also Daten vom µC zum Raspi? Ok... ich hatte das zunächst anders verstanden, dass der RasPi ein paar Bytes zum Atmel schickt und der Atmel dann durch sein ACK den I2C versaut.

  • Die Kommunikation geht ja in beide Richtungen.

    Als erstes schickt mir der RasPi mit einem Write-Befehl die Bufferadresse. Dann, mit dem "repeatet start" schickt mir der Raspi einen Lesebefehl, woraufhin ich dann meinen Buffer-Wert auf die Leitung lese.

    Abschmieren tut der Bus dann in der Tat beim ersten Zugriff, also wenn mir der RasPi mit dem Write-Befehl die Bufferadresse zuschicken möchte.

    Auf den Oszi-Bildern erkennt man ja die Reihenfolge.

    Es sind zwei Übertragungs-Phasen erkennbar (auf dem Bild mit dem intakten Bus):

    Die Erste beinhaltet meine Adresse (die ersten 7bits), den Write-Befehl(8.bit, Low-Signal), dann kommt das Ack vom uC, dann das Byte mit der Bufferadresse (in dem Fall 10) gefolgt vom nächsten Ack.

    Dann der "repeatet start" -> Beide Leitungen gehen auf High und dann zieht der RasPi die Datenleitung nach unten, während der Takt noch auf high ist.
    Dann wieder Die Adresse vom uC, der Read-Befehl (high-Signal), der Ack vom uC, und meine Daten in dem Fall 200.
    Mit dem letzten Ack beendet der RasPi die Kommunikation und nach 20ms fängt alles von vorne an, bis die Leitung dann tot ist... :)

    • Offizieller Beitrag

    Hab' Deine o.g. Fehlerbeschreibung noch einmal durchgelesen. Das mit dem Pegeleinbruch bei einer Leitung, wenn sich der Pegel auf der anderen Leitung ändert, ist mir dabei aufgefallen.

    Darum mal in eine ganz andere Richtung gedacht. Wie "stabil" sind denn Deine Stromversorgungen bzw. die Masseleitungen?
    - Gemeinsames Netzteil für beide Komponenten?
    - Kann eine "Brummschleife" über die Masseleitung der I2C-Verbindung entstanden sein? (Geh' mit dem Oszi mal auf den Masseanschluss am RasPi und dann auf die Masse am µC. Ist da ein "Gezappel" festzustellen?
    - Bei den Stromversorgungen an den Geräten mal jeweils ein paar fette Elkos anbringen.

    Ich kann total falsch liegen. Aber vielleicht ist es wirklich nur der Dreckeffekt, dass ein kleiner Einbruch auf den Signalleitungen schon als "gewolltes Signal" für das nächste Bit interpretiert wird.
    Dass der Bus dann hinterher blockiert wird, das wäre ein schwerer Bug in der Firmware, aber soll vorkommen....

    Bin neugierig, ob eine Reduzierung der Taktfrequenz das Verhalten verbessert. *VielGlück*

  • Zuerst einmal die schlechte Nachricht:

    Laut meinem Bro ist die TWI-Frequenz schon am Minimum. 100kHz ist die geringste Takt-Frequenz, die man einstellen kann...


    Dann habe ich mal die Masse-Messung vorgenommen.
    Auf meinem Board ist die Masse einsame Spitze, da ist alles ohne ein Ansatz von einem Peak...

    Wenn ich dann aber auf den RasPi gehe (Tastkopf-Masse auf Board-Masse, Messspitze iwo auf dem RasPi-Board) Habe ich Konstante 20mV mit gelegentlichen Rechteckpulsen von wenigen mV drauf...

    Ok, ist auch logisch: Der RasPi braucht um die 700mA und versorgt wird der von einem Flachbandkabel... Also mit minimalem Querschnitt!
    Aber dennoch die Frage: Könnte das ein Grund sein? 20mV klingen für mich erstmal nach nicht viel...

    • Offizieller Beitrag
    Zitat

    Original von Replikator


    Laut meinem Bro ist die TWI-Frequenz schon am Minimum. 100kHz ist die geringste Takt-Frequenz, die man einstellen kann...

    Wundert mich, dass die so eine hohe Übertragungsrate als Minimum festlegen. Schade, erschwert die Fehlersuche.


    Zitat

    Original von Replikator

    Ok, ist auch logisch: Der RasPi braucht um die 700mA und versorgt wird der von einem Flachbandkabel... Also mit minimalem Querschnitt!
    Aber dennoch die Frage: Könnte das ein Grund sein? 20mV klingen für mich erstmal nach nicht viel...



    Dann wäre es nicht verwunderlich, wenn hier manchmal ein paar Absurditäten auftauchen.
    So einen ähnlichen Fall hatte ich auch mal bei einem externen Datenkonverter. Zuhause bei mir im Labor alles in Ordnung. Dann zu meinem Auftraggeber geschickt, die haben ihn in ein Gerät eingebaut, und.... sporadische Datenübertragungsfehler (war aber RS422). Versorgung erfolgte über 9polige SUB-D-Stecker und Flachband mit einem halben Meter Länge. Lösung: Die Stromversorgung separat über ein 0.5qmm-Kabel gelegt und vor allem am Dekoder dann einen fetten Elko angebracht.

    Heißt in Deinem Fall, dass Du Testweise mal die Stromversorgung mit brauchbaren Drahtquerschnitten überbrückst und dann am RasPi einen Kondensator bei der Spannungs-Einspeisung setzt.

    Viel Erfolg !

  • Hi, hab direkt ein dickes Kabel zwischen dem RasPi und dem MB gelötet. Die Messung ergab ein perfekter GND-Pegel!


    Dann direkt einen neuen Versuch gestartet aber... Naja... Pustekuchen... *seufz* ;(

    Also auch daran scheint es nicht gelegen zu haben...


    Die Suche geht weiter...

    • Offizieller Beitrag

    Ok, GND ist jetzt in Ordnung. Die Versorgungsspannung auch mit einem dickeren Draht verstärkt? Einen Elko beim RasPi platziert? => Dann kannst Du eigentlich einen Ripple-Fehler ausschließen.

    Wenn Du nicht geschrieben hättest, dass dieses Modul auch bei anderen Atmels funktioniert, dann hätte ich gesagt, dass in diesem Softwareteil ein Hund begraben wurde. Auf den ersten Blick kann ich aber in dem Teil, den Du gepostet hast, nichts Schlechtes entdecken. Das sagt aber nichts, denn die Atmels kenne ich nicht im Detail, kann also nur allgemeinen C-Code-BlaBla checken.

    Was wäre dann der augenblickliche Zustand?: Der µC legt seine Leitungen auf Low und verharrt in hektischer Passivität. (Korrekt?)
    Also kriegt er irgendwas zum Versenden in den falschen Hals. Denn wenn er auf ein Signal vom RasPi warten würde, wären die Leitungen freigegeben und nicht auf Low gelegt.

    Ich denke jetzt mal laut vor mich hin. Es kann viel Blödsinn dabei sein, aber vielleicht ist irgendein Ansatz dabei, den Du prüfen könntest:

    - Das Protokoll des Datenaustausches passt zwischen RasPi und µC zusammen? Also : Senden Byte, ACK, Antwort, ACK,....
    - Gibt's irgendein Prüfbit, das falsch gesetzt sein könnte?
    - Ist im Timing von Senden und Empfangen ein Fehler? Dass also das ACK zu schnell versendet wird und der Empfänger seine Register noch gar nicht auf "passiv" gestellt hat? => Wäre mal ein Test, zwischen den einzelnen Blöcken vor dem Versenden eine Delay einzubauen.

    Nachdem der RasPi nach Deinen Angaben mit allen anderen I2C-Komponenten zusammenarbeiten kann, ausser mit Deinem µC, müßte also dieser Softwareteil verantwortlich sein.

    Kannst Du mal an den RasPi ein funktionsfähiges Bauteil anhängen (z.B. EEPROM) und dann mit dem Oszi das Timing aufnehmen? Also messen, wieviel Zeit zwischen den einzelnen Bytes beim "Ping-Pong" der Telegramme vergeht. Vielleicht fällt dann was auf, dass der µC zu sportlich ist und zu flott auf Telegramme reagiert. (?)

  • Er legt nur die Datenleitung (SDA) auf Low. Das wars. Wie gesagt: ansich hängen bleibt der Kasten nicht. Alles andere läuft ja wie gewohnt weiter...

    Das Protokoll sollte eig auch passen. Das TWI hat doch nur einen Standart. Und wir beide nutzen ja eine Lib für die Kommunikation. ;(

    Das Timing wird ja im Normalfall auch komplett durch die Taktleitung vorgegeben. Ich gehe davon aus, dass das alles korrekt sein muss.
    Ich konnte mir vorstellen, das da etwas Bitmäßig verrutsch ist und somit fälschlicherweise eine Stop-Condition o.ä. erkannt wurde.
    Aber auf den Oszi-Bildern sieht ja alles Tiptop aus...


    Die +5V-Leitung habe ich gestern auch nochmal mit einem neuen Kabel verstärkt, da war nämlich (logischerweise) auch eine Spannungsdifferenz zu finden.
    Elkos o.ä. habe ich aber nicht dazugebaut. Ich gehe ja mit den Leitungen direkt auf den Versorgungsspannungs-Eingang. Da sind ja direkt die Elkos und Keramik-Kondis vom RasPi.

    Aber auch da gab es keinerlei Änderungen... o_O

    • Offizieller Beitrag

    Hmmm.... wieder nichts....

    Ich habe jetzt mal in Wikipedia beim I2C nachgelesen, weil ich das Timing von den vorgefertigten Chips nicht mehr richtig wußte.

    Zunächst mal: Du hast recht, dass der Slave sich nach dem Takt vom Master richten muss. (... war ich mir nicht ganz sicher...)

    Zitat aus http://www.Wikipedia.de (Suchbegriff "I2C"):

    Eine Dateneinheit besteht aus 8 Datenbits = 1 Oktett (welche protokollbedingt entweder als Wert oder als Adresse interpretiert werden) und einem ACK-Bit. Dieses Bestätigungsbit (Acknowledge) wird vom Slave durch einen Low-Pegel auf der Datenleitung während der neunten Takt-High-Phase (welche nach wie vor vom Master generiert wird) und als NACK (für engl. not acknowledge) durch einen High-Pegel signalisiert. Der Slave muss den Low-Pegel an der Datenleitung anlegen bevor SCL auf high geht, andernfalls würden weitere eventuelle Teilnehmer ein Start-Signal lesen.


    Dieses "bevor" von "an der Datenleitung anlegen bevor SCL auf hight geht", ist markant.

    Das wäre mal ein neuer Test, mit dem Oszi genau dieses Verhalten "unter der Lupe" anzusehen. Nicht dass da ein Timingfehler enthalten ist.
    Wie gesagt, die 100kBit halte ich für sehr sportlich (auch wenn es "Standard" ist). Nicht dass da ein Bit auf der SDA zu spät gesetzt wird. (?)

    //Edit:
    Habe gerade Deine o.g. beiden Bilder noch einmal angesehen. => Das falsche Timing beim ACK kann's auch nicht sein, weil die SDA nicht nach dem 8ten Bit, sondern bereits nach dem 3ten Bit krepiert.

  • Hi,

    ich habe letzte Woche aus Zufall eine neue Erkenntnis erhalten...

    Und zwar habe ich neben dem TWI-Interrupt noch einen CTC-Interrupt des Timer0.

    Dieser Interrupt sorgt einfach nur dafür, drei Variablen hochzuzählen. Diese sind für die Operationen, die halt eine definierte Zeit brauchen. Die LEDs z.B. die blinken sollen.

    Diesen TIMER0-Interrupt habe ich einfach mal ausgeklammert und siehe da... Das TWI läuft!! Seltsam ist allerdings folgendes:

    Und zwar hat jedes Kommunikations-Telegramm 18 Takte.
    (7 Adressbits, 1 R/W-Bit, 1 Ack/Nack-Bit, 8 Datenbits, 1 Ack/Nack-Bit)

    Diese Taktreihenfolge, die eig. stumpf durchläuft, also je Telegramm 18 Takte, dann eine Pause, wieder 18 Takte, etc.
    Jetzt gibt es allerdings nach jedem neunten Takt eine Pause von ~80µs, bevor es mit den zweiten 9 Takten weiter geht...

    Verrecken tut das TWI aber dafür nicht...!


    Trotz dieser Erkentniss wirft das für mich eher noch mehr Fragen auf...

    Was hat das Eine mit dem Anderen zu tun???

    Die TWI-ISP wird normal nicht von dem Timer-Interrupt unterbrochen. Die hat zwar eine höhere Priorität, aber während eine ISR durchläuft wird das "globale Interrupt Enable-Bit" zurückgesetzt. Also während einer ISR, kann keine weitere ISR auftreten. Sollte ein Ereignis auftreten, wird diese direkt nach der vorherigen ISR ausgeführt.

    Ich hab auch schon in der TIMER0-ISR das "global Interrupt enable-Bit" wieder manuell gesetzt, damit diese ISR jederzeit von der TWI-ISR unterbrochen werden kann. Und ich habe die Befehle in der Timer-ISR (also das Hochzählen der drei Variablen) auskommentiert, sprich die ISR macht nichts mehr und wird direkt wieder verlassen.

    Aber keine Änderung, mit der Aktivierung der Timer-ISR verreckt auch wieder der TWI...

    Ich habe gelsesen, das ein Slave das Takt-Signal künstlich auf Low halten kann, um etwas mehr Zeit für das abarbeiten der TWI-ISR zu haben, wenn er nicht hinterher kommt. Aber warum macht der das dann, wenn ich die Timer-ISR lösche???

    Ich hoffe nach wie vor, das mir da jemand helfen kann... Die Fragezeichen über meinem Kopf werden größer und größer! ;)


    Edit:
    Wenn ich zusätzlich die komplette Initialisierung des Timer0 aus meinem Programm werfe, hat sich das mit den Pausen nach den 9 Takten auch erledigt... Alles sieht wunderbar aus!

    Wenn ich das Fuse-Bit CKDIV8-Bit setze, also der CPU-Takt von 8MHz auf 1Mhz verringere, sind die Pausen wieder da, bzw. wenn die Timer-Initialisierung noch drin ist, acht mal so lang oder so, keine Ahnung. Auf jeden Fall verreckt mir das TWI dann quasi augenblicklich...

    btw: ich habe diesen 8Mhz

    http://www.reichelt.de/8-0000-HC49-SM…2C0000-HC49-SMD

    mit 22pF Keramik-Kondis (SMD0804) drin, bin mir aber nicht so ganz sicher was dann eig. die richtige Einstellung bei den Fuse-Bits ist... ich habe jetzt einfach den: EXTXOSC_8MHZ_XX_KCKMS1 eingestellt. Das Ändern auf andere Modis bringt allerdings keine Änderungen mit sich.

  • Bingo!

    Auch wenn mir der Grund nach wie vor Schleierhaft ist:

    Das TWI läuft wieder!!

    Und zwar lag das nur daran, das der Timer0 es wagte, einen interrupt zu machen. Auch wenn die sich wie gesagt eig. nicht behaken dürfen.

    Ich bin die Timer0-Initialisierung mal durchgegangen und hab zum Schluss nurnoch die Zeile ausgeklammert, in der ich den CTC-Interrupt aktiviere! Dann lief es!
    Dann bin ich einfach umgeschwungen auf den Timer Overflow-Interrupt, aber das selbe Ergebnis...


    Jetzt lasse ich den Timer ganz normal laufen, und gucke in der main() immer nach, wie hoch der Timer (TCNT0) gezählt wurde. Bei einem Ergebniss von ">=x" setzte ich den Zählwert zurück und zähle meine drei Variablen hoch. Feddich! :D


    Jetzt bin ich mal gespannt ob der Fehler Dauerhaft beseitigt wurde. Also nach 1h dauerlauf ging es noch! :)


    Aber wie gesagt: Warum ist das so?!
    Kann jemand was mit meiner Fehlerbeschreibung anfangen??


    Vorab aber dennoch ein riesen Dank dich Reiner für deine Unterstützung!! Ich hoffe das Thema kann damit beendet werden!

    • Offizieller Beitrag

    Freut mich, wenn es jetzt klappt!
    War ja doch eine ziemliche Würgerei, den Fehler einzugrenzen. Aber.... that's live ! ;)

    Im Detail habe ich Deine Fehlerbeschreibung nicht verstanden, weil ich den Prozessor zu wenig kenne und mein PIC anscheinend andere Kommandos verwendet.
    Ich vermute, dass der I2C bei diesem Timer der alleinige Herrscher sein muss und jede Unterbrechung (egal ob Interrupt oder das manuelle Zurücksetzen) dazu führt, dass die fest verbauten Prozessorfunktionen (=I2C) nicht mehr in Schuss kommen.

    Aber auch bei mir muss ich immer aufpassen, welche Timer von wem gerade verwendet werden. Beispielsweise der Watchdog. Wenn ich da einen Prescaler oder Postscaler ansetze, dann macht das im praktischen Betrieb nicht viel aus. Die Main-Schleife macht meinetwegen alles in 2ms, während der Watchdog nach 100ms auslöst. Passt.
    Aber ich kann mir schon vorstellen, dass z.B. der Timer, der von meiner PWM für die Motoren benötigt wird, sauer reagiert, wenn ich ihm für einen anderen Zweck plötzlich einen Prescaler einbaue.

    Mit Interrupts fehlt mir etwas das Feeling, "wann" das gefährlich werden kann. Aus dem einfachen Grund: Ich benutze keine Interrupts, weil das immer Ärger macht. Gerade dann, wenn man es nicht brauchen kann, schlägt der Interrupt zu und versaut mir das Timing in einer Subroutine. Natürlich kann man den Interrupt jedesmal sperren. Aber so etwas auszutesten und wasserdicht zu kriegen (so dass es beim Kunden keine Probleme gibt), da steckt dann viel Aufwand drin. Also lieber KISS (= Keep It Simple and Stupid ;) ) wenn es um die Architektur von einem Programm geht.

    Hatte in der Arbeit schon Lieferverzögerungen von Lieferanten, weil sie das Programm zwar im Debug-Modus zum Laufen brachten, aber nicht im Release-Mode. Die armen Jungs hatten da tagelang ohne Erfolg gesucht. Solche Fehler, auch mit Interrupts können einem das Programmieren zur Hölle machen.

    So denne, genieß den Erfolg. Jetzt kannst Du ja endlich das tun, was Du mit dem I2C eigentlich realisieren wolltest. :D