Forum: Mikrocontroller und Digitale Elektronik 2 Atmega168 per TWI verbinden


von DS (Gast)


Lesenswert?

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

von Spess53 (Gast)


Lesenswert?

Hi

>In den AN steht etwas von c-libs für Slave und Master. Doch wo bekomme
>ich diese her?

ATMEL WEbseite.

http://www.atmel.com/products/microcontrollers/avr/megaavr.aspx?tab=documents

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?


von Christoph H. (christoph_b)


Lesenswert?


von DS (Gast)


Lesenswert?

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

von katastrophenheinz (Gast)


Lesenswert?

> 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.

von DS (Gast)


Lesenswert?

...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

von DS (Gast)


Lesenswert?

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

von katastrophenheinz (Gast)


Lesenswert?

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

von DS (Gast)


Lesenswert?

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

von holger (Gast)


Lesenswert?

>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.

von katastrophenheinz (Gast)


Lesenswert?

>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.

von DS (Gast)


Lesenswert?

>>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

von DS (Gast)


Lesenswert?

ok, Adresse sitzt in TWAR...trotzdem hatte ich schon mal den Zustand das 
Master und Slave nicht zusammengefunden haben... warum auch immer...

von katastrophenheinz (Gast)


Lesenswert?

1
{
2
  TWDR = byte;
3
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
4
  while (!(TWCR & (1<<TWINT)));
5
}
>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.

von DS (Gast)


Lesenswert?

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.

von Spess53 (Gast)


Lesenswert?

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

von DS (Gast)


Lesenswert?

danke.

DS

von DS (Gast)


Lesenswert?

das bringt Klarheit...

Gibt es bei dem TWI IF eigentlich 2 Register für "in" und "out" - 
interessiert mich nur der vollständigkeit halber...

DS

von katastrophenheinz (Gast)


Lesenswert?

>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.

von DS (Gast)


Lesenswert?

>>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

von HerrHase (Gast)


Lesenswert?

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.

von DS (Gast)


Lesenswert?

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

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.