Forum: Projekte & Code USI-Slave als TWI-Logger auf Tiny2313


von Michael S. (Gast)


Angehängte Dateien:

Lesenswert?

Anliegend eine Hilfsmittel für alle TWI/USI-Bastler:

Ein TINY2312 als USI-Slave lauscht am TWI-Bus und zeichnet alle Daten 
mit,
einschließlich TWI-START, ACK, NACK und TWI-STOP.

Eine fiktive Ausgabezeile sieht dann z.B. so aus:

33 <02,FF,>
34 <02,65,66;>

34   Zeile 34 (laufend durchnummeriert von 1 bis 99)
<    TWI-START-Condition (des Masters)
02   Byte1 (Adresse gesendet vom Master)
,    ACK (des Slave)
65   Datenbyte gesendet vom Master
;    NACK (des Slave)
>    STOP-Condition (des Masters)

Die Daten werden hexadezimal mit 2 Zeichen ausgegeben.

Mit diesem Tool sollte man erkennen können, warum TWI-Geräte nicht 
miteinander reden wollen.
Z.B., weil sie nicht das sagen, was sie sagen sollen.

Das Programm basiert auf Bibliotheken für/von:
- LCD-lib von Peter Fleury
- AVR312 von ATMEL
- Überarbeitung dieser Bibliothek von Frank Jonischkies
  (hier auf mikrocontroller.net gefunden)

Ursprünglich habe ich mit einer eigenen Interpretation der AVR312 
gearbeitet.
Allerdings steckten darin mehrere Probleme, an denen ich lange laboriert 
habe:
- Festklemmen von SDA auf gnd bei geringem TWI-Takt (>50 KHz) bzw. bei 
hohem Prozessortakt
 (8MHz),
- schräges Verhalten bei einigen Programmvariation (wenn die 
Klammersetzung
  {} bei if/else syntaktisch (nach meiner Meinung) richtig war, dann gab
  es Fehlfunktionen im Programmablauf.

Das Ergebnis der Fehlersuche:
Zwei Korrekturen in der USI_START_ISR haben das erste Problem 
nachvollziehbar beseitigt.
Nach der Ursache für das zweite Problem habe ich nicht weiter geforscht, 
nachdem ich die usi-slave.c von Frank Jonischkies gesehen hatte.
Mit seine Interpretation habe ich einerseits keine syntaktischen 
Probleme.
Und andererseits hat das Programm den großen Vorteil, dass das Erkennen 
des USI-STOP verzögerungsfrei (ohne das Pollen von Flags im 
Hauptprogramm) möglich ist.
Bei meiner alten Logger-Version habe ich nämlich häufig das TWI-STOP 
verloren, wenn der nächste START zu schnell erfolgte.

Eine (bekannte) Einschränkung hat das Tool:
Der SRAM des 2313 ist begrenzt. Wenn die Daten schneller ankommen, als 
sie
wieder über LCD oder serielle Schnittstelle ausgegeben werden können, 
dann wird der Puffer von hinten her überrannt.
Die Puffergröße beträgt 20 TWI-Bytes (wenn LCD und COM-Ausgabe eingebaut 
sind), bei Beschränkung auf COM-Ausgabe können 32 TWI-Bytes gepuffert 
werden.
Ein blockread() über 128 Byte von einem eeprom wird also nicht zu
protokollieren sein (es sei denn, man reduziert den TWI-Takt hinreichend 
weit).
Im normalen Alltag werden pro Transaktion deutlich weniger Bytes 
fließen.
Und Pausen zwischen den Transaktionen wird es auch geben.

Die Beschaltung ergibt sich aus der Hardware:
SDA, SCL, TxD , GND und VCC werden an den vom Schöpfer dafür 
vorgesehenen Pins angelötet.
Der Anschluss des LCD's ist in der LCD-Header-Datei dokumentiert.
Bei der Ausgabe auf COM mit 38400 Baud ist ein XTAL Pflicht (mit 7.3728 
MHz
getestet, vielleicht funktioniert es auch mit 8 MHz (aber makefile 
anpassen)), für die Ausgabe auf dem LCD reicht der interne 
RC-Oszillator.

Es sind zwei Programmvariationen beigefügt:
usi_logger_lcd_com.zip  -> Ausgabe alternativ auf LCD oder COM

(Beim Start wird ein Pin abgefragt, er legt fest, ob COM oder LCD 
initialisiert wird, die Ausgabe auf dem LCD erfolgt zweizeilig, in der 
ersten Zeile steht die vorletzte Message)

usi_logger_com.zip      -> LCD-Routinen gelöscht, nur COM Ausgabe

mfg

Michael S.

von Michael S. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

beim Versuch, den Logger auf einen größeren mc mit 1KB SRAM und 
Hardware-TWI zu portieren (hier sind einige Klimmzüge erforderlich, 
damit ein passives Verhalten möglich ist) ist mir ein logischer Fehler 
in meinem Programm beim Zwischenspeichern des TWI-STOP aufgefallen.

Ergebnis: Jedes 0x3e im Datenstrom wird als STOP interpretiert.

Der Fehler sollte im angehängten Code beseitigt sein.

Michael S.

von Peter D. (peda)


Lesenswert?

Michael S. wrote:
> Ursprünglich habe ich mit einer eigenen Interpretation der AVR312
> gearbeitet.

Ja, die AN finde ich auch äußerst unübersichtlich geschrieben.
Besonders die vielen Macros macht es schwer lesbar. Man weiß nie, was 
ein Macro macht und welche Bits es nun setzt, wenn es im C-File steht.

Ich hatte eher den Eindruck, der Autor wollte nur zeigen, wie schlau er 
ist.
Nichts für Einsteiger ins USI.

Das einzige, was ich übernommen habe, war das Warten auf SCL = low nach 
dem Start.
Danach habe ich stur nach der Registerbeschreibung im Datenblatt 
weitergemacht.


> - Festklemmen von SDA auf gnd bei geringem TWI-Takt (>50 KHz) bzw. bei
> hohem Prozessortakt
>  (8MHz),

Für nen Sniffer das DDR des SDA auf Input setzen, dann klemmt nichts 
mehr.


>   {} bei if/else syntaktisch (nach meiner Meinung) richtig war, dann gab
>   es Fehlfunktionen im Programmablauf.

Wäre aber schön, wenn man das genauer wüßte, wo der Compiler den buggy 
Code erzeugen soll.
Es kann leicht sein, daß man einen logischen oder Ablauf-Fehler drin hat 
und den bei der Umstellung beseitigt.


> Und andererseits hat das Programm den großen Vorteil, dass das Erkennen
> des USI-STOP verzögerungsfrei (ohne das Pollen von Flags im
> Hauptprogramm) möglich ist.

Könnte bei mir auch passieren, daß Stop und Start vertauscht dargestellt 
werden.
Ist mir aber noch nicht aufgefallen, da das USI sauschnell in der 
Mainloop abgearbeitet wird (der ganze Interrupt-Ballast fällt weg).
Der I2C-Master wird meistens langsamer sein.


> Der SRAM des 2313 ist begrenzt. Wenn die Daten schneller ankommen, als
> sie
> wieder über LCD oder serielle Schnittstelle ausgegeben werden können,
> dann wird der Puffer von hinten her überrannt.

Sollte aber nicht passieren.
Mein I2C-Sniffer verzögert dann einfach den I2C-Bus (SCL = low). Dazu 
muß man nur das DDR-Bit von SCL auf Ausgang setzen.
Ein 128Byte Page-Write des EEPROM wird vollständig und korrekt 
angezeigt.


Peter

von Michael S. (Gast)


Lesenswert?

@ Peter Dannegger

Ein bug in der AVR312 liegt nach meiner Erkenntnis in der 
Verzögerungsschleife der USI-START-ISR:

      while ( (PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF)) 
);

Hier soll nach dem START solange gewartet werden, wie SCL high ist UND 
kein STOP aufgetreten ist.
Hier sollte ein logisches AND (&&) stehen.
Die obige Schleife verzögert nicht.
Zufälligerweise passt aber der Zeitablauf bei einem CPU-Takt von 4MHz 
und 100 KHz TWI-Takt.
Setzt man den TWI-Takt aber herab (oder den CPU-Takt herauf), dann 
beginnt der Zählmechanismus des USI-Moduls zu früh und zählt die 
fallende SCL-Flanke im START mit - und damit kommt die gesamte 
Synchronisation (die ja auf "blödem" Mitzählen der SCL-Flanken beruht) 
aus dem Tritt.
Der Erfolg ist z.B. ein auf Masse "klemmendes" SDA.

Das andere Problem hatte ich in USI-OVERFLOW-ISR

    case USI_SLAVE_CHECK_ADDRESS:
      if ((USIDR == 0) || (( USIDR>>1 ) == TWI_slaveAddress))
      {
        if ( USIDR & 0x01 )
          USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA;
        else
          USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA;
          SET_USI_TO_SEND_ACK();
      }
      else
      {
        SET_USI_TO_TWI_START_CONDITION_MODE();
      }
      break;

Wenn ich hier ordentlich in der inneren if..else Abfrage {} gesetzt 
habe, dann meckerte der Compiler (das war in der Version des letzten 
Sommers ...).
Der Compiler vom 12/2007 (?) schwieg zwar, dafür funktionierte das 
Programm nicht mehr.
Aber die Ursachen für die Probleme will ich heute nicht mehr 
herausfinden.

Meine Versuche, Hardware-TWI zum Loggen einzusetzen, habe ich inzwischen 
kleinlaut aufgegeben.
Meine Hoffnung war:
Der mega168 hat ein Register zur Adressmaskierung. Mit 0xFE beschrieben 
antwortet der Chip auf alle Adressen.
Wenn man SCL und SDA durch Dioden vom Bus abkoppelt (damit der Logger 
nach aussen hin passiv bleibt)
kann man schreibende Aktionen des Masters und die Antworten der Slaves 
aufzeichnen.
Aber wenn der Master lesen will (der Logger also selbst schreiben muss), 
dann gibt ein unlösbares Problem.
Wenn es gelänge, das TWI-Modul zum Lesen zu veranlassen (obwohl Bit0 der 
Adresse gesetzt war), dann wäre die Kuh vom Eis.
Allerdings finde ich dafür z.Z. keine Möglichkeit.

Zu Vergrößerung des Puffers bleibt dann wohl nur der Einsatz eines 
kleinen Tiny/mega_xy als USI-Slave, der die Daten per SPI an einen mega8 
übergibt, der sie puffert und über seine serielle Schnittstelle wieder 
ausgibt.

Michael S.

von Peter D. (peda)


Lesenswert?

Michael S. wrote:
>       while ( (PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF))
> );
>
> Hier soll nach dem START solange gewartet werden, wie SCL high ist UND
> kein STOP aufgetreten ist.
> Hier sollte ein logisches AND (&&) stehen.

Und warum steht es dann nicht da?

Mit dem binären AND wird es komplett wegoptimiert.
Da beim 2313 der SCL-Pin auf PB7 liegt, kann der linke Ausdruck nur 0 
oder 0x80 sein.
Der rechte Ausdruck wird logisch negiert, kann also nur 0 oder 1 sein.
Das binäre AND ergibt dann immer 0:

0x80 & 1 = 0
0x80 && 1 = 1

Funktionieren würde auch:
1
while ( !!(PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF))


Peter

von Michael S. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

nachdem der Versuch gescheitert ist, Hardware-TWI eines mega168 zu 
überlisten, habe ich zumindest die USI-Lösung so überarbeitet, wie der 
TWI-Ansatz eigentlich werden wollte:
Der Programmablauf und die Datenpufferung ist leichter durchschaubar - 
und nebenbei lassen sich nun auch 50 Byte puffern.
Würde man die "Steuercodes" jeweils in 2-Bit codiert zu viert in einem 
Byte ablegen, dann würde der Puffer auch für 80 Byte reichen.
Das erfordert dann aber einiges an Bit-Schiebereien, die den Code gleich 
wieder verkompliziert.

Michael S.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.