Atmega128 - Wieder mal Probleme mit UART Interrupt

Gast #1228134
Lesenswert?

Hallo,

jetzt probier ich schon seit einigen Stunden Daten mittels dem 
USART0_RX_vect Interrupt zu empfangen, aber aus irgendeinen Grund wird 
die ISR anscheinend nie aufgerufen.
Daten Senden mittels USART0_UDRE_vect funktioniert ohne Probleme. Daten 
empfangen mittel Polling ebenfalls.

Hier mal der vereinfachte Code der nur überprüft ob die ISR aufgerufen 
wird.
Wenn ja, dann sollten sich 4 LEDs die am PortC hängen einschalten. Nach 
spätestens 4 sek sollen sich die LEDs aber auf jedenfall einschalten. 
Und da passiert jetzt was seltsames: Wenn ich im Hyperterminal nichts 
eingebe werden die LEDs nach 4 sekunden eingeschalten, aber wenn ich 
Daten sende, dann scheint das Programm abzustürzen, weil dann garnichts 
mehr passiert.
1
...
2

3
void uart_init()
4
{
5
  uint8_t sreg = SREG;
6

7
    UBRR0H = UBRR_VAL >> 8;
8
    UBRR0L = UBRR_VAL & 0xFF;
9

10
    // Interrupts kurz deaktivieren
11
    cli();
12

13
    // UART Receiver und Transmitter anschalten, Receive Interrupt setzen
14
    // Data mode 8N1, asynchron
15
    UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
16
    UCSR0C = (1<<UCSZ1) | (1<<UCSZ0);
17

18

19
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
20
    do
21
    {
22
        // UDR auslesen (Wert wird nicht verwendet)
23
        UDR0;
24
    }
25
    while (UCSR0A & (1 << RXC0));
26

27
    // Rücksetzen von Receive und Transmit Complete-Flags
28
    UCSR0A = (1 << RXC0) | (1 << TXC0);
29

30
    // Global Interrupt-Flag wieder herstellen
31
    SREG = sreg;
32
}
33

34
ISR(USART0_RX_vect)
35
{
36
    uint8_t sreg = SREG;
37
    cli();
38

39
    // LEDS einschalten
40
    DDRC = 0xFF;
41
    PORTC = 0b11110000;
42

43
    UDR0;
44

45
    SREG = sreg;
46
}
47

48
int main (void)
49
{
50
    sei();
51

52
    uart_init();
53

54
    // Nach 4 Sekunden sollen die LEDs auf jedenfall eingeschalten werden
55
    for(int i = 0; i< 4000; i++)
56
        _delay_ms(1);
57

58
    DDRC = 0xFF;
59
    PORTC = 0b11110000;
60
    while(1);
61

62
    return 0;
63
}

Sieht hier jemand einen Fehler? Kann das irgendwie mit AT103 
Kompatibilitätsmodus zusammenhängen? Oder liegts vielleicht sogar am 
Bootloader?.

Danke schon mal im vorraus,

Thomas
Gast #1228186
Lesenswert?

>BTW: Das RXC-Flag ist Read-Only. Das kann man mit
>> UCSR0A = (1 << RXC0) | (1 << TXC0);
>nicht löschen.

Ah ok, hab das von irgendeinem Musterbeispiel kopiert.

>Außerdem: Was soll diese Abfrage bewirken:
>> while (UCSR0A & (1 << RXC0));

Hab ich ebenfalls kopiert. Die Schleife läuft halt solangen das Receive 
Complete Flag gesetzt ist und liest solange UDR0 aus.

Weglassen der beiden Programmteile ändert leider auch nichts.
Meinst nicht das der Bootloader vielleicht an dem Problem schuld sein 
kann? Oder irgendeine Fuse?
#1228210
Lesenswert?

Thomas wrote:

> Hab ich ebenfalls kopiert. Die Schleife läuft halt solangen das Receive
> Complete Flag gesetzt ist und liest solange UDR0 aus.

Genau genommen, liest sie UDR0 immer mindestens 1mal aus.
1
  ...
2
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
3
    while (UCSR0A & (1 << RXC0))
4
        // UDR auslesen (Wert wird nicht verwendet)
5
        UDR0;
6
  ...
#1228222
Lesenswert?

Stefan Ernst wrote:
> Johannes M. wrote:
>
>> Die Schleife liest außer UCSR0A überhaupt nichts aus...
>
> Schau nochmal hin und beachte den do-Block davor.
Yep, hast natürlich Recht. Oben ging es mir nur um die Abfrage an sich, 
hab dann beim Weiterkopieren den Kontext nicht mehr mitgeschleppt...

Allerdings habe ich auf den zweiten Blick auch gesehen, dass die 
Schleife und die Abfrage doch für was gut sind...
Gast #1228223
Lesenswert?

> Schon möglich.

Komisch ist dabei, dass das die USART0_UDRE_vect Interrupt funktioniert 
und ich auch sonst noche keine Probleme hatte.

> Hast du denn die M103 Fuse verändert?
Nein, ich hab programmiere nur per USB. Siehe 
Beitrag "Programmvorstellung "CCPro-Loader" - natives C (ohne Interpreter) auf der C-Control Pro"
Mittels einem Programm was auf den MC läuft kann man die Fuses sicher 
nicht rücksetzen, oder? Würde dabei eigentlich auch der Bootloader 
entfernt werden? Ich nehm mal an schon, sonst könnte man den Lese-Fuse 
ja ganz einfach umgehen.
#1228229
Lesenswert?

Thomas wrote:

> Komisch ist dabei, dass das die USART0_UDRE_vect Interrupt funktioniert
> und ich auch sonst noche keine Probleme hatte.

Das wäre allerdings ein Indiz, dass die 103 Fuse richtig steht.
Steht die falsch, geht bereits der erste Funktionsaufruf in die Hose.
Bei deinen eigenen Funktionen könnte der Compiler per inline den 
Funktionsaufruf überflüssig gemacht haben. Aber bei einer ISR muss ein 
Aufruf erfolgen.

>> Hast du denn die M103 Fuse verändert?
> Nein, ich hab programmiere nur per USB. Siehe

LOL. Das hat damit nicht das geringste zu tun.
Die 103 Fuse sorgt dafür, dass sich ein Mega128 wie ein Mega103 verhält.
Blöderweise ist die per Default im Auslieferungszustand des Prozessors 
aktiviert.
Gast #1228241
Lesenswert?

>>> Hast du denn die M103 Fuse verändert?
>> Nein, ich hab programmiere nur per USB. Siehe

>LOL. Das hat damit nicht das geringste zu tun.
Wie soll ich den die Fuses verändert haben? Ich verwende weder ISP noch 
JTAG.

>Die 103 Fuse sorgt dafür, dass sich ein Mega128 wie ein Mega103 verhält.
Schon klar...
Gast #1228259
Lesenswert?

>Dreh hier auch mal die Reihenfolge um:

Danke für den Tipp, zumindest schalten sich die LEDs jetzt nach 4 
sekunden wieder ein. Aber auf eine gesendetes Zeichen wird noch immer 
nicht reagiert.

> Die Fuse fällt als mögliche Fehlerquelle also definitiv raus.
Hab ich mir auch schon gedacht. Dann kanns doch eigentlich nurmehr am 
Bootloader liegen, oder?
Gast #1228273
Lesenswert?

Es hat sich übrigens noch was geändert. Interessanterweise werden die 
LEDs erst 4 sekunden nach dem ich das letztes Zeichen im Hyperterminal 
eingegeben habe eingeschalten. Irgendwie scheint der MC doch auf das 
Interrupt zu reagieren.

Hier ist der aktuell Code:
1
void uart_init()
2
{
3
  uint8_t sreg = SREG;
4

5
    UBRR0H = UBRR_VAL >> 8;
6
    UBRR0L = UBRR_VAL & 0xFF;
7

8
    // Interrupts kurz deaktivieren
9
    cli();
10

11
  // Buffer initialisieren
12

13
    // UART Receiver und Transmitter anschalten
14
    // Data mode 8N1, asynchron
15
    UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
16
    UCSR0C = (1<<UCSZ1) | (1<<UCSZ0);
17

18

19
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
20
    do
21
    {
22
        // UDR auslesen (Wert wird nicht verwendet)
23
        UDR0;
24
    }
25
    while (UCSR0A & (1 << RXC0));
26

27
    // Rücksetzen von Receive und Transmit Complete-Flags
28
    //UCSR0A = (1 << RXC0) | (1 << TXC0);
29

30
    // Global Interrupt-Flag wieder herstellen
31
    SREG = sreg;
32
}
33

34
ISR(USART0_RX_vect)
35
{
36
  DDRC = 0xFF;
37
  PORTC = 0b11110000;
38

39
  UDR0;
40
}
41

42
int main (void)
43
{
44
  uart_init();
45
  sei();
46

47
  for(int i = 0; i< 4000; i++)
48
    _delay_ms(1);
49
  
50
  DDRC = 0xFF;
51
  PORTC = 0b11110000;
52
  while(1);
53

54
  return 0;
55
}
Gast #1228324
Lesenswert?

> Richtiger µC-Typ ist auch ganz sicher ausgewählt?
Das ist gar nicht so einfach zu beantworten. Laut beigelegten Datasheet 
ist da ein AT90CAN128 drinnen. Wenn ich den auswähle startet aber gar 
kein Programm mehr.
Mit normalen Atmega128 hat bis auf das eine Interrupt jetzt alles 
funktioniert.

> Ansonsten hätte ich keine Idee mehr.
Trotzdem danke für deine Mühe.
Gast #1228337
Lesenswert?

> Warum versucht man eigentlich Jemandem zu helfen, der sich beharrlich
> weigert, den ganzen Code zu posten?

He mal ruhig Blut, ich wollte nur nicht den Thread zumüllen und den Code 
auf die wichtigsten Teile beschränken. Keiner liest sich gerne durch zig 
Zeilen trivialen Code.
Aber bitte sehr:
1
#define F_CPU 14745600L
2

3
#define BAUD 38400L
4

5
// Berechnungen
6
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
7
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
8
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille
9
 
10
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
11
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
12
#endif
13

14
#include <avr/io.h>
15
#include <avr/interrupt.h>
16
#include <util/delay.h>
17

18
void uart_init()
19
{
20
  uint8_t sreg = SREG;
21

22
    UBRR0H = UBRR_VAL >> 8;
23
    UBRR0L = UBRR_VAL & 0xFF;
24

25
    // Interrupts kurz deaktivieren
26
    cli();
27

28
  // Buffer initialisieren
29

30
    // UART Receiver und Transmitter anschalten
31
    // Data mode 8N1, asynchron
32
    UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
33
    UCSR0C = (1<<UCSZ1) | (1<<UCSZ0);
34

35

36
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
37
    do
38
    {
39
        // UDR auslesen (Wert wird nicht verwendet)
40
        UDR0;
41
    }
42
    while (UCSR0A & (1 << RXC0));
43

44
    // Rücksetzen von Receive und Transmit Complete-Flags
45
    UCSR0A = (1 << RXC0) | (1 << TXC0);
46

47
    // Global Interrupt-Flag wieder herstellen
48
    SREG = sreg;
49
}
50

51
ISR(USART0_RX_vect)
52
{
53
  DDRC = 0xFF;
54
  PORTC = 0b11110000;
55

56
  UDR0;
57
}
58

59
int main (void)
60
{
61
  uart_init();
62
  sei();
63

64
  for(int i = 0; i< 4000; i++)
65
    _delay_ms(1);
66
  
67
  DDRC = 0xFF;
68
  PORTC = 0b11110000;
69
  while(1);
70

71
  return 0;
72
}
#1228345
Lesenswert?

Thomas wrote:
>> Richtiger µC-Typ ist auch ganz sicher ausgewählt?
> Das ist gar nicht so einfach zu beantworten. Laut beigelegten Datasheet
> ist da ein AT90CAN128 drinnen. Wenn ich den auswähle startet aber gar
> kein Programm mehr.

Also du musst schon genau wissen, welchen µC du da eigentlich 
programmierst. Bei AT90CAN128 und ATmega128 liegt der 
USART-RXC-Interrupt z.B. auf unterschiedlichen Vektoren. Und wenn der 
Vektor nicht stimmt, wird halt nach 0 gesprungen, das Programm also neu 
gestartet (was du ja auch beobachtet hast).

Wieso eigentlich CAN? War nicht von USB die Rede? Ist es nicht 
vielleicht doch ein AT90USB128?
#1228355
Lesenswert?

Thomas wrote:

> He mal ruhig Blut, ich wollte nur nicht den Thread zumüllen und den Code
> auf die wichtigsten Teile beschränken. Keiner liest sich gerne durch zig
> Zeilen trivialen Code.

Keiner liest sich aber auch durch 25 Postings mit jeweils einem 
nichtssagenden Code Schnipsel, nur um den Rest zu erraten.
Gast #1228360
Lesenswert?

> Also du musst schon genau wissen, welchen µC du da eigentlich
> programmierst. Bei AT90CAN128 und ATmega128 liegt der
> USART-RCX-Interrupt z.B. auf unterschiedlichen Vektoren.

Hab im Datenblatt schon nachgesehen, wenn es wirklich ein AT90CAN128 
wäre, würde auch USART0_UDRE_vect nicht funktionieren.

>Wieso eigentlich CAN? War nicht von USB die Rede? Ist es nicht
>vielleicht doch ein AT90USB128?

Hab nur gesagt, dass ich das Programm per USB und integrierten 
Bootloader raufspiele. Sry, hätt noch dazusagen soll, dass in dem 
Programmierkabel ein Rs232 Wandler drinnen ist. Es wird also eigentlich 
über UART programmiert.

>Grrrrrrrrr Lass endlich das SREG in Ruhe!
Sry, habs von der ISR raus, aber im Init noch vergessen.
Ändert aber auch nichts.
Gast #1228366
Lesenswert?

> Keiner liest sich aber auch durch 25 Postings mit jeweils einem
> nichtssagenden Code Schnipsel, nur um den Rest zu erraten.

Dieser nichtsagende Teil ist jener der nicht funktioniert. Und wenn man 
noch Information braucht, kann man nachfragen und muss nicht 
herummotzen.
Gast #1228454
Lesenswert?

Nachdem ich jetzt alle ISR's durchprobiert habe (auch BADISR_vect) und 
noch mal das Datenblatt studiert habe, gehe ich davon aus, dass Conrad 
das IVSEL Bit aktiviert hat, was bedeuted, dass die Interrupts in den 
Bootloader-Bereich abgelenkt werden. Da kann ich wohl nichts dagegen 
machen.

Danke noch mal alle die mitgeholfen haben.
Gast #1228469
Lesenswert?

>So so, und was ist dann damit:
>> Komisch ist dabei, dass das die USART0_UDRE_vect Interrupt funktioniert

Ich nehme an, dass bestimmte Interrupts vom Bootloader wieder umgeleitet 
werden.

> (ganz davon abgesehen, dass man das Bit auch wieder löschen könnte)
Ohne ISP oder JTAG? Echt? Wie?
#1228486
Lesenswert?

Thomas wrote:

> Ich nehme an, dass bestimmte Interrupts vom Bootloader wieder umgeleitet
> werden.

Ja stimmt, die unbenutzten könnten auf die "unteren" Vektoren 
weiterleiten.

>> (ganz davon abgesehen, dass man das Bit auch wieder löschen könnte)
> Ohne ISP oder JTAG? Echt? Wie?
Das ist keine Fuse. Das ist ein "normales" Bit, das zur Laufzeit 
modifiziert wird.

Datenblatt:
1
• Bit 1 – IVSEL: Interrupt Vector Select
2
When the IVSEL bit is cleared (zero), the interrupt vectors are placed at the start of the Flash
3
memory. When this bit is set (one), the interrupt vectors are moved to the beginning of the Boot
4
Loader section of the flash. The actual address of the start of the Boot Flash section is determined
5
by the BOOTSZ fuses. Refer to the section “Boot Loader Support – Read-While-Write
6
Self-Programming” on page 273 for details. To avoid unintentional changes of interrupt vector
7
tables, a special write procedure must be followed to change the IVSEL bit:
8
1. Write the Interrupt Vector Change Enable (IVCE) bit to one.
9
2. Within four cycles, write the desired value to IVSEL while writing a zero to IVCE.
10
Interrupts will automatically be disabled while this sequence is executed. Interrupts are disabled
11
in the cycle IVCE is set, and they remain disabled until after the instruction following the write to
12
IVSEL. If IVSEL is not written, interrupts remain disabled for four cycles. The I-bit in the Status
13
Register is unaffected by the automatic disabling.
Gast #1228512
Lesenswert?

>Das ist keine Fuse. Das ist ein "normales" Bit, das zur Laufzeit
>modifiziert wird.

Ah danke hab ich auch gerade gesehen.
Der Aufruf von:

MCUCR = (1<<IVCE);
MCUCR &= ~(1<<IVSEL);

vor dem Programmstart hat allerdings nichts gebracht. Der Fehler muss 
wohl doch woanders liegen. Komisch hab echt alle ISRs durchprobiert.

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