Der Beginn einer I2C-Übertragung ist das Herstellen einer Start-Kondition. Nun ist es aber so, daß die Funktion i2c_start() wesentlich mehr macht. Sie ist schon der erste Teil der Übertragung, denn sie sie sendet auch noch das Adressbyte. Daß man das in einer Funktion zusammengefaßt ist, hat der Programmierer dieser Funktion zu verantworten. Ich würde das nicht so machen, sondern daraus zwei Funktionen bauen, auch einer der Gründe das selbst zu machen.
Und jetzt zu dieser Funktion selbst. Als erstes setzt sie das TWISTA-Bit (sorry, wenn ich die Bitnamen mal etwas falsch schreibe, ich müßt sonst jedesmal nachschlagen). der TWI-Controler macht dann laut Datenblatt folgendes: er wartet, bis der Bus idle wird, und setzt dann Start. Da macht sogar schon die Hardware einen Check. Geht dabei etwas schief, meldet die Funktion i2c_start() einen Fehler. Dann sendet die Funktion die Adresse, wird sie nicht mit ACK quitiert, meldet die Funktion den gleichen Fehler (schlecht). Antwortet ein Slave nicht auf seine Adresse mit ACK, muß die Transaktion mit einem Stop abgebrochen werden!. Also muß der Returnwert ausgewertet werden. Dies erstmal zum Speziellen.
Oder das Device ist Busy, das EEPROM schreibt gerade, ein US-Sensor misst, dein selbstgemachter Slave ist noch nicht hochgelaufen oder, oder ...Ausnahme ist Mister Murphy-Law, der schon mal, wie sein Kollege Wackel-Kontakt und andere, dreinpfuschen kann. Aber normalerweise sollte doch der I²C-Bus zu Beginn der Übertragung nicht besetzt sein - ist ja kein Multimaster
Es ist also eher umgekehrt, beim Verbindungsauf ist es Pflicht. Aber, wenn ich bei einer Datenübertragung nun schon eine minimale Rückmeldung bekomme, sollte man sie auch verwenden. Das ist jetzt das Inhaltliche.Beim anschließenden Schreiben oder Lesen wird/kann das sinnvoll sein. Aber auch da überlege ich noch.
Nicht dass es mir auf die paar zusätzlichen Maschinenbefehle für das "if" ankäme. Ich finde nur überflüssige Befehle sind ebenso unschönes Programmieren wie falsche.
Prinzipiell gilt aber:
Errorcodes sind dazu da, ausgewertet zu werden! Ein Code, der das nicht macht, fällt durch jedes Audit. Und ja, es führt dazu daß Fehlerbehandlung manchmal den größten Teil des Codes ausmacht. Und eigentlich sollte eine Library wie z.B. die I2C Library, die von fremden Programmieren verwendet wird, jeden Übergabeparameter auf gültige Werte überprüfe, und im Fall ungültiger Werte mit einem Fehlercode zurückkehren. Schau dir mal einige Funktionen der libc oder andere professionelle Libraries an, da ist die Beschreibung der Errorcodes häufig länger als die Funtionsbeschreibung.
Das ist eher "unschlau". Dazu müßte man erstmal die I2C Hardware abschalten. Und dann dauert die Sequenz natürlich viel länger, als den Controler auf idle prüfen zu lassen, und einfach den Status auszulesen.
Und es ist mitnichten eine "Zauberformel" sondern leicht zu erklären. Wenn der Slave mit Read adressiert worden ist, wartet er auf 8 Clocks um Datenbits zu liefern und ein neuntes mit dem ACK. Führt der Host diese Sequenz nicht vollständig durch (Absturz, Reset o.ä.), hängt der Slave (es gibt kein Timeout bei I2C). Das Toggeln von SCL führt das zuende und das High auf SDA ist ein NAK. Das bricht dann die Übertragung ab.
Das passiert nicht nur beim Flashen sondern auch beim Debuggen. Single Step oder Breakpoint, Register anschauen .. noch mal von vorne, Peng!Konkretes Beispiel gefällig?
Mein aktuelles Projekt mit I2C-Bus hängt nach dem Flashen häufig.
Ein einziger Controller als Master und ein einziger Gesprächspartner, der nur Slavemodus kann; alles ganz elementar und minimal.
Mein eigener, ursprünglicher Ansatz, den Bus in einen geordneten Zustand zu bringen war, zu Beginn jedes Datenaustauschs das I2C-Modul des Controllers zu deaktivieren, wieder zu aktivieren und dann einen I2C-Startzustand auf den Bus zu bringen.
Nette Idee, hilft aber leider nicht. Ein PowerUp dagegen hilft immer.
Und genau hier kommt die Resetsequenz ins Spiel. Wenn beim Init nach Reset der Bus nicht idle ist, schick die 8 Clocks. Ich mache das, bevor ich überhaupt die I2C Hardware anschmeiße. SDA und SCL als Input und auf High abfragen. Wenn nicht, SCL als Output und toggeln. Dann wieder Input. Wenn sie dann nicht high sind, Errorcode ausgeben und Halt (embedded Bluescreen).
MfG Klebwax
Lesezeichen