USI: I²C/TWI Slave sendet kein ACK :-/

OP #641884
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
OP #642477
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
OP #642611
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.
OP #642692
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren