Forum: Mikrocontroller und Digitale Elektronik Interrupt-Routine ruft sich selber auf


von Alex (Gast)


Lesenswert?

Hallo,

Ich bin dabei gerade einen kleines Programm zu schreiben, und verwende
hierzu den Assembler.

Ich habe Interupt-Vektoren vergeben, die einen Timer den Compare-Wert
übergeben sollen, um eine Frequenz zu generiern.

Jedoch kommt mit steigender Frequenz der Timer-Interupt so oft, das er
sobald er fertig ist schon wieder aufgerufen wird.
In der Routine steht nur ein Befehl:

  Lad:
     out OCR1AL,temp
     reti

Dabei wird das restlich Programm garnichtmehr abgearbeitet und er
bleibt quasi in dieser Schleife hängen.

Was kann ich dagegen tun, daß das Programm nicht wegschmiert?

Könnt Ihr mir vielleicht helfen?
Liebe Grüsse Alex

von Benedikt (Gast)


Lesenswert?

Für was brauchst du beim Timer Compare einen Interrupt ? Es geht doch
auch ohne, mit Pin Toggle.

von Alex (Gast)


Lesenswert?

Hallo,

ich möchte immer wenn der Timer ( im CTC-Mode ) seinen Compare-Match
ausführt, also Rückgesetzt wird, einen OCR-Wert neu setzten.

Ich kenne leider PIN-Toggle nicht?
Muss ich Pin-toggle mit sbis abfragen?

Ich dachte mit nem Interupt sei es am besten, aber nun macht das solche
Probleme :-(

von thkais (Gast)


Lesenswert?

Wie oft muß denn tatsächlich der OCR-Wert aktualisiert werden? Wenn der
Interrupt wirklich so oft ausgeführt wird, muß der Wert im
temp-Register ja äußerst klein sein.
Möglichkeit 1: Aktualisierung des OCR im Hauptprogramm. Dann aber muß
der Zugriff synchronisiert werden, weil sonst der Timer "hustet". Ist
für sehr hohe Frequenzen nicht geeignet, da das Hauptprogramm auch zu
langsam ist.
Möglichkeit 2: Den Wert in "temp" begrenzen, so daß er einen
bestimmten Wert nicht unterschreitet.

von Rolf Magnus (Gast)


Lesenswert?

> Ich dachte mit nem Interupt sei es am besten, aber nun macht das
>  solche Probleme :-(

Nun, dein Prozessor hat eben eine betrenzte Rechengeschwindigkeit.
Daran kann auch die Verwendung von Interrupts nichts ändern. Sie
verschlimmert das Problem eher noch ein wenig, da die Ausführung einer
Interrupt-Routine selbst noch einen gewissen Overhead hat.
Was mir hier so einfällt sind nur die offensichtlichen Sachen (keine so
hohen Frequenzen erzeugen oder Prozessortakt erhöhen).

von Sandro (Gast)


Lesenswert?

disable doch einfach den interrupt, wärend die interrupt rutine läuft...
damit übersiehst du zwar einige intrrupts, doch scheller als der prozzi
ist kann er nicht rechnen...

von Pöschi (Gast)


Lesenswert?

Hi, Poste doch mal deinen Code, vieleicht ist ja was verkehrt. Hast du
den Stackpointer richtig Initialisiert, sonst kann es auch passieren,
das das Programm nach der Interruproutine nicht richtig weiter macht.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
erstmal danke für Eure Antworten.


Der Timer ist mit clk 1 (no prescaling) eingestellt, wobei der
Interne-Controller-Oszi auf 4MHz steht.

Der kleinste Compare-Wert sollte bei 50 liegen, da so eine Freqeunz von
ca. 40kHz entsteht, die ich brauche.

Ich möchte den OCR-Wert halt immer zum bestimmten Zeitpunkt laden,
nämlich dann, wenn der Timer gerade rückgesetzt geworden ist.
Da sonst ein "überzählen" des Timers vorkommen könnte.

Der Wert für den OCR wird dabei in einem zweiten Timer (T0) von 255
runtergezählt, sodaß eine definiert ansteigende Frequenz entsteht.

Es wäre aber egal wenn der OCR-Wert ein paar Matches (Toggles) später
aktualisiert wird, hauptsache er wird nach dem Rücksetzen gleich
geladen (wegen dem überzählen).

Vieln Dank nochmals
Alex

von Pöschi (Gast)


Lesenswert?

Hast du dein Programm mal im Simulator vom AVR-Studio laufen lassen?
Wenn nicht, dann mach das mal, da wirst du genau sehen wo er sich
verrennt. Die ganzen "reti's" die du am Anfang hast sollte man so
auch nicht schreiben, wenn überhaupt, dann ein reti pro Interrupt und
jedes Interrupt am besten mit .org [Interruptadresse].
Nochwas, was mir grad aufgefallen ist, ein "ret" oder "reti"
funktioniert nur mit "rcall" nicht mit "rjmp"

von Alex (Gast)


Lesenswert?

Natürlich debugge ich es,
jedoch ist es aufgrund der vielen Zählerei mit den Timern sehr sehr
aufwendig Schritt für Schritt das Programm zu analysieren.
Ich habe deswegen an allen Interrupt-Vektoren Breakpoints gesetzt, an
denen ich erkennen kann wo er hinspringen will.

Doch wenn ich feststelle, daß er zu Reset will, weiß ich aber nicht wo
er herkommt.

@Pöschi:
Deine Aussage mit den Retis an den Interruptadressen verwirrt mich. Ich
habe mehrfach gelesen, dases so gemacht werden soll.

Ich habe lediglich die nichtgebrauchten Interrupts mit reti versehen.
Und pro Interruptadresse habe ich auch jeweils nur ein Reti gesetzt.

Die Retis die im Programm auftauchen habe ich als Rücksprung für die
Interrups gedacht.
Da ich beim Interrupt in ein Unterprogramm springe, dort durch einen
Vergleich zweier Werte eine Verzweigung kommt, dann jenachdem also ein
anderes Unterprogramm mit rjmp oder branch..... angesprungen wird, und
wenn dieses durchgearbeitet ist kommt reti.

Ich will hiermit lediglich meine Auffassung darlegen um korrigiert
werden zu können.
Bitte tut das auch wenn ich falsch liege !

Grüße
Alex

von Rolf Magnus (Gast)


Lesenswert?

Die Ablaufstruktur deines Programms ist ziemlich konfus. So wird z.B.
deine Hauptschleife, die eigentlich ja schon nach der Initialisierung
anläuft, vom Timer1-Overflow immer wieder neu aufgerufen. Dann gibt's
rjmp und rcall kreuz und quer durch den Code, und es gibt kein einziges
ret im ganzen Programm.

von Andreas Hesse (Gast)


Lesenswert?

Hi,
braucht der Mega32 nicht jmp-Befehle anstatt rjmp Befehle bei den
Interrupts?

Ich schreibe immer für alle Interrupts einen jmp Befehl. Für die nicht
verwendeten definiere ich ein Label WrongInterupt, das dann irgendwas
macht (meistens einen RESET).

Gruss
Andreas

von Pöschi (Gast)


Lesenswert?

Hi,

Mal kurz ne erläuterung:
jmp: Sprung zur Adresse (belibige Adresse)
rjmp: Sprung relativ zur gegenwärtigen Adresse (+-2k Worte entfernt)

rcall: Aufruf eines Unterprogramms relativ zur gegenwärtigen Adresse
(auch +-2k Worte entfernt) vorherige Programmadresse wird auf dem Stack
abgelegt

ret: Rücksprung vom Unterprogramm auf die Adresse im Stack (adresse wo
der rcall Befehl stand)

reti: Rücksprung vom Interrupt und löschen des Interrupt Flag im Status
Register (Bei diesem Befehl wir normalerweise an die Stelle
zurückgesprungen wo der Interrupt ausgelöst wurde

Hier mal ein Beispie wie sowas bei mir aussieht
;Start
.CSEG
.ORG  0x00
  rjmp  init

.ORG  $016
  rjmp  rs232      ;RS232 Interupt

.ORG  $022
  rjmp  twi

init:
  ;Stack init
  ldi   temp,LOW(RAMEND)
  out    SPL,temp
  ldi    temp,HIGH(RAMEND)
  out    SPH,temp
        .
        .
        .

rs232:
        ;Code
        reti

Funktioniert einwandfrei auf diese Art. Die Interrupts die ich nicht
benötige lasse ich einfach weg, du kannst sowieso jedes Interrupt in
den jeweiligen Registern ein und aus schalten.

von Hannes L. (hannes)


Lesenswert?

Schau dir einfach mal im Datenblatt des Mega32 (und als Vergleich auch
in dem des Mega8535) die Interrupt-Vektortabelle an.

Aus Unterprogrammen springt man übrigens nicht mit reti zurück sondern
mit ret.

...

von Andreas Hesse (Gast)


Lesenswert?

Hi,

das mit org und rjmp funktioniert sicher, solange die Interruptroutine
im rjmp Sprungbreich liegt.
Ich gebe alle Interrupts an, damit ich eine definierte Reaktion bei
fälschlicherweise auftretenden Interrupts habe.

Gruss
Andreas

von Pöschi (Gast)


Lesenswert?

Bei mir sind noch keine falschen Interrupts aufgetreten, man schaltet ja
eigentlich nur die Interrupts ein, die man benötigt :-)

Ich würd das Programm trozdem mal durch den Simulator laufen lassen,
auch wenn es eine mühselige Arbeit ist.

von Hexel (Gast)


Lesenswert?

mal 'ne dumme Frage: löscht der Mega das Anforderungsflag beim
Interrupteintritt?

von Phlibi (Gast)


Lesenswert?

Jap.

von Harrtmut Grölger (Gast)


Lesenswert?

Hi

Deine Interruptvektoren am Programmanfang sinf falsch.
Wenn du es schon so machen willst muss es so aussehen:

.org 0x0

rjmp Reset
nop
reti
nop
reti
nop ...

ist aber die unsaubere Variante.
Wenn du sicher gehen willst übenimm den Aufbau aus dem Datenblatt.

MfG HG

von Peter D. (peda)


Lesenswert?

"Ich gebe alle Interrupts an, damit ich eine definierte Reaktion bei
fälschlicherweise auftretenden Interrupts habe."

Die Reaktion ist dann aber, daß Programmierfehler verschleiert werden.
Mit etwas Pech fallen sie erst dann auf, wenn schon viele Geräte beim
Kunden sind und zurückgerufen werden müssen.


Wenn Du einen definierte Reaktion haben willst, dann nimm eine, die
möglichst auffällig ist, z.B. eine Endlosschleife, die alle LEDs
blinken läßt.


Peter

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.