vielleicht kann mir jemand auf die Sprünge helfen. Derzeit simuliere ich einen ATTiny13A (default-Fuses) im AVR Studio 4.16.628 unter Linux mit Wine.
Dabei ist mir eine Anomalie aufgefallen, für die ich keine Erklärung habe.
Anbei voneinander nur leicht abweichende Assembler-Codes (die vielen Leerzeilen werden hier scheinbar vom Forums-Editor eingefügt, weiß nicht wo die herkommen. Im Original sind die nicht vorhanden).
Der eine nutzt drei Interrupts: einmal beim Match von OC0B im Timer0, dann beim Überlauf des Timers und als dritten den Watchdog in der Interrupt-only-Variante. Das funktioniert erst mal wie erwartet. Der OC0B-Match-Interrupt wird ausgelöst, danach der erste Timer-Überlauf. Der passende Interrupt wird auch hier ausgelöst und abgearbeitet - dann bleibt der Timer0 einfach auf Null stehen und das Programm verbleibt in der Endlosschleife, der Watchdog springt niemals an.
Darunter eine leicht abgewandelte Programmversion, die auf dem Vergleich OC0B verzichtet, alles andere ist gleich. Hier ein ähnliches Verhalten: Der erste Interrupt beim Timerüberlauf wird ausgelöst und abgearbeitet - der Timer bleibt auch jetzt bei Null stehen und läuft nicht mehr.
Allerdings funktioniert im Gegensatz zur ersten Variante jetzt der Watchdog, der wie erwartet etwa alle 32 simulierten Millisekunden auslöst.
Hat zufällig jemand eine Erklärung?
Variante A: Drei Interrupts
1
.nolist
2
.include "tn13adef.inc" ; Define device ATtiny13A
3
.list
4
.def sreg_bak = R15
5
.def rmp = R16
6
.dseg
7
.org SRAM_START
8
.cseg
9
.org 0x0000
10
rjmp Main ; Reset vector
11
reti ; INT0
12
reti ; PCI0
13
rcall isr_timer_overflow ; OVF0
14
reti ; ERDY
15
reti ; ACI
16
reti; OC0A
17
rcall isr_oc0b; OC0B
18
rcall isr_watchdog ; WDT
19
reti ; ADCC
20
21
init_watchdog:
22
wdr
23
in rmp, MCUSR
24
andi rmp, (0xff - (1<<WDRF))
25
out MCUSR, rmp
26
in rmp, WDTCR
27
ori rmp, (1<<WDTIE)|(1<<WDP0) ; Interrupt-only und prescaler 32ms
rcall isr_watchdog ; WDT
reti ; ADCC
mutet seltsam an, soll das nicht 'rjmp' heißen?
Habe ich mal getestet, scheint beides zu funktionieren. Aber nachdem auch im Tutorial überall rjmp verwendet wird, werde ich das künftig auch tun. Danke für den Hinweis.
Ansonsten hat sich leider nichts geändert - der Timer0 bleibt nach dem ersten Überlauf einfach stehen.
Kann ich mir nicht vorstellen - in der 1. Version zum Beispiel wird ja grundsätzlich nach isr_oc0b auch noch isr_watchdog abgearbeitet.
Ansonsten: Simulator & Interrupts - ob das immer funktioniert? Da gab es mal Beiträge ...
Und warum nicht der ATtiny85 - den könnte ich hier gegebenenfalls realiter laufen lassen.
Habe ich mal getestet, scheint beides zu funktionieren.
Nicht wirklich. Bei jedem Interrupt werden zwei Byte auf dem Stack "verbraucht". Ist nur eine Frage der Zahl der Interrupts, bis der Stack überlauft (bzw. eigentlich: unterläuft). Das sinnlose (und am Ende tödliche) Wachsen des Stack sollte sich im Simulator wirklich sehr gut verfolgen lassen.
Ansonsten hat sich leider nichts geändert - der Timer0 bleibt nach dem
ersten Überlauf einfach stehen.
Das kann nicht sein. Dem Timer ist der Stack egal, dem Timer ist überhaupt egal, was die MCU tut. Einmal gestartet, läuft der einfach. Es sei denn, die MCU hält ihn an. Dafür gibt es aber keinen Code.
Und übrigens: in deiner Variante A gibt es darüber hinaus auch keinen Code für isr_watchdog. Das dürfte also nichtmal assemblierbar sein...
Ansonsten: Simulator & Interrupts - ob das immer funktioniert?
Jedenfalls bezüglich der MCU habe ich beim SimulatorV2 noch nie Gegenteiliges feststellen können.
Bugs gibt es aber reichlich in der Simulation der Peripherie und auch Peripherie, die praktisch garnicht simuliert wird. Bei letzterem kann man natürlich ewig auf das Auftreten der entsprechende Interrupts warten. Es werden keine erfolgen...
Wie auch immer, das Entscheidende scheint mir zu sein, dass angeblich der Timer stoppt. Das tut er natürlich nicht. Weder in der Simulation noch in der Realität. Ich tippe mal auf einen Bedienfehler. Möglicherweise ausgelöst durch einen Anzeigefehler, der durch Wine verursacht wird.
Ich kann mich erinnern, dass ich auch mal versucht habe, das Studio4 unter Wine zu betreiben, das dann aber wegen extremer Anzeigefehler schon im Editor schnell wieder aufgegeben habe. Bis zum Einsatz des Simulators bin ich also unter Wine niemals gekommen.
Nicht im Simulator. Der kann Stack-Unterlauf diagnostizieren und hält dann an. Gibt aber natürlich dann auch eine ensprechende Fehlermeldung auf der Debugger-Console aus.
Nein, das meinte ich nicht, sondern: es gibt hier keinen Stack-Unterlauf
wo sollte der auch auftreten?
Es passiert folgendes:
IRQ:
SREG_I wird gelöscht
die Rücksprungadresse wird auf den Stack gelegt
der Vektor wird angesprungen
Vektor:
rcall legt legt erneut eine Rücksprungadresse auf den Stack
springt das angegebene Ziel an
Ziel (ISR):
-wird abgearbeitet
-endet mit reti (setzt SREG_I, holt 1x Rücksprungadresse vom Stack)
-das ist die vom (falschen) rcall gesetzte Rücksprungadresse
-führt effektiv dazu, das der nächste Vektor in der Reihenfolge der
Vektortabelle durchlaufen wird.
Und jetzt wird es spannend. Beim Overflow steht auf dem nächsten Vektor ein reti. Das holt die zweite Rücksprungadresse vom Stack (setzt das in diesem Fall bereits gesetzte SREG_I) und springt zur Rücksprungadresse. Alles gut hier, die Bilanz stimmt. Schwachsinn ist es trotzdem.
Aber, nun spiele mal selber durch, was bei OC0B passiert...
Mit V1 gehts auch nicht. Und das Interrupt-Flag wird verspätet gesetzt, zumindest in der Anzeige der IO Register, da läuft die ISR schon ;-)
Aber auch bei Prescaler 1 bleibt der Timer stehen. Ein Bug im AVR-Studio.
Mit V1 gehts auch nicht. Und das Interrupt-Flag wird verspätet gesetzt,
zumindest in der Anzeige der IO Register, da läuft die ISR schon ;-)
Aber auch bei Prescaler 1 bleibt der Timer stehen. Ein Bug im
AVR-Studio.
Der V1-Simulator ist ziemlicher Rotz. Der bildet nichtmal die MCU vollständig korrekt ab. Der V2 hingegen tut wenigstens dies, hat aber auch immer noch ziemliche Mankos bezüglich der Peripherie. Für einen Tiny13 sollte es aber eigentlich reichen, der hat ja nun nicht sehr viel an Peripherie und im konkreten Fall ist nur Timer0 und Watchdog involviert.
Aber klar: Ein Bug im Simulator wäre definitiv möglich. Kann man am einfachsten dadurch umgehen, dass man halt echte Hardware verwendet...
Zunächst mal vielen Dank für die Antworten.
Was ich daraus mitgenommen habe:
ISRs werden ab sofort nur noch per rjmp aufgerufen, nicht mehr per rcall.
Mehrzeilige Kommentare wie in z.B. c++ oder JavaScript möglich (wußte ich bei assembler tatsächlich noch nicht)
Der Timer-stop könnte tatsächlich ein Bug sein - ein extra Dank an die Tester. Ggf. kann ich das ja mit einem extra Timer-init im Interrupt im Quellcode "umgehen", mal schau'n.
Habe ich mal getestet, scheint beides zu funktionieren.
Als Assemblerprogrammierer sollte man schon die Bedeutung der einzelnen Befehle gelesen und verstanden haben. Sonst funktionieren Deine Programme nur zufällig bzw. meistens nicht.
Zwischen JMP und CALL besteht ein gewaltiger Unterschied.