Forum: Mikrocontroller und Digitale Elektronik Atmega88pa - Absturz bei Timerinterrupt


von Cyclon (Gast)


Lesenswert?

Moin,
ich habe hier ein kleines Problem mit meinem mega88pa.
In meinem Programm nutze ich alle 3 Timer. Doch egal bei welchem und 
egal ob Timer-Overflow oder Output-Compare, jedesmal wenn ein Interrupt 
ausgelöst werden soll, startet der µC neu. Allerdings nur bei 
Timer-Interrupts. Daher befürchte ich, habe ich dort nen Denkfehler 
drinnen.
Ich hab meinen Code schon auf ein Minimum reduziert, um evtl. 
Fehlerquellen auszuschließen. Vielleicht mag sich das einer von euch mal 
ansehen:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "uart.h"
4
5
6
ISR(TIMER2_OVF_vect) {
7
  TCCR2B = 0;
8
  sendData(1,1,1,0,0);
9
}
10
11
int main(void) {
12
  initUart(0);
13
  sei();
14
  sendData(0,0,0,0,0);
15
16
  TIMSK2 = (1<<TOIE2);
17
  TCCR2B = (1<<CS22) | (1<<CS20);
18
  while(1) {
19
  }
20
  return 0;
21
}

sendData überträgt mir Daten über nen RS485-Bus an den PC. Die Funktion 
arbeitet einwandfrei und kann als Fehlerquelle ausgeschlossen werden, 
daher habe ich sie nicht extra mit aufgeführt. Wenn ich den Timer 
deaktiviert lasse, werden die Daten des nach sei() kommenden sendData 
genau einmal übertragen, wie erwartet.
Stelle ich jedoch den Timer so ein, das er ein Interrupt generiert, 
bekomme ich die Daten im Takt des Interrupts. Das sendData in der ISR 
hingegen wird nie erreicht. Folglich wird die ISR nie ausgeführt und der 
µC resettet sich ständig.

Die Interrupt-Vektortabelle sieht für mich auch ok aus:
1
00001800 <__vectors>:
2
    1800:  19 c0         rjmp  .+50       ; 0x1834 <__ctors_end>
3
    1802:  28 c0         rjmp  .+80       ; 0x1854 <__bad_interrupt>
4
    1804:  27 c0         rjmp  .+78       ; 0x1854 <__bad_interrupt>
5
    1806:  26 c0         rjmp  .+76       ; 0x1854 <__bad_interrupt>
6
    1808:  25 c0         rjmp  .+74       ; 0x1854 <__bad_interrupt>
7
    180a:  24 c0         rjmp  .+72       ; 0x1854 <__bad_interrupt>
8
    180c:  23 c0         rjmp  .+70       ; 0x1854 <__bad_interrupt>
9
    180e:  22 c0         rjmp  .+68       ; 0x1854 <__bad_interrupt>
10
    1810:  21 c0         rjmp  .+66       ; 0x1854 <__bad_interrupt>
11
    1812:  35 c0         rjmp  .+106      ; 0x187e <__vector_9>
12
    1814:  1f c0         rjmp  .+62       ; 0x1854 <__bad_interrupt>
13
    1816:  1e c0         rjmp  .+60       ; 0x1854 <__bad_interrupt>
14
    1818:  1d c0         rjmp  .+58       ; 0x1854 <__bad_interrupt>
15
    181a:  1c c0         rjmp  .+56       ; 0x1854 <__bad_interrupt>
16
    181c:  1b c0         rjmp  .+54       ; 0x1854 <__bad_interrupt>
17
    181e:  1a c0         rjmp  .+52       ; 0x1854 <__bad_interrupt>
18
    1820:  19 c0         rjmp  .+50       ; 0x1854 <__bad_interrupt>
19
    1822:  18 c0         rjmp  .+48       ; 0x1854 <__bad_interrupt>
20
    1824:  17 c0         rjmp  .+46       ; 0x1854 <__bad_interrupt>
21
    1826:  16 c0         rjmp  .+44       ; 0x1854 <__bad_interrupt>
22
    1828:  15 c0         rjmp  .+42       ; 0x1854 <__bad_interrupt>
23
    182a:  14 c0         rjmp  .+40       ; 0x1854 <__bad_interrupt>
24
    182c:  13 c0         rjmp  .+38       ; 0x1854 <__bad_interrupt>
25
    182e:  12 c0         rjmp  .+36       ; 0x1854 <__bad_interrupt>
26
    1830:  11 c0         rjmp  .+34       ; 0x1854 <__bad_interrupt>
27
    1832:  10 c0         rjmp  .+32       ; 0x1854 <__bad_interrupt>

Hat jemand ne Idee, wo mein Fehler liegt?
Achja, mein Controller läuft mit 16Mhz auf 5V und im AvrStudio-Simulator 
scheint der Code ohne Probleme zu laufen...

von Frank L. (franklink)


Lesenswert?

Hallo,
wenn die Fehlerbeschreibung die du gepostet hast, tatsächlich so ist, 
wie Du beschreibst, würde ich den Fehler erstmal in sendData suchen, da 
anscheinend dort etwas nicht stimmt.

Gruß
Frank

von Uwe (de0508)


Lesenswert?

Was ist/ steht in uart.h und der uart.c ?

Wie sieht dein Makefile aus ?

Läuft evtl. noch eine Watch Doc Timer ?

von Uwe .. (uwegw)


Lesenswert?

Was passiert, wenn du in der ISR nicht senddata aufrufst, sondern z.B. 
nur eine LED blinken lässt?

von Cyclon (Gast)


Lesenswert?

uart.h
1
#ifndef UART_H_
2
#define UART_H_
3
4
#define UART_DIR_DDR  DDRD
5
#define UART_DIR_PORT  PORTD
6
#define UART_DIR_PIN  PD2
7
8
typedef void (*uartRxFnct) (uint8_t*,uint8_t);
9
10
void initUart(uartRxFnct rec);
11
void sendData(uint8_t dst, uint8_t src, uint8_t cmd, uint8_t size, uint8_t *data);
12
13
14
#endif /* UART_H_ */

uart.c
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "uart.h"
4
5
volatile uartRxFnct g_uartRxFnct;
6
7
void send(unsigned char c) {
8
  while( !(UCSR0A&(1<<UDRE0)) );
9
  UDR0 = c;
10
}
11
12
void sendData(uint8_t dst, uint8_t src, uint8_t cmd, uint8_t size, uint8_t *data) {
13
  uint8_t i=0;
14
  uint8_t crc = 0;
15
16
  UART_DIR_PORT |= (1<<UART_DIR_PIN);
17
  send('#');
18
  send(size+3);
19
  send(dst);
20
  send(src);
21
  send(cmd);
22
  for(;i<size;i++) {
23
    send(data[i]);
24
  }
25
  send(crc);
26
  while( !(UCSR0A&(1<<TXC0)) );
27
  UCSR0A = (1<<TXC0);
28
  UART_DIR_PORT &= ~(1<<UART_DIR_PIN);
29
}
30
31
32
void initUart(uartRxFnct rec) {
33
  // Configure direction pin for rs485 driver
34
  UART_DIR_PORT &= ~(1<<UART_DIR_PIN);
35
  UART_DIR_DDR |= (1<<UART_DIR_PIN);
36
37
  UBRR0L = 0x33;  // Set default baudrate to 19200
38
39
  UCSR0B = (1<<TXEN0);  // Enable transmitter
40
41
  g_uartRxFnct = rec;  // Set receive callback function
42
}

Makefile gibt's nicht, ist ein Eclipse Projekt mit AVRGCC-Plugin.

Watchdog ist nicht an.

Das mit der LED wird schwirig, da es sich um eine fertige Platine 
handelt, wo ich nicht einfach was anschließen kann. Aber evtl. könnte 
ich einen Eingang vom RS485 Receiver dafür missbrauchen.

von Stefan E. (sternst)


Lesenswert?

Cyclon schrieb:
> Die Interrupt-Vektortabelle sieht für mich auch ok aus:
1
00001800 <__vectors>:

Und wo in deinem Minimal-Code werden die Interrupt-Vektoren in den 
Bootloader-Bereich umgeschaltet?

von stru_aus (Gast)


Lesenswert?

mee..

zuerst dachte ich:
-falscher interrupt definiert, das problem hatte ich letztens kurz, dann 
springt der avr immer in einen reset.

aber dann kurz überflogen:
-in der ISR wird eine grosse funktion aufgerufen welche daten ausgibt - 
die wird ewig brauchen, während dessen kommen neue interuppts und 
schwupps ist der stack voll...

empfehlung: nie in einer ISR eine funktion aufrufen, statt dessen nur an 
volatile variablen schrauben.
die zu sendenden daten einfach in einen kleinen ringpuffer schieben, und 
den dann entweder per ISR oder in der main-schleife ausspucken.

von Oliver (Gast)


Lesenswert?

stru_aus schrieb:
> -in der ISR wird eine grosse funktion aufgerufen welche daten ausgibt -
> die wird ewig brauchen, während dessen kommen neue interuppts und
> schwupps ist der stack voll...

Alle AVR's blockieren per default weitere Interrupts beim Einsprung in 
eine ISR. Da läuft nix über.

Mit dem Problem desr "ewig dauernden" sendDAta in der ISR hast du zwar 
recht, das führt abe nicht zum o.a. Problem.

Ansonsten gefällt mir die Initialisierungsreihenfolge des Timers nicht.

Prinzipiell sollte man erst die Konfigurationsregister setzen, und dann 
per die Interrupts freigeben.

Stefan Ernst schrieb:
> Und wo in deinem Minimal-Code werden die Interrupt-Vektoren in den
> Bootloader-Bereich umgeschaltet?

Das sieht in der Tat seltsam aus.

Oliver

von Simon K. (simon) Benutzerseite


Lesenswert?

Ja, für ein normales Programm müssen die Vektoren natürlich an Adresse 0 
liegen. Oder du musst die Interruptvektoren in den Bootloader verlegen.

Dass man in einer ISR keine Funktionen aufrufen darf ist Mumpitz. Da 
darf man eigentlich so gut wie alles machen, was man auch woanders 
machen darf. Bei Atomizität (ATOMIC_BLOCK) und Race Conditions 
(volatile) muss man eben aufpassen.
Überlaufen bei langen Funktionen tut da auch nichts. Es gibt nur ein 
einziges Interruptflag für jeden Interrupt, das zum entsprechenden 
Zeitpunkt gesetzt wird. Und wenn alle Bedingungen erfüllt sind 
(Interrupt aktiviert, globale Interrupts aktiviert, nicht in einer 
aktiven ISR) wird das Flag gelöscht (in der Regel) und der Interrupt 
Vektor ausgeführt.
Wenn nicht, dann eben nicht.

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.