Sooo... wieder mal neues vom TWI.
Folgendes... der Treiber ist BETA und noch nicht fertig. Ich kann ihn noch nicht zur allgemeinen Nutzung frei geben. Er funktioniert aber schon mal soweit, das man es sehen kann und ich denke, zum betatesten langts auch schon mal.
Basis zum testen ist weiterhin Dirks Programm, was ich leicht modifiziert habe. Beide Programme (Base/M32) sind beigefügt, incl. der dazugehörenden TWI_TARGET.H
Es sind einige Optionen hinzu gekommen in twi_target, ansich sind sie aber dort jeweils kurz erklärt.
Was passiert da jetzt genau?
Nun auf beiden CPUs läuft jeweils ein masterfähiger Slave. Die beiden werfen sich Daten zu, die sie umkopieren so das die wieder abgeholt werden können. Die Ergebnisse werden vom Master verglichen und wenn Fehler auftauchen, werden diese erkannt und ausgegeben.
Starten tuen die jeweiligem Mastertasks z.Z. nur auf verlangen, das heisst beim drücken der Bumpertasten bzw. Key 1 auf der M32. Das habe ich deshalb gemacht, weil die sich z.Z. noch gegenseitig überrennen würden, wenn aber nur je einer sendet, klappts. Kann man einfach testen indem man auf beiden Boards die Taster drückt. Ziel wird sein, das beide auch dauerhaft senden können. Dafür ist das System jedoch noch nicht robust genug. Daher auch Beta. Derzeit dürften es die beiden Funktionen I2CTWI_request* nicht tuen.... also nicht wundern. Auch ein Grund für Beta.
Es gibt neben dem normalen Debug nun ein Debug für eine State Engine, diese überwacht ob ein kompletter Transport erfolgte (incl. Stop) sowie eine allgemeine Ausgabe für Bufferüberläufe.
Es gibt da noch ein paar ungereimtheiten im Timing, ich hoffe aber das beseitigen zu können. U.a. gehen ab und zu Daten verloren bzw. ist der Slave der Meinung, das Daten reinkamen obwohl die Register noch nicht beschrieben wurden. Je mehr Befehle in der ISR ausgeführt werden - und sich damit das Clocksignal streckt - um so seltener werden die Fehler. Es macht dabei z.B. einen Unterschied ob man die Stateengine einschaltet oder nicht. Das sind vielleicht 20 Maschinenbefehle mehr als sonst... also keine wirklich langen Zyklen. Mir ist aber nicht klar warum das so ist. Es gehen aber bis auf dieses kleine Problem keine Daten flöten, der Master macht bis zu 10 neue Anläufe mit je 5ms Pause dazwischen (alles einstellbar), der Slave nackt wenn er Busy ist und so kommen normal auch alle Daten zielsicher an.
Viel Spass beim testen
LG Rolf
EDIT: Einen längeren Test über mehrmalig je 1-2 Std. überstanden mein reparierter RP6 und der 2.te damit auch schon. Also keine Sorge. Übrigends sind seid der Reparatur komischer Weise ALLE Buserrors weg.
Edit: Weitere Änderung, ich hatte nicht bedacht, das bei Dirty Regs der Host (Slave) zwar ein weiteres Schreiben mit I2CTWI_doneAction(); frei geben muss, der Client (Master) aber die Regs bisher auslesen kann wärend der Slave sie ändert bzw. bearbeitet - was vor allem auf der schnelleren M32 zu Fehlern führt. Daher muss man die case TWI_STX_DATA_ACK gegen Folgende austauschen. Dies verhindert dann ein Auslesen wenn der Client noch nicht so weit ist - auch wenn kein Registerpointer geschrieben wird.
Code:
case TWI_STX_DATA_ACK: // 0xB8 TW_ST_DATA_ACK Data byte in TWDR has been transmitted; ACK has been received
if (TWI_statusReg.needAction && TWI_statusReg.NACKonAction) { //if Registers dirty, now send nacks
#ifdef DEBUG
logmyaction(TWI_STATUS,"/ STX_(ADR|DATA)_ACK NACK (Slave busy)");
#endif
TWI_statusReg.SendNACK=1; //dead end, master must retry, I2CTWI_doneAction/TWINIT will reset this
} else {
if (current_register < I2CTWI_SLAVE_READ_REGISTERS) {
TWDR = I2CTWI_readableRegisters[current_register++];
TWI_statusReg.SendACK=1;
#ifdef DEBUG
logmyaction(TWDR,"<- STX_DATA_ACK -> ACK (data)");
#endif
} else {
#ifdef DEBUG_MISC
writeString_P("Register read boundary violation\n");
TWI_statusReg.SendNACK=1;
#else
TWDR = 0;
TWI_statusReg.SendACK=1; // THIS should not happen... count your Regs please...
#endif
}
}
break;
Dieser Fix ist für eine Anwendung wie in dem RP6-Slave weniger wichtig, in Dirks Programm jedoch, wo sich beide CPU's mit Daten bewerfen und requesten spielt es eine gewichtige Rolle.
Damit macht nun auch ein weiterer Befehl in der RP6I2CTWI.h Sinn.
#define I2CTWI_doAction() TWI_statusReg.needAction=1
was quasi den Slave jederzeit in die Lage versetzt, dem Master anzuzeigen das er grade keine Daten kriegt, was man aber durch
I2CTWI_doneAction(); auch wieder freigeben sollte. Dabei sind die Retrys und der Timer in twi_target.h zu berücksichtigen.
Der Slave sollte also nur max so lange die Regs blockieren wie sich aus den beiden Zahlen Millisekunden + Reserve ergeben.
Leider liefern die asyncronen Funktionen ja kein echten Errorcode zurück, sonst könnte man das besser abfangen.
Kleine Änderung für TWI_MRX_ADR_NACK, bisher wurde hier ein Error initiiert, dies sollte durch ein Restart ersetzt werden. Zum einen entscheidet der Retrycode ob und was ein Error ist, zum anderen ist ein NACK auf Grund von "Device Bussy" ja kein Grund, den ganzen Transport abzuwürgen. Die case TWI_MRX_ADR_NACK wird daher ersetzt mit:
Code:
case TWI_MRX_ADR_NACK: // 0x48 TW_MR_SLA_NACK SLA+R has been transmitted and NACK received
#ifdef DEBUG
logmyaction(TWDR,"<- MRX_DATA_NACK RESTART (busy)");
#endif
TWI_STATUS_state = TWI_STATUS;
TWI_statusReg.SendStop=1;
TWI_old_operation = I2CTWI_NEED_RESTART;
break;
Das System verhält sich damit bei einem NACK im Master Receive (MRX) Mode genau so wie im Master Send (MTX) Mode und versucht es erneut bis die Retry Defaults aus twi_target.h erreicht sind.
EDIT:
Ich habe ein weiters Problem gefixt, der Slave war zu früh der Meinung, das der Transport fertig ist wesshalb teilweise Daten nur halb ankamen bzw. zu früh verarbeitet wurden. Die Änderungen im Code sind zu verstreut als das ich sie hier posten kann, es wird also demnächst wieder eine Beta geben. Ich Suche z.Z. aber noch ein Fehler, der dann zu Stande kommt wenn beide CPUs quasi zeitgleich senden. Das ist ein Laufzeitproblem und hat wohl noch nichts mit Arbitierung zu tun.
Lesezeichen