Forum: Mikrocontroller und Digitale Elektronik TWI mit zwei ATmega8 funktioniert nicht :-(


von Paul H. (powl)


Lesenswert?

Hi :-)

Ich bin gerade dabei einen kleinen Test mit dem I²C-Bus zur Einarbeitung 
durchzuführen. Leider klappt das nicht so wie ich mir dachte. Der Slave 
will einfach nicht hören.

bei Master und Slave habe ich einfach SDA und SCL miteinander verbunden 
und jeweils über einen Pull-Up Widerstand von 4,7kOhm nach Vcc gelegt.

Am Master hängen 4 unterschiedlichfarbige Status-LEDs an PortB 0-3 und 
eine dicke rote Error-LED an PortB 4. Ausserdem ein hardwareentprellter 
Taster an PinD 2 (INT0) welcher bei fallender Flanke den Interrupt 
auslöst um mein Programm auszuführen.

Am Slave hängen am PortD 0-7 insgesamt 8 gelbe LEDs nebeneinander. So 
kann ich  einen 8-Bit-Wert schön parallel ausgeben.

Das Testprogramm soll erstmal einen 8-Bit Wert an den Slave schicken der 
diesen dann an seinem PortD ausgibt und anschließend hochzählen. Soweit 
bin ich jedoch noch garnicht gekommen da der Slave nichtmal den 
Interrupt auszulösen scheint. Irgendwie tut er überhaupt nichts und ist 
taub. Habe ich im Code vielleicht irgendwas vergessen? Der Master erhält 
nach dem Senden der Slave-Adresse ein NOT ACK bzw eben kein ACK vom 
Slave worauf sich schließen lässt dass sich dieser nicht angesprochen 
fühlt. Die ersten beiden Status-LEDs und die Error-LED an meinem Master 
leuchten. Am Slave tut sich nichts..

Master:
1
.include "m8def.inc"        ; Deklarationen für ATmega8
2
3
.cseg                ; Programm-Flash
4
    rjmp  init        ; Reset-Einsprung
5
6
.org  0x001            ; INT0 Interrupt
7
    rjmp  send
8
9
.org  0x013            ; Interrupteinsprünge übergehen
10
11
12
init:  ldi    R16, LOW(RAMEND)  ; Stapel anlegen
13
    out    SPL, R16
14
    ldi    R16, HIGH(RAMEND)
15
    out    SPH, R16
16
17
18
    ; INT0 Interrupt
19
    ldi    R16, (1 << ISC01)  ; Fallende Flanke an INT0 generiert Interrupt
20
    out    MCUCR, R16
21
22
    ldi    R16, (1 << INT0)  ; INT0 Interrupt aktiviern
23
    out    GICR, R16
24
25
26
    ; Two-Wire-Interface
27
    ldi    R16, 10        ; Bitratenfaktor für 10kHz Bustakt bei 1Mhz
28
    out    TWBR, R16
29
30
31
    ; Status LED Ausgang
32
    ldi    R16, 0b00011111    ; PB0-3 als Ausgang
33
    out    DDRB, R16
34
35
    sei              ; Interrupts aktivieren
36
37
    clr    R17          ; Zu benutzende Register leeren
38
39
40
loop:  rjmp  loop        ; Endlosschleife
41
42
43
44
send:  ; Start Condition senden
45
    ldi    R16, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN)
46
    out    TWCR, R16
47
48
    ; Warten bis ausgeführt
49
send1:  in    R16, TWCR
50
    sbrs  R16, TWINT
51
    rjmp  send1
52
53
    sbi    PORTB, 0      ; Rote Status-LED an
54
55
    in    R16, TWSR      ; TWI-Statusregister checken
56
    cpi    R16, 0x08      ; Code 0x08 = A START condition has been transmitted
57
    brne  error        ; Springe zu error wenn ungleich
58
59
60
    ; 7-Bit Slave Adresse + R/W senden (R=High, W=Low)
61
    ldi    R16, (0b1111111 << 1) | (0 << 1)
62
    out    TWDR, R16
63
64
    ; Daten senden
65
    ldi    R16, (1 << TWINT) | (1 << TWEN)
66
    out    TWCR, R16
67
68
    ; Warten bis ausgeführt
69
send2:  in    R16, TWCR
70
    sbrs  R16, TWINT
71
    rjmp  send2
72
73
    sbi    PORTB, 1      ; Grüne Status-LED an
74
75
    in    R16, TWSR      ; TWI-Statusregister checken
76
    cpi    R16, 0x18      ; Code 0x18 = SLA+W has been transmitted; ACK has been received
77
    brne  error        ; Springe zu error wenn ungleich
78
79
80
81
    ; Zählerdaten senden
82
    out    TWDR, R17      ; Zählerdaten ins Ausgangsregister laden
83
    inc    R17          ; Zähler inkrementieren
84
85
    ; Daten senden
86
    ldi    R16, (1 << TWINT) | (1 << TWEN)
87
    out    TWCR, R16
88
89
    ; Warten bis ausgeführt
90
send3:  in    R16, TWCR
91
    sbrs  R16, TWINT
92
    rjmp  send3
93
94
    sbi    PORTB, 2      ; Gelbe Status-LED an
95
96
97
98
    ; Stop Condition senden
99
    ldi    R16, (1 << TWINT) | (1 << TWSTO) | (1 << TWEN)
100
    out    TWCR, R16
101
102
    ; Warten bis ausgeführt
103
send4:  in    R16, TWCR
104
    sbrs  R16, TWINT
105
    rjmp  send4
106
107
    sbi    PORTB, 3      ; Blaue Status-LED an
108
109
    reti
110
111
112
113
error:  sbi    PORTB, 4      ; Rote Error-LED an
114
    rjmp  error

Slave:
1
.include "m8def.inc"        ; Deklarationen für ATmega8
2
3
.equ  adress = 0b1111111      ; TWI-Adresse
4
5
.cseg                ; Programm-Flash
6
    rjmp  init        ; Reset-Einsprung
7
8
.org  0x011
9
    rjmp  rec          ; TWI Interrupt
10
11
.org  0x013            ; Interrupteinsprünge übergehen
12
13
14
init:  ldi    R16, LOW(RAMEND)  ; Stapel anlegen
15
    out    SPL, R16
16
    ldi    R16, HIGH(RAMEND)
17
    out    SPH, R16
18
19
20
    ; TWI und Interrupt aktivieren
21
    ldi    R16, (1 << TWEN) | (1 << TWIE)
22
    out    TWCR, R16
23
24
    ; Slave Adresse 0001111 + TWGCE
25
    ldi    R16, (adress << 1) | (1 << TWGCE)
26
    out    TWAR, R16
27
  
28
29
    ; Status LEDs Ausgang
30
    ldi    R16, 0b11111111    ; PortD als Ausgang
31
    out    DDRD, R16
32
33
    sei              ; Interrupts aktivieren
34
35
36
37
loop:  in    R16, TWCR
38
    sbrc  R16, TWINT      ; Überspringe wenn TWINT-Bit low
39
    sbi    PORTD, 1      ; Status-LED 2 an
40
41
    rjmp  loop        ; Endlosschleife
42
43
44
45
rec:  sbi    PORTD, 0      ; Status-LED 1 an
46
47
/*
48
    in    R16, TWSR      ; Statusregister einlesen
49
    out    PORTD, R16
50
*/
51
52
    reti

von ecslowhand (Gast)


Lesenswert?

Nur mal kurz über den Empfänger-Code geschaut, grundsätzlich:

In der Interruptroutine musst Du als erstes mal die verschiedenen 
Statuscodes des TWSR auswerten. Diese sind im Datasheet beschrieben.

Erkennt der Slave beispielsweise, dass seine SLA-Adresse gesendet wurde, 
steht im TWSR beispielsweise 0x60.
Wenn im TWSR dann 0x80 steht, hast der µC ein Byte empfangen.

Halte Dich mal an das Datasheet, dort sind ja auch Routinen angegeben.

Ansonsten findest Du im Netz sicherlich Beispielcodes.

LG EC

von Anderer (Gast)


Lesenswert?


von Paul H. (powl)


Lesenswert?

Hi, danke schonmal für die Antworten.

Ich weiß dass ich in der Empfänger Interruptroutine die Statuscodes zur 
weiteren Verarbeitung erstmal auswerten muss :-) Aber dazu kommt es erst 
garnicht. Der Interrupt wird überhaupt nicht ausgeführt, der Slave 
reagiert garnicht erst.

Habe mir auch das Beispiel hier obendrüber mal angeschaut, alles 
plausibel aber helfen tuts mir leider nicht wirklich :-( Einen Fehler in 
der Schaltung kann ich auch nicht wirklich entdecken. Irgendwo im 
Programm ein Fehler? Ich hab leider auch kein digitales 
Speicheroszilloskop.

mfg PoWl

von Johannes M. (johnny-m)


Lesenswert?

Sicher, dass die LEDs auch richtig rum am Port hängen? Nicht, dass die 
Low-Side angeschlossen sind. Dann schaltest Du sie mit sbi... nämlich 
aus.

von Paul H. (powl)


Lesenswert?

Nein die LEDs funktionieren alle, hab ich schon getestet :-)

von Paul H. (powl)


Lesenswert?

Got it. Tja das passiert wenn man das Manual nicht von vorne bis hinten 
hin wort für wort durchließt.
1
    ; TWI und Interrupt aktivieren
2
    ldi    R16, (1 << TWEN) | (1 << TWIE)
3
    out    TWCR, R16

Da muss noch das TWEA Bit rein damit das ACK überhaupt gesendet wird... 
schwupp, schon funktioniert es :-)

Danke trotzdem für die Hilfen, ich werde mich melden wenn es wieder 
probleme gibt.

mfg PoWl

von Paul H. (powl)


Lesenswert?

Das Teil bringt mich noch zur verzweiflung. Nachdem ein erster Transfer 
geklappt hat, dafür ein zweiter aber nicht habe ich mal weitere 
Untersuchungen angestellt. Irgendwie ist da der Wurm drin. Entweder der 
Master sendet die Stop-Condition nicht richtig raus oder der Slave 
erkennt sie irgendiwe nicht?! Nach einschalten der Versorgungsspannung 
drücke ich auf meinen magischen INT0 Taster. Prompt leuchten alle 4 
bunten StatusLEDs am Master die mir anzeigen dass er mit seiner 
senderoutine fertig ist. Am Slave jedoch nur die beiden ersten gelben 
Status LEDs die mir zeigen dass die Adresse empfangen und ACK gesendet 
und dass die daten empfangen und ack gesendet worden sind. Jedoch wurde 
die stop condition nicht erkannt. Findet da jemand den fehler?

Master:
1
.include "m8def.inc"        ; Deklarationen für ATmega8
2
3
.cseg                ; Programm-Flash
4
    rjmp  init        ; Reset-Einsprung
5
6
.org  0x001            ; INT0 Interrupt
7
    rjmp  send
8
9
.org  0x013            ; Interrupteinsprünge übergehen
10
11
12
init:  ldi    R16, LOW(RAMEND)  ; Stapel anlegen
13
    out    SPL, R16
14
    ldi    R16, HIGH(RAMEND)
15
    out    SPH, R16
16
17
18
    ; INT0 Interrupt
19
    ldi    R16, (1 << ISC01)  ; Fallende Flanke an INT0 generiert Interrupt
20
    out    MCUCR, R16
21
22
    ldi    R16, (1 << INT0)  ; INT0 Interrupt aktiviern
23
    out    GICR, R16
24
25
26
    ; Two-Wire-Interface
27
    ldi    R16, 10        ; Bitratenfaktor für 10kHz Bustakt bei 1Mhz
28
    out    TWBR, R16
29
30
31
    ; Status LED Ausgang
32
    ldi    R16, 0b00011111    ; PB0-3 als Ausgang
33
    out    DDRB, R16
34
35
    sei              ; Interrupts aktivieren
36
37
    clr    R17          ; Zu benutzende Register leeren
38
    ldi    R17, 100      ; Startwert zum Test
39
40
loop:  rjmp  loop        ; Endlosschleife
41
42
43
44
send:  cbi    PORTB, 0
45
    cbi    PORTB, 1
46
    cbi    PORTB, 2
47
    cbi    PORTB, 3
48
    cbi    PORTB, 4
49
50
    sei
51
52
53
54
    ; Start Condition senden
55
    ldi    R16, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN)
56
    out    TWCR, R16
57
58
    ; Warten bis ausgeführt
59
send1:  in    R16, TWCR
60
    sbrs  R16, TWINT
61
    rjmp  send1
62
63
    sbi    PORTB, 0      ; Rote Status-LED an
64
65
    in    R16, TWSR      ; TWI-Statusregister checken
66
    cpi    R16, 0x08      ; Code 0x08 = A START condition has been transmitted
67
    brne  error        ; Springe zu error wenn ungleich
68
69
70
71
    ; 7-Bit Slave Adresse + R/W senden (R=High, W=Low)
72
    ldi    R16, (127 << 1) | (0)
73
    out    TWDR, R16
74
75
    ; Daten senden
76
    ldi    R16, (1 << TWINT) | (1 << TWEN)
77
    out    TWCR, R16
78
79
    ; Warten bis ausgeführt
80
send2:  in    R16, TWCR
81
    sbrs  R16, TWINT
82
    rjmp  send2
83
84
    sbi    PORTB, 1      ; Grüne Status-LED an
85
86
    in    R16, TWSR      ; TWI-Statusregister checken
87
    cpi    R16, 0x18      ; Code 0x18 = SLA+W has been transmitted; ACK has been received
88
    brne  error        ; Springe zu error wenn ungleich
89
90
91
92
    ; Zählerdaten senden
93
    out    TWDR, R17      ; Zählerdaten ins Ausgangsregister laden
94
    inc    R17          ; Zähler inkrementieren
95
96
    ; Daten senden
97
    ldi    R16, (1 << TWINT) | (1 << TWEN)
98
    out    TWCR, R16
99
100
    ; Warten bis ausgeführt
101
send3:  in    R16, TWCR
102
    sbrs  R16, TWINT
103
    rjmp  send3
104
105
    sbi    PORTB, 2      ; Gelbe Status-LED an
106
107
    in    R16, TWSR      ; TWI-Statusregister checken
108
    cpi    R16, 0x28      ; Code 0x28 = Data byte has been transmitted; ACK has been received
109
    brne  error        ; Springe zu error wenn ungleich
110
111
112
113
    ; Stop Condition senden
114
    ldi    R16, (1 << TWINT) | (1 << TWSTO) | (1 << TWEN)
115
    out    TWCR, R16
116
117
    sbi    PORTB, 3      ; Blaue Status-LED an
118
119
    reti
120
121
122
123
error:  sbi    PORTB, 4      ; Rote Error-LED an
124
    reti

Slave:
1
.include "m8def.inc"        ; Deklarationen für ATmega8
2
3
.equ  adress = 127        ; TWI-Adresse
4
5
.cseg                ; Programm-Flash
6
    rjmp  init        ; Reset-Einsprung
7
8
.org  0x011
9
    rjmp  twis        ; TWI Interrupt
10
11
.org  0x013            ; Interrupteinsprünge übergehen
12
13
14
init:  ldi    R16, LOW(RAMEND)  ; Stapel anlegen
15
    out    SPL, R16
16
    ldi    R16, HIGH(RAMEND)
17
    out    SPH, R16
18
19
20
    ; Slave Adresse 1111111 + TWGCE
21
    ldi    R16, (adress << 1) | (1 << TWGCE)
22
    out    TWAR, R16
23
24
    ; TWI und Interrupt aktivieren
25
    ldi    R16, (1 << TWEA) | (1 << TWEN) | (1 << TWIE)
26
    out    TWCR, R16
27
  
28
29
    ; Status LEDs Ausgang
30
    ldi    R16, 0b11111111    ; PortD als Ausgang
31
    out    DDRD, R16
32
33
    sei              ; Interrupts aktivieren
34
35
36
37
loop:  rjmp  loop        ; Endlosschleife
38
39
40
41
twis:  in    R16, TWSR
42
    cpi    R16, 0x60      ; 0x60 = Own SLA+W has been received; ACK has been returned
43
    brne  twis1        ; Springe wenn ungleich
44
45
    ; Data byte will be received and ACK will be returned
46
    ldi    R16, (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE)
47
    out    TWCR, R16
48
49
    sbi    PORTD, 0      ; Gelbe Status-LED 1 an
50
51
    rjmp  twis3
52
53
54
twis1:  in    R16, TWSR
55
    cpi    R16, 0x80      ; 0x80 = Previously addressed with own SLA+W; data has been received; ACK has been returned
56
    brne  twis2        ; Springe wenn ungleich
57
58
    sbi    PORTD, 1      ; Gelbe Status-LED 2 an
59
60
;    in    R16, TWDR      ; Daten an PortD ausgeben
61
;    out    PORTD, R16
62
63
    rjmp  twis3
64
65
66
twis2:  in    R16, TWSR
67
    cpi    R16, 0xA0      ; 0xA0 = A STOP condition or repeated START condition has been received while still addressed as Slave
68
    brne  twis3        ; Springe wenn ungleich
69
70
    ; Switched to the not addressed Slave mode; own SLA will be recognized; GCA will be recognized if TWGCE = 1
71
    ldi    R16, (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE)
72
    out    TWCR, R16  
73
74
    sbi    PORTD, 2      ; Gelbe Status-LED 3 an
75
76
77
twis3:    reti            ; Kehre zurück

von Paul H. (powl)


Lesenswert?

Leider kann ich den Post nicht mehr editieren. Mir ist aufgefallen dass 
wenn ich das erste mal die Übertragung starte eine zweite nicht möglich 
ist. Die Start Condition wird vom Master irgendwie nicht gesendet bzw. 
das TWINT-flag wird einfach nicht gesetzt?! Wenn ich den Slave nach der 
ersten Übertragung jedoch resette dann geht es wieder. Wenn ich den 
Slave resette nachdem ich die zweite übertragung gestartet habe (also 
einfach 2 mal hintereinander auf den taster drücken) dann läuft das 
programm im master weiter und sendet die SLA + R/W. Danach geht die 
Error LED an was bedeutet dass der Slave kein ACK sendet.

Ich habe das Masterprogramm mal geringfügig modifiziert.. testweise. 
Egal ob ich die Stop-conidition am ende nun sende oder nicht, der slave 
reagiert gleich. Er erkennt sie einfach nicht. Irgendwo ist da der Wurm 
drin aber ich bin schon ganz verzweifelt.. ich finde keinen Fehler 
mehr.. möglicherweise hab ich ja was übersehen, nur was :-S

mfg PoWl

von Paul H. (powl)


Lesenswert?

tut mir leid dass ich hier soviele postings mache.. kann leider 
irgendwie nicht editieren!?

Ich habe mal im slave einen zähler eingebaut der die interrupts zählt 
und am PortD ausgibt.

dann habe ich mal im master die 4 schritte Start-Condition senden, SLA + 
W senden, Daten senden, Stop Condition senden schrittweise 
auskommentiert. Zuerst habe ich die letzten 3 auskommentiert, d.h. der 
master sendet nur eine startcondition und macht garnix. Wie zu erwarten 
führt der slave kein interrupt aus. Die LEDs an Port D bleiben aus.

als nächstes habe ich nur die letzten beiden schritte im master 
auskommentiert, es wird jetzt also die startcondition gesendet und 
SLA+W. Der Interruptzähler im Slave zeigt an Port D nun einen interrupt 
an, wie zu erwarten. Am Master leuchten natürlich die ersten beiden 
bunten Status-LEDs.

dann habe ich mal den letzten schritt auskommentiert. D.h. es werden 
jetzt startcondition, SLA+W und das Datenbyte gesendet. 
Unerwarteterweise leuchteten nun sämtliche LEDs an Port D, d.h. es 
würden 255 Interrupts ausgelöst. Wieso denn so viele? Und wieso denn 
genau 255? Ich nehme mal an das liegt am Master aber ich kann im code 
auch keinen fehler entdecken der soviele datenbytes hintereinander 
sendet. Ist meine TWI hardware kaputt oder habe ich irgendwas grob 
falsch gemacht?

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.