mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrupt Problem


Autor: Carlos (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Mega32 hat 2 Words je Eintrag in der Sprungtabelle.

Meine Sprungtabelle sieht so aus:
.include "m32def.inc"   ;Namen für Systemkonstanten (I/Os, Bits...)

;(es folgen Vereinbarungen...)

.cseg       ;Code-Segment (Flash, Programmspeicher)
.org 0      ;Interrupt-Sprungtabelle ATmega32
 jmp RESET          ;Reset Handler
 jmp nix;EXT_INT0       ;IRQ0 Handler
 jmp nix;EXT_INT1       ;IRQ1 Handler
 jmp nix;EXT_INT2       ;IRQ2 Handler
 jmp nix;TIM2_COMP      ;Timer2 Compare Handler
 jmp nix;TIM2_OVF       ;Timer2 Overflow Handler
 jmp nix;TIM1_CAPT      ;Timer1 Capture Handler
 jmp nix;TIM1_COMPA     ;Timer1 CompareA Handler
 jmp nix;TIM1_COMPB     ;Timer1 CompareB Handler
 jmp nix;TIM1_OVF       ;Timer1 Overflow Handler
 jmp nix;TIM0_COMP      ;Timer0 Compare Handler
 jmp nix;TIM0_OVF       ;Timer0 Overflow Handler
 jmp nix;SPI_STC        ;SPI Transfer Complete Handler
 jmp nix;USART_RXC      ;USART RX Complete Handler
 jmp nix;USART_UDRE     ;UDR Empty Handler
 jmp nix;USART_TXC      ;USART TX Complete Handler
 jmp nix;ADCC           ;ADC Conversion Complete Handler
 jmp nix;EE_RDY         ;EEPROM Ready Handler
 jmp nix;ANA_COMP       ;Analog Comparator Handler
 jmp nix;TWI            ;Two-wire Serial Interface Handler
 jmp nix;SPM_RDY        ;Store Program Memory Ready Handler
nix: rjmp nix           ;Falle für falschen Interrupt-Aufruf
reset:

Bei den benutzten Vektoren wird das "nix;" entfernt.

...

Autor: Carlos (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: obake (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Carlos,

sieh mal in ""m32def.inc" nach, an welcher Adresse der Timer0 OVF Vektor 
stehen müsste!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In etwa so, wenn du die RETIs behalten willst:


#ifdef mym16
.ORG $000 ;RESET External Pin, Power-on Reset, Brown-out, Reset, Watchdog Reset, and JTAG AVR Reset
rjmp  start 
.ORG $002 ;INT0 External Interrupt Request 0
reti
.ORG $004 ;INT1 External Interrupt Request 1
reti
.ORG $006 ;TIMER2 COMP Timer/Counter2 Compare Match
reti
.ORG $008 ;TIMER2 OVF Timer/Counter2 Overflow
reti
.ORG $00A ;TIMER1 CAPT Timer/Counter1 Capture Event
reti
.ORG $00C ;TIMER1 COMPA Timer/Counter1 Compare Match A
reti
.ORG $00E ;TIMER1 COMPB Timer/Counter1 Compare Match B
reti
.ORG $010 ;TIMER1 OVF Timer/Counter1 Overflow
reti
.ORG $012 ;TIMER0 OVF Timer/Counter0 Overflow
;reti
rjmp Timer0Overflow
.ORG $014 ;SPI, STC Serial Transfer Complete
reti
.ORG $016 ;USART, RXC USART, Rx Complete
reti
.ORG $018 ;USART, UDRE USART Data Register Empty
reti
.ORG $01A ;USART, TXC USART, Tx Complete
reti
.ORG $01C ;ADC ADC Conversion Complete
reti
.ORG $01E ;EE_RDY EEPROM Ready
reti
.ORG $020 ;ANA_COMP Analog Comparator
reti
.ORG $022 ;TWI Two-wire Serial Interface
reti
.ORG $024 ;INT2 External Interrupt Request 2
reti
.ORG $026 ;TIMER0 COMP Timer/Counter0 Compare Match
reti
.ORG $028 ;SPM_RDY Store Program Memory Ready
reti
#endif ;mym16

#ifdef mym88
.ORG 0x000 ;RESET External Pin, Power-on Reset, Brown-out Reset and Watchdog System Reset
rjmp  start 
.ORG 0x001 ;INT0 External Interrupt Request 0
reti
.ORG 0x002 ;INT1 External Interrupt Request 1
reti
.ORG 0x003 ;PCINT0 Pin Change Interrupt Request 0
reti
.ORG 0x004 ;PCINT1 Pin Change Interrupt Request 1
reti
.ORG 0x005 ;PCINT2 Pin Change Interrupt Request 2
reti
.ORG 0x006 ;WDT Watchdog Time-out Interrupt
reti
.ORG 0x007 ;TIMER2 COMPA Timer/Counter2 Compare Match A
reti
.ORG 0x008 ;TIMER2 COMPB Timer/Counter2 Compare Match B
reti
.ORG 0x009 ;TIMER2 OVF Timer/Counter2 Overflow
reti
.ORG 0x00A ;TIMER1 CAPT Timer/Counter1 Capture Event
reti
.ORG 0x00B ;TIMER1 COMPA Timer/Counter1 Compare Match A
reti
.ORG 0x00C ;TIMER1 COMPB Timer/Coutner1 Compare Match B
reti
.ORG 0x00D ;TIMER1 OVF Timer/Counter1 Overflow
reti
.ORG 0x00E ;TIMER0 COMPA Timer/Counter0 Compare Match A
reti
.ORG 0x00F ;TIMER0 COMPB Timer/Counter0 Compare Match B
reti
.ORG 0x010 ;TIMER0 OVF Timer/Counter0 Overflow
rjmp Timer0Overflow
.ORG 0x011 ;SPI, STC SPI Serial Transfer Complete
reti
.ORG 0x012 ;USART, RX USART Rx Complete
reti
.ORG 0x013 ;USART, UDRE USART, Data Register Empty
reti
.ORG 0x014 ;USART, TX USART, Tx Complete
reti
#endif ;mym88

Autor: Carlos (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:

.include "m168def.inc"

        rjmp    init

.org    INT_VECTORS_SIZE        ; start after all interrupt vectors
init:
        nop
; place your init stuff, main loop and so on
; ...

; e.g. insert a SPM interruppt handler:
.set    curr_addr = PC
.org    SPMRaddr
        rjmp    SPM_handler     ; jump to handler
.org    curr_addr               ; restore address
SPM_handler:
;insert interrupt stuff here
        reti


Peter

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, das wäre mir (mir persönlich) zu unübersichtlich, ich habe es 
nicht so mit dem Abstrahieren...

...

Autor: Carlos (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.