Liste der Anhänge anzeigen (Anzahl: 1)
So.. der Fehler mit hängen bleiben lang tatsächlich an E_INT1.
Kurze Beschreibung dazu: Ich habe eine pcf8583 Uhr am i2c hängen dessen INT Leitung am E_INT1 der Base liegt. Dies ist ansich ein harmloser ADC-Port. Ich möchte deren Alarmfunktion später mal nutzen.
Die Uhr gibt wenn das Register 0 mit 0 beschrieben ist, pro Sek ein Impuls aus. Ich hatte dem Baustein das die Tage abgewöhnt aber irgend ein rumflitzendes Byte auf dem i2c bus hat es zurück gesetzt. Die Base juckt das nicht weiter, für sie ist das nur ein normaler Port an dem jemand klopft. Die Leitung ist aber auch über den XBUS an den INT1 der M32 geführt was ein echter Interrupt ist - und ich nicht bedacht hatte. Dem zu Folge löste die M32 pro Sek ein irq aus wo der Master drauf läuft. Die INT Leitung hat eine höhere Priorität als TWI - daher wurde die TWI immer wieder unterbrochen was zu Timingproblemen und letztlich zum Abbruch des Datenflusses führte.
Für euch interssant ist eigentlich die Info, das wenn man den E_INT1 z.B. als Ausgang nutzt - warum auch immer - ihr damit die M32 quasi ständig in eine ISR schickt. Ich finde das sogar sehr gut durchdacht vom Entwickler... nur darf man das halt nicht vergessen wenns um die Leitung geht. Die E_INT1 ist als Steuerleitung Tabu wenn man eine M32 oder vermutlich auch M128 nutzt. Eigentlich logisch aber man denkt eben nicht immer dran.
Nun zum TWI. Ich hab euch meine aktuellen Files zum Projekt bzw. Dirks modifiziertes Testprogramm zusammen mit der TWI in ein Zip gepackt. Damit können jetzt auch mehr Leute mal versuchen wie es klappt. Achtet bitte auf Pfade und Abhänigkeiten im makefile und kommentiert die defines zum lcd und das lcd.h aus wenn ihr kein i2c lcd mit pcf Baustein habt. Benötigt zum testen mit Dirks Programm werden die Base, eine M32 sowie ein M32Display.
I2CTWI_isBusy() (bit_is_set(TWI_statusReg,STR_isr))
#define I2CTWI_needAction() (bit_is_set(TWI_statusReg,STR_needAction) && bit_is_clear(TWI_statusReg,STR_isr))
#define I2CTWI_waitAction() (bitset(TWI_statusReg,STR_needAction))
#define I2CTWI_doneAction() (bitclr(TWI_statusReg,STR_needAction))
#define I2CTWI_NACKonAction() bitset(TWI_statusReg,STR_NACKonAction)
#define I2CTWI_ACKonAction() bitclr(TWI_statusReg,STR_NACKonAction);bitclr(TWI_ statusReg,STR_needAction)
Das hier sind Befehle, die für die Ablaufsteuerung relevant sind. Sie fragen oder setzen alle Flags ab die die ISR steuert.
I2CTWI_isBusy() ist gesetzt wenn die ISR ein Datagram überträgt. Egal ob als Master oder Slave, vom Start bis zum Stop.
Achtung, die Befehle
I2CTWI_requestRegisterFromDevice
und
I2CTWI_readRegisters
bestehen je aus 2 Einzelbefehlen in denen die ISR zwischendurch "Frei" meldet was zur Ausführung nachfolgend wartender TWI Befehle führen kann. Dafür muss ich noch eine Lösung stricken. Alle anderen TWI-Befehle sind Einzelbefehle, da sollte das Problem nicht auftauchen.
I2CTWI_needAction() prüft ob die Slave Register beschrieben wurden was mit einem gesetzten Bit angezeigt wird. Wenn ja, sollte der Slave als Zeichen das er die Daten verarbeitet hat immer I2CTWI_doneAction() ausführen was das Bit zurück setzt. Der Master hat dazwischen keine Schreibmöglichkeit und wird geblockt (was der natürlich auch über I2CTWI_isBusy() merken kann). Will man den Master ohne vorherige Schreiboperation zwingen zu warten (was eigentlich nur für mich zum testen relevant ist) nutzt man I2CTWI_waitAction() was das schreiben der Register simuliert. Soll der Master immer schreiben können (Verhalten wie bisher, führt zum überschreiben von Registern) nutzt man I2CTWI_ACKonAction(), mit I2CTWI_NACKonAction() blockt der Slave wieder das überschreiben.
Das Blocken geschiet durch senden von NACK wäred der Master ein Datenbyte auf ein bereits beschriebenes Registerset schreiben will, was wiederum mit einen neuen Anlauf der Übertragung mündet bis er erfolgreich war. Quasi eine Endlosschleife. Das Beschreiben des Adressbytes müsste aber noch gehen so lange der Master keine Daten mitsendet. Zur Not könnte der Master also auch noch darüber dem Slave was mitteilen. Morsen sozusagen... Vielleicht eine Möglichkeit für weitere Master zu signalisieren, wenn sie Daten haben und der Slave gefälligst die Register frei zu geben hat.... aber das ist dann schon leicht abgedreht und scheitert noch an fehlender Busarbitierung :). Derzeit ist der Bus belegt wenn der Slave nackt und ein 2.ter Master müsste den ersten von der Leitung schubsen um reden zu dürfen, wobei sich der erste vermutlich dann gehörig verschluckt. Bildlich gesprochen...
I2CTWI_waitAction() werde ich vermutlich wieder entfernen da es für euch kaum Sinn macht. I2CTWI_(N)ACKonAction() wird bleiben.
Die Variablen
I2CTWI_genCallCMD
I2CTWI_dataWasRead
I2CTWI_dataReadFromReg
I2CTWI_readBusy
I2CTWI_writeBusy
sind obsolet, I2CTWI_genCallCMD tut es eh nicht weil gencalls derzeit garnicht gehen, die anderen 4 Vars machen quasi das gleiche wie I2CTWI_isBusy() und I2CTWI_needAction() mit der Ausnahme das sie nun auch zu gebrauchen sind und den Ablauf am TWI beeinflussen.
Konfiguriert wir die Anwendung mit twi_target.h, sie ist selbsterklärend, jedes Projekt hat sein eigenes File. Es gelten die üblichen Vorgaben für TWI.
Flags wie DEBUG, XDEBUG können kommentiert wreden (//) dabei bedeutet:
TWISLAVE=Slave & Master
TWIMASTER=Master
TWILOW=(Slave & Master | Master) & TWILOW
Ich glaube, es geht nichts kaputt wenn man TWISLAVE und TWIMASTER setzt aber es ist doppelt gemoppelt. TWILOW sind Bascom ähnliche Funktionen die - wenn genutzt - das Handling auf dem TWI erlauben ohne das die ISR dazwischen funkt. Dazu müssen die Funktionen ein paar Dinge berücksichtigen, insbesondere das Ausschalten des TWI Interrupts und das Einschalten wenn man fertig ist. Gedacht ist das zum debuggen eigener Devices/Hardware, man kann sich natürlich auch kompexe Funktionen daraus basteln die mit der ISR koexistieren. Damit ist jedoch kaum Slave Betrieb möglich oder man müsste wie blöde TWI-Register pollen, daher nur einfache Masterfunktion.
Im Base Programm sitzt noch ein vagabundierender extINT Befehl, der kann/muss raus... und einige Kommentare wo ich am basteln war.. kann auch raus.
Ich bin mir noch nicht sicher wie die TWI auf Busarbitation reagiert, grundsätzlich können und dürfen am Bus mehrere Master laufen. Evtl. stürtzt aber die aktuelle TWI ab bzw. baut Mist. Aber es geht nichts kaputt.
Wer möchte, kann also Dirks Programm so umbauen das auf beiden Prozessoren Master und Slave laufen und die sich gegenseitig Daten zuwerfen und abfragen.... schlimmstenfalls bleiben die Programme nur nach einigen Bytes hängen. Nur hätte ich den Source dann bitte gern am Montag da ich dann auch die Arbitation in Angriff nehmen kann. :) Sonst muss ich mir das erst selbst schreiben.
Das sind mal grob alle wichtigen Infos zusammen gepackt.
Sonst schaut auch mal in die .h und .c files ... die beissen nicht...
Der compilerlauf mit gcc klappt hier, wenn was nicht klappt, bitte zuerst in der twi_target prüfen. Dirks Programm testet alle 4 Teilfunktionen der TWI, also MR/MT/SR/ST und sollte damit auch in eigenen Projeken funktionieren. Alles weitere findet sich auch im Thread hier.
Ich hab am WE keine Zeit und werde mich erst Montag wieder intensiv darum kümmern, ihr habt also die Möglichkeit damit zu spielen bevor ich wieder alles auf den Kopf stell. :) Es werden noch weitere Veränderungen und Betatests kommen, insbesondere Fabian sollte mit der Lösung und Remotrol aber schon arbeiten können. Sonst fragt einfach hier, ich werde sicher mal reinschauen am WE.
LG Rolf
Liste der Anhänge anzeigen (Anzahl: 1)
6502 ? nettes Teil... auch einer der mit ner Brotkiste angefangen hat? :) Mein erster war ein ZX81 :) Hach ja die alten Zeiten ... :)
Aber zur TWI. Ich war unzufrieden, das der IRQ mir die Daten auf dem i2c zerbröselte - auf Grund der Sache mit der Uhr - und hab eine Lösung gefunden. Einfach aber effektiv. Die ISR wird zukünftig (steuerbar über twi_target.h) im Eingang ein cli(); ausführen und im Ausgang ein sei(); , das verhindert nach nun 24h lang laufenden Dauertests absolut zuverlässig die Unterbrechung und Abbruch trotz sekündlichen Uhrenticks. Wird in der nächsten Release drin sein.
Dann freut es mich erst mal sehr, das Du reproduzierbar stabile Funktion berichten kannst. Zu Deiner Frage, nun wenn Du dich nicht um das "Protokoll" kümmern willst, kannst Du mit I2CTWI_ACKonAction() kurz nach der Initialisierung das so einstellen, das der Master nicht behindert wird.
I2CTWI_init()
I2CTWI_ACKonAction();
...
Programmlauf
...
Wenn aber dein Programm auf der Base sowas wie ein Handshake braucht, (Fabians Remotrol braucht das z.B. zwingend) oder verhindert werden muss das der Master Daten überschreibt (weil Befehlssequenzen übertragen werden, kommst Du um eine Verarbeitung der Daten/Befehle und letztlich auch einem Handshake.. nicht rum. Da bietet sich die default Einstellung bzw. I2CTWI_NACKonAction(); und dann endsprechendes bearbeiten mit I2CTWI_needAction() und I2CTWI_doneAction() an.
Es kommt also ein wenig auf deine Anforderungen an das Programm an, es gibt keine ja/nein Antwort dazu. Man kann überlegen, die Defaulteinstellung auf I2CTWI_ACKonAction zu setzen was dem alten Verhalten entspricht, ohne ein Handshake ist allerdings eine gesicherte Datenübertragung nicht möglich. Vergleich es mit den RTS/CTS Leitungen und dem Software Protokoll XON/XOFF, es würde auch keiner eine stabile UART ohne die Leitungen betreiben können und wenn doch, so muss zumindest das Softwareprotokoll XON/XOFF vorhanden sein. I2C hat kein RTS/CTS bzw. XON/XOFF, also braucht es da was anderes, die ACK/NACK Signale sind quasi eine Mischumg aus beidem und ohne die klappt so gut wie nix wirklich sicher auf dem Bus - der alte Treiber welcher alles ACKte, ist bester Beleg dazu. Natürlich muss man sich als Programm... nein.. man muss nicht, man kann... sich drum kümmern... und sicher stellen das die Daten korrekt verarbeitet werden. Aber es gibt auch Anwendungen wo das nicht so wichtig ist. Das entscheidest letztlich Du als Programmierer bzw. die Aufgabenstellung.
Man kann grundsätzlich das Ganze in ein Task packen und mit einem
If I2CTWI_needAction() task_do_i2c();
erledigen, wo dann halt in task_do_i2c alles verarbeitet wird. Incl. einem I2CTWI_doneAction(); am Taskende. Die Libs und Examples liefern dazu reichlich Beispiele. Das hatte ich in deinem Programm auch schon im Kommentar irgendwo angemerkt. Ich werde dazu am Montag ein kleines Beispiel bauen, denke aber das ihr da jetzt schon mit klar kommt.
Eigentlich reicht für das genannte Programm also:
while (true)
{
die_üblichen_System_Tasks();
If I2CTWI_needAction() task_do_i2c(); //Receiver bedienen (Daten kopieren wie im Slavebeispiel)
Master_task();//Selber aktiv werden, so wie in dem Masterbeispiel
}
Das ist echt nicht kompliziert, Du hast bereits alles geschrieben da was wir da brauchen...
LG Rolf
PS: Ich hab noch was für Dich Dirk, extra eben noch geknipst :) Du wirst sie erkennen, für die anderen: Eine 6502 CPU von MOS aus dem Jahr 1983 aus meiner Grabbelkiste. Hier noch bissel Text dazu. http://de.wikipedia.org/wiki/MOS_Technology_6502
Die 6509 war ein direkter Verwandter und wurde im CBM610 z.B. verbaut. http://www.zock.com/8-Bit/D_CBM610.HTML Ich hatte auch mal einen. Und nicht zu vergessen die allseits berühmte 6510 CPU aus dem C64 und die 6508 aus dem NES :) Eine Z80 CPU aus der Generation hab ich auch noch, und hüte sie wie Dagobert Duck sein ersten Taler :)
EDIT: Ich hab über die Handshake Geschichte nachgedacht und stelle fest, das es da noch einiges zu verbessern gibt. Z.B. kann der Masterzugriff bisher nicht beeinflussen was bei einem NACK passiert, bzw. ist einem hängendem Slave quasi ausgeliefert. Das ist unschön und wird demnächst behoben. Beide Seiten werden also steuern können, ob und wie sie mit NACKS umgehen. Dazu wird die ISR ein weiters Flag bekommen, das mit 1 oder 2 Funktionen/Macros steuerbar ist.