Forum: Mikrocontroller und Digitale Elektronik Timer0 COMPA Bad interrupt


von Timer COMP (Gast)


Lesenswert?

Hallo liebe µC-Gemeinde,

so, falls ihr neben den anderen Post noch etwas Zeit habt, so künnt ihr 
mir sicherlich helfen und durch eine andere Brille schauen:

µC: AT90USB646 / 16MHz
HW: erfolgreich gestestet mit ext. beschalteten Schieberegistern i.O.

Problem:

Timer0 (oder auch TImer1) im CTC Modus entsprechend über Prescaler 
eingestellt und mittels Comparewert vergleichen.

So der kleine Code:
1
void init_Timer_1(void) 
2
{
3
  // für Atmega644:
4
   TCCR1B |= (1<<WGM12); // CTC Modus
5
   TCCR1B |= (1<<CS10); // CS11 == /8 CS10 /1  @ Compare 160 = 10µs
6
  OCR1A = 1250;        // Bestimmt die ton einer LED (1/256) 
7
  TIMSK1 |= (1<<OCIE1A);// Compare Interrupt erlauben
8
}
9
10
//aufruf ca. jede 40us (640) neue Übetragung starten
11
ISR (TIMER1_COMPA_vect)
12
{
13
  sf = 1;
14
}

Problem: In der xyz.lss wird immer
1
   4:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
gemeldet. Einen größeren Wert als 3500 (ist ja schließlich ein 16Bit) 
hängt den kompletten µC auf und es passiert gar nix mehr. Kann dies 
aussagen, da ich nebenbei auf dem HW-SPI Daten auf dem SPI ausgebe und 
erfolgreich (oder dann nicht mehr!) in das Schieberegister schiebe.

Daher: Habe ich wieder irgendwas übersehen, es scheint so, dass ich den 
IRQ nicht richtig initialisiere?... Den anderen Thread zu Presaclern 
(gerade aktuell) habe ich schon gelesen...

Vielen Dank

von Timer COMP (Gast)


Lesenswert?

Hi,

kann den mir keiner die schleier von den Augen nehmen?

Ich bin das DS zigmal durchgegangen und es ist nicht mein erster Timer.. 
Aber halt nur auf dem AT90USB

Danke

von Karl H. (kbuchegg)


Lesenswert?

Hast du den richtigen µC eingestellt?

von Karl H. (kbuchegg)


Lesenswert?

>    4:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>

4?
wen interessiert 4?
Der TIMER1_COMPA_vect ist der Vektor 17. Und der beginnt an
1
  44:  0c 94 74 00   jmp  0xe8  ; 0xe8 <__vector_17>


Testprogramm
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
uint8_t sf;
5
6
void init_Timer_1(void) 
7
{
8
  // für Atmega644:
9
   TCCR1B |= (1<<WGM12); // CTC Modus
10
   TCCR1B |= (1<<CS10); // CS11 == /8 CS10 /1  @ Compare 160 = 10µs
11
  OCR1A = 1250;        // Bestimmt die ton einer LED (1/256) 
12
  TIMSK1 |= (1<<OCIE1A);// Compare Interrupt erlauben
13
}
14
15
//aufruf ca. jede 40us (640) neue Übetragung starten
16
ISR (TIMER1_COMPA_vect)
17
{
18
  sf = 1;
19
}
20
21
int main()
22
{
23
  init_Timer_1();
24
25
  while( 1 ) {
26
  }
27
}
und Prozessor auf AT90USB646 eingestellt.

von Timer COMP (Gast)


Lesenswert?

Hallo für die Hilfe,

so habe das alles noch einmal durch den Compiler gejagt und jawohl die 
Sprungadresse
1
44:  0c 94 40 01   jmp  0x280  ; 0x280 <__vector_17>

(wie oben) gefunden.
Das Build zeigt die richtige Wahl des AT90USB646
1
avr-gcc.exe  -mmcu=at90usb646 -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT swmatrixsend.o -MF dep/swmatrixsend.o.d  -c  ../swmatrixsend.c

Allerdings ändert sich bei einem Wert > 3500 nix am Absturz des Systems, 
(der hat ja schließlich mehr Bitbreite.)

Zufällig bekannt, was das hier heißen mag: (auch wenn es ggf. nicht zum 
Thema gehört)
1
  0:  0c 94 4c 00   jmp  0x98  ; 0x98 <__ctors_end>
2
   4:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
3
   8:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
4
   c:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
5
  10:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
6
  14:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
7
  18:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
8
  1c:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
9
  20:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
10
  24:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
11
  28:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
12
  2c:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
13
  30:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
14
  34:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
15
  38:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
16
  3c:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
17
  40:  0c 94 69 00   jmp  0xd2  ; 0xd2 <__bad_interrupt>
18
  44:  0c 94 40 01   jmp  0x280  ; 0x280 <__vector_17>

Heißt das _bad_interrupt, dass die nicht genutzt werden? Oder wie kann 
ich das verstehen.

PS: Gute Seite: 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts#Die_Interruptvektoren. 
Demnach ist ja alles richtig geschrieben.

Was ich parallel noch an HW nutze ist die HW-SPI ohne nen IRQ
1
void init_SPI_hw(void)
2
{
3
DDRB |= (1<<PB4)|(1<<PB5) | (1<<PB7) | (1<<PB2) | (1<<PB0);   // Set MOSI , SCK , and SS output
4
SPCR |=  (1<<SPE)|(1<<MSTR)| (1<<CPHA)| (0<<SPR0) | (0<<SPR1) ;  // Enable SPI, Master, set clock rate fck/128  
5
SPSR |= (1<<SPI2X);
6
}

Danke!

von Timer COMP (Gast)


Lesenswert?

Aaah,

bei dem Code von dir (ohne meinen anderen Krempel)  wird auch das hier:

  44:  0c 94 74 00   jmp  0xe8  ; 0xe8 <__vector_17>

anstatt

 44:  0c 94 40 01   jmp  0x280  ; 0x280 <__vector_17>

erzeugt. Hmm, obwohl das Build doch den richtigen µC ausgewählt hat und 
in den Projekteinstellungen auch identisch und das Verify auch mit 
übereinstimmt

von Timer COMP (Gast)


Lesenswert?

Hi,

so nun habe ich den Code mal in ein neues frisches Projekt reingeladen 
und nun kann ich auch Werte im ganzen Bereich eingeben und den timer 
entsprechend nutzen.

Eine andere Frage hätte ich aber noch, wenn ich das noch "darf":

Wie verstehe ich die Meldungen zu dem  <__bad_interrupt> ?

und warum das vorher nicht auf den richtigen ISR_Vect compiliert wurde, 
obwol der µC korrekt ausgewählt wurde... WEr weiß das schon...

von (prx) A. K. (prx)


Lesenswert?

Timer COMP schrieb:

> Wie verstehe ich die Meldungen zu dem  <__bad_interrupt> ?

Interruptvektor ohne definertem Handler.

von Karl H. (kbuchegg)


Lesenswert?

Timer COMP schrieb:

> Wie verstehe ich die Meldungen zu dem  <__bad_interrupt> ?

__bad_interrupt
ist der Name des Default Interrupt Handlers, der immer dann angesprungen 
wird, wenn du zwar einen Interrupt freigegeben aber keine ISR dafür 
definiert hast. Und: dieser __bad_interrupt Handler resettet das System.


Insofern liegt die Vermutung nahe, dass du irgendwo einen Interrupt 
freigegeben hast, für den die keinen Handler hast.

von Timer COMP (Gast)


Lesenswert?

Hi, thx

Heißt das, das ich irgendwelche IRQ aktiviert habe, die keine ISR_vect 
haben? Allerdings doch nur bisher den Timer.

Oder heißt das, dass ich keine aktiviert habe, aber weil ich Sie nicht 
nutze der "nichtgebrauch" gemeldet wird?

PS: Ich habe hier mal gelesen, dass wenn die ISR fehlt, der µC 
automatisch immer an 0x00 springt und immer nen Reset ausführt. Wie kann 
ich das den so mitbekommen, der Resetpin ist doch "nur" nen Input?

von Timer COMP (Gast)


Lesenswert?

Hi,

danke euch beiden. Dann muss ich mal suchen gehen auf den ungenutzen 
IRQ... Wobei das ja argh viele sein müssen...

von Karl H. (kbuchegg)


Lesenswert?

Timer COMP schrieb:
> Hi,
>
> danke euch beiden. Dann muss ich mal suchen gehen auf den ungenutzen
> IRQ... Wobei das ja argh viele sein müssen...

Einer reicht.
Man gibt keinen Interrupt frei, für den es keinen Handler gibt.

Vielleicht hast du dich aber auch bei irgendeiner Einstellung vertan und 
ein Konfigurationsbit im falschen Register auf 1 gestellt, welches dann 
zufällig die Interruptfreigabe war.

von Timer COMP (Gast)


Lesenswert?

Japp,

aber ich habe neben dem o.g. Timer nur etwas bitshifterei IOs 
einschalten und die HW-SPI drinne:
1
void init_SPI_hw(void)
2
{
3
DDRB |= (1<<PB4)|(1<<PB5) | (1<<PB7) | (1<<PB2) | (1<<PB0);   // Set MOSI , SCK , and SS output
4
SPCR |=  (1<<SPE)|(1<<MSTR)| (1<<CPHA)| (0<<SPR0) | (0<<SPR1) ;  // Enable SPI, Master, set clock rate fck/128  
5
SPSR |= (1<<SPI2X);
6
}
7
8
void write_Byte_SPI_hw(unsigned char byte)
9
{
10
SPDR = byte;          //Load byte to Data register
11
while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete 
12
}
13
14
char read_Byte_SPI_hw(char addr)
15
{
16
  SPDR = addr;          //Load byte to Data register
17
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete 
18
  addr=SPDR;
19
  return addr;
20
}

Bit 7 – SPIE: SPI Interrupt Enable
This bit causes the SPI interrupt to be executed if SPIF bit in the SPSR 
Register is set and the if
the Global Interrupt Enable bit in SREG is set.
• Bit 6 – SPE: SPI Enable
When the SPE bit is written to one, the SPI is enabled. This bit must be 
set to enable any SPI
operations.

==> Demnach keinen IRQ dafür verwendet...


Naja, immerhin geht das nun für den Timer_COMPA_vect schonmal :-)

von Timer COMP (Gast)


Lesenswert?

Sorry liebe Helfer,

nun zurück zu den Sachen oben.

Ganz ganz jungfreudiges Projekt mit AT90USB646 und dem Code hier ohne 
alles:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
5
int main()
6
{
7
 
8
9
  while( 1 ) {
10
  }
11
}

erzeugt ebenfalls einen _bad_interrupt:
1
00000000 <__vectors>:
2
   0:  0c 94 4c 00   jmp  0x98  ; 0x98 <__ctors_end>
3
   4:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
4
   8:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
5
   c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
6
  10:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
7
  14:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
8
  18:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
9
  1c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
10
  20:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
11
  24:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
12
  28:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
13
  2c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
14
  30:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
15
  34:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
16
  38:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
17
  3c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
18
  40:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
19
  44:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
20
  48:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
21
  4c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
22
  50:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
23
  54:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
24
  58:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
25
  5c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
26
  60:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
27
  64:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
28
  68:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
29
  6c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
30
  70:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
31
  74:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
32
  78:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
33
  7c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
34
  80:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
35
  84:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
36
  88:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
37
  8c:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
38
  90:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>
39
  94:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>

Könnte das nen AVR GCC Fehler sein? GLaube ich aber kaum, bin ja nicht 
der erste mit dem µC..

von Karl H. (kbuchegg)


Lesenswert?

Timer COMP schrieb:
> Sorry liebe Helfer,
>
> nun zurück zu den Sachen oben.
>
> Ganz ganz jungfreudiges Projekt mit AT90USB646 und dem Code hier ohne
> alles:
>
>
1
> #include <avr/io.h>
2
> #include <avr/interrupt.h>
3
> 
4
> 
5
> int main()
6
> {
7
> 
8
> 
9
>   while( 1 ) {
10
>   }
11
> }
12
>
>
> erzeugt ebenfalls einen _bad_interrupt:

Logisch.
Du hast ja auch keine einzige eigene ISR, also sind alle ISR auf die 
__bad_interrupt Funktion gemappt.


> Könnte das nen AVR GCC Fehler sein? GLaube ich aber kaum, bin ja nicht
> der erste mit dem µC..

Definitiv nicht.
Bei der Art und Weise wie du fragst, kannst du davon ausgehen, dass du 
die nächsten 2 Jahre mit ziemlicher Sicherheit keinen Compiler-Fehler 
finden wirst. In 99% aller Fälle sitzt der Fehlerverursacher vor dem 
Bildschirm.

Lass doch mal den __bad_interrupt in Ruhe.
Wenn du Resets hast, die nicht sein sollten, dann hast du
* Glitches in der Spannungsversorgung
* Einen Reset-Eingang, der sich Störungen einfängt
* einen Interrupt freigegeben, für den es keine ISR gibt
* irgendwo den Stack zerschossen
* den falschen µC eingestellt
* den Watchdog freigegeben aber nicht gefüttert

Noch was? Im Moment fällt mir nichts mehr ein. Auf jeden Fall sind das 
die häufigsten Fälle und praktisch mehr als 99.9% aller derartigen 
Probleme lassen sich auf eines dieser 6 Probleme zurückführen, wobei die 
Sache mit der ISR der absolute Spitzenreiter ist.

von Timer COMP (Gast)


Lesenswert?

Hi,

also dann (wenn ich dreist nachfrage)

zu den Aussagen:

Vielleicht hast du dich aber auch bei irgendeiner Einstellung vertan und
ein Konfigurationsbit im falschen Register auf 1 gestellt, welches dann
zufällig die Interruptfreigabe war.

Also klar, dass kann immer sein, aber die Meldung _Bad_interrupt sagt 
dann aus:

Var a) IRQ aktiviert/ gesetzt aber keine ISR zum reinspringen gefunden
Var b) keine IRQs aktiviert, also keine ISRs eingetragen, also alles ok, 
obwohl die meldung erzeugt wird..

und ja, ich bekenne mich schuldig .-)

Thx

von Timer COMP (Gast)


Lesenswert?

hups, da war ich zu langsam, drucke mir die 6 Punkte sofort aus :-)

von Noname (Gast)


Lesenswert?

>Heißt das _bad_interrupt, dass die nicht genutzt werden? Oder wie kann
ich das verstehen.
>Wie verstehe ich die Meldungen zu dem  <__bad_interrupt> ?
>erzeugt ebenfalls einen _bad_interrupt:

Ich denke, das ist ein Missverständnis. Die Zeilen:
1
  94:  0c 94 56 00   jmp  0xac  ; 0xac <__bad_interrupt>

sind keine "Meldungen", auch keine "Fehlermeldungen".

Was Du dort anschaust ist der Assemblertext den der Compiler erzeugt. 
Also die Befehle die ausgeführt werden, falls und wenn ein Interrupt 
auftritt, für den Du keine Interrupt Service Routine geschrieben hast.

Die Tatsache alleine, das diese Assemblerbefehle (JMP) für nicht 
geschriebene Interrupt Service Routinenen erzeugt werden ist kein 
Hinweis auf einen Fehler. Vielmehr ist das eine "Feature", eine 
Eigenschaft die einen Nutzen hat (oder haben soll).

Zum einen kann man mit einem Breakpoint auf der __bad_interrupt routine 
überhaupt erkennen resp. debuggen für den Fall das man einen Interrupt 
aktiviert hat, für den es keine Interruptroutine gibt.

Zum anderen steht damit an den jeweiligen Stellen etwas Sinnvolles 
anstelle des FF FF FF FF nach dem löschen der Flash-Speicherseite. (Bin 
jetzt zu faul nachzugucken was das für ein Befehl wäre, wenn überhaupt).
Falls dann nämlich wieder ein Interrupt auftritt, der keine 
Interruptroutine hat, so würde er zwar etwas definiertes aber völlig 
zweckfreies machen, das man vermutlich nicht mal per Breakpoint abfangen 
kann.

von Timer COMP (Gast)


Lesenswert?

Super, danke! Sehr lehrreich. Auch an die User zuvor :-)

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.