Forum: Projekte & Code TWI / I2C einf. MASTER SLAVE Beispiel(Assembler) ATmega8


von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Ein einfaches Beispiel für einen TWI / I2C Master und Slave.

Es werden 2 Daten-Bytes an den Slave gesendet und anschließend zwei
Daten-Bytes vom Slave empfangen.

Es ist kein fertiges Projekt, aber es hilft hoffentlich,
die Grundmechanismen schneller zu erkennen.

z.B: - Initialisierung
     - Adressvergabe
     - Interrupt-Handling
     - mögliche Error-Routinen
     - TWSR / TWCR - Auswertung

Die LEDs vom MASTER zeigen den Zustand der Datenübertragung
(z.B. erfolgreicher START) an und
die LEDs vom SLAVE, welcher TWSR Zustand anliegt, wenn der
TWI-Interrupt aufgerufen wird.

Absichtlich habe ich alle Vorgänge stark durch Warteschleifen und eine
sehr niedrige SCL Frequenz gebremst, damit man besser nachvollziehen
kann, wann was und wo passiert.


Bernhard

von Thorran M. (kleineronkel)


Lesenswert?

Hallo,
finde ich echt ne super sache das du das mal online gestellt hast,
werde es sofort mal ausprobieren.

Eine Frage hätte ich jedoch noch mit was für einem programm hast du den
Plan gezeichnet?

von Bernhard S. (bernhard)


Lesenswert?

@Thorran Microlovic

>finde ich echt ne super sache das du das mal online gestellt hast,

Danke, ich hoffe, dass dieses kleine Beispiel bei den Grundlagen etwas
weiter hilft.

>mit was für einem programm hast du den Plan gezeichnet?

mit sPLAN 4.0, ist ein sehr einfaches und leicht zu bedienendes
Programm mit vielen interessanten Spezialfunktionen.

von Mareike (Gast)


Lesenswert?

Hey super !
Danke das du das Programm online gestellt hast.
Möchte das selbe Programm in C-realisieren ! Nun habe ich von Assembler
nicht so den Plan! Kann mir jemanden einen Tipp geben?

von Uwe O. (schwede)


Lesenswert?

Hallo..
ich bin begeistert - genau das habe ich schon lange gesucht.
Jetzt habe ich begonnen, das ganze für mein eigenes Programm
abzuändern, und bin da auf ein Problem gestossen.
Es gibt da 2 Sachen die ich nicht verstehe. Das ist die Abfrage des
TW_INT_FLAG. WANN und von WEM wird es gesetzt oder gelöscht?
Die andere Sache ist der Check des Status-Registers (TWSR) - dieses
Register hat sehr unterschiedliche Werte. Ich möchte gern wissen, wie
sich die einzelnen Werte zusammensetzen? Also der Wert im Register
addiert mit 0xF8 ergibt einmal 0x08 oder 0x18 oder 0x40 usw.
Könnte man das mal zum besseren Verständnis in einer Tabelle
darstellen?

Gruss Uwe

von Bernhard S. (bernhard)


Lesenswert?

@Uwe Ortmann (Schwede)

>Das ist die Abfrage des TW_INT_FLAG.
>WANN und von WEM wird es gesetzt oder gelöscht?

Gesetzt wird es, ganz allgemein ausgedrückt, wenn ein Ereignis am TWI
registriert wird.
z.B.

-eine bestimmte Aktion (zB. Start) durchgeführt wurde
-wenn ein Slave von einem Master angesprochen wird
-ein Zeichen vom Master gesendet wurde
-ein "Error" auftrat


Gelöscht wird es, in dem es auf "1" gesetzt wird


>Die andere Sache ist der Check des Status-Registers (TWSR) - dieses
>Register hat sehr unterschiedliche Werte. Ich möchte gern wissen, wie
>sich die einzelnen Werte zusammensetzen? Also der Wert im Register
>addiert mit 0xF8 ergibt einmal 0x08 oder 0x18 oder 0x40 usw.

Der Wert des Registers wird nicht mit 0xF8 addiert, sondern die
untersten 3Bit auf 0 gesetzt (2xVorteiler und 1xReserviertes-Bit), sie
werden sozusagen ausgeblendet.

Die Werte und die Bedeutungen findest Du ab Seite 177 im Datenblatt.

Anmekung: Für viele Anwendungen empfielt es sich, wenn man nach einem
INT-Flag-Interrupt prüft, warum dieses INT-Flag gesetzt wurde.

Ich hoffe, ich habe Dir etwas weiter helfen können?

Demnächst werde ich hier ein sehr interessantes "RS232-TWI-Interface"

veröffentlichen, dort sind die einzelnen Funktionen detaillierter
angewendet worden.

Gruß

Bernhard

von Bernhard S. (bernhard)


Lesenswert?


von Uwe O. (schwede)


Lesenswert?

Hallo...
erstmal Danke für die Tipps, haben mir sehr viel geholfen. Allerdings
machen mir noch 2 Sachen "Kopfschmerzen".
Ein kleines Problem:
Ich takte meinen mega8 mit 16MHz - das macht dann pro Zyklus 60 ns. Wie
baut man am besten eine Zählschleife auf, um eine Pause von 6 ms zu
bekommen?
Das grössere Problem:
Ich möchte einen externen Interrupt an Int0 auswerten (also ein
Unterprogramm starten). Ich bekomme das einfach nicht hin. Könnte ich
ein wenig Hilfe bekommen?

Gruss  Uwe

von Bernhard S. (bernhard)


Lesenswert?

@UWE

>Wie baut man am besten eine Zählschleife auf, um eine Pause von 6 ms
>zu bekommen?

Du hast es schon richtig formuliert, mit einer Zählschleife,
bei 16MHz Takt vergehen 0.0625µs pro Takt, d.h.
Du müsstest den µC mit 96.000 Takten mit sich selbst beschäftigen, um
eine Pause von 6ms zu erzeugen.

Schau mal bitte nach unter:
http://www.mikrocontroller.net/forum/read-4-57760.html#


>Ich möchte einen externen Interrupt an Int0 auswerten (also ein
>Unterprogramm starten).

Vor langer Zeit habe ich hier mal einen kleinen Beitrag dazu
geschrieben:

http://www.mikrocontroller.net/forum/read-4-156657.html

Vielleicht hilft es Dir etwas weiter?

Bernhard

von Uwe O. (schwede)


Lesenswert?

Hallo...
nachträglich noch vielen Dank, hat mir weitergeholfen.

Bei einer Sache muss ich allerdings noch mal nachfragen, damit ich da
nichts falsch verstehe.
Im Programm ganz oben ist der Vorteiler für das TWI mit 0, 4, 16 und 64
angegeben. Ist die 64 der grösst mögliche Teilungsfaktor?
Denn wenn ich meinen Mega8 mit vollen 16MHz takte dann hätte ich auf
dem TWI noch 250 KHz - also deutlich zu viel. Da wäre es wohl besser
ich takte den Controller mit 1MHz. Da komme ich auf ca. 15KHz, was für
eine längere Busleitung von Vorteil ist.

Habe ich das so richtig verstanden?

Gruss Uwe

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@UWE

>Ist die 64 der grösst mögliche Teilungsfaktor?
>Da wäre es wohl besser ich takte den Controller mit 1MHz


Ja das ist er und zusätzlich kannst Du auch die Bitrate ändern, um die
SCL-Frequenz zu verändern,
aber sie sollte größer als 11 sein, da es ansonsten zu Problemen bei
der Busverbindung kommen kann.


Ich stell Euch mal eine Excel-Tabelle zur Verfügung, womit man die
SCL-Frequenz berechnen kann.

Bernhard

von Ingo (Gast)


Lesenswert?

Hallo,

kämpfe gerade mit TWI und bin dan hierauf gestoßen.
Da ist mir was aufgefallen: Die Berechnung der TWI-Bitrate
funktioniert
laut Atmel-Datenblättern so:
                    CPU Clock frequency
  SCL frequency = ----------------------------

                    16 + 2(TWBR) x 4 ^ TWPS
In dem Excel-Sheet steht aber:
  =Fcpu/(16+(2*TWBR)*TWPS)
Also, wenn ich die Frequenz für zwei gleich hoch getaktete Controller
berechne wird das vielleicht gehen, aber bei verschiedenen Frequenzen?
Oder übersehe ich was ganz entscheidendes?

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@Ingo


>In dem Excel-Sheet steht aber:
>  =Fcpu/(16+(2*TWBR)*TWPS)
>Also, wenn ich die Frequenz für zwei gleich hoch getaktete Controller
>berechne wird das vielleicht gehen, aber bei verschiedenen
>Frequenzen? Oder übersehe ich was ganz entscheidendes?

Du hast Recht, hab's auch gerade gesehen.

In der euen Excel-Tabelle habe ich meinen Berechnungs-Fehler behoben.

Danke für den Hinweis.

Bernhard

von Bernhard S. (bernhard)


Lesenswert?

@Mareike

>Möchte das selbe Programm in C-realisieren ! Nun habe ich von
>Assembler nicht so den Plan! Kann mir jemanden einen Tipp geben?

...wo drückt denn der Schuh ?

von Läubi (Gast)


Lesenswert?

Hätte da eine Frage:

Aus der Slave.asm:
"TWSI_TW_SR_DATA_ACK:          ; x80  10000000 (die vorher adressierten
(SLA+W) Daten wurden empfangen;  ACK wurde zurückgesendet
  cbi PORTB,4
  in DATA, TWDR  ; DATA
  rjmp TWSI_w"

Ich will über TWI dem Slave einfach Daten zusenden.
Seh ich das recht das ich an obiger Stelle die Empfangenen Datennn
auswerten kann?
Also sagen wir mal ich sende vom Master 0xFA an den Slave, und an der
stelle wird dies empfangen?

Und kann ich dann einfach alle LED ausgaben Auskommentieren oder ist
noch mher nötig? Der Slave braucht auch nichts zurückzusenden, soll nur
Daten empfangen.

von Bernhard S. (bernhard)


Lesenswert?

@Läubi

>Ich will über TWI dem Slave einfach Daten zusenden.
>Seh ich das recht das ich an obiger Stelle die Empfangenen Datennn
>auswerten kann?
>Also sagen wir mal ich sende vom Master 0xFA an den Slave, und an der
>stelle wird dies empfangen?

Ja das ist korrekt, das empfangene Byte vom Master liegt nun im
"DATA" zur weiteren Verarbeitung bereit


>Und kann ich dann einfach alle LED ausgaben Auskommentieren oder ist
>noch mher nötig? Der Slave braucht auch nichts zurückzusenden, soll
>nur Daten empfangen.


Die LEDs müssen nicht unbedingt sein, sie dienen nur dazu, zu zeigen,
welchen Wert gerade das "TWSR" - Register gehabt hat.

Bernhard

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!
Ich weiß dass ich einen ziemlich alten, aber nützlichen Beitrag hier 
entstaube.
Ich habe dazu mal eine Frage:
Ich brauche für einen Aufbau den I2C Bus. Ich habe mir mal dieses 
Beispiel heruntergeladen und ausprobiert. Es funktioniert, nur eben sehr 
langsam (ist ja auch oben gesagt).
Also habe ich mir gedacht: Unnötige Wait-Befehele wegfallen lassen und 
die Prescaler und Bitrate-Werte so einrichten, dass die Übertragung 
recht schnell gehen müsste.
Anhand der LEDs in den I2C-Leitungen kann man erkennen, dass die 
Datenübertragung recht schnell läuft (nur ganz kurzes aufblinken). 
Dennoch ist nach der Übertragung noch eine recht lange Pause, ehe die 
nächste Übertragung (neues Aufblinken) stattfindet. Hat jemand eine 
Idee, woran das liegen könnte?

Vielen Dank schonmal für eure Hilfe!

von Bernhard S. (bernhard)


Lesenswert?

Hallo Martin,


>Dennoch ist nach der Übertragung noch eine recht lange Pause

Ich vermute, dass noch irgendwo ein rcall wait_xxx sein unwesen treibt.

Entferne doch mal spaßenshalber komplett die wait Routinen ?

Gruß

Bernhard

von Martin (Gast)


Lesenswert?

Gesagt...getan...und eine äußerst verblüffende Antwort:

Es gab in der Master-datei 2 wait-Zugriffe:
- der erste nach der Initialisierung, den hatte ich vorher da gelassen 
weil der ja nur einmal durchlaufen wird und nicht stört.
- der zweite im Abschnitt "TWI_ERROR". Das verwundert mich sehr, weil 
ich daraus schließe, dass nach jeder Übertraung anscheinend auch ein 
Fehler auftritt. Darf das sein?
Ich meine es läuft jetzt schnell, also so wie gewünscht, aber es ist 
doch irgendwie ein komisches Gefühl zu wissen dass da immer ein Fehler 
drin ist. Oder ist das normal so?

von Bernhard S. (bernhard)


Lesenswert?

>dass nach jeder Übertraung anscheinend auch ein Fehler auftritt. Darf das >sein ?

Nein, das darf natürlich nicht sein.

Also, Ursache suchen.

Vielleicht SCL-Takt zu hoch? Adresse falsch? usw...

Vielleicht gibts im Slave noch ein wait, so das das Antwort-Bit nicht 
bereitgestellt wird?

von Martin (Gast)


Lesenswert?

Hm da habe ich sicher was zu suchen, weil ich im Grunde genommen deine 
möglichen Fehlerquellen ausschließen kann:
SCL-Takt: Habe mit Bitrate 255 und Prescaler 64 bis zu Bitrate 11 und 
Prescaler 1 allerlei Tests gemacht, also bei 255/64 kann er ja nicht 
mehr zu hoch sein^^.
Adresse kann nicht falsch sein, da der IC dann ja gar nicht angesprochen 
würde. Anhand von LEDs erkennt man ja dass er angesprochen wird, nur 
eben auch dass er wegen der langen Pause die Fehler-Routine aufruft.
Im Slave ist kein Wait mehr vorhanden.

Nunja ein Glück geht es ja schonmal jetzt sehr schnell - wofür ich sehr 
dankbar bin - der Fehler wird sich wohl im Laufe der Zeit und mit einer 
noch genaueren Vertiefung in den Bus hoffentlich finden.

von Xine (Gast)


Lesenswert?

Hallo alle zusammen,

ich bin gerade auf der Suche nach I2C-Beiträgen auf diesen Artikel 
gestoßen.

Oben ist dieses klasse Assembler-Programm gepostet. Leider habe ich von 
Assembler fast gar keine Ahnung und beschäftige mich gerade mit C für 
eine einfache Sende-Empfangs-Routine zwischen zwei AVR.

Das Ding läuft leider noch nicht und langsam gehen mir die Ideen aus.

1. Frage: Hat schon einmal jemand den i2c.h Header in CodeVisionAVR 
benutzt? Nachdem mein selbst geschriebenes Programm Probleme macht, 
dachte ich versuche ich den mal zu verwenden. Hat da jemand zufällig ein 
kurzes Codebeispiel? Bei mir hakt es nämlich noch, der Slave versteht 
aus irgendeinem Grund nicht, dass er angesprochen wird...

2. Frage: Existiert ein diesem Assembler-Programm ähnliches C-Programm? 
Für eine C-Anfängerin wie mich wäre das nämlich echt hilfreich, da es 
ewig dauert, bis man ein laufendes Programm gebastelt bekommt (mit 
Datasheets, Atmel-Beispielen für andere Anwendungen, etc.)...

Danke und viele Grüße!!!

Xine.

von TechInfo (Gast)


Lesenswert?

Hi Xine,

beschäftige mich auch grade mit TWI/I2C in C. Habe es mit der Procyon 
avrlib zum Laufen bekommen (Tastatur und Display).

Schick mir doch mal genauere Angaben - welche Slaves willst du 
ansteuern, wie ist dein Aufbau, etc.

Ich kann Dir dann meine Codebeispiele schicken.

seventh_son@gmx.de

von Siem (Gast)


Lesenswert?

Ich suche im Forum seit Stunden nach so einem Beispiel in C ( =>negativ 
:-( )
Hat jemand vielleicht das Beispiel hier in C übersetzt? Kann jemand 
ähnliches Beispiel in C geben?

Gruß
Siem

von Matt M. (mtbmatt)


Lesenswert?

@siem: was suchst DU denn genau?

von Manni (Gast)


Lesenswert?

@siem:
Ich habe heute sowas hier in Codesammlung gestellt.

Gruss
Manni

von Hendrik B. (kirvandax)


Lesenswert?

Hallo.

Ich beschäftige mich erst seit ein paar Tagen mit Microcontrollern und 
bin bei der Suche nach Hilfe zur TWI Schnittstelle in diesem Thread 
fündig geworden. Erste Versuche haben mit dem (gering modifizierten) 
Code auch schon geklappt (nur Daten senden an einen PCF8575 I/O 
Extender).

Nun wollte ich den den Code etwas aufräumen und in handliche 
Unterprogramme
zerlegen und bin dabei über zwei Stellen gestolpert.

1. Warum wird beim Senden der Stardbedingung für den Receiver Teil das 
TWEA Bit gesetzt? Wenn ich das richtig verstanden habe wird dadurch doch 
ein ACK ausgeführt, was an der stelle eigentlich gar nicht passieren 
sollte. Die Startbedingung sollte doch bei MR und MT Teil identisch 
sein, oder nicht?

2. Ich habe in den Beiträgen weiter oben etwas über multiple 
Fehlermeldungen bei der Kommunikation gelesen.
Diesbezüglich hätte ich eine Vermutung.
Angenommen der Slave antwortet nicht, weil z.B. die Adresse falsch ist, 
dann würde, weil kein ACK kommt der Errorhandler ausgeführt. Dieser 
stoppt
und initialisiert das TWI neu. Springt dann aber wieder in die 
abgebrochene Kommunikation zurück:

TWI_ERROR:
....

; TWI INITIALISIERUNG
   rcall TWI_INI
  rcall wait_1s
  sbi PORTD,0
ret   <<< Diesen Rücksprung meine ich

Als nächstes sollen Daten empfangen/gesendet werden , dabei fehlen Start 
und SLA+R, also gibt es wieder eine Fehlermeldung. Solange bis der Code 
mit dem STOP durch ist und wieder von vorne anfängt.

So zumindest verstehe ich den Code.

Kann das jemand bestätigen bzw. mir das TWEA Bit erklären?
Danke im Voraus.

MfG
 Hendrik

von Name (Gast)


Lesenswert?

>Kann das jemand bestätigen bzw. mir das TWEA Bit erklären?

Ich lese Quelltexte von dieser Website nie, weil sie sehr oft fehlerhaft 
sind und totalen Schwachfug enthalten, aber den zweiten Wunsch kann ich 
dir erfüllen:

TWEA sorgt dafür, dass beim nächsten TWINT eines Empfangs auch direkt 
ein ACK gesendet wird, ergo ist es die "Empfangsbestätigung" über TWI.

von Alex M. (Gast)


Lesenswert?

Hallo Bernhard Schulz,
möchte mich bei dir für das einwandfreie Beispiel bedanken!!!

Ständig erhielt ich nach SLA+R  --  NACK($48), erst nachdem ich das 
Programm vom Mega 16 zu Mega 8 portierte ist dieser Fehler verschwunden. 
Etweder hat mein Mega 16 einen TWI- Bug oder alle M16 sind 
verbuggt(keine Ahnung).
Dann konnte ich keine Daten auslesen erst mit deiner MR_LeseRoutine ist 
es mir gelungen Daten aus’m DS1307 auszulesen, was für ein tolles Gefühl 
:-)
Davor habe ich mich 3 Tage mit TWI rumgeplagt.

Nochmals vielen Dank !

Mit freundlichen Grüßen
gtf

von Flo S. (agemta)


Angehängte Dateien:

Lesenswert?

hey.. ich plage mich jetzt schon fast eine Woche mit TWI rum. Ich hab 
genau das Beispiel aufgebaut. 2 ATMega8 mit Leds am PORTB usw. Das 
einzige was ich geändert habe ist, das ich vom Master aus nur 1 Bit 
sende und der Slave es empfangen soll. Außerdem habe ich das ganze in C 
gemacht. Trotzdem ist vom Aufbau alles gleich.
Mein Problem:
Adresse wird gesendet und Master erhält ACK.
Danach sendet er aber keine Daten sondern macht sofort Stop.
ich poste auch mal meine Programme.
Vllt findet jemand auf die schnelle ein Fehler?

von Manni (Gast)


Lesenswert?

Versuch's mal mit meinen Routinen, die bei mir seit langer Zeit absolut 
stabil laufen.

[[Beitrag "AVR TWI Master und Slave Funtionen in C"]]

Gruss
Manni

von Flo S. (agemta)


Lesenswert?

Ich hab die Routinen ausprobiert. und siehe da.. es klappt! Frag  mich 
aber trotzdem was mit meinen nicht stimmte?

von Manni (Gast)


Lesenswert?

Und schon wieder einen Baster zufrieden gestellt, ja das freut doch auch 
mich :-)

Gruß
Manni

von Obermayer F. (Firma: tbd) (foikei)


Lesenswert?

Hallo zusammen,

ich werd hier noch wahnsinnig. Ich kapier die Funktion des TWINT-Flags 
einfach nicht, drum wollte ich mal vorsichtig nachfragen, ob mir einer 
helfen kann (obwohl der Beitrag schon etwas älter ist).

In dem Beispiel von Bernhard S. heißt es in der MASTER.ASM unter 
TWI-MASTER-RECEIVER:
1
TWI_MASTER_RECEIVER:
2
; LEDs aus                      
3
  ldi temp,255
4
  out PORTB,temp
5
; START                       
6
  ldi temp, (1<<TWINT | 1<<TWEA | 1<<TWSTA | 1<<TWEN )
7
  out TWCR, temp  
8
; warten, bis TWINT wieder = 1            
9
  rcall TWI_TWINT_wait
10
  cbi PORTB,0

LED's aus is noch ok, aber dann:
ins 'temp'-Register kommt bei TWINT ne "1" rein, und geb das ganze ins 
TWCR aus. Und dann warte ich, bis TWINT wieder "1"??? Es wurde doch grad 
ne 1 reingeschoben, also steht da auch gleich ne 1 drin, oder? Oder wird 
das TWINT-Flag dann sofort auf 0 gezogen und kommt erst wieder auf 1, 
wenn die Aktion fertig ist?

Wär echt nett, wenn mich einer auf den richtigen Weg leitet...
Danke euch!

mfg
Foikei

P.S.: wenn mein 30-Kanal-Temperatur-Logger fertig ist, stelle ich ihn 
euch vor...wenn ich es denn schaffe, das TWI zu kapieren ;-)

von MWS (Gast)


Lesenswert?

Es gibt einige Flags bei den Atmels, die gelöscht werden, indem man sie 
auf "1" setzt.

> Oder wird das TWINT-Flag dann sofort auf 0 gezogen und kommt erst wieder > auf 
1, wenn die Aktion fertig ist?

Yep, durch Schreiben von 1 in TWINT wird es auf 0 gesetzt.

von Axel K. (axel)


Angehängte Dateien:

Lesenswert?

Habe mir vorgestern nen Layout nach dem Schaltplan gemacht)

von Axel K. (axel)


Angehängte Dateien:

Lesenswert?

...........................

von Axel K. (axel)


Angehängte Dateien:

Lesenswert?

Hmpf garnicht bemerkt, das die LEDs garnicht in der Reihenfolge sind - 
aber ist wiegesagt auf die Schnelle geschehen..

Anbei der Assembler Code von Bernhard von der 1. Seite 1zu1 in C 
uebersetzt.

gruss

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.