Hallo Christian Paier,
auch ich würde vermuten, dass sich der Zähler nicht verzählt.
Aber er könnte ja etwas anderes zählen, als Du vermutest !?
Ich habe selbst einige USI-TWI-Slaves aufgebaut und mit dem Code nach
AVR312 gefüttert.
Als Master verwende ich einen M8.
Die Slaves funktionieren tadellos bei einem Controller-Takt von 4MHz und
TWI-Takt von 100KHz.
Wenn ich aber den TWI-Takt reduziere (z.B. auf 25 KHz), dann zieht der
Slave SDA auf Masse und unterbindet jegliche weitere Kommunikation.
Das hatte ich bislang mit Verwunderung und etwas Beunruhigung zur
Kenntnis genommen, war doch klar, dass hier irgendwo ein Bug steckt.
Kürzlich tauchten nun das gleiche Sympthome wie oben auf, als ich den
Controller mit 8MHz laufen lassen musste - schon wieder klemmte der
Slave SDA auf Masse.
Als Ursache habe ich (nach allerdings mehr als 2 Tagen Suche und nur mit
der geduldigen Unterstützung eine Logic-Analysers) etwas festgestellt,
dass ich als Fehler im USI-TWI-Modul bezeichnen möchte.
In der USI-START-ISR gibt es eine Warteschleife, die solange abwartet,
wie SCL high ist UND das USI-Stop-Flag nicht gesetzt ist.
Und in letzterer Bedingung liegt das Problem:
Nach einer erfolgreichen Transaktion beendet der Master mit einem STOP.
Der USI-Slave bekommt das aber nicht mit, da das USI-Stop-Flag keinen
Interrupt auslöst.
Beim nächsten USI-START ist nun in der Verzögerungsschleife (die bis zur
fallenden Flanke von SCL warten soll) die Bedingung UND !(USI-STOP-FLAG)
nicht erfüllt.
Somit wird die Warteschleife sofort beendet.
Zufälligerweise bereitet das keine Probleme bei einem 100KHz TWI-Takt
und 4MHz Controller-Takt (hier ist die "natürliche" Wartezeit bedingt
durch das Abarbeiten des Codes lang genug).
Aber wehe, man vergrößert das Verhältnis von TWI zu Controller-Takt
(indem man den TWI-Takt verkleinert oder den Controller-Takt
vergrößert).
Dann passiert nämlich folgendes:
Durch die nicht ausgeführte Verzögerung (Wartezeit bis zur fallenden
Flanke von SCL) wird der USI-Mechanismus (das Zählen von Flanken bis 16)
zur früh ausgelöst:
die fallende SCL-Flanke des USI-Starts wird bereits als 1 Flanke der
Daten gezählt.
Nach 16 Flanken glaubt das USI-Modul, die Daten seien übermittelt. In
Wahrheit sind aber erst 15 Flanken angekommen + der irrtümlich
mitgezählten Flanke aus dem USI-Start.
Und dann kommt es zum Exitus, wenn mitten im ACK die Kommunikation
abgeschlossen wird: SDA liegt dauerhaft (bis zu RESET) auf Masse.
Wie kann man das Problem lösen ?
Ganz am Anfang der USI-START-ISR das Stop-Flag durch Beschreiben mit 1
löschen.
oder
Aus der while Schleife einfach die Abfrage nach dem USI-Stop-Flag
rauswerfen (hat hoffentlich keine Nebenwirkungen).
oder
Das USI-Stop-Flag durch Pollen o.ä. abfragen und löschen (macht
normalerweise keinen Sinn).
Ich habe mich für die 2. Lösung entschieden, bin mir aber noch nicht
ganz bezüglich möglicher Nebenwirkungen sicher.
Und ich meine gelesen zu haben, dass ein STOP direkt auf ein START nicht
definiert ist ??
Meine USI-Slaves funktionieren jetzt übrigens - auch bei 8MHz
Controller-Takt und 5KHz TWI-Takt !!
mfg
Michael S.