Avr assmebler Programm funktioniert nur sporadisch

Gast #2052109
Lesenswert?

Hallo,

Ich habe ein kleines Assembler Programm geschrieben, welches alle 
Farbkombinationen einer RGB-Led durchlaufen soll. Leider funktioniert 
dieses nur bei ca. 1 von 10 Programmstarts , sonst werden völlig 
"falsche" Farbkombinationen durchlaufen. Ich bin nun etwas ratlos, da 
ich keinen Fehler finden kann und ziemlicher Anfänger bin.

Normalerweise sollte das Programm den Farbverlauf
Grün->Gelb->Rot->Lila->Blau->Türkis->Grün... darstellen
Meistens macht es aber:
Weiß-> lila->Blau->Türkis->Weiß
oder
Weiß->plötzlich Lila->Rot->plötzlich Blau->plötzlich Türkis->plötzl. 
Blau->plötzl. Weiß
oder andere komische Dinge

Hier der Programmcode:
1
.include "m8def.inc"
2

3

4

5
.org 0x000
6

7
  rjmp main
8

9
.org ovf0addr
10

11
  rjmp pwm
12

13
.org ovf1addr
14

15
  rjmp changer
16

17

18

19

20

21

22

23

24

25
.def temp= r16
26

27
.def led1 =r17
28

29
.def led2 =r18
30

31
.def led3 =r19
32

33
.def outport =r20
34

35
.def pwmcounter= r23
36

37
.def counter = r21
38

39
.def ccounter = r22
40

41

42

43
.org INT_VECTORS_SIZE
44

45

46

47
main:
48

49

50

51

52

53
ldi temp, LOW(RAMEND)
54

55
out spl, temp
56

57
ldi temp, high(ramend)
58

59
out sph, temp
60

61

62

63
ldi temp, 1<<CS01
64

65
out tccr0,temp
66

67
ldi temp, 1<<CS11
68

69
out tccr1b, temp
70

71
ldi temp, 1<<toie0 | 1<<toie1
72

73
out timsk, temp
74

75
ldi led1, 150 ; Grün an
76

77
ldi temp,0xff  ; portc als Ausgang
78

79
out ddrc, temp
80

81

82

83
sei
84

85

86

87
  pwmloop:
88

89
  out portc, outport
90

91
  rjmp pwmloop
92

93

94

95

96

97

98

99
pwm:
100

101
inc pwmcounter
102

103

104

105
  ldi outport,0xff  ;Alle leds an
106

107
  cp pwmcounter, led1
108

109
  brsh l1off
110

111
l2:        ;Prüfen ob leds aus sollen
112

113
  cp pwmcounter, led2
114

115
  brsh l2off
116

117
l3:
118

119
  cp pwmcounter, led3
120

121
  brsh l3off
122

123
l4:
124

125
  cpi pwmcounter, 150
126

127
  brsh killpwm
128

129
  rjmp end
130

131
killpwm:ldi pwmcounter,0x00
132

133
end:  
134

135
reti
136

137
l1off:
138

139
  cbr outport, 0x01
140

141
  rjmp l2
142

143
l2off:
144

145
  cbr outport, 0x02
146

147
  rjmp l3
148

149
l3off:
150

151
  cbr outport, 0x04
152

153
  rjmp l4
154

155

156

157
changer:
158

159

160

161
    cpi     counter,11        ;Counter resetten?
162

163
    brsh    clearcounter
164

165
    ldi     ZL,low(faelle)         
166

167
    ldi     ZH,high(faelle)
168

169
    add     ZL,counter                     
170

171
    ldi     temp,0                   
172

173
    adc     ZH,temp
174

175
    ijmp        
176

177

178

179
clearcounter:
180

181
  clr counter
182

183
  rjmp changer
184

185

186

187
faelle:
188

189
  inc led2  ;Rot +
190

191
  rjmp endtime
192

193
  dec led1  ; Gruen -
194

195
  rjmp endtime
196

197
  inc led3  ; Blau+
198

199
  rjmp endtime
200

201
  dec led2  ; Rot -
202

203
  rjmp endtime
204

205
  inc led1  ; Gruen+
206

207
  rjmp endtime
208

209
  dec led3  ; Blau-
210

211
  rjmp endtime
212

213

214

215
endtime:
216

217
  inc ccounter  ; Wenn ccounter 150 wird counter erhöht
218

219
  cpi ccounter, 150
220

221
  breq newcounter
222

223
reti
224

225
newcounter:
226

227
  subi counter, -2
228

229
  ldi ccounter, 0x00
230

231
reti

Die verwendete Hardware ist das Atmel Evalution Board von Pollin+ 
eigenbau Leistungstreiber. In meiner Werkstatt werkeln (mit Ausnahme des 
PCs) keine Schaltnetzteile o.Ä. , sodass ein EMV-Problem leider eher 
unwahrscheinlich ist.

Ich hoffe mir kann jemand beim finden des Fehlers helfen.

MfG David
Gast #2052122
Lesenswert?

Entweder habe ich jetzt ein Knoten im Kopf oder es ist ein wunder das es 
überhaupt geht?

Hast mal mal etwas von einem Stack gehört? ISR müssen Register sichern! 
Und dann sollte man auch reti und call für ISR verwenden.
#2052420
Lesenswert?

Hallo,

also rjmp passt schon, und reti sehe ich auch am Ende der ISR's. Aber 
wie Peter schon sagte: beim Eintritt in die ISR zuerst mal das 
Statusregister sichern (in r..,SREG), und dann alle Register die von der 
ISR und der Hauptschleife gemeinsam genutzt werden und getrennte 
Funktionen erfüllen.
In deinem speziellen Fall scheint die Hautschleife ja nun nichts zu tun 
(von dem Out mal abgesehen), und sich ISR's nicht gegenseitig 
unterbrechen können müsste das Programm eigentlich laufen.
Kannst du dein Programm nicht mal als ordentlich formatierten Code und 
ohen die ganzen Leerzeilen reinstellen, beim durchsehen in dem Format 
bekomme ich irgendwie einen Knoten in Sehnerv.

Sascha
Gast #2052519
Lesenswert?

Hi!
>Ich bin nun etwas ratlos, da
>ich keinen Fehler finden kann und ziemlicher Anfänger bin.
Dafür schreibst du aber schon recht verwirrende Programme und das fast 
alles ohne Kommentar.;-)
Du könntest led1 bis led3 mal einen eindeutigen Startwert geben.
So ganz erklärt es allerdings die plötzlichen Farbwechsel nicht.

Viel Erfolg, Uwe
(Firma: TH Köln) Persönliche Seite #2052551
Lesenswert?

Könnte es sein, dass es immer läuft, wenn du den Strom neu einschaltest 
oder neu flashst?

So rein funktional betrachtet sollte dein Programm eigentlich laufen, 
ich hab zumindest keine groben Fehler gesehen. Der AVR setzt aber die 
Register nicht einfach auf 0 beim Reset, wie du augenscheinlich 
voraussetzt, daher ist es schon ratsam, diese vor Verwendung mit einem 
festen Wert zu initialisieren. (clr led2, clr led3 etc. hinter main: 
einfügen)

Dein Programm hier ist ein 'klassisches' Beispiel, dass ISRs weder das 
SREG noch irgendwelche Register sichern MÜSSEN. Da du dich aber als 
'ziehmlichen Anfänger' bezeichnest: besser zuviel sichern, sich dafür 
aber an das routinemäßige Sichern gewöhnen. Spart später viele Tage 
Lebenszeit für die Fehlersuche.

Mark
#2052558
Lesenswert?

Hallo,

die nicht geretteten Register sind vermutlich zufällig nicht ganz so 
tragisch, in der main loop gibt es keine Flag-abhägigen Befehle und auch 
keine, die die Flags ändern.
Allerdings habe ich mir das pwm-Chaos nicht im Detail angeschaut.

Die ijmp gehen aber in jedem Fall die Hose.
Die Adresse ist eim Flash, also eine Word-Adresse, die Label sind 
Byte-Label.

Also
    ldi     ZL,low(faelle*2)
    ldi     ZH,high(faelle*2)

Dann addierst Du counter dazu, der kann offenbar 0...11 annehmen, 
soviele Fälle sehe ich garnicht.
Dazu kommt: alle Befehle des AVR sind Word lang (mindestens), Du 
addierst aber z.B. 1 und der AVR fällt auf die Nase, weil ein Befehl 2 
lang ist...
Ein Tabelleneintrag ist ja wohl:

  inc led2  ;Rot +
  rjmp endtime

inc ist 1 Word (2 Byte)
rjmp ebenfalls.

Ein Eintrag ist also 4 Byte lang und nicht nur ein Byte...

Gruß aus Berlin
Michael
Gast #2052571
Lesenswert?

Hi

>Also
>    ldi     ZL,low(faelle*2)
>    ldi     ZH,high(faelle*2)

Das gilt nur für lpm. ijmp und icall arbeiten mit den Wordadressen.

>Dazu kommt: alle Befehle des AVR sind Word lang (mindestens), Du
>addierst aber z.B. 1 und der AVR fällt auf die Nase, weil ein Befehl 2
>lang ist...

Macht er auch richtig:

  subi counter, -2

MfG Spess
(Firma: TH Köln) Persönliche Seite #2052606
Lesenswert?

Michael U. schrieb:
> ldi     ZL,low(faelle*2)
>     ldi     ZH,high(faelle*2)

Ist bei dem ijmp genau nicht so, da hier die word-Adresse verwendet 
wird. Adresse *2 ist nur für byteweisen Datenzugriff mit lpm. 'subi 
counter, -2
' berücksichtigt auch ganz richtig die 4 bytes, weshalb die Sprünge 
korrekt laufen sollten. Sehr eigenwillig geschrieben aber durchaus 
kreativ.
Gast #2053051
Lesenswert?

Auch wenn der Code tatsächlich recht "creativ" ist, so scheint er doch 
so weit zu funktionieren, auch der IJMP.

Allerdings wird zu Beginn nur das Register für "grün" led1 
initialisiert, led2 und led3 haben einen zufälligen Zustand und werden 
von diesem Zustand aus weiter gezählt, inklusive möglicher Überläufe.

Initialisieren der beiden Register dürfte das Problem beheben, hatte Uwe 
bereits geschrieben.
Gast #2053884
Lesenswert?

hallo,
Danke für die vielen Antworten.

Des Rätselts Lösung war:

MWS schrieb:
> Allerdings wird zu Beginn nur das Register für "grün" led1
> initialisiert, led2 und led3 haben einen zufälligen Zustand und werden
> von diesem Zustand aus weiter gezählt, inklusive möglicher Überläufe.
>
> Initialisieren der beiden Register dürfte das Problem beheben, hatte Uwe
> bereits geschrieben.

Nachdem ich nun alle Register beim Programmstart initialisiere 
funktionierts perfekt.

Grüße David

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