Hi,
ich lese mich gerade in diesen Artikel ein:
http://www.mikrocontroller.net/articles/AVR_TWI
Unten sind 2 AN angezogen:
AVR311 und AVR315
In den AN steht etwas von c-libs für Slave und Master. Doch wo bekomme
ich diese her?
Gruß,
DS
Hi,
hatte imemr nur die ANs gefunden, jetzt aber - danke!
War nun auch hier:
Beitrag "AVR TWI Master und Slave Funtionen in C"
unterwegs.
Hat jemand Erfahrungen mit dem Code von Atmel?
@Christoph B.
Schaue ich mir an.
Gruß,
DS
> Hat jemand Erfahrungen mit dem Code von Atmel?
Ja, ich hab mir den vor Jahren auch gegriffen, um TWI zu machen.
Ist für IAR geschrieben, kann man aber leicht für avr-gcc umstellen und
er funktioniert. Fehlerhandling nur ansatzweise vorhanden. Der Code
arbeitet Interrupt-gesteuert, was wiederum zur Folge hat, daß man sich
in die ISR nicht beliebig Debug-Ausgaben reinbasteln kann. Ich hab das
für mich damals so gelöst, daß ich zum Debugging in der ISR mit jedem
Aufruf den Wert von TWSR und TWCR in ein Array geschrieben habe, um
hinterher in Ruhe zu analysieren, was denn da so abgegangen ist. Du
benötigtst dann den Beispielcode für TWI-Master und -Slave. Vergiss die
Pullups an SDA und SCL nicht und fang erstmal mit einer niedrigen
Übertragungsrate an. Du brauchst weiterhin zwei AVRs zum Testen: Einen
Master und einen Slave. Ich habe damals den Code für TWI-Master und
TWI-Slave aus Bequemlichkeit in einen Topf geschmissen, d.h. nur ein
Projekt im AVR-Studio und Master bzw. Slave dann über EEPROM
konfiguriert. Macht das Ganze TWI-Geraffel noch komplexer, aber du hast
eben nur ein Hexfile, was du auf die AVR flashen musst. Alternatives
Vorgehen: Du besorgst dir ein TWI- oder I2C-Teil, von dem du weißt, daß
und wie es funktioniert und bastelst auf dem AVR nur das entsprechende
Gegenstück. Forschungsintensiver und spannender ist aber alle Mal die
Aktion mit selbstgemachtem TWI-Master und -Slave. Viel Erfolg.
...ich sehe das auch schon, das kann noch was werden...
Ich wollte eigentlich nicht viel forschen, nur nutzen...
Geht das ganze denn auch ohne Interrupts? Habe hier Zeitscheiben von 1ms
und brauche keine hohen Datenraten, ich möchte nur gelegentlich ein
Steuerbyte von einem Drehencoder übertragen. Momentan zudem nur vom
Slave zum Master, naja ein ACK gibt es da ja, so wie ich verstanden
habe...
DS
Hardware ist schon fertig, mir fehlt nur noch die TWI Verbindung...
ACHTUNG GROSSER THREAD
Beitrag "Re: Zeigt her eure Kunstwerke (2)"
Steller - TWI - Steuerung - 10V - Leuchtstoffröhre
fertig i.a. fertig fertig fertig
Gruß,
DS
Wenn der Leuchtsoffröhrendimmer der Master ist, dann fragt der also
aktiv den Steller ab, welchen Wert er gerade hat? D.h. solange der
Dimmer nicht fragt, kann auch der Steller nicht antworten.
Ich würde den Steller zum Master machen, damit er sofort, wenn an ihm
gedreht wird, dem Dimmer den neuen Wert weitergeben kann, .d.h.
Steller=Master, Dimmer=Slave. Aber das nur nebenbei.
Wenn der Steller nun doch der Slave sein muss, dann spricht nichts
dagegen, den Slave-Beispielcode von Atmel zu nehmen, auch wenn er
Interruptgesteuert ist.
Die für den Steller relevante Funktion ist
1
TWI_Start_Transceiver_With_Data(&temp,1);
Diese Funktion macht den Slave "scharf", damit er antworten kann, wenn
ein Master ihn fragt.
Die immer mit dem aktuellen Stellerwert bestückt werden muss, damit der
Slave antworten kann, wenn der Master fragt, s. TWI_slave.c aus der
AppNote AVR311.
TWI-Slave ohne Interrupts halte ich für keine gute Idee, weil der Slave
dann ständig aktiv gucken muss, ob der Master was von ihm will. Genau
aus diesem Grund erfand die Evolution die Interrupts.
Mit google findest du mit sicherheit noch andere
TWI-Slave-Implementierungen, aber -egal welche- jede muss von dir an
deine spezielle Anwendung angepasst werden. Daher würde ich ruhig die
Implementierung von Atmel nehmen, die ist klein, ausreichend generisch
und die funktioniert
Hi,
ich habe soeben die Funktionen aus diesem Thread
Beitrag "AVR TWI Master und Slave Funtionen in C"
eingebunden, lief auf Anhieb. ABer schön ist was anderes denke ich.
>>weil der Slave dann ständig aktiv gucken muss...
Genau so läuft es momentan. Der Slave pollt.
>>Daher würde ich ruhig die Implementierung von Atmel nehmen
Werde ich auch ausprobieren.
>> .d.h. Steller=Master, Dimmer=Slave. Aber das nur nebenbei.
Wäre denkbar.
>>ob der Master was von ihm will
ist ok, ich versuche immer Interrupts zu vermeiden, wenn es geht. Das
meiste bekomme ich mit meinen Zeitscheiben hin.
Wie ist es denn Prinzipiell bei TWI? Damit eine Information von einem
Slave zum Master kommt, muss der Master immer anfragen, oder kann der
SLave auch aktiv werden?
Wenn ich also 127 SLaves habe, mit 127 Stellknöpfen, dann müsste ich die
ständig alle abfragen!?
Wäre es möglich das Prinzip zu ändern, und nur die Daten von den Slaves
zu übertragen die Änderungen haben um den Bus zu entlasten. Ansonsten
hätte ich eine Verlangsamung des Bussystems proportional zur Anzahl
seiner Teilnehmer...da der Master immer meht abfragen muss. Kollisionen,
Broadkast?
Danke schonmal,
DS
>Wie ist es denn Prinzipiell bei TWI? Damit eine Information von einem>Slave zum Master kommt, muss der Master immer anfragen, oder kann der>SLave auch aktiv werden?
Der Slave wird nie von alleine aktiv.
>Wenn ich also 127 SLaves habe, mit 127 Stellknöpfen, dann müsste ich die>ständig alle abfragen!?
Ja.
>Wäre es möglich das Prinzip zu ändern, und nur die Daten von den Slaves>zu übertragen die Änderungen haben
Möglich ist alles. Nur hast du dir wohl den falschen Bus
dafür ausgesucht.
>Wie ist es denn Prinzipiell bei TWI? Damit eine Information von einem>Slave zum Master kommt, muss der Master immer anfragen, oder kann der>SLave auch aktiv werden?
Nein die Rollen sind klar definiert: Wie im echten Leben darf der Slave
nur aktiv werden, wenn der Master das wünscht. Jeder Busteilnehmer kann
aber sein Verhalten jederzeit ändern und selbst den Master machen. Kann
man machen, macht aber alles noch komplizierter, weil bei mehreren
potentiellen Mastern die Master dann wieder auf verlorene
Bus-Arbitration reagieren müssen, später noch mal versuchen, usw.
Einfacher: 1 Master + viele Slaves.
>Wäre es möglich das Prinzip zu ändern, und nur die Daten von den Slaves>zu übertragen die Änderungen haben um den Bus zu entlasten. Ansonsten>hätte ich eine Verlangsamung des Bussystems proportional zur Anzahl>seiner Teilnehmer...da der Master immer meht abfragen muss. Kollisionen,> Broadcast
Wie gesagt, jeder Busteilnehmer kann den Master mimen, muss aber dann,
wenn den Kampf um den Bus verloren hat, diesen wieder freigeben und
später nochmal versuchen. Ist komplizierter zu implementieren und führt
zu Totzeiten. Einfacher: Ein Master, Rest Slaves. Vorteil: Keine
Buskollisionen und keine Totzeiten, weil nur ein Master die Spielregeln
bestimmt und der kann quasi ohne Pause alle Slaves abfragen:
Protokoll-Overhead ist auch sehr gering: Die Anfrage vom Master an einen
Slave ist man gerade 9 oder Bit lang, dh. bei 100kHz SCL dauert das
weniger als 100µs. Lass es mit der Antwort vom Slave 400µs dauern, dann
reicht das für 2500 Abfragen an einen Slave pro Sekunde. Ansonsten hast
du immer noch die Option SCL zu Lasten der max. Leitungslänge
hochzudrehen.
>>Kann man machen, macht aber alles noch komplizierter
ok, klar á la CSMA CD oder CA...
>>Ansonsten hast du immer noch die Option SCL zu Lasten der max. Leitungslänge
hochzudrehen.
da es hier nicht um einen Hausbus geht, wäre das kein Problem. Aber es
geht ja zudem auch nicht mal um eine Zeitkritische Anwenung o.ä... ist
alles Kindergarten, mir gings nur um das Prinzip...
Ich schaue gerade mal in den Code von Manni
Beitrag "Re: 2 Atmega168 per TWI verbinden"
welchen ich mal eingebaut habe, läuft auf Anhieb. Nun sehe ich das:
{
TWDR = byte;
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
}
warum macht man soetwas (while). Ich werde es also anpassen und zu einer
vernünftigen state machine machen müssen...
Wenn nun also 8 Byte gesendet werden, wartet der Controller auf jedes
Byte in dieser Schleife... das ist doch Grütze.
Was mich bei TWI auch noch interessiert. Wie läuft das prinzipiell mit
der Adresse, was ist wenn mal ein Byte flöten geht, dann verschiebt sich
doch alles und das erste Byte aus dem Datenrahmen wird zur Adresse?
Gibts einen Sync o.ä.?
Gruß,
DS
>warum macht man soetwas (while). Ich werde es also anpassen und zu einer>vernünftigen state machine machen müssen...
Ein Funktionsprinzip des dort verwendeten Code heißt: Wenn ich eine
TWI-Funktion aufrufe, dann kann ich immer davon ausgehen, daß die letzte
TWI-Aktion abgeschlossen ist.
Schreiben einer 1 ins TWINT-Bit löscht das Bit ( hat Atmel so definiert
) und die While-Schleife wartet drauf, daß die TWI-Operation fertig ist
(was durch das erneute Setzen des TWINT-Bit) signalisiert wird. Das ist
halt der Nachteil, wenn man aktiv wartet und keine Interruptgesteuerten
Routinen verwendet.
> Was mich bei TWI auch noch interessiert. Wie läuft das prinzipiell mit> der Adresse, was ist wenn mal ein Byte flöten geht, dann verschiebt sich> doch alles und das erste Byte aus dem Datenrahmen wird zur Adresse?
Atmel Manual 22.4: Es wird Aufwand betrieben um sicherzustellen, daß nur
ein Master sendet. Wenn Daten verlorengehen, dann die ganze Sequenz,
weil sich alle Teilnehmer auf die Start-Sequenz synchronisieren.
Außerdem gibt es nach jedem Byte ein ACK vom Slave. Damit weiß der
Master daß das Byte korrket angekommen ist.
Wenn dir das als Sicherheit nicht reicht, dann musst du per SW halt noch
einen Quittungsmechanismus implementierten. Kann man machen, muß man
aber nicht, solange kein Leben davon abhängt.
Referenz:
http://www.atmel.com/Images/doc2545.pdf>>wenn man aktiv wartet und keine Interruptgesteuerten Routinen verwendet.
Wenn ich die Verbindung zum Master trenne, dann steht der Slave. Das
kann ja nicht richtig sein.
Im Main ist es so implementiert:
for (i=0;i<8;i++)
{
TWIS_Write (j++);
}
TWIS_Stop ();
Wie schon geschrieben, bleibt einem nichts anderes übrig als selbst was
zu stricken.
22.5
dort ist ein Blockschaltplan, aber noch sehr grob. Ich meine ich habe
irgendwo noch mal etwas detailierteres gesehen. ALso eine Übersicht in
der man ausgangs und eingangs shift reg sieht, wenn es denn bei twi
überhaupt 2 getrennte Register gibt. Naja, da immer eine Adresse als
erstes kommt, erkennt die Arbitration bereits beim schreiben der Adresse
ob es noch weitergehen darf, richtig!? Es kommt also nie soweit das 2
Teilnehmer ob nun Master oder Slave (bei entsprechender Implementierung)
gleichzeitig Daten schreiben. Das heißt beim Daten Schreiben muss nicht
zurückgelesen werden was geschrieben wurde, wird sicher auch nicht
gemacht, oder?
Ich habe bereits oben im Artikel danach gesucht wie die Start Marke
überhaupt aussieht, ist es wirklich nur das fallen von SDA bevor SCL
fällt, und STOP wirklich nur das spätere Hochziehen von SDA oder ist es
hier das längere hoch bleiben des SCL?
TWINT Flag
muss gesetzt werden um es zurückzuseten. Ist es richtig das man
eigentlich immer über dieses Bit geht um die grundsätzliche
Kommunikation zu regeln ob nun Interruptgesteuert oder nicht?
TWEA Flag
setzt man im single Master Systemen nur beim Slave!? richtig, oder?
TWCR:TWIE
Welches Bit setzt man um den TWI Interrupt zu aktivieren, ich hätte
erwartet das dies Bit für TW Interrupt Enable steht. Ich finde die
Beschreibung im Atmel DB recht gewöhnungsbedürftig, da die Bits nicht
einzeln erklärt sind...
Bei den Atmel Beispielen ist es auch so, das dort gleich riesen
Abhandlungen, case fälle abgefangen werden und auch noch Taster
abgefragt und lampen angesteuert, das ist viel zu viel.
TWSR
gibts dazu eigentlich nur diese riesentabellen? Man sieht das Register
also immer als ganzes?
Nun stecke ich doch mitten drin...
Gruß,
DS
PS.:
Ich habe es selten gesehen das man so eine einfache Steuerung zu
kompliziert beschreibt...das geht mir allerdings mit den Atmel Timern
genauso.
Hi
>Ich finde die>Beschreibung im Atmel DB recht gewöhnungsbedürftig, da die Bits nicht>einzeln erklärt sind...
Schon mal im Datenblatt unter 22.9 Register description nachgesehen? Da
wird jedes Bit erklärt.
MfG Spess
>Gibt es bei dem TWI IF eigentlich 2 Register für "in" und "out" ->interessiert mich nur der vollständigkeit halber...
Es gibt nur ein TWDR für Lese- und Schreiboperationen.
Aber Atmel wäre nicht Atmel, wenn sie dafür nicht etwas erfunden hätten:
Das TWWC-Bit im TWCR. Hilft nicht wirklich.
>Wenn ich die Verbindung zum Master trenne, dann steht der Slave. Das>kann ja nicht richtig sein.
Bist du sicher? Eigentlich sollte in jedem Fall nach 9 Bits ein Status
mit gesetztem TWINT-Bit zurückgegeben werden, enweder mit Fehlerstatus
oder auch nicht.
>Wie schon geschrieben, bleibt einem nichts anderes übrig als selbst was>zu stricken.
Das sind genau die 20% Progammcode, die 80% der Zeit fressen und aus
einem Showcase eine (fast) fehlerfreie und robuste Anwendung machen.
>Das heißt beim Daten Schreiben muss nicht zurückgelesen werden was>geschrieben wurde, wird sicher auch nicht gemacht, oder?
Nein
>Ich habe bereits oben im Artikel danach gesucht wie die Start Marke>überhaupt aussieht, ist es wirklich nur das fallen von SDA bevor SCL>fällt, und STOP wirklich nur das spätere Hochziehen von SDA oder ist es>hier das längere hoch bleiben des SCL?
s. 22.3.2 : Start und Stop sind entsprechende Flnakenwechsel von SDA bei
SCL=High. Musst du dich aber nicht drum kümmern, das macht die
TWI-Hardware.
>>TWWC-Bit ok, wird gesetzt wenn man ins register schreibt wenn TWINT low ist...>>Bist du sicher?
kommt vor, ist ja auch klar, ich habe ja das Beispiel von Manni ohne
Interrups am Haken, nun wenn ich zufällig trenne während der Slave auf
eine Anfrage vom Master antwortet, befindet er sich in der While
Schleife die so lange läuft wie das TWINT nicht gesetzt ist, oder? Wenn
aber der Masterclock fehlt kommt der Slave nie dazu das das TWINT
gesetzt wird, da er seine Restbits nicht los wird...oder!?
*******************************************************/
void TWIS_Write (uint8_t byte)
{
TWDR = byte;
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
}
>>eine (fast) fehlerfreie und robuste Anwendung machen
YES! so ists wohl. Ich würde ja gerne zumindest sicherstellen das die
Kommunikation auf jeden Fall wieder anläuft wenn man sie wieder
verbindet (Master - Slave) habe ja nicht mehr.
Ich bin gerade im Slave am Umstricken und hier angekommen:
uint8_t TWIS_ReadAck (void)
uint8_t TWIS_ReadNack (void)
/*******************************************************
Public Function: TWIS_ReadAck
Purpose: Read a byte from the master and request next byte
Input Parameter: None
Return Value: uint8_t
- uint8_t Read byte
*******************************************************/
uint8_t TWIS_ReadAck (void)
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
return TWDR;
}
/*******************************************************
Public Function: TWIS_ReadNack
Purpose: Read the last byte from the master
Input Parameter: None
Return Value: uint8_t
- uint8_t Read byte
*******************************************************/
uint8_t TWIS_ReadNack (void)
{
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
return TWDR;
}
A)ReadNack wird aufgerufen wenn das letzte Byte einer Übertragung vom
Master zum Slave gesendet wird, es gibt nur einen unterschied:
TWEA wird nicht gesetzt. Also wird das letzte Byte vom Slave nicht
quittiert!? Ist das richig?
B)Es steht zudem nirgens geschrieben das man es für jedes empfangene
Byte erneut setzen muss, oder? Das ist doch nur ein Schalter wie TWEN
auch. Die muss man doch nicht bei jedem Byte neu einschalten...oder
verstehe ich das falsch? 22.9.2
So ist der Aufruf im Main:
case TWIS_ReadBytes:
for (i=0;i<1;i++)
{
byte[i] = TWIS_ReadAck ();
}
byte[1] = TWIS_ReadNack ();
TWIS_Stop ();
break;
Vielen viele Dank bis hierher.
DS
DS schrieb:
> TWEA wird nicht gesetzt. Also wird das letzte Byte vom Slave nicht> quittiert!? Ist das richig?>> B)Es steht zudem nirgens geschrieben das man es für jedes empfangene> Byte erneut setzen muss, oder? Das ist doch nur ein Schalter wie TWEN> auch. Die muss man doch nicht bei jedem Byte neu einschalten...oder> verstehe ich das falsch? 22.9.2
Dieses ACK musst du eher als "Bereit für nächstes Byte" interpretieren.
D.h. Solange ein Teilnehmer mit ACK bestätigt heißt das "ich kann weiter
Senden/Empfangen" oder anders rum: NACK heißt: Ich kann nicht mehr
empfangen/ich will nicht weiter senden. Im Falle eines NACK muss der
andere Teilnehmer auch seine Sendung/Empfang einstellen und den Bus
freigeben. Also wenn du soll willst, ist TWEA das Flag für
"weitermachen"
Google mal nach I2C Specification, da wird das besser erklärt als im
Atmel-Manual.
Hi,
danke für die Hinweise. Das muss ich dann ggf mal machen.
Ich habe meine Datenstrecke nun eigentlich fast komplett. Ich habe zur
Zeit das Problem das ich bei meiner bidirektionalen Datenstrecke nach
dem Programmstart ein Problem mit der Übertragung vom Master zum Slave
bekomme.
Zur zeit habe ich das so angelegt, das es alle 500ms eine Aktion auf dem
Bus gibt. Der Master fragt abwechselnd lesen und schreiben beim Slave an
- eigentlich nichts wildes. Die Übertragung vom Slave zum Master, also
wenn der Master lesend anfragt funktioniert tadellos.
Der andere Weg geht nur 1x dann kommt der Master Write immer mit einer
0x28 zurück am ende der Übertragung. Es geht nur 1x wenn zuvor kein
Master Read war ich also das Programm mit einem Master Write starten
lasse.
Sobald 1x ein Master Read war, geht das Master write nicht mehr. Wenn
ich das Master Read ganz weg lasse dann geht das Master write tadellos,
wie das Master read das eh immer geht...
nun heißt 0x28 nach dem letzten Master Write byte:
#define TWI_MTX_DATA_ACK 0x28 // Data byte has been tramsmitted
and ACK received
#define TWI_MTX_DATA_NACK 0x30 // Data byte has been tramsmitted
and NACK received
das ein ACK vom Slave kam. Wenn ich das Master Read weg lasse, kommt er
mit 0x28 zurück und die Strecke läuft wie gesagt....
Ich stecke in der Klemme...
DS