mikrocontroller.net

Forum: Compiler & IDEs Kann sich ein USI verzählen, wohl vermutlich nicht


Autor: Christian Paier (christian_paier)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute

Ich sitze nun schon fast 2 Tage an der Sache und stehe am Rande der 
Verzweiflung, am Punkt an dem man glaubt nichts mehr zu verstehen und 
nichts gelingt. Und obwohl ich es gerne selbst geschafft hätte muss ich 
jetzt leider doch jemanden von euch um Hilfe bitten.
Denn irgendwo verzählt sich mein USI...

Es geht um das USI-TWI. Als Basis verwende ich die APP-Notes 310 und 312 
von Atmel. Da diese aber für einen anderen Compiler sind wollte ich 
(auch zum Zweck des Verständnisses des USI) die Libaries an meine 
Bedürfnisse anpassen. Was mir bis jetzt mit mehr oder weniger gut 
gelungen ist.

Verwendete AVR's: Master:Tiny2313; Slave: Tiny25

Start-Conditon plus Erkennung =OK
Adressübertragung plus Erkennung =OK (Der Slave fühlt sich angesprochen)
Das große Problem ist beim Austausch des ACK/NACK Bits nach der 
Adress-Übertragung.

Im Anhang(ist besser formatiert und einfacher zu lesen) findet ihr 
meinen Source-Code und die von mir verwendeten APP-Notes.

Zuerst mal der Master: Über das HyperTerminal kontrollliere ich was er 
alles macht

//HYPERTERMINAL//
Tiny2313 initialized
SCL Released!
START  //Start-Bedingung gesendet

SCL  //Jedes mal wenn er eine SCL Puls generiert
SCL  //wird es hier ausgegeben
SCL  //ingesamt 8mal
SCL
SCL
SCL
SCL
SCL
USIOIF  //Da der Counter hier mit 0x00 vorgeladen wurde kommt es braf
//zum Überlauf
SCL  //Ein SCL-PULS für das ACK/NACK
USIOIF  //Da der Counter hier mit 0xE0 vorgeladen wurde kommt es braf 
zum Überlauf
ACK  //Lade ich den Slave-Counter auch mit 0xE0 vor bekomme ich ein
        //Nack, bei 0xC0 ein ACK

So sendet der Master die Slave-Adresse und den ACK/NACK SCL-Puls:
//Write Address Byte to Slave
PORT_USI &= ~(1<<PIN_USI_SCL);   // Pull SCL LOW.
USIDR = ((TWI_targetSlaveAddress<<1)|MASTER_READ_BIT); // Setup data.
USI_TWI_Master_Transfer(tempUSISR_8bit );   // Send 8 bits on bus.    
for(i=0;i<=200;i++)_delay_ms(20);  //Warteschleife um mit dem 
                                   //Multimeter zu sehen ob der Slave 
                                   //Portpin PB1 zu früh auf high 
                                   //geht, bevor unten ein
                                   //weiterer Clock erzeugt wurde
//Clock and verify /Ack/Nack
DDR_USI  &= ~(1<<PIN_USI_SDA);  // Enable SDA as input.
if( USI_TWI_Master_Transfer(tempUSISR_1bit) & (1<<TWI_NACK_BIT) ) 
{
  usart_puts("NACK");usart_putc(13);    
}
else
{
  usart_puts("ACK");usart_putc(13);
}


//So bereitet der Slave nach erhalten der Richtigen Adresse sein ACK vor
USIDR = 0; //Prepare ACK
DDR_USI |=  (1<<PORT_USI_SDA);  // Set SDA as output
// Clear all flags, except Start Cond., load Counter
USISR   =   (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|
(0xE0<<USICNT0);  
while ( !(USISR & ( (1<<USISIF)|(1<<USIOIF) )) ); // Hier wartet der 
//Slave  bis 2 Counterpulse oder 1 SCL-Clock aufgetreten sind

DDR_USI &=  ~(1<<PORT_USI_SDA); //Set SDA as Imput
PORTB|=(1<<PB1);//Jedoch kann ich an diesem PIN mit dem 
//Multimeter den High-Pegel schon messen bevor die lange Warteschleife 
//beendet ist.

Wenn ich den Counter allerdings mit 0xC0 vorlade geht der PIN erst nach 
der ca. 2 Sekunden Wartezeit auf High, und der Maser bekommt sein ACK.

Irgendwo muss sich da entweder der Slave oder Master verzählen aber ich 
komm einfach nicht drauf wo.
Ich hoffe jemand der ein wenig Abstand zu dem Ganzen hat, hat den 
erfordelichen Geistesblitz der mir verwehrt bleibt.

Danke im Vorraus

mfg Christian Paier

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sollte so korrekt sein. Wenn das USI im Slavemode betrieben wird, 
dann wird der USI-Zähler auf beiden Taktflanken am SCL Pin 
hochgezählt! Siehe Datenblatt.

Beim Slave muss also mit 14 vorgeladen werden, völlig korrekt.

PS: Ich wäre dir dankbar wenn du deine Sourcen vielleicht in der 
Codesammlung zur Verfügung stellen würdest, da ich die Tage selber einen 
USI-TWI Slave basteln möchte :-)

EDIT: Moment, was lese ich da? Warum lädst du den 4Bit Timer mit werten 
wie 0xE0/0xC0 vor?

Autor: Christian Paier (christian_paier)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh ja, lusig, das war aber nicht der Fehler im Code. Das hatte ich jetzt 
hier im Beitrag falsch im Code ist es natürlich 0xE und 0xC. (DARAN KANN 
MAN MEINEN ZUSTAND EH SCHON GUT ERKENNEN ;-) )

Ich vermute nun auch dass ich den Fehler bereits gefunden habe.

Beim Slave in der Zeile:
while ( !(USISR & ( (1<<USISIF)|(1<<USIOIF) )) );

warte ich bis ein Overflow-Interrupt-Flag auftritt, der auch kommt. Das 
Problem ist vermutlich dass er dann die dazu passenden ISR anspringt und 
es deshalb zum Fehler kommt. Solche Interrupt-Fehler sind leider immer 
schwer zu entdecken. Ist mir dann  beim Abendessen eingefallen. Jaja mit 
ein wenig Abstand kommen einem wieder die Ideen.

Ich bin aber heute weder geistig, noch seelisch dazu in der Lage dem 
Verdacht genauer nachzugehen. Das werd ich dann morgen in die Hand 
nehmen.

Wenn ich es schaffen sollte ein paar schöne Libarys hinzukriegen die gut 
funktionieren stell ich sie gern in die Codesammlung.

Auf jeden Fall mal Danke

mfg Christian Paier

Autor: Michael S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.