Hallo zusammen,
ich habe bei einem Projekt eine Master-Slave Kommunikation über TWI-Schnittstelle zwischen 2 mega128. Dabei ist mir aufgefallen, dass der TWIStat Befehl im Slave nicht korrekt abgearbeitet wird. Es gibt hierzu auch schon ein paar Beiträge die dieses Verhalten auch beschreiben.
Nach dem Senden eines TWIStat wird der anschließende Befehl im TWISlave nicht korrekt verarbeitet. Schickt man 2 TWIStats hintereinander gehts. Da dieses Verhalten, im Forum schon ein paar Mal thematisiert wurde, aber nie wirklich gelöst, habe ich mir 2 Mini-Programme geschrieben, TWIMaster und TWISlave um das ganze genauer anschauen zu können. Desweitern habe ich mir das Assembler-File des Slaves nochmals genau durchgeschaut. Folgende Variablen werden in der "State-machine" des TWISlaves verwendet:
_TWISLRES - LastTWIStatus
_TWISLRWPTR - Read/Write Pointer to RX/TX Buffer
TWIRXBUFFER - TWI Rx Buffer
TWITXBUFFER - TWI TX Buffer
Im TWI_Interrupt wird zuerst überprüft, ob kein Fehler bei der Übertragung vorlag, d.h. TWSR <> 0. Ist dies der Fall wird anschließend anhand des letzten TWIStatus (_TWISLRES) weiterverfahren.
Normalerweise ist dieses nach einem kompletten Read oder Write Befehl 0. In meinem Projekt kann ich über die serielle Schnittstelle die unterschiedlichen Werte der Variablen auslesen. Schicke ich vom Master ein TWIOut(I2CAdd,Addr,Data), dann steht anschließend im _TWISLRES =0. Wird allerdings ein TWIStat(I2CADD) gesendet steht nachher in _TWISLRES = $A0. Dies ist laut Datenblatt der Statuscode für eine gesendete Stop Condition.
Nach erneutem Senden des TWIStat(I2CAdd) steht dann wieder _TWISLRES =0 drin. Und so weiter und so fort.
Um das noch genauer untersuchen zu können, habe ich mich mit
interrupt TWSI;
an den Interrupt angehängt. Wie zu Erwarten werden bei einem TWIStat 2 Interrupts ausgelöst. Nach dem Empfang der Adresse und nach dem Erkennen der StopCondition. Dier Erkennung der Stop Condition müsste aber eigentlich die Statemachine wieder zurücksetzen, was sie aber nicht tut. Und zwar aus folgendem Grund:
- Beim ersten Interrupt ist _TWISLRES=0 und TWIStatus = $60.
Dies bedeutet laut Datenblatt "Own SLA+W has been received;ACK has been returned"
Damit wird am Ende des Interrupts _TWISLRES = $60 gesetzt.
- Beim zweiten Interrupt (Stop Condition) ist _TWISLRES = $60 und TWIStatus = $A0
LDS _ACCB, _TWISLRES
CPI _ACCB, 00h
BREQ SYSTEM._L0051
CPI _ACCB, 060h
BREQ SYSTEM._L0052
.....
SYSTEM._L0052:
LDS _ACCB, TWDR
STS _TWISLRWPTR, _ACCB
Da aber in der Statemachine in diesem Fall der aktuelle Status gar nicht abgefragt wird, wird einfach das Datenregister in den Pointer gelesen, obwohl gar keine Daten da sind. Eigentlich müsste mit der Stop Condition die Statemachine zurück- und _TWISLRES = 0 gesetzt werden. Aber in diesem Fall wird _TWISLRES = $A0 gesetzt.
Es fehlt im Prinzip also der Fall eines SLA+W (TWIStat) ohne dass Daten hinterherkommen.
Die beiden Mini-Programme habe ich angehängt.
Gruß Mario
ich habe bei einem Projekt eine Master-Slave Kommunikation über TWI-Schnittstelle zwischen 2 mega128. Dabei ist mir aufgefallen, dass der TWIStat Befehl im Slave nicht korrekt abgearbeitet wird. Es gibt hierzu auch schon ein paar Beiträge die dieses Verhalten auch beschreiben.
Nach dem Senden eines TWIStat wird der anschließende Befehl im TWISlave nicht korrekt verarbeitet. Schickt man 2 TWIStats hintereinander gehts. Da dieses Verhalten, im Forum schon ein paar Mal thematisiert wurde, aber nie wirklich gelöst, habe ich mir 2 Mini-Programme geschrieben, TWIMaster und TWISlave um das ganze genauer anschauen zu können. Desweitern habe ich mir das Assembler-File des Slaves nochmals genau durchgeschaut. Folgende Variablen werden in der "State-machine" des TWISlaves verwendet:
_TWISLRES - LastTWIStatus
_TWISLRWPTR - Read/Write Pointer to RX/TX Buffer
TWIRXBUFFER - TWI Rx Buffer
TWITXBUFFER - TWI TX Buffer
Im TWI_Interrupt wird zuerst überprüft, ob kein Fehler bei der Übertragung vorlag, d.h. TWSR <> 0. Ist dies der Fall wird anschließend anhand des letzten TWIStatus (_TWISLRES) weiterverfahren.
Normalerweise ist dieses nach einem kompletten Read oder Write Befehl 0. In meinem Projekt kann ich über die serielle Schnittstelle die unterschiedlichen Werte der Variablen auslesen. Schicke ich vom Master ein TWIOut(I2CAdd,Addr,Data), dann steht anschließend im _TWISLRES =0. Wird allerdings ein TWIStat(I2CADD) gesendet steht nachher in _TWISLRES = $A0. Dies ist laut Datenblatt der Statuscode für eine gesendete Stop Condition.
Nach erneutem Senden des TWIStat(I2CAdd) steht dann wieder _TWISLRES =0 drin. Und so weiter und so fort.
Um das noch genauer untersuchen zu können, habe ich mich mit
interrupt TWSI;
an den Interrupt angehängt. Wie zu Erwarten werden bei einem TWIStat 2 Interrupts ausgelöst. Nach dem Empfang der Adresse und nach dem Erkennen der StopCondition. Dier Erkennung der Stop Condition müsste aber eigentlich die Statemachine wieder zurücksetzen, was sie aber nicht tut. Und zwar aus folgendem Grund:
- Beim ersten Interrupt ist _TWISLRES=0 und TWIStatus = $60.
Dies bedeutet laut Datenblatt "Own SLA+W has been received;ACK has been returned"
Damit wird am Ende des Interrupts _TWISLRES = $60 gesetzt.
- Beim zweiten Interrupt (Stop Condition) ist _TWISLRES = $60 und TWIStatus = $A0
LDS _ACCB, _TWISLRES
CPI _ACCB, 00h
BREQ SYSTEM._L0051
CPI _ACCB, 060h
BREQ SYSTEM._L0052
.....
SYSTEM._L0052:
LDS _ACCB, TWDR
STS _TWISLRWPTR, _ACCB
Da aber in der Statemachine in diesem Fall der aktuelle Status gar nicht abgefragt wird, wird einfach das Datenregister in den Pointer gelesen, obwohl gar keine Daten da sind. Eigentlich müsste mit der Stop Condition die Statemachine zurück- und _TWISLRES = 0 gesetzt werden. Aber in diesem Fall wird _TWISLRES = $A0 gesetzt.
Es fehlt im Prinzip also der Fall eines SLA+W (TWIStat) ohne dass Daten hinterherkommen.
Die beiden Mini-Programme habe ich angehängt.
Gruß Mario
Attachments
Filename: | TWI_MasterSlave.zip |
Filesize: | 1.64 KB |
Title: | |
Download counter: | 33 |