Forum: Mikrocontroller und Digitale Elektronik USI: I²C/TWI Slave sendet kein ACK :-/


von Paul H. (powl)


Lesenswert?

Hi mal wieder,...

Ich habe es nun soweit geschafft dass er die Start Condition erkennt und 
darauf die ISR ausführt in der der Overflow interrupt aktiviert wird. 
Beim Empfangen des ersten Bytes, also Adresse + R/W wird die 
Overflow-ISR ausgeführt in der anhand meines virtuellen TWI 
Statusregisters im SRAM entschieden wird was nun getan wird. Das 
funktioniert soweit alles ganz prima. Nur das USI weigert sich strikt 
ein ACK zu senden.

Hierfür leere ich nämlich das Schieberegister, stelle die 
SDA-Portleitung über das DDRB als Ausgang ein und stelle den Counter auf 
den Wert 14. Bei den nächsten 2 Taktflanken in denen das ACK nun vom 
Master sozusagen "abgeholt" wird läuft der 4-bit-Counter wieder über und 
die Overflow ISR wird ausgeführt.

Das funktioniert alles soweit gut aber das ACK kommt einfach nicht an. 
Der Master meldet mir dass er ein NOT ACK empfangen hat und bricht wie 
erwartet ab. Fehlt irgendwas?
1
.include "tn26def.inc"        ; Deklarationen für ATtiny26
2
3
.equ  adress = 127        ; TWI Adresse
4
5
6
.cseg                ; Programm-Flash
7
    rjmp  init        ; Reset-Einsprung
8
9
.org  0x007            ; USI Start Interrupt
10
    rjmp  usi_start
11
12
.org  0x008            ; USI Overflow Interrupt
13
    rjmp  twis
14
15
16
.org  0x00C            ; Interrupteinsprünge übergehen
17
18
init:  ldi    R16, RAMEND      ; Stapel anlegen
19
    out    SP, R16
20
21
    ldi    R16, 0b11111111    ; PortA als Ausgang
22
    out    DDRA, R16
23
24
    ; USI Control Register
25
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
26
    out    USICR, R16
27
28
    sei              ; Interrupts aktivieren
29
30
loop:  rjmp  loop        ; Endlosschleife
31
32
33
34
usi_start:
35
    push  R16          ; Register retten
36
37
    ; Start Condition Interrupt Flag zurücksetzen
38
    ldi    R16, (1 << USISIF)
39
    out    USISR, R16
40
41
    ; Overflow Interrupt aktivieren
42
    ldi    R16, (1 << USISIE) | (1 << USIOIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
43
    out    USICR, R16
44
45
    ldi    R16, 10        ; Neuen Status laden
46
    sts    TWSR, R16      ; Status im SRAM speichern
47
48
    pop    R16          ; Register wiederherstellen
49
    reti            ; Kehre zurück
50
51
52
53
twis:  push  R16          ; Register retten
54
55
    ; Counter Overflow Interrupt Flag zurücksetzen
56
    ldi    R16, (1 << USIOIF)
57
    out    USISR, R16
58
59
;- Adresse ---------------------------------------------------------------------------
60
61
    lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
62
    cpi    R16, 10        ; 10 = A START condition has been transmitted
63
    brne  twis2        ; Springe zu twis2 wenn ungleich
64
65
    ; Adresse überprüfen
66
    in    R16, USIDR      ; Adresse + R/W in R16 laden
67
    andi  R16, 0b11111110    ; Maskieren
68
69
    push  R17          ; Register retten
70
    ldi    R17, (adress << 1)  ; Slave Adresse laden
71
72
    cp    R16, R17      ; Vergleichen
73
    pop    R17          ; Register wiederherstellen
74
    breq  twis1        ; Überspringe nächste 3 Befehle wenn gleich
75
76
    ; Adresse stimmt nicht überein
77
    ; Overflow Interrupt bis zur nächsten START condition deaktivieren
78
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
79
    out    USICR, R16
80
81
    rjmp  twis_end      ; Springe zum Ende der ISR
82
83
    ; Adresse stimmt überein, ACK senden
84
twis1:  clr    R16          ; Schieberegister leeren
85
    out    USIDR, R16
86
87
    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren
88
89
    ldi    R16, 14        ; Counter laden
90
    out    USISR, R16
91
92
    sbi    PORTA, 0      ; Status-LED 1 an
93
94
    ldi    R16, 20        ; Neuen Status laden
95
    sts    TWSR, R16      ; Status im SRAM speichern
96
97
    rjmp  twis_end      ; Springe zum Ende der ISR
98
99
;- Daten ---------------------------------------------------------------------------
100
101
twis2:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
102
    cpi    R16, 20        ; 20 = Own SLA+W has been received; ACK has been returned
103
    brne  twis_end      ; Springe wenn ungleich
104
105
    sbi    PORTA, 1      ; Status-LED 2 an
106
107
    cbi    DDRB, 0        ; DDR an SDA auf low
108
109
twis_end:  
110
    pop    R16          ; Register wiederherstellen
111
    reti            ; Kehre zurück
112
113
114
115
.DSEG
116
117
118
; USI - TWI Status Register
119
TWSR:
120
.byte  1

von Paul H. (powl)


Lesenswert?

Besteht denn eine geringe Chance das Problem jemals gelöst zu bekommen? 
Ich weiß ja dass USI nicht gemocht wird und nicht so verbreitet ist aber 
irgendwen muss das doch auch interessieren oder jemand muss sich damit 
doch mal beschäftigt haben :-(

mfg PoWl

von Andi (Gast)


Lesenswert?

Hast du schon mal die Atmel Application notes dazu studiert?
z.B. -> AVR312

auf dieser Webseite:
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607

Gruss Andi

von Paul H. (powl)


Lesenswert?

Ja, hab mich jetzt mal getraut. Da gehts aber schon gleich mit der Frage 
los warum die die SCL-Leitung als Ausgang setzen und auf High ziehen. 
Damit erzeug ich dochn satten Kurzschluss wenn mein Master versucht die 
SCL leitung aktiv auf LOW zu ziehen und ich darf mir mal wieder n neuen 
ATmega8 und n neuen ATtiny26 kaufen. Solche befehle habe ich auch drin 
aber Daten werden trotzdem empfangen von meinem Tiny. Nur das ACK mag er 
nicht senden, trotz dass ich SDA kurzzeitig als Ausgang schalte.

von Paul H. (powl)


Lesenswert?

Got it..

ich habs.. allerdings wird mich jeder Atmelkönig für diesen Code 
hinrichten lassen. Diesen Käse, die SCL leitung aktiv auf high zu 
ziehen, habe ich garnicht drin!? Desweiteren wird der Counter auf 13 
anstatt auf 14 gestellt um das ACK zu senden.. ziemlich paradox aber es 
funktioniert nur so.

Der Empfang funktioniert soweit. Je nach Masterprogramm sollte ein 
Empfang von mehreren Datenbytes hintereinander auch möglich sein.. da 
muss man aber das Programm für die Datenauswertung noch individuell 
anpassen. Ausserdem wird Repeatet Start noch nicht unterstützt, 
irgendwie müsste man die Stop-Condition erkennen? Könnte man in der 
Start-Condition ISR vielleicht überprüfen und entsprechend dem inhalt 
des TWI Statusregisters reagieren... will das mal jemand ausprobieren?

Aehm, das Programm empfängt als Slave unter der Adresse 127 ein 
Datenbyte. Auf R/W wird derzeit noch nicht eingegangen.. da müsste man 
auch noch ne Weiche einbauen.

Immerhin schonmal ein Anfang :-)

mfg PoWl
1
.include "tn26def.inc"        ; Deklarationen für ATtiny26
2
3
.equ  adress = 127        ; TWI Adresse
4
5
6
.cseg                ; Programm-Flash
7
    rjmp  init        ; Reset-Einsprung
8
9
.org  0x007            ; USI Start Interrupt
10
    rjmp  usi_start
11
12
.org  0x008            ; USI Overflow Interrupt
13
    rjmp  twis
14
15
16
.org  0x00C            ; Interrupteinsprünge übergehen
17
18
init:  ldi    R16, RAMEND      ; Stapel anlegen
19
    out    SP, R16
20
21
    ldi    R16, 0b11111111    ; PortA als Ausgang
22
    out    DDRA, R16
23
24
    ; USI Control Register
25
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
26
    out    USICR, R16
27
28
    ldi    R16, 0xF0
29
    out    USISR, R16
30
31
    sei              ; Interrupts aktivieren
32
33
loop:  rjmp  loop        ; Endlosschleife
34
35
36
37
usi_start:
38
    push  R16          ; Register retten
39
40
    ; Start Condition Interrupt Flag zurücksetzen
41
    ldi    R16, (1 << USISIF)
42
    out    USISR, R16
43
44
    ; Overflow Interrupt aktivieren
45
    ldi    R16, (1 << USISIE) | (1 << USIOIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
46
    out    USICR, R16
47
48
    ldi    R16, 10        ; Neuen Status laden
49
    sts    TWSR, R16      ; Status im SRAM speichern
50
51
    pop    R16          ; Register wiederherstellen
52
    reti            ; Kehre zurück
53
54
55
56
twis:  push  R16          ; Register retten
57
58
    ; Counter Overflow Interrupt Flag zurücksetzen
59
    ldi    R16, (1 << USIOIF)
60
    out    USISR, R16
61
62
;- Adresse überprüfen -----------------------------------------------------------------
63
64
    lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
65
    cpi    R16, 10        ; 10 = Start Condition wurde erkannt, Adresse wurde gesendet
66
    brne  twis2        ; Springe zu twis2 wenn ungleich
67
68
    in    R16, USIDR      ; Adresse + R/W in R16 laden
69
    andi  R16, 0b11111110    ; Maskieren
70
71
    push  R17          ; Register retten
72
    ldi    R17, (adress << 1)  ; Slave Adresse laden
73
74
    cp    R16, R17      ; Vergleichen
75
    pop    R17          ; Register wiederherstellen
76
    breq  twis1        ; Überspringe nächste 3 Befehle wenn gleich
77
78
    ; Adresse stimmt nicht überein
79
    ; Overflow Interrupt bis zur nächsten START condition deaktivieren
80
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
81
    out    USICR, R16
82
83
    rjmp  twis_end      ; Springe zum Ende der ISR
84
85
;- Adresse stimmt überein, ACK senden -------------------------------------------------
86
87
twis1:  clr    R16          ; Schieberegister leeren
88
    out    USIDR, R16
89
90
    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren
91
92
    ldi    R16, 13        ; Counter laden
93
    out    USISR, R16
94
95
    ldi    R16, 20        ; Neuen Status laden
96
    sts    TWSR, R16      ; Status im SRAM speichern
97
98
    rjmp  twis_end      ; Springe zum Ende der ISR
99
100
;- Datenempfang vorbereiten------------------------------------------------------------
101
102
twis2:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
103
    cpi    R16, 20        ; 20 = Eigene Slave-Adresse + R/W wurde empfangen; ACK wurde gesendet
104
    brne  twis3        ; Springe wenn ungleich
105
106
    cbi    DDRB, 0        ; DDR an SDA auf low
107
108
    ldi    R16, 30        ; Neuen Status laden
109
    sts    TWSR, R16      ; Status im SRAM speichern
110
111
    rjmp  twis_end      ; Springe zum Ende der ISR
112
113
;- Daten wurden empfangen -------------------------------------------------------------
114
115
twis3:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
116
    cpi    R16, 30        ; 30 = Daten wurden empfangen
117
    brne  twis4        ; Springe wenn ungleich
118
119
    in    R16, USIDR      ; Daten einlesen
120
    out    PORTA, R16
121
122
;- Daten wurden empfangen, ACK senden -------------------------------------------------
123
124
    clr    R16          ; Schieberegister leeren
125
    out    USIDR, R16
126
127
    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren
128
129
    ldi    R16, 13        ; Counter laden
130
    out    USISR, R16
131
132
    ldi    R16, 40        ; Neuen Status laden
133
    sts    TWSR, R16      ; Status im SRAM speichern
134
135
    rjmp  twis_end      ; Springe zum Ende der ISR
136
137
;- Datenempfang vorbereiten------------------------------------------------------------
138
139
twis4:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
140
    cpi    R16, 40        ; 40 = Daten wurden empfangen; ACK wurde gesendet
141
    brne  twis_end      ; Springe wenn ungleich
142
143
    cbi    DDRB, 0        ; DDR an SDA auf low
144
145
    ldi    R16, 20        ; Neuen Status laden
146
    sts    TWSR, R16      ; Status im SRAM speichern
147
148
twis_end:  
149
    pop    R16          ; Register wiederherstellen
150
    reti            ; Kehre zurück
151
152
153
154
.DSEG
155
156
157
; USI - TWI Status Register
158
TWSR:
159
.byte  1

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.