Atmega88pa - Absturz bei Timerinterrupt

Gast #2296117
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...
Gast #2296188
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.
Gast #2296504
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.
Gast #2296540
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
Persönliche Seite #2296543
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren