Hallo Leute, bei der Simulation unten angegebenen Programms habe ich ein Problem: innerhalb der loop schleife verweilt der µc bis der timer überläuft anstatt in den Interrupthandler zu springen, springt er in die dritte Zeile des maincodes!? dabei deaktiviert er I im statusregister und verändert den Stackpointer(08;5F) um eins(08;5D)). wenn er dann aber in Zeile vier geht verändert er den Stackpointer auf (01;5D) was wahrscheinlich der alte ion temp gespeicherte wert ist. Demnach führt er also kein reset aus, sondern springt beim interrupt einfach falsch. habt ihr eine Erklärung? Viele Grüße .include "m32def.inc" .def temp = r16 .def durchlauf=r17 .def ausgabe=r18 .def eingabe=r19 .def end_data=r20 .def temp2=r21 .org 0x000 ; kommt ganz an den Anfang des Speichers rjmp main ; Interruptvektoren überspringen ; und zum Hauptprogramm reti ; IRQ0 Handler reti ; IRQ1 Handler reti reti reti ; Timer1 Capture Handler reti ; Timer1 CompareA Handler reti ; Timer1 CompareB Handler reti ; Timer1 Overflow Handler rjmp TIM0_OVF ; Timer0 Overflow Handler reti ; SPI Transfer Complete Handler reti ; USART RX Complete Handler reti ; UDR Empty Handler reti ; USART TX Complete Handler reti ; ADC Conversion Complete Interrupthandler reti ; EEPROM Ready Handler reti ; Analog Comparator Handler reti ; Two-wire Serial Interface Handler reti ; SPM_RDY ;Speicherreservierung für Daten main: ldi temp, Low(RAMEND) ;Stackpointer Initialisieren out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ldi temp, 0b11111101 ;Port A: Pin1 ist Eingang, Pin0 ist Ausgang out DDRA, temp ;Rest ebenfalls als Ausgang ldi temp, 0b00000001 ; Prescaler von Timer0 auf eins gesetzt out TCCR0, temp ; ~4kHz bei 1MHz Systemtakt ldi temp, 0b00000001 ; TOIE0: Interrupt bei Timer Overflow out TIMSK, temp ;TIMSK=Timer Interrupt Mask Register erlaubt ;oder verbietet die jeweiligen Timerinterrupts ldi ZL, LOW(0x60) ;Beginn des Datenbereichs im SRAM ldi ZH, HIGH(0x60) ldi durchlauf,0b00000001 ldi eingabe,0b00000000 ldi ausgabe,0b00000000 ldi end_data,0b10111000 sei ; Alle Interrupts werden freigegeben loop: jmp loop TIM0_OVF: push temp ; Das SREG in temp sichern. Vorher in temp, SREG ; muss natürlich temp gesichert werden ldi temp2, 8 cpse durchlauf,temp2 ; wenn bit 8ist muss gespeichert und gelesen werden RJMP in_out ;relativer Sprung zu Datenein/-ausgabe LD ausgabe, Z ST Z+, eingabe cpse r30, end_data rjmp in_out ldi ZL,Low(0x60) ldi durchlauf, 0b00000001 ldi eingabe, 0b00000000 in_out: ldi temp2, 0b10000000 LSR eingabe sbic PINA ,1 add eingabe, temp2 SBRS ausgabe,0 ;skip if bit in register is set rjmp ausgabe_aus rjmp ausgabe_an ausgabe_aus: cBI PORTA,0 rjmp weiter ausgabe_an: SBI PortA, 0 weiter: LSR ausgabe inc durchlauf out SREG, temp ; Die Register SREG und temp wieder pop temp ; herstellen reti
Der Mega32 hat 2 Words je Eintrag in der Sprungtabelle. Meine Sprungtabelle sieht so aus:
1 | .include "m32def.inc" ;Namen für Systemkonstanten (I/Os, Bits...) |
2 | |
3 | ;(es folgen Vereinbarungen...) |
4 | |
5 | .cseg ;Code-Segment (Flash, Programmspeicher) |
6 | .org 0 ;Interrupt-Sprungtabelle ATmega32 |
7 | jmp RESET ;Reset Handler |
8 | jmp nix;EXT_INT0 ;IRQ0 Handler |
9 | jmp nix;EXT_INT1 ;IRQ1 Handler |
10 | jmp nix;EXT_INT2 ;IRQ2 Handler |
11 | jmp nix;TIM2_COMP ;Timer2 Compare Handler |
12 | jmp nix;TIM2_OVF ;Timer2 Overflow Handler |
13 | jmp nix;TIM1_CAPT ;Timer1 Capture Handler |
14 | jmp nix;TIM1_COMPA ;Timer1 CompareA Handler |
15 | jmp nix;TIM1_COMPB ;Timer1 CompareB Handler |
16 | jmp nix;TIM1_OVF ;Timer1 Overflow Handler |
17 | jmp nix;TIM0_COMP ;Timer0 Compare Handler |
18 | jmp nix;TIM0_OVF ;Timer0 Overflow Handler |
19 | jmp nix;SPI_STC ;SPI Transfer Complete Handler |
20 | jmp nix;USART_RXC ;USART RX Complete Handler |
21 | jmp nix;USART_UDRE ;UDR Empty Handler |
22 | jmp nix;USART_TXC ;USART TX Complete Handler |
23 | jmp nix;ADCC ;ADC Conversion Complete Handler |
24 | jmp nix;EE_RDY ;EEPROM Ready Handler |
25 | jmp nix;ANA_COMP ;Analog Comparator Handler |
26 | jmp nix;TWI ;Two-wire Serial Interface Handler |
27 | jmp nix;SPM_RDY ;Store Program Memory Ready Handler |
28 | nix: rjmp nix ;Falle für falschen Interrupt-Aufruf |
29 | reset: |
Bei den benutzten Vektoren wird das "nix;" entfernt. ...
aber dann bleiben verirrte interrupts doch auf immer und ewig bzw. bis der nächste interrupt kommt hängen!? Ist die Reihenfolge von code, Interrupttabelle wichtig? Ich kann trotz der schnellen Antwort meinen Fehler nicht erkennen. Viele Grüße
Hi Carlos, sieh mal in ""m32def.inc" nach, an welcher Adresse der Timer0 OVF Vektor stehen müsste!
Carlos wrote: > Ist die Reihenfolge von code, Interrupttabelle wichtig? Die Interrupt-Sprungadressen müssen an der richtigen Stelle im Programmspeicher stehen (nämlich an der entsprechenden Stelle in der Vektortabelle). Wo der restlichen Code steht ist wurscht, aber in Assembler sollte man tunlichst von oben nach unten programmieren, sonst gibt's Bruch. > Ich kann trotz der schnellen Antwort meinen Fehler nicht erkennen. In den AVRs mit bis 8 KiB Flash sind die Interrupt-Vektoren 16 Bit (ein Wort) breit. In ein Wort passt ein rjmp-Befehl rein, der bis 8 KiB adressieren kann (und damit den kompletten Speicher der betreffenden µCs). Bei allen AVRs, die mehr als 8 KiB Flash haben, kann man mit rjmp nicht mehr den kompletten Speicher adressieren, so dass es da den jmp-Befehl gibt. Der ist aber 32 Bit (2 Worte) lang, und dementsprechend sind auch die Vektoren 32 Bit breit, damit ein jmp reinpasst. reti ist aber auch nur 16 Bit breit und füllt deshalb die Vektoren nur halb aus. Der jeweils nächste reti bzw. rjmp steht dann an der falschen Stelle (zu weit vorne). Entweder wie vorgeschlagen aus nicht benutzten Vektoren in eine Auffangroutine springen oder vor jedes reti ein nop stellen, dann passt es. Oder mit der .org-Direktive arbeiten und die Adressen angeben. Am besten immer die Vektortabelle aus dem jeweiligen Datenblatt 1:1 übernehmen. Dann geht nichts schief.
In etwa so, wenn du die RETIs behalten willst:
1 | #ifdef mym16 |
2 | .ORG $000 ;RESET External Pin, Power-on Reset, Brown-out, Reset, Watchdog Reset, and JTAG AVR Reset |
3 | rjmp start |
4 | .ORG $002 ;INT0 External Interrupt Request 0 |
5 | reti |
6 | .ORG $004 ;INT1 External Interrupt Request 1 |
7 | reti |
8 | .ORG $006 ;TIMER2 COMP Timer/Counter2 Compare Match |
9 | reti |
10 | .ORG $008 ;TIMER2 OVF Timer/Counter2 Overflow |
11 | reti |
12 | .ORG $00A ;TIMER1 CAPT Timer/Counter1 Capture Event |
13 | reti |
14 | .ORG $00C ;TIMER1 COMPA Timer/Counter1 Compare Match A |
15 | reti |
16 | .ORG $00E ;TIMER1 COMPB Timer/Counter1 Compare Match B |
17 | reti |
18 | .ORG $010 ;TIMER1 OVF Timer/Counter1 Overflow |
19 | reti |
20 | .ORG $012 ;TIMER0 OVF Timer/Counter0 Overflow |
21 | ;reti |
22 | rjmp Timer0Overflow |
23 | .ORG $014 ;SPI, STC Serial Transfer Complete |
24 | reti |
25 | .ORG $016 ;USART, RXC USART, Rx Complete |
26 | reti |
27 | .ORG $018 ;USART, UDRE USART Data Register Empty |
28 | reti |
29 | .ORG $01A ;USART, TXC USART, Tx Complete |
30 | reti |
31 | .ORG $01C ;ADC ADC Conversion Complete |
32 | reti |
33 | .ORG $01E ;EE_RDY EEPROM Ready |
34 | reti |
35 | .ORG $020 ;ANA_COMP Analog Comparator |
36 | reti |
37 | .ORG $022 ;TWI Two-wire Serial Interface |
38 | reti |
39 | .ORG $024 ;INT2 External Interrupt Request 2 |
40 | reti |
41 | .ORG $026 ;TIMER0 COMP Timer/Counter0 Compare Match |
42 | reti |
43 | .ORG $028 ;SPM_RDY Store Program Memory Ready |
44 | reti |
45 | #endif ;mym16 |
46 | |
47 | #ifdef mym88 |
48 | .ORG 0x000 ;RESET External Pin, Power-on Reset, Brown-out Reset and Watchdog System Reset |
49 | rjmp start |
50 | .ORG 0x001 ;INT0 External Interrupt Request 0 |
51 | reti |
52 | .ORG 0x002 ;INT1 External Interrupt Request 1 |
53 | reti |
54 | .ORG 0x003 ;PCINT0 Pin Change Interrupt Request 0 |
55 | reti |
56 | .ORG 0x004 ;PCINT1 Pin Change Interrupt Request 1 |
57 | reti |
58 | .ORG 0x005 ;PCINT2 Pin Change Interrupt Request 2 |
59 | reti |
60 | .ORG 0x006 ;WDT Watchdog Time-out Interrupt |
61 | reti |
62 | .ORG 0x007 ;TIMER2 COMPA Timer/Counter2 Compare Match A |
63 | reti |
64 | .ORG 0x008 ;TIMER2 COMPB Timer/Counter2 Compare Match B |
65 | reti |
66 | .ORG 0x009 ;TIMER2 OVF Timer/Counter2 Overflow |
67 | reti |
68 | .ORG 0x00A ;TIMER1 CAPT Timer/Counter1 Capture Event |
69 | reti |
70 | .ORG 0x00B ;TIMER1 COMPA Timer/Counter1 Compare Match A |
71 | reti |
72 | .ORG 0x00C ;TIMER1 COMPB Timer/Coutner1 Compare Match B |
73 | reti |
74 | .ORG 0x00D ;TIMER1 OVF Timer/Counter1 Overflow |
75 | reti |
76 | .ORG 0x00E ;TIMER0 COMPA Timer/Counter0 Compare Match A |
77 | reti |
78 | .ORG 0x00F ;TIMER0 COMPB Timer/Counter0 Compare Match B |
79 | reti |
80 | .ORG 0x010 ;TIMER0 OVF Timer/Counter0 Overflow |
81 | rjmp Timer0Overflow |
82 | .ORG 0x011 ;SPI, STC SPI Serial Transfer Complete |
83 | reti |
84 | .ORG 0x012 ;USART, RX USART Rx Complete |
85 | reti |
86 | .ORG 0x013 ;USART, UDRE USART, Data Register Empty |
87 | reti |
88 | .ORG 0x014 ;USART, TX USART, Tx Complete |
89 | reti |
90 | #endif ;mym88 |
Leute, ihr seid der Hammer! Vielen Dank! Hatte die Interruptvektoren aus dem Tutorial entnommen und mir keine Gedanken darüber gemacht, dass die unterschiedlich breiten Befehle die gute Ordnung kaputtmachen. Jetzt klappts! Besten Dank nochmal Carlos
Carlos wrote: > aber dann bleiben verirrte interrupts doch auf immer und ewig bzw. bis > der nächste interrupt kommt hängen!? Das ist ja auch der Zweck der Übung. Ein "verirrter Interrupt" ist ein schwerer Programmierfehler, den ich in die Endlosschleife schicke, damit ich ihn erkenne. Selbstverständlich kannst Du da auch ein "reti" platzieren, doch dann besteht halt die Möglichkeit, solche Fehler zu übersehen. > > Ist die Reihenfolge von code, Interrupttabelle wichtig? > Ich kann trotz der schnellen Antwort meinen Fehler nicht erkennen. > Siehe die anderen Antworten... > > Viele Grüße Dito, Bit- & Bytebruch, Hannes
Carlos wrote: > aber dann bleiben verirrte interrupts doch auf immer und ewig bzw. bis > der nächste interrupt kommt hängen!? Du kannst ja in der Routine noch ne LED togglen lassen, damit Du merkst, daß Du einen Programmierfehler gemacht hast. > Ist die Reihenfolge von code, Interrupttabelle wichtig? Nein, sie ist im Quelltext völlig wurscht. Durch die Vektordefinitionen in Deinem Include sicherst Du ja ab, daß im Hexfile alles an seinen richtigen Platz landet (man muß die Definitionen natürlich auch benutzen). Ich schreibe daher die Interrupts genau dahin, wo sie behandelt werden:
1 | .include "m168def.inc" |
2 | |
3 | rjmp init |
4 | |
5 | .org INT_VECTORS_SIZE ; start after all interrupt vectors |
6 | init: |
7 | nop |
8 | ; place your init stuff, main loop and so on |
9 | ; ... |
10 | |
11 | ; e.g. insert a SPM interruppt handler: |
12 | .set curr_addr = PC |
13 | .org SPMRaddr |
14 | rjmp SPM_handler ; jump to handler |
15 | .org curr_addr ; restore address |
16 | SPM_handler: |
17 | ;insert interrupt stuff here |
18 | reti |
Peter
Sorry, das wäre mir (mir persönlich) zu unübersichtlich, ich habe es nicht so mit dem Abstrahieren... ...
Jeder einzelne Interrupt muss ja ausser mit sei nochmal einzeln aktiviert werden, daher sollte, sofern man das nicht getan hat ja eigentlich keiner auftreten können!? Auf alle Fälle funktioniert es jetzt - zumindest in der Simulation. Nochmal Danke, habe eine weitere Frage, aber die werde ich passenderweise in einem neuen Thread stellen: "Asynchrones Signal einlesen" Viele Grüße Carlos
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.