AVRStudio4 Simulation und Zeitschleifendarstellung

Oskar01

Mitglied
24. März 2008
267
0
16
Köln
Sprachen
  1. Assembler
Hallo,
Erfahrung mit AVR Studio 4 Simulation von Zeitschleifen in Assemblerprogrammen:

Mir fiel auf, dass erst bei Hex84 die Auto-Step-Funkion im Debugger die einzelnen Schritte zeigt, sonst läuft die Zeitschleifenanweisung einmal durch, es wird direkt, ohne Wiederholung auf den Befehl hinter dem rcall gesprungen.
Bestimmte Befehle hinter rcall-Anweisung werden nicht ausgeführt, es wird direkt wieder an den Anfang des Programms gesprungen.
Ein solcher ignorierter Befehl ist z. B. rol
Wird statt dessen auf ein Label verwiesen, wo dann dieser rol Befehl steht,
läuft der Debugger wie er sollte.

Zur Veranschaulichung habe ich noch die Zeitschleifen-Temporärregister auf Ports gelegt. Hier kann man dann schön sehen, wie und was sich beim Durchlauf der Schleifen verändert.

Assembler-Programm:

(Stapelzeiger-Einrichtungs-Routine vorausgesetzt)
Dann:

Ldi temp1, 0x84
Rcall Verzoegerung
Verzoegerung:
Ldi temp2, 0x84
Verzoegerung1:
Dec temp1
Out ddrb, temp1 ;nur zur Veranschaulichung
Out portb, temp1; was sich in der Zeitschleife tut
Cpi temp1,1
Brlt Verzoegerung
Ldi temp1, 0x84; noch mal aufladen, da sonst „negative Werte“in temp1
Dec temp2
Out ddrc, temp2; ditto kann hinterher entfallen
Out portc, temp2; ditto zur Veranschaulichung
Brlt Verzoegerung1
ret

Liege ich da richtig?

Es grüßt,
Oskar01
 
Hallo Oscar,

wenn du in diesen Programmteil "reinläufst", gibt es mit Sicherheit einen Absturz, bedingt durch einen Return mit nicht definiertem Stack-Inhalt.
  1. Du initialisierst zuerst die Zählvariable für die Zeitschleife, das ist ok
  2. danach rufst du die Routine Verzoegerung auf (rcall), das ist ok
  3. die Routine Verzoegerung wird ausgeführt und wird durch ret beendet, der Programmcounter wird damit auf die Adresse nach dem rcall gesetzt.
  4. die Routine Verzoegerung wird wieder ausgeführt und mit ret beendet.
  5. jetzt besteht aber das Problem, dass die Routine nicht mit rcall aufgerufen wurde, das heisst es wurde der Programmcounter nicht auf dem Stack gesichert. ret lädt nun den Programmcounter mit dem Stackinhalt, das entspricht einem Sprung zu der Adresse, welche sich im Stack befindet, die ist nicht definiert, das Programm stürzt ab.
Du müsstest hier so vorgehen:

Code:
   ldi temp1, 0x84
   rcall Verzoegerung

loop:
   ;* mach irgendwas
   rjmp loop

Verzoegerung:
...
ret
Mir fällt auch auf, dass du innerhalb der Routine Verzoegerung das Register DDRB laufend änderst, das macht eigentlich hier keinen Sinn, da du die Datenrichtung der Pins vom PortB ständig änderst.

Ein Beispiel einer Verzögerungsschleife in Assembler:
(1ms bei fosc=16MHz oder waren es 8MHz? ... hmmm, das wäre mal etwas zum Nachrechnen;))

Code:
Pause1ms:
   wdr                             ; Watchdog-Timer reset
 
   ldi TempReg1, 39
pause1ms_loop1: ldi TempReg2, 200  ; Schleife 3 : t3= (3+t2)*TempReg1
pause1ms_loop2: dec TempReg2       ; Schleife 2 : t2=2*TempReg2
   brne pause1ms_loop2             ; t3 = (3+2*TempReg2)*TempReg1

   dec TempReg1                    
   brne pause1ms_loop1  
   wdr                             ; Watchdog-Timer reset          
ret
Grüße,
Dirk
 
Hallo Dirk,
danke erstmal für prompte Antwort.

Nun, da ist mir beim Abtippen wieder mal ein kleiner Fehler unterlaufen.

Der Sprung erfolgt ja nicht wieder ins Label "Verzoegerung" sondern allesamt hinter dem brlt-Befehl nach "Verzoegerung1".

Die Sache mit dem Brlt Befehl ist ja die, daß er nur zusammen mit einem anderen definierten Befehl hier CPI also Compare-Befehl, hier auf die nächstfolgende Programmzeile, hier "Auftanken" von Register temp1 - Fortfahren im Programm springt, wenn das zu dekrementierende Register kleiner als 1, also Null wird.
Damit aber nicht wieder auf den Anfang gesprungen wird, solange diese Bedingung nicht erfüllt ist, wird auf ein hinter dem BRLT-Befehl stehendes Label verwiesen, in dem Falle also Verzoegerung1, nicht Verzoegerung, sonst würde sich das Register ja wieder auf den vollen Wert laden und die Schleife würde immer von vorne mit Subtrahieren zu tun haben. Von daher ein zweites Label ohne den "Nachladevorgang".
(Zu Beginn der zweiten Schleife soll dann aber der Ladewert des ersten Registers wieder vollgeladen werden.
Dieses Register wird ja dann im folgenden Befehl nicht dekrementiert sondern ein anderes (temp2). Ist das leer, sprich kleiner 1, dann erst return zum Hauptprogramm, so daß beide Schleifen sich also quasi wie Zähler verhalten, die sich "multiplizieren" in ihren Werten und nicht nur zwei Register, die nacheinander etwas Vorgegebenes abziehen.
Die Lade-Werte können nun auch variiert werden.)
Wenn man so will, bestimmt die "zweite" Schleife die Anzahl, wie oft die "erste" Schleife durchlaufen werden soll.


Nun nochmal zur eigentlichen Frage.
Der Simulator (Debugger) läßt bei "Auto-Step" den gelben Pfeil-Cursor so schööön rauf- und runterspringen bei den Schleifen. Aber erst bei "Ladewerten" ab etwa Hex90 oder - wie oben angegenen Hex84.
Wird ein niedrigererer Wert auch nur in einen Teil der Schleifen"register" eingegeben, läuft der Cursor einmal durch und springt dann an die Stelle zurück, wo der auf den recall-Befehl folgende stand und setzt dort das Programm fort.
Das ist doch eine Macke des Simulators. Wer konnte ähnliches berichten?

Gerade bei kleinen Zeitschleifen wäre es doch interessant zu erfahren, was zum Beispiel nach dem dritten Aufruf der Schleife passiert etc.,
255 x Schleifendurchlauf - Cursorspringen interresiert keinen, ja, führt zu argem Verdruß, da man keine halbe Stunde warten möchte.
Wer hat hier schon ähnliche Beobachtungen mit dem Debugger gemacht oder ist hier evtl. ein "Windows"-Problem hintergründig am Werkeln?




Also, das Ganze soll eine Art Lauflicht darstellen, aber nicht mit den Befehlen, die im STK500-Testprogramnm angegeben sind.
Zunächst kommt es auf die Zeitschleifen an.
Diese sollen auch nicht ständig durchlaufen werden, sondern irgendwie so, daß ich das noch einstellen kann, zum Beispiel, daß deren Durchlaufhäufigkeit noch variiert werden kann im Sinne einer Beschleunigung oder Verlangsamung.
(Soweit bin ich aber noch nicht-hi).



Dann ist die Darstellung der LEDs invertiert. Das heißt, eine Null im Programm läßt die LED leuchten.
Was im Klartext heißt, die Ausgabe muß invertiert werden, damit nur immer eine Leuchtdiode "rennt".
Dies erreiche ich dadurch, daß der Registerwert vor bzw. nach dem Rorate (rol) Befehl in ein anderes Register kopiert wird mit "mov", dann mit com invertiert wird und so zur Ausgabe gelangt.
Es ergab sich das weitere Problem, daß dann immer nur von Leuchtdiode 2 an das Lauflicht startete.
Und so weiter. Habe aber wohl IMHO ne passable Lösung dafür gefunden, siehe angehängtes "Prögchen" . Hier wird wieder Registerinhalt "verglichen" etc.

Also, werde den Quellcode mal hier reinstellen, momentan nicht im dem Kopf (Internetcafe) nur auf der heimischen Platte.

Bis dann

Gruß Oskar01

Es geht weiter:
Habe ein paar wichtige Screenshots zusammengezipt ( die 1,7 MB-großen bunten Bildchen mit Hilfe von Scannerbildbearbeitungssoftware in Schwarzweiß-PNGs umgemodelt).
Man sieht auch deutlich, daß die Register für die Serielle Schnittstelle aktiviert dargestellt werden, weil wohl Port D damit standardmäßig korreliert ist. Soll uns aber hier nicht weiter stören. Der Cursorpfeil steht auch oft an der Stelle, wo der vorausgegangene Befehl in der I/O-Darstellung erst nachklapperte. Also auch nicht weiter stören lassen dadurch.
Also mit F11 step by step durchgeorgelt, dann jeweils ein paar Screenshots. Video wäre zu lang, wills aber vielleicht auch mal probieren, bitte etwas Geduld.

So, hier nun das getestete "neue" Progrämmchen,
das ein Lauflicht darstellt, bei dem die LEDs zunächst etwas langsamer "links" geschoben, dann etwas schneller "rechts" geschoben werden.
Dabei gab es noch ein paar Problemchen zwischenzeitlich mit den Zeitschleifen, die nunmehr als drei Binärzähler hintereinander aufgestockt wurden.

Es ergab sich ein Aha-Effekt, insofern, daß von mir immer irrigerweise angenommen wurde, man könne im Assembler-Programmablauf ohne Sprungbefehl direkt auf die im Listing angegebene nächste Befehlszeile springen lassen, auch wenn dort ein Label vorangestellt ist, was Dirk oben auch schon erläutert hatte.
Das ist IMHO ein "alter" BASIC-Programmierer-Fehler. Da ich auch noch manchmal mit GWBASIC (Token) und QBASIC (editorbezogen) arbeitete, setzte ich ja den "linearen" Programmaufbau mit den fortlaufenden Listing-Nummern 100, 200, 300 etc. zugrunde.
Label ohne Listing-Adresse gibt's da ja dort nicht (jedenfall für den Anfänger so). Unterprogramme werden ja im klassischen BASIC- wie bekannt - etwa mit GOSUB etc. eingeleitet und mit RETURN abgeschlossen. Aber immer mit vorangestellter Absolutadresse im Listing. Da mußte ich erst ein bisschen umdenken.
 

Anhänge

  • Debug_01a.zip
    80,9 KB · Aufrufe: 5
  • Lauflicht.txt
    1,4 KB · Aufrufe: 5
  • Lauflicht2.txt
    2,9 KB · Aufrufe: 6
kleines Video vom Lauflicht

Hallo,
ok.Was mir noch auffiel, daß trotz relativ "großer" Zeitschleifen die LEDs bei OSCSEL "default" nur flimmerten. Wurde Jumper auf "Extern" gesetzt, läuft es so wie ich es mir gedacht hatte. (Fuses auf dem ATMega8515 sind auf externen Quarz und 64 ms Security-Gap eingerastet.)
Komisch. Oft auch die Meldung: "Reading flash FAILED" und "leaving programming mode FAILED". Obwohl das zu flashende Programm nach Power Reset hinterher einwandfrei lief. Dann auf einmal kam diese Meldung nicht mehr, ohne daß ich etwas von mir aus dazu beigetragen hätte, also "leaving programming mode OK". Nehme an, der Onboard-Oszillator ist, wie ich es auch schon mit dem Oszilloskop feststellen konnte, manchmal aus dem Soll-Takt.
Kann das damit zusammenhängen, daß vorher im Simulationstest sich was verstellt hatte? Eigentlich nicht, denn die Oszillatorfrequenzangabe im Studio4 Menü zeige korrekte Werte. Wenn sich diese verstellten, hatte ich sie ja korrigiert und "writen" lassen.
Auch wurden Fuses richtig ausgelesen. Nun ja, am Ende klappt es ja. (Habe diesmal kein 4-MHz-Quarz in die Board-Fassung gesteckt, lief auch so.)

http://www.kbra01.de/Lauflicht2.mpg

Schönen Sonntag noch
wünscht

Euer Oskar01
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)