Forum: Mikrocontroller und Digitale Elektronik ASM Problem beim ATMEGA32 von einem fortgeschrittenen Anfän


von Wolfram Q. (quehl)


Lesenswert?

In der Initialisierungsphase wird vor dem Programmteil des Fehlers der 
Interrupt freigegeben, weil in diesem Programmteil Wartezeiten 
auftreten, die zwar jetzt noch Softwarewartezeiten sind, aber später auf 
Hardwarewartezeiten umgestellt werden sollen. Die verfrühte Freigabe 
dürfte aber keine Fehler verursachen.
Als Ergebnis wird 00Inf ausgegeben. Interrupts und andere Ausgaben 
erfolgen nicht, obwohl dies so sein müßte.

Nun erstmal die wichtigen Code-Brocken:

w002us:
cli
;     7 Zyklen:      ; +9 takte =16 Takte
          ldi  R17, $02    ; warte 6 Zyklen
WLOOP0:   dec  R17
          brne WLOOP0
          nop      ; warte 1 Zyklus
sei
ret

Ist das so richtig, daß ich in den Wartezeiten den Interrupt sperre und 
diese im Unterprogramm liegen?

DSinfo:    rcall rssend
     ret

Hier passiert noch nichts, ist nur eine Umlenkung auf evtl. andere 
Ausgabegeräte.

Bei RSSEND wird in den Pufferspeicher RS232 geschrieben, das ist 
einwandfrei.

sea910:
  ldi  r19,0      ;Busnummer=0 setzen
sensor:  ldi  zl,low (senstb)
  ldi  zh,high(senstb)    ;Zeiger auf Sensortabelle
  ldi  r18,maxsen    ;16 Werte durchsuchen
  ldi  r17,'0'      ;Sensorzähler=0 setzen (ASCII)
sen100:  ld  r16,z+      ;Wert aus Tabelle lesen
  cp  r16,r19      ;Sensor am aktuellen Bus?
  brne  sen200      ;nein -> weiter
  inc  r17      ;sonst Sensorzähler erhöhen
sen200:  dec  r18      ;alle Tabellenplätze gelesen?
  brne  sen100      ;nein -> Schleife
  cpi  r17,'9'+1    ;mehr als 9 Sensoren am Bus?
  brcs  sen210      ;nein -> weiter
  ldi  r16,7      ;sonst Zahl in Buchstaben
  add  r17,r16      ;wandeln: 10..16 -> A..G
sen210: mov  temp,r17
  rcall  DSinfo      ;Sensoranzahl speichern
  inc  r19      ;nächsten Bus testen
  cpi  r19,maxbus    ;alle Busse getestet?
  brne  sensor      ;nein -> Schleife

; Informationen ausgeben
  ldi  temp,'I'
  rcall  DSinfo
  ldi  temp,'n'
  rcall  DSinfo
  ldi  temp,'f'
  rcall  DSinfo
  ldi  temp,'o'
  rcall  DSinfo
  ldi  zl,low (senstb)    ; Sensortabelle ausgeben
  ldi  zh,high(senstb)
  ldi  r17,0
W21:  ld  temp,z+
  rcall  DSinfo
  inc  r17
  cpi  r17,maxsen
  brne  W21
  ldi  temp,cr
  rcall  DSinfo
  ldi  zl,low (sensid)    ; ROM-ID von allen Sensoren ausgeben
  ldi  zh,high(sensid)
  ldi  r18,0
W23:  ldi  r17,0
W22:  ld  temp,z+
  rcall  DSinfo
  inc  r17
  cpi  r17,8
  brne  W22
  call   craus
  inc  r18
  cpi  r18,maxsen
  brne  W23
;  --- Initialisierung Ende  -----------------------

Ich habe mich hier etwas festgebissen, weil der Ablauf bis zur 
Informationsausgabe vermutlich richtig ist, da die 00 dort 
richtigerweise ausgegeben wird, auch das Inf wird noch richtig 
ausgegeben, aber das o und die nachfolgenden Ausgaben erfolgen nicht 
mehr.
Auch eine Endlosschleife kann ich hier nicht erkennen. Da im 
Mainprogramm Daten ohne Interrupt ausgegeben werden, liegt die Vermutung 
nahe, daß das Programm hier nicht drüber wegkommt. Doppelt vergebene 
Register können gerade an dieser Stelle nicht auftreten, weil das 
Ergebnis vorher beendet wurde und danach nur noch diese tlw. RAM 
Ausgaben zur Information erfolgen. Ist ja nur geradlinig angehängt.

Da waren mir eben die Timer eingefallen, darum nachfolgende Infos:

; Interrupt-Vektoren für ATmega 32
;
.org  0    rjmp start  ;Programm-Start
.org  INT0addr    reti    ;External Interrupt Request 0
.org  INT1addr  reti    ;External Interrupt Request 1
.org  INT2addr  reti    ;External Interrupt Request 2      nicht in 
ATMega 8
.org  OC2addr   rjmp oc2int  ;Timer/Counter2 Compare Match 8ms, Funkuhr
.org  OVF2addr  reti    ;Timer/Counter2 Overflow
.org  ICP1addr  reti    ;Timer/Counter1 Capture Event
.org  OC1Aaddr  reti ;ocr1a  ;Timer/Counter1 Compare Match A, frei
.org  OC1Baddr  reti ;ocr1b  ;Timer/Counter1 Compare Match B, Warte
.org  OVF1addr  reti    ;Timer/Counter1 Overflow
.org  OC0addr    rjmp oc0int  ;Timer/Counter0 Compare Match, ZMD  nicht 
in ATMega 8
.org  OVF0addr  reti    ;Timer/Counter0 Overflow
.org  SPIaddr    reti    ;SPI, STC Serial Transfer Complete
.org  URXCaddr  rjmp UART_Rx_C  ;RXC USART, Rx Complete
.org  UDREaddr  rjmp UART_Empty  ;UDRE USART Data Register Empty
.org  UTXCaddr  reti      ;TXC USART, Tx Complete
.org  ADCCaddr  reti     ;ADC Conversion Complete
.org  ERDYaddr  reti    ;EEPROM Ready
.org  ACIaddr    reti    ;Analog Comparator
.org  TWIaddr    reti    ;Two-wire Serial Interface
.org  SPMRaddr  reti    ;Store Program Memory Ready

;  Timer0   48 khz, CTC, Vorteiler wird wegen ausreich. Genauigkeit 
nicht resettet. für ZMD Sensor
  ldi temp, (1<< ctc0)|(1<<cs01)  ; CTC-Modus, Vorteiler = 8
  out TCCR0,temp
;  Timer2, ctc, Vorteiler/256, oc=250, 8 Mhz ---- 125 OV = 1 sek. 
150=1,2 sek. DCF-Uhr
  ldi temp, (1<< ctc2)|(1<<cs21)|(1<<cs22); CTC-Modus, Vorteiler = 256, 
resetbar
  out TCCR2,temp
  ldi temp, ( 250 - 1 ) ; Compare Wert setzen auf 8ms  (clock/Vorteiler 
*32µs)
  out OCR2, temp
  ldi temp, (1<<OCIE1B)|(1<<OCIE2); Compare Interrupt für Timer 1B,2 
aktivieren
  out TIMSK,temp

Timer1 hat noch keinen Interrupt, kann also nicht stören.
Timer2 hat einen Compare wert von 8ms, dürfte daher auch nicht in 
Betracht kommen.
Timer0 hat noch keinen comparewert, wird erst in der Anwendung gesetzt.
Wie der Timer0 abläuft, würde mich jetzt interessieren, vielleicht liegt 
da die Störung.
Bleibt ja fast nichts mehr übrig. Der Vorteiler wird nicht resettet.

mfg

von Johannes M. (johnny-m)


Lesenswert?

Stack korrekt initialisiert?

von Wolfram Q. (quehl)


Lesenswert?

der Stack ist in Ordnung. Sind auch noch 29 KB dafür frei. Ohne das 
kontrolliert zu haben, sollte das auch reichen.

mfg

von Wolfram Q. (quehl)


Lesenswert?

der Stack ist in Ordnung. Sind auch noch 1300 Bytes dafür frei. Ohne das 
kontrolliert zu haben, sollte das auch reichen.

mfg

hab mich eben vertan. War ein Irrtum

von Johannes M. (johnny-m)


Lesenswert?

Wolfram Quehl wrote:
> der Stack ist in Ordnung. Sind auch noch 29 KB dafür frei.
Öhhh, wo nimmst Du beim Mega32 29 KB RAM her?

EDIT:
> hab mich eben vertan. War ein Irrtum
Aha...

von Johannes M. (johnny-m)


Lesenswert?

BTW: Wär schön, wenn Du den Code beim nächsten Mal formatiert schicken 
könntest (mit "[avrasm]"...). Die Zeilenumbrüche bei den Kommentaren 
sind etwas lästig. Das nur am Rande...

von Wolfram Q. (quehl)


Lesenswert?

in meinem Notepad ist das alles schön formatiert. Hab das nur kopiert. 
Beim Kopieren nach Wordpad gibt es ähnliche Probleme, aber nur mit den 
Tabs.
Wie könnte ich das überhaupt erreichen, daß der Kommentat hier nicht in 
die nächste Zeile kommt. Wenn ich mir das so ansehe, kann ich nur den 
Kommentar verkürzen. Soll ich also Kommentare verkürzen?

mfg

von Johannes M. (johnny-m)


Lesenswert?

Hab ich doch oben geschrieben wie's geht:
<eckigeKlammerauf>avrasm<eckigeKlammerzu>
Dein Code
<eckigeKlammerauf>/avrasm<eckigeKlammerzu>
Steht unten bei "Formatierung"!

von Wolfram Q. (quehl)


Lesenswert?

muß ich gleich mal probieren.
1
;  Timer0   48 khz, CTC, Vorteiler wird wegen ausreich. Genauigkeit
2
nicht resettet. für ZMD Sensor
3
  ldi temp, (1<< ctc0)|(1<<cs01)  ; CTC-Modus, Vorteiler = 8
4
  out TCCR0,temp
5
;  Timer2, ctc, Vorteiler/256, oc=250, 8 Mhz ---- 125 OV = 1 sek.
6
150=1,2 sek. DCF-Uhr
7
  ldi temp, (1<< ctc2)|(1<<cs21)|(1<<cs22); CTC-Modus, Vorteiler = 256,
8
resetbar
9
  out TCCR2,temp
10
  ldi temp, ( 250 - 1 ) ; Compare Wert setzen auf 8ms  (clock/Vorteiler
11
*32µs)
12
  out OCR2, temp
13
  ldi temp, (1<<OCIE1B)|(1<<OCIE2); Compare Interrupt für Timer 1B,2
14
aktivieren
15
  out TIMSK,temp

mal sehen, ob das klappt.

von Johannes M. (johnny-m)


Lesenswert?

> mal sehen, ob das klappt.
Dafür gibts die Vorschau-Option...

OK, die Zeilenumbrüche müsstest Du dann von Hand entfernen...

von Wolfram Q. (quehl)


Lesenswert?

1
;  Timer0   48 khz, CTC, Vorteiler wird wegen ausreich. Genauigkeit nicht resettet. für ZMD Sensor
2
  ldi temp, (1<< ctc0)|(1<<cs01)  ; CTC-Modus, Vorteiler = 8
3
  out TCCR0,temp
4
;  Timer2, ctc, Vorteiler/256, oc=250, 8 Mhz ---- 125 OV = 1 sek. 150=1,2 sek. DCF-Uhr
5
  ldi temp, (1<< ctc2)|(1<<cs21)|(1<<cs22); CTC-Modus, Vorteiler = 256, resetbar
6
  out TCCR2,temp
7
  ldi temp, ( 250 - 1 ) ; Compare Wert setzen auf 8ms  (clock/Vorteiler *32µs)
8
  out OCR2, temp
9
  ldi temp, (1<<OCIE1B)|(1<<OCIE2); Compare Interrupt für Timer 1B,2 aktivieren
10
  out TIMSK,temp

war nicht so einfach, weil man das Löschen der Zeilenumbrüche nicht 
sieht, erst in der Vorschau.
Hab jetzt auch gesehen, daß ich den Compare von Timer 0 nicht 
freigegeben habe. Daher kann der Fehler dann da auch nicht liegen.

mfg
das Editieren hat nicht funktioniert

von Hauke S. (hauke)


Lesenswert?

Also was mir aufgefallen ist, das du deine Flags nicht sicherst.
Ich nehme dafür immer eines der unteren Register (R2 oder R3).
Mit den ganzen Rechen- und Vergleichsbefehlen zerschießt man sich 
ruckzuck die Flags. Und dadurch zählt ein Zähler dann mal schnell 
falsch. (mit Zähler meine ich keinen Hardwarecounter, sondern eine 
Softwareschleife be der ein Register oder ein Registerpaar hochgezählt 
wird)
Weiterhin wenn so ein Interrupt zwischen einem Vergleich (cpi, cpc, dec) 
und dem Sprungbefehl landet dann geht das üblicherweise auch in die 
Hose.
1
w002us:
2
in   R2,SREG
3
cli
4
;     7 Zyklen:      ; +9 takte =16 Takte
5
          ldi  R17, 0x02    ; warte 6 Zyklen
6
WLOOP0:   dec  R17
7
          brne WLOOP0
8
          nop      ; warte 1 Zyklus
9
out  SREG,R2
10
ret

bis dann
Hauke

von Johannes M. (johnny-m)


Lesenswert?

Hauke Sattler wrote:
> Also was mir aufgefallen ist, das du deine Flags nicht sicherst.
> Ich nehme dafür immer eines der unteren Register (R2 oder R3).
> Mit den ganzen Rechen- und Vergleichsbefehlen zerschießt man sich
> ruckzuck die Flags. Und dadurch zählt ein Zähler dann mal schnell
> falsch.
Solange es kein Interrupt-Handler ist, ist es wurscht. Nur in 
Interrupt-Handlern muss man das SREG sichern (und das eigentlich auch 
nur dann, wenn im Interrupt Handler Flags verändert werden), weil man 
bei einem Interrupt keine Kontrolle darüber hat, wann er auftritt.

Wer allerdings zwischen eine flagrelevante Operation und die 
nachfolgende Auswertung einen (r)call setzt, ist selbst Schuld...

von Wolfram Q. (quehl)


Lesenswert?

danke, hat ich zwar schon mal daran gedacht, auch die Register zu 
sichern, hab das wieder aus den Augen verloren, weil ja bei einer 
Wartezeit nach Rückkehr keine Flags abgefragt werden. Und genaugenommen 
ist das nur bei Interrupts notwendig. Hier aber sicherlich zweckmäßig, 
weil man sonst alle Wartezeiten daraufhin kontrollieren müßte.
Erklärt aber noch nicht, warum das gerade an dieser Stelle nicht mehr 
funktioniert. Dann müßte der vorhergehende Ablauf schon 
durcheinandergeraten sein und rein zufällig die richtigen Ergebnisse 
rauskommen. Das mag ja noch sein, aber nach dem Inf werden keine 
Wartezeiten aufgerufen. Erst wieder in der Mainloop.

mfg

von Hauke S. (hauke)


Lesenswert?

Ich hab mal weitergeschaut.

Dein Zählen in ASCII-Zahlen ist "sagen wir mal" gewöhnungsbedürftig.
Weiterhin ist deine Schleifengeometrie etwas verwirrend. Aber jeder hat 
seinen eigenen Stil.
Was ich vermute ist, das der AVR bei der Ausgabe der Werte aus dem 
Z-Pointer abschmiert. (Also erst nach dem 'o') Das 'o' ist schon im 
Zwischenbuffer des USART aber worde noch nicht ausgegeben. Evt. fischt 
dir dein Pointer ein "nicht-ASCII-Zeichen" raus.

Probier mal folgenden Code
1
 Informationen ausgeben
2
  ldi  temp,'I'
3
  rcall  DSinfo
4
  ldi  temp,'n'
5
  rcall  DSinfo
6
  ldi  temp,'f'
7
  rcall  DSinfo
8
  ldi  temp,'o'
9
  rcall  DSinfo
10
  ldi  zl,low(senstb)    ; Sensortabelle ausgeben
11
  ldi  zh,high(senstb)
12
  ldi  r17,0
13
W21:
14
  ld     temp,z
15
  swap   temp
16
  andi   temp,0b00001111
17
  subi   temp,-6
18
  sbrc   temp,3
19
     subi   temp,'6'-'A'
20
  subi   temp,6-'0'
21
  rcall  DSinfo
22
23
  ld     temp,z+
24
  andi   temp,0b00001111
25
  subi   temp,-6
26
  sbrc   temp,3
27
     subi   temp,'6'-'A'
28
  subi   temp,6-'0'
29
  rcall  DSinfo
30
31
nirvana:
32
nop
33
rjmp nirvana

Dadurch wird das Zeichen aus dem Pointer als Hexzahl ausgegeben.
Danach landet das dingen in einer Endlosschleife.
Mal schauen was dabei rauskommt.

cu
Hauke

P.S.
Die Hexzahlausgabe mag umständlich sein, aber ich vermeide gerne 
Sprünge.
Weiterhin baue ich mir immer irgendwelche Marker ein, um zu schauen wie 
weit er denn wirklich gekommen ist.

von Wolfram Q. (quehl)


Lesenswert?

danke,

die Ausgabe wird sicherlich irgendeine Hexzahl zwischen 0x00 und 0xFF 
sein. Wahrscheinlich 0x00 oder 0xFF.

Aber das kann nicht das Problem sein. An anderer Stelle habe ich die A/D 
Wandlung mit 03FF ausgegeben. Da gab es keine Probleme.

Das Programm vor der Informationsausgabe habe ich nicht selber 
programmiert, darum wollte ich ja auch mal sehen, was da rauskommt bei 
diesem Programmteil.
Die Ausgabe von 00 habe ich noch dazwischen gebracht.
das mit dem o im Puffer klingt logisch. Das er das aber nicht mehr 
sendet, kann eigentlich nur mit einem abgeschalteten Interrupt zu tun 
haben. Oder mit einer Endlosschleife. Da müßte ich mal sehen, wie die 
Pufferzeiger stehen.

Jetzt könnte ich wohl echt ein Simulationsprogramm gebrauchen. Ob mir 
das jemand simulieren kann, das Gesamtprogramm  würde ich dann per Email 
zusenden.

Quehl ett gmx punkt de

von Hauke S. (hauke)


Lesenswert?

Für Simulationen nehm ich VMLAB.
Leider wird das nicht mehr weitergepflegt.
Ist ideal um bis zu zwei AVR mitsamt Peripherie zu simulieren.
Das Dickste was ich bisher durchsimuliert habe, war eine Kombination aus 
einem Mega8, einem Mega32 und diversen TWI Busbausteinen.
War ein Logger(Mega8), welcher über einen Terminalserver(Mega32) 
konfiguriert und ausgelesen wurde. Das Mega32 Programm war hinterher 
über 19kB groß und bestand aus fast 11.000 Zeilen Assemblercode.

Wenn du  mir den Code schickst dann kann ich den ja mal durchlaufen 
lassen.

cu
Hauke

P.S.
die elektrische Postadresse ist
hsattler(at)uni-potsdam.de

von Wolfram Q. (quehl)


Lesenswert?

ich hab im Augenblick erst mal einen Verdacht.

Nachdem das o in den Pufferspeicher gekommen ist, wird dieses erst ca. 
270µs später abgesandt. (Baud 38400). In der Zeit sind die nachfolgenden 
Ausgaben auch in den Pufferspeicher gelangt und das Programm läuft in 
der Mainloop weiter, wo der mögliche Fehler in der Warteschleife 
auftritt, aber wahrscheinlich Register in den verschiedenen Aufgaben 
doppelt belegt sind und daher einen Absturz verursachen.

Dazu hätte ich die Frage, wie ich die Register der einzelnen Aufgaben 
sichern kann. Innerhalb der Aufgabe ist das kein Problem. Diese können 
von der nächsten Aufgabe wieder benutzt werden. Aber wenn die Register 
über die Mainloop erhalten bleiben müssen, dann weiß ich nicht, wie ich 
das machen soll. Mit Push und Pop in jeder Aufgabe wird das wohl nicht 
funktionieren.

Muß man diese Register dann vielleicht im RAM speichern? Wäre ja bei 
einer Abfrage der Flags ziemlich umständlich.

Danke,

mfg

von Hauke S. (hauke)


Lesenswert?

Sicher funktioniert das mit push und pop.
Man muß sich bloß vorher ansehen welche Register von der Sub-Routine 
verändert werden.
Mit in Ram Speichern kannst du vergessen. Das dauert im Prinzip genauso 
lang wie push und pop.

cu
bis dann
Hauke

von Hannes L. (hannes)


Lesenswert?

Nunja, globale und statische Variablen sollte man schon im RAM halten.

...

von winne (Gast)


Lesenswert?

....

Es sollten beim Einsprung in Interruptservicroutinen alle in dieser 
Routine benutzten Register durch push gesichert werden und vor dem 
Rücksprung mit pop restauriert werden.

Globale Variablen gehören ins sRAM.

Bei lokalen Variablen welche nur in Registern aufbewahrt werden ist es 
wichtig diese auf dem Stack zu sichern, wenn z.B. innerhalb einer 
Routine eine weitere Routine aufgerufen wird, welche die selben Register 
benutzt. Nach der Rückkehr aus dem Unterprogramm sind diese zu lokalen 
Variablen zu restaurieren.

noch ein paar Tips

 Ein Speicherplan erleichtert den Überblick über globale Variablen

ebenso hilft es beim pushen und poppen den Stackpointer im Auge zu 
behalten. D.h er muss beim Verlassen einer Routine den gleichen Stand 
aufweisen wie beim Eintritt in dieselbe, und es wird in umgekehrter 
Reihenfolge gepoppt, in welcher gepusht wurde.

Ausnahmen bilden Parameterübergaben via Stack. Hier ist die übernehmende 
Routine für die Bereinigung des Stacks verantwortlich. In solchen Fällen 
empfiehlt sich die Anzahl der übergeben Bytes als ersten Parameter zu 
übergeben.

In jedem Fall sollte man sich ein eineheitliches Protokoll für 
Variablenübergaben und Registernutzung zu eigen machen. Dies erleichtert 
die Übersicht über den Programmablauf bei strukturierten ASM-Programmen 
erheblich und wirkt der Verspaghettierung entgegen, welche bei ASM 
bedeutend grafierendere Knoten und Nestys (bis zu Abstürzen)bedingt als 
z.B. in einem unstrukturierten Basicprogramm.

von Wolfram Q. (quehl)


Lesenswert?

danke,

die Behandlung bei Interrupts war sowieso klar. Bei Unterprogrammen 
hatte ich das zunächst nicht gepusht, hab dann aber gemerkt, daß es die 
Programmierung vereinfacht. Mach ich also auch. Muß noch nachsehen, ob 
ich das konsequent gemacht habe. Da rutscht dann schon leicht mal was 
durch.

Worum es hier ging, waren die verschieden Aufgaben, verschiedene 
Sensorenbearbeitung in einem Chip, die hier im Forum jeweils als 
getrenntes Programm in unterschiedl. Chips behandelt werden. Diese 
Aufgaben sind unabhängig und habe ich auch unabhängig programmiert. Auch 
wenn jede Aufgabe für sich unabhängig funktioniert, so ist das in einem 
Chip nicht unbedingt der Fall. Die Aufgaben laufen nacheinander in einer 
Loop ab. Dabei müssen Variablen tlw. bis zum nächsten Durchgang 
aufbewahrt werden. Z.B. Flags, wo abgefragt wird, ob ein Interrupt 
fertig ist.
Ich habe schon öfter überlegt, vor und nach jeder Aufgabe die benutzten 
Register zu pushen und poppen. Dies wird aber nur bei 2 Aufgaben 
funktionieren, wobei eine ungepusht bleibt. Bei mehr Aufgaben wird das 
wohl nicht mehr gehen.
Ich dachte, ich hätte über die Register Überblick, aber der Überblick 
bezieht sich nur jeweils auf eine Aufgabe. Jetzt werde ich erst mal eine 
Register Übersicht machen und die globalen Register von den lokalen 
Registern unterscheiden. Ist "globale" Register überhaupt das richtige 
Wort? Global heißt doch, daß verschiedene Aufgaben die gleichen 
Variablen verwenden. Das ist hier aber nicht der Fall. Die Variablen 
werden von der gleichen Aufgabe verwendet, müssen aber bis zur nächsten 
Runde gerettet werden.

mfg

von Hannes L. (hannes)


Lesenswert?

Wolfram Quehl wrote:
> Ist "globale" Register überhaupt das richtige
> Wort? Global heißt doch, daß verschiedene Aufgaben die gleichen
> Variablen verwenden.

Ich verstehe unter "globale Variable" Variablen, deren Inhalt einem 
bestimmten Zweck zugeordnet sind und auf die von verschiedenen Routinen 
aus zugegriffen werden kann.

> Das ist hier aber nicht der Fall. Die Variablen
> werden von der gleichen Aufgabe verwendet, müssen aber bis zur nächsten
> Runde gerettet werden.

Dann sind es (für mich) lokale "statische Variable", sie dienen einem 
speziellen Zweck, werden aber nur von einer Routine verwendet.

Im Gegenzug dazu gibt es lokale temporäre Variable, deren Wert bis zur 
"nächsten Runde" verloren geht. Diese werden nur in Registern gehalten.

Bei Registermangel (der bei Deinem sehr großen Projekt ja besteht) hält 
man nur die Variablen in Registern, auf die sehr häufig und zeitkritisch 
zugegriffen wird, alles Andere hält man im RAM. Da man im RAM nicht 
rechnen und operieren kann, müssen die Werte bei Bearbeitung in Register 
kopiert werden.

Globale Variable im RAM: Register (falls nötig) freimachen (push), Wert 
in Register laden, verarbeiten, geänderten Wert ins RAM zurück, Register 
wiederherstellen (pop).

Statische lokale Variable im RAM: Register freimachen, Wert in Register 
laden, verarbeiten, bei Änderung ins RAM zurück, Register 
wiederherstellen.

Lokale Variablen (temporär): Register freimachen (push), verarbeiten, 
Register wiederherstellen (pop).


>
> mfg

...

von Wolfram Q. (quehl)


Lesenswert?

ich hab jetzt folgendes System rausgefunden:

Interrupts: verwendete Register vorrangig nach R2 und R3, sonst Push und 
pop.
Unterroutinen, die eine Funktion enthalten, push und pop, weil diese von 
verschiedenen Stellen aufgerufen werden können.
Unterroutinen, die nur zur Programmverkürzung erstellt wurden, benötigen 
keine Sicherung, da diese in einer Programmfunktion zusammengefaßt sind.
Aufgaben, deren Register am Ende nicht mehr benötigt werden, bekommen 
ein Push-Pop.
Register, die am Ende nicht mehr benötigt werden und in allen Aufgaben 
diese Funktion erfüllen, benötigen kein Push-Pop.
Aufgaben, deren Register am Ende weiter benötigt werden, kommen ins RAM.

das sind 6 verschiedene Möglichkeiten und nicht nur global und lokal.

Jetzt noch eine Frage zur Sourcenreihenfolge:

Bisher habe ich die folgende Reihenfolge verwendet:

Definitionen (.def und .equ)
Datensegment
Programmsegment
   Interrupts
   Flashprogrammierungszähler
   Initialisierung
   Mainloop
     Aufgabe1
     Aufgabe2
     u.s.w.
   Interruptprogramme
   Funktionale Unterprogramme

Ich neige jetzt dazu, folgende Änderungen vorzunehmen.

   Mainloop
     Aufgabe1
       Definitionen
       Hauptprogramm
         zugehörige Unterprogramme
         Interruptprogramm zu Aufgabe1
     Aufgabe2
       Definitionen
       Hauptprogramm
         zugehörige Unterprogramme
         Interruptprogramm zu Aufgabe
     u.s.w.
   Funktionale Unterprogramme, die von mehreren Aufgaben verwendet 
werden

kleiner Nachteil wäre hier, daß von einer Aufgabe zur nächsten mit RJMP 
gesprungen werden muß, was jetzt nicht der Fall ist. Der Vorteil wäre, 
daß fast alles, was zu einer Aufgabe gehört, zusammensteht. Man hat eine 
bessere Übersicht, was eine Aufgabe betrifft. Ob man auch die 
Initialisierung in die Aufgabe selbst bringen kann, weiß ich noch nicht. 
Zumindest Register und Ports wären denkbar. Möglicherweise auch die 
Peripherie. Es wäre dann eine zusätzliche Programmierung erforderlich.

Wie sind jetzt Eure Meinungen dazu?

mfg

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.