Forum: Compiler & IDEs ATmega16 startet von allein neu?


von AVRli (Gast)


Lesenswert?

Hallo,

ich habe nun twas erfahrung mit den ATmegas. Habe das Problem noch nie 
gehabt und frage mich von daher was das nun sein soll.

- Programmspeicher ist zu 80% gefüllt
- SRAM zu 60% voll
- Watchdog ist aus
- CKOPT is nicht gesetzt

Ich habe die Möglichkeit zur Zeit mit einem JTAG MK-II "in den Speicher" 
zu sehen und auch die Möglichkeit damit einen Breaakpoint unmittelbar 
nach dem Programmstart abzufragen.

Aus freien Stücken wird ein Reset ausgelöst, warum weiß ich allerdings 
absolut nicht.

Alle Variablen die einen Interrupt/Main Zugriff haben sind volatile und 
die Variablen die breiter as 8-Bit sind werden im Main Programm nur über 
ATOMIC Abschnitte eingelesen.

Das ganze tritt sporadisch auf, manchmal geht es über Minuten gut 
manchmal nur 20 Sekunden. Berechnungen finden nicht statt also so was 
wie Division durch 0.

Nun würde mich interessieren wie ich der Sache auf den Grund gehen kann.

Für jeden Tip wirklich sehr dankbar.

Grüße AVRli...

von Karl H. (kbuchegg)


Lesenswert?

AVRli schrieb:

> Das ganze tritt sporadisch auf, manchmal geht es über Minuten gut
> manchmal nur 20 Sekunden.

Kurze Zwischenfrage.
Hast du dieses Problem vor ein paar Wochen schon mal gepostet?

>
> Nun würde mich interessieren wie ich der Sache auf den Grund gehen kann.

Alle freigegebenen Interrupts abklappern und nachsehen ob es dafür eine 
ISR gibt.
Das ist so ziemlich die Software-Hauptursache Nummero Uno

Dann Spannungsversorgung überprüfen.
Sind Spikes drauf? Sind die Versorgungsspannungspins des µC sauber 
abgeblockt?

Reset-Pin. Kleinen Kondensator nach Masse schalten.

von Uwe .. (uwegw)


Lesenswert?

Die letzte Reset-Quelle ist in MCUCSR abfragbar. Was ist dort nach einem 
Reset zu finden?

von g457 (Gast)


Lesenswert?

> Alle freigegebenen Interrupts abklappern und nachsehen ob es dafür eine
> ISR gibt.

Ergänzend dazu kann man (abhängig von der libc/dem Compiler/..) den 
BADISR_vect implementieren, der dann z.B. (ein-eindeutig erkennbar) an 
einer Status-LED blinkt. Spart auch später graue Haare :-)

von AVRli (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Kurze Zwischenfrage.
> Hast du dieses Problem vor ein paar Wochen schon mal gepostet?

Ich hoffe doch nicht! :-)

Uwe ... schrieb:
> Die letzte Reset-Quelle ist in MCUCSR abfragbar. Was ist dort nach einem
> Reset zu finden?

Alle Bits gelöscht... dazu ist zu sagen ich starte das Programm mit dem 
JTAG und AVR Studio dann kommt der Startbreakpoint und da setze ich alle 
Bits dann manuell zurück, wenn der erneute RESET kommt stehen immer noch 
alle Bit's auf 0.

g457 schrieb:
> Ergänzend dazu kann man (abhängig von der libc/dem Compiler/..) den
> BADISR_vect implementieren,

Gute Idee, ich habe mir da mal bewusst eine Endlosschleife eingebaut, 
mal sehen was da kommt.


Ich suche weiter...

von AVRli (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mein Programm nun nochmal minimiert um zu sehen wo der RESET 
ausgelöst wird. So wie es aussieht stimmt was mit der UART Geschichte 
nicht... :-(

BAD_ISR wird nicht angesprungen, und die Reset Flags bleiben alle auf 0.

Ihr findet das Programm im Anhang, ich würde mich freuen wenn jemand mal 
einen Blick drauf werfen könnte und mir verraten kann was ich da falsch 
mache.

Es geht nur darum das Daten empfangen werden sollen. Und wenn ich da mal 
richtig Gas gebe auf der PC Seite dann gibt es diesen RESET.

Die einzelnen Kommandos haben ca. 10 Byte, ich habe die Buffer auf 128 
Byte gesetzt damit nichts verloren geht wenn mal ein paar schnell 
hintereinander kommen.

MfG AVRli...

von Karl H. (kbuchegg)


Lesenswert?

1
#define INC_OVERLAPED( x, max )  x = ++x >= max ? 0 : x
2
#define DEC_TO_ZERO( x )    x > 0 ? x-- : x

das geht so nicht.
Du kannst nicht in einem Statement gleichzeitig eine Variable mittels ++ 
oder -- verändern UND eine Zuweisung an diese Variable haben. In einem 
Statement ist nur eine Veränderung einer Variablen erlaubt. Alles andere 
führt zu undefiniertem Verhalten.

Diese Dinge kann man zwar in einem Makro machen, aber eine Funktion wäre 
besser dafür gewesen.
1
uint8_t IncOverlapped( uint8_t i, uint8_t max )
2
{
3
  ++i;
4
5
  if( i < max )
6
    return i;
7
8
  return 0;
9
}

und du bist einen Haufen Probleme los, von denen du noch gar nicht 
weißt, dass sie existieren.

Selbiges für DEC_TO_ZERO( x )

Generell solltest du um Makros, bei denen das MAkroargument mehrmals 
benutzt wird, immer einen großen Bogen machen. Das ist es einfach nicht 
wert und Inline Funktionen sind genauso effizient, haben aber die 
Probleme nicht.

von Karl H. (kbuchegg)


Lesenswert?

Für den Rest.
Ob deine Interrupt Freigabe/Löschen so stimmt, bzw ob die Bufferzugriffe 
alle stimmen, bin ich mir noch nicht im klaren.

Aber das ++ Problem ist so schwerwiegend, dass man es erst einmal 
beheben sollte, ehe man weitersieht.

von AVRli (Gast)


Lesenswert?

Das es so schlimm aussieht das man gar nicht weiß wo man anfangen soll 
hätte ich ja nun auch nicht erwartet... :-(

Das mit dem MAKRO habe ich aus der Codesammlung, da wurde das bei einem 
UART Buffer auch so gemacht. Das ist ja echt ein Ding.

habe nun die Zeilen an den 3 Stellen mal ausgeschrieben...
1
ISR(USART_RXC_vect) {
2
...
3
i++;
4
if (i >= UART_RX_ISR_BUFFER_SIZE) i=0;
5
...
6
}
7
8
show_uart_data{
9
...
10
pos_uart_read++;
11
if (pos_uart_read >= UART_RX_READ_BUFFER_SIZE) pos_uart_read=0;
12
...
13
pos_read_uart_rx++;
14
if (pos_read_uart_rx >= UART_RX_ISR_BUFFER_SIZE) pos_read_uart_rx=0;
15
...
16
}

Gleiches Verhalten mit RESET, ist als wohl auch falsch... :-(

von Karl H. (kbuchegg)


Lesenswert?

AVRli schrieb:

> Das mit dem MAKRO habe ich aus der Codesammlung, da wurde das bei einem
> UART Buffer auch so gemacht. Das ist ja echt ein Ding.

Wann immer du so etwas

   i = ++i;

oder Variationen davon siehst, kannst du sofort und ungesehen zu heulen 
anfangen.

Es ist nicht definiert, wann denn das Ergebnis vom ++ in die Variable 
zurückgeschrieben wird. Weder bei Postinkrement noch beim Preinkrement. 
Wenn der Compiler beschliesst, den erhöhten Wert nach der Zuweisung in 
die Variable zurückzuschreiben, dann ist die Zuweisung flöten gegangen.
Alles was definiert ist, ist dass der erhöhte Wert mit dem Ereichen des 
Sequence Points (hier der ;) in der Variablen gelandet sein muss. Aber 
wann genau - das darf sich der Compiler aussuchen.

> Gleiches Verhalten mit RESET, ist als wohl auch falsch... :-(

Das muss jetzt noch nicht dein eigentliches Problem sein. Aber es ist 
zumindest mal eine Problemstelle.

von AVRli (Gast)


Lesenswert?

Ok noch einmal zur meiner Sicherheit...
1
pos_uart_read++;
2
if (pos_uart_read >= UART_RX_READ_BUFFER_SIZE-1) pos_uart_read=0;

ist aber schon ok und definiert?

Er darf natürlich jetzt nur bis BUFFER_SIZE-1 zählen ist mir gerade 
aufgefallen.

Test steht noch aus...

von Hc Z. (mizch)


Lesenswert?

Karl heinz Buchegger schrieb:
> Wann immer du so etwas
>
>    i = ++i;
>
> oder Variationen davon siehst, kannst du sofort und ungesehen zu heulen
> anfangen.
>
> Es ist nicht definiert, wann denn das Ergebnis vom ++ in die Variable
> zurückgeschrieben wird.

Einverstanden.  Ich begge aber zu differn, was
1
 x = ++x >= max ? 0 : x
anbelangt, denn darauf ist das nicht übertragbar (obwohl es ähnlich 
aussieht).  Denn:  Hier ist nach dem ++x ein Sequence Point (das „?“). 
Somit ist das Schreiben von (x+1) nach x abgeschlossen, bevor entweder 0 
oder x ausgewertet wird und an x zugewiesen wird.  Somit ist das 
Ergebnis eindeutig entweder 0 oder x+1.

von Torsten K. (ago)


Lesenswert?

Hc Zimmerer schrieb:
> x = ++x >= max ? 0 : x
> anbelangt, denn darauf ist das nicht übertragbar (obwohl es ähnlich
> aussieht).  Jedoch:  Hier ist nach dem ++x ein Sequence Point (das „?“).
> Somit ist das Schreiben von (x+1) nach x abgeschlossen, bevor entweder 0
> oder x ausgewertet wird und an x zugewiesen wird.  Somit ist das
> Ergebnis eindeutig entweder 0 oder x+1.

Nein. Gerade der Letzte Punkt "0 : x" -> Hier kannst du nicht davon 
ausgehen, ob x AN DIESER STELLE nun "x" oder "x+1" ist. Die komplette 
Zeile gehört zum sequence point, somit kann der Ausdruck "0 : x" vorher 
berechnet sein, bevor ++x ausgeführt wird.

Also: genauso wie "x = ++x" "undefiniert" ist, so ist x in der 
kompletten Zeile (bis zum sequence point) möglicherweise falsch. Das 
kann sogar mit einer Compilergeneration funktionieren, mit einem 
Nachfolger dann nicht mehr. Undefiniertes Verhalten :)

von Hc Z. (mizch)


Lesenswert?

Torsten K. schrieb:
> Nein. Gerade der Letzte Punkt "0 : x" -> Hier kannst du nicht davon
> ausgehen, ob x nun "x" oder "x+1" ist. Die komplette Zeile gehört zum
> Sequence point

Nein.  Da ist noch ein Sequence Point (wie oben geschrieben, das „?“) 
dazwischen.  Der Teil links davon ist also abgeschlossen, bevor der Teil 
rechts drankommt (für den x bereits den neuen Wert hat).  Und nur 0 oder 
der neue Wert werden letztendlich zugewiesen.

von (G)Ast (Gast)


Lesenswert?

AVRli schrieb:
> Ok noch einmal zur meiner Sicherheit...
> pos_uart_read++;
> if (pos_uart_read >= UART_RX_READ_BUFFER_SIZE-1) pos_uart_read=0;
>
> ist aber schon ok und definiert?

Alles prima...

von Torsten K. (ago)


Lesenswert?

Mist.. während ich meinen Beitrag editiere muß natürlich wer 
dazwischenfunken ;-)))

Also Nachtrag:

http://msdn.microsoft.com/en-us/library/azk8zbxd.aspx
weiß nichts von "?" als Sequence Point

http://publications.gbdirect.co.uk/c_book/chapter8/sequence_points.html
# The end of the first operand of the ?: conditional operator.
Kennt den offenbar.

Wenn dem so ist, hättest du recht und meine Ausführungen oben sind 
falsch.

von Hc Z. (mizch)


Lesenswert?

@Torsten K. (ago)

C99 6.5.15.4, habe sicherheitshalber nachgeschaut.  Hier zu zitieren 
scheint mir nicht sinnvoll, weil der Abschnitt nur im Kontext 
verständlich ist.

von Torsten K. (ago)


Lesenswert?

@Hc Zimmerer (mizch)
Ja danke, ich habe es inzwischen auch gefunden. Ich muß zugeben, daß ich 
bei dem conditional operator echt Probleme habe (wie man unschwer 
erkennen kann). Finde es eigentlich fast unleserlich, nutze es aber 
selber auch...

Außerdem stehts in meinem 1. Link ebenfalls. Ich habe es nur nicht 
wahrgenommen:
"First operand of the conditional operator. The first operand of the 
conditional operator is completely evaluated and all side effects 
complete before continuing."

Aschewolke auf mein Haupt!

von Hc Z. (mizch)


Lesenswert?

> Aschewolke auf mein Haupt!

Nö, da braucht's keine Asche.  War ein interessantes Diskussionsthema 
und sich darin zu täuschen ist gut möglich und gewiss keine Schande.

von AVRli (Gast)


Lesenswert?

Ujuijui... also ich hätte nicht gedacht das es einen Unterschied macht 
aber in der Tat scheint es so zu sein!

Nun läuft das Programm schon 1h ohne RESET, das ist gut!
Einmal hat er noch gezuckt, was das nun war, weiß ich noch nicht.

Habe das tolle Makro komplett raus genommen. Das lasse ich dann lieber.

Welche Regel darf ich mir dann für Makros generell merken?

Gruß und danke AVRli...

von Hc Z. (mizch)


Lesenswert?

AVRli schrieb:
> Welche Regel darf ich mir dann für Makros generell merken?

Das hatte mit Makros nichts zu tun, am besten googlest Du mal nach 
„Sequence Point“.  So als allgemeine Richtschnur ist das, was Karl Heinz 
über i = ++i sagte, ein guter Rat.

Das hier war eine Ausnahme davon, und eine leicht trickreiche dazu. 
Wenn's bei Dir trotzdem den Fehler behoben hat, ist vielleicht der PSI 
drin.  Ich drücke Dir die Daumen, dass es so bleibt.  So wie Du das 
Thema jetzt komplett umgangen hast, ist es auf keinen Fall falsch.

von AVRli (Gast)


Lesenswert?

Hc Zimmerer schrieb:
> Ich drücke Dir die Daumen, dass es so bleibt.  So wie Du das
> Thema jetzt komplett umgangen hast, ist es auf keinen Fall falsch.

Da hast Du wohl nicht doll genug gedrückt... ;-)
Es passiert nun noch immer, allerdings viel längere Laufzeiten.

Also werde ich wohl noch einen Riesen Bock drin haben.

Stimmt es das es reicht bei Variablen die nur 8bit breit sind und im 
Main sowie Interrupt verwendet werden ein volatile reicht oder muss auch 
hier ein ATOMIC Zugriff erfolgen?

Ich vermute das noch immer irgendwas mit meinen Positionen in den 
Buffern nicht stimmt. :-( RESET ansich schließe ich mal aus, das müsste 
ich an den Flag's sehen, da ist keines gesetzt. Ich glaube eine falsche 
Rücksprungadresse wird genommen. Wie findet man so was nur?

Gruß AVRli...

von Walter (Gast)


Lesenswert?

AVRli schrieb:
> Stimmt es das es reicht bei Variablen die nur 8bit breit sind und im
> Main sowie Interrupt verwendet werden ein volatile reicht oder muss auch
> hier ein ATOMIC Zugriff erfolgen?

du solltest im main den IRQ deaktivieren wenn du die Variable 
verwendest!
Kann ja sonst sein das dir der IRQ was anderes reinschreibt was du dann 
im main wieder überbügelst.
wolltest du wahrscheinlich auch denn ich sehe ein enable IRQ, es fehlt 
aber das disable vorher

von AVRli (Gast)


Lesenswert?

Ich habe nun sämtliche Zugriffe in ATOMIC Blöcke gelegt und hole mir das 
die Werte in Lokale Variable, wenn die Werte geändert werden, schreibe 
ich sie auch in ATOMIC zurück... noch immer das RESET Problem...
1
#define UART_RX_ISR_BUFFER_SIZE 32
2
volatile char buf_uart_rx[UART_RX_ISR_BUFFER_SIZE];
3
volatile uint8_t pos_uart_rx_in;
4
volatile uint8_t pos_uart_rx_read;
5
6
#define UART_RX_READ_BUFFER_SIZE 64
7
char buf_uart_read[UART_RX_READ_BUFFER_SIZE];
8
uint8_t pos_uart_read;
9
10
...
11
12
//--- ISR - UART Zeichen empfangen
13
ISR(USART_RXC_vect) {
14
  uint8_t i;
15
16
  i = pos_uart_rx_in;
17
  
18
  i++;
19
  if (i > UART_RX_ISR_BUFFER_SIZE-1) i=0;
20
21
  if (i == pos_uart_rx_read) {                // buffer overflow
22
    CLEAR_BIT(UCSRB, RXCIE);                  // RX interrupt aus
23
    return;
24
  }
25
  buf_uart_rx[pos_uart_rx_in] = UDR;
26
  pos_uart_rx_in = i;
27
}
28
29
...
30
31
//--- Zugriff im Main Programm
32
33
void show_uart_data (void) {
34
uint8_t bytTMP;
35
uint8_t bytUartIn, bytUartRead;
36
37
  ATOMIC_BLOCK(ATOMIC_FORCEON) {
38
    bytUartIn = pos_uart_rx_in;
39
    bytUartRead = pos_uart_rx_read;
40
  }
41
42
  while (bytUartRead != bytUartIn) {
43
    SET_LED_INF;
44
    bytTMP = buf_uart_rx[bytUartRead];
45
    buf_uart_read[pos_uart_read] = bytTMP;
46
47
    if (bytTMP == 13) {
48
      // CR = Kommando auswerten...
49
    }
50
51
    if (pos_uart_read < UART_RX_READ_BUFFER_SIZE-1) pos_uart_read++;
52
    if (bytTMP==13) pos_uart_read = 0;
53
54
    bytUartRead++;
55
    if (bytUartRead > UART_RX_ISR_BUFFER_SIZE-1) bytUartRead = 0;
56
57
    ATOMIC_BLOCK(ATOMIC_FORCEON) {
58
      bytUartIn = pos_uart_rx_in;
59
      pos_uart_rx_read = bytUartRead;
60
    }
61
62
    SET_BIT(UCSRB, RXCIE);  // RX interrupt ein
63
64
    CLR_LED_INF;
65
  }
66
}

Jetzt gehen mir die Ideen echt langsam aus...
Bin mir noch nicht einmal sicher ob ich wirklich alles als volatile 
deklarieren muss oder ob ich mir damit schon wieder ein Verhalten an den 
Tag hole, der ein RESET auslöst.

In dem GGC Toturial wird gesagt ein volatile reicht bei 8bit breiten 
Int/Main Zugriffe, dann ist mit Interrupt's immer wieder die Rede von 
ATOMIC Geschichten. Bisher habe ich die nur verwendet wenn ich mit 16bit 
Zählern gearbeitet habe,

Ich habe schon andere Sachen geschrieben wo auch massig UART Daten 
abgefertigt werden, da hatte ich das Reset Problem nicht. Das ist mir 
alles ein Rätsel, noch glaube ich das ich im Quelltext was falsch mache, 
doch so langsam freunde ich mich mit dem Gedanken an, es mal mit einer 
anderen CPU zu probieren. Nur wenn's am Quelltext liegt, dann ist das 
wohl auch kein Weg. :..-(

Für jeden weiteren Tip sehr dankbar, AVRli...

von Daniel V. (danvet)


Lesenswert?

AVRli schrieb:

>
> //--- ISR - UART Zeichen empfangen
> ISR(USART_RXC_vect) {
>   uint8_t i;
>
>   i = pos_uart_rx_in;
>
>   i++;
>   if (i > UART_RX_ISR_BUFFER_SIZE-1) i=0;
>
>   if (i == pos_uart_rx_read) {                // buffer overflow
>     CLEAR_BIT(UCSRB, RXCIE);                  // RX interrupt aus
>     return;
>   }
>   buf_uart_rx[pos_uart_rx_in] = UDR;
>   pos_uart_rx_in = i;
> }
>

Mir fällt auf, dass du "i" auf Überlauf prüfst, dann aber 
"pos_uart_rx_in" zum Speichern für UDR verwendest. Falls 
"pos_uart_rx_in" aus irgendeinem Grund aus dem Ruder gelaufen ist (z.B. 
im Hauptprogramm), bekommst du eine Speicherverletzung!

von Karl H. (kbuchegg)


Lesenswert?

Hc Zimmerer schrieb:

> anbelangt, denn darauf ist das nicht übertragbar (obwohl es ähnlich
> aussieht).  Denn:  Hier ist nach dem ++x ein Sequence Point (das „?“).

Mist.
Auf diesen Sequence Point vergess ich immer.

> Somit ist das Schreiben von (x+1) nach x abgeschlossen, bevor entweder 0
> oder x ausgewertet wird und an x zugewiesen wird.  Somit ist das
> Ergebnis eindeutig entweder 0 oder x+1.

Du hast recht. Mein Fehler.
Trotzdem: Es schadet nichts, diese Funktionalität in Funktionen zu 
stecken, auch wenn es jetzt das Problem (offenbar) nicht gelöst hat.

Danke für die Richtigstellung


Wobei es überhaupt seltsam ist.
Durch einen ordinären Softwarefehler ist es gar nicht so einfach einen 
Reset auszulösen.

von Rolf Magnus (Gast)


Lesenswert?

Torsten K. schrieb:
> Ich muß zugeben, daß ich bei dem conditional operator echt Probleme
> habe (wie man unschwer erkennen kann).

Ist aber eigentlich nicht schwer. Er ist sozusagen ein if mit 
Return-Wert und verhält sich ziemlich genau so.
1
    a = b ? c : d;
würde dann diesem Pseudocode entsprechen:
1
    a = if (b) c; else d;

So wie beim if nach der Bedingung ein Sequenzpunkt kommt, kommt der auch 
bei ?:.

von Rolf Magnus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Durch einen ordinären Softwarefehler ist es gar nicht so einfach einen
> Reset auszulösen.

Zwar kein Reset, könnte aber als einer fehlinterpretiert werden: Ein 
Aufruf über einen Funktionszeiger, der NULL ist.

von AVRli (Gast)


Lesenswert?

Daniel V. schrieb:
> Mir fällt auf, dass du "i" auf Überlauf prüfst, dann aber
> "pos_uart_rx_in" zum Speichern für UDR verwendest. Falls
> "pos_uart_rx_in" aus irgendeinem Grund aus dem Ruder gelaufen ist (z.B.
> im Hauptprogramm), bekommst du eine Speicherverletzung!

Die Variable pos_uart_rx_in wird im main nur in einem ATOMIC Block 
ausgelesen und nicht verändert. Die Überprüfung von i++ soll zeigen ob 
das Byte überhaupt in den Buffer passen kann. Ist dem nicht so, dann 
soll das Main in show_uart_data erstmal "Platz" dafür schaffen. Wenn 
Platz ist dann darf der Inhalt von UDR in den Buffer an aktueller 
Position und dann ist die aktuelle Position i. Sollte passen denk ich...

Rolf Magnus schrieb:
> Zwar kein Reset, könnte aber als einer fehlinterpretiert werden: Ein
> Aufruf über einen Funktionszeiger, der NULL ist.

Hmm das befürchte ich eher... denn wie gesagt ein RESET Flag ist bei 
meinem Breakpoint nicht gesetzt. :-(

Nur wie kommt man an die Funktionszeiger... ich glaube das geht so 
garnicht oder? Man weiß ja nicht wann es abschmiert... :-(

Gruß AVRli...

von Georg A. (Gast)


Lesenswert?

Stackoverflow?

von Daniel V. (danvet)


Lesenswert?

AVRli schrieb:
> Daniel V. schrieb:
>> Mir fällt auf, dass du "i" auf Überlauf prüfst, dann aber
>> "pos_uart_rx_in" zum Speichern für UDR verwendest. Falls
>> "pos_uart_rx_in" aus irgendeinem Grund aus dem Ruder gelaufen ist (z.B.
>> im Hauptprogramm), bekommst du eine Speicherverletzung!
>
> Die Variable pos_uart_rx_in wird im main nur in einem ATOMIC Block
> ausgelesen und nicht verändert. Die Überprüfung von i++ soll zeigen ob
> das Byte überhaupt in den Buffer passen kann. Ist dem nicht so, dann
> soll das Main in show_uart_data erstmal "Platz" dafür schaffen. Wenn
> Platz ist dann darf der Inhalt von UDR in den Buffer an aktueller
> Position und dann ist die aktuelle Position i. Sollte passen denk ich...

Ich reite jetzt trotzdem mal weiter drauf rum:

Wo werden diese Variablen initialisiert?:
volatile uint8_t pos_uart_rx_in;
volatile uint8_t pos_uart_rx_read;


Eventuell hängt es auch mit dem JTAG-MKII zusammen? Sind die Parameter 
richtig eingestellt? Ist das Kabel zu lang?

von Rolf Magnus (Gast)


Lesenswert?

AVRli schrieb:
> Rolf Magnus schrieb:
>> Zwar kein Reset, könnte aber als einer fehlinterpretiert werden: Ein
>> Aufruf über einen Funktionszeiger, der NULL ist.
>
> Hmm das befürchte ich eher... denn wie gesagt ein RESET Flag ist bei
> meinem Breakpoint nicht gesetzt. :-(
>
> Nur wie kommt man an die Funktionszeiger... ich glaube das geht so
> garnicht oder?

Welche? Wenn du keine definierst, gibt es auch keine. Und wenn du welche 
definiert hast, kommst du ja auch dran.
Andere Möglichkeit: Dein Programm überschreibt eine Rücksprungadresse 
aus einer Funktion (z.B. indem du irgendwo über Arraygrenzen 
hinausschreibst), und statt zum Aufrufer springt er dann irgendwo hin, 
wodurch das Programm von vorne anfängt.

von Daniel V. (danvet)


Lesenswert?

Aus dem JTAG UserGuide:

"To ensure proper communication between the JTAG ICE and the target AVR, 
the OCD communication frequency from the JTAG ICE must be equal or less 
than 1/4 of the target AVR frequency."

Das hat bei mir schon mal für trouble gesorgt...

von Daniel V. (danvet)


Lesenswert?

> //--- ISR - UART Zeichen empfangen
> ISR(USART_RXC_vect) {
>   uint8_t i;
>
>   i = pos_uart_rx_in;
>
>   i++;
>   if (i > UART_RX_ISR_BUFFER_SIZE-1) i=0;
>
>   if (i == pos_uart_rx_read) {                // buffer overflow
>     CLEAR_BIT(UCSRB, RXCIE);                  // RX interrupt aus
>     return;
>   }
>   buf_uart_rx[pos_uart_rx_in] = UDR;
>   pos_uart_rx_in = i;
> }
>

Hmm... ist "pos_uart_rx_in" die Stelle in die du reinschreiben möchtest 
(Offensichtlich, siehe zweitletzte Code-Zeile), oder in die du zuvor 
reingeschrieben hast (das würde das i++ erklären, weil du dann die 
nächste freie Stelle suchst)? Irgendwie ist aber beides gemischt..??!!

Ich würde es so machen:

ISR(USART_RXC_vect) {
uint8_t i;

   i = pos_uart_rx_in;                    // hier will ich reinschreiben

   if (i > UART_RX_ISR_BUFFER_SIZE-1) i=0;

   if (i == pos_uart_rx_read) {                // buffer overflow
     CLEAR_BIT(UCSRB, RXCIE);                  // RX interrupt aus
     return;
   }
   buf_uart_rx[i] = UDR;
   i++;
   pos_uart_rx_in = i;
}

oder so:

ISR(USART_RXC_vect) {
uint8_t i;

   i = pos_uart_rx_in;                    // hier habe ich geschrieben

   i++;
   if (i > UART_RX_ISR_BUFFER_SIZE-1) i=0;

   if (i == pos_uart_rx_read) {                // buffer overflow
     CLEAR_BIT(UCSRB, RXCIE);                  // RX interrupt aus
     return;
   }
   buf_uart_rx[i] = UDR;
   pos_uart_rx_in = i;
}

von Daniel V. (danvet)


Lesenswert?

>
>     bytUartRead++;
>     if (bytUartRead > UART_RX_ISR_BUFFER_SIZE-1) bytUartRead = 0;
>
>     ATOMIC_BLOCK(ATOMIC_FORCEON) {
>       bytUartIn = pos_uart_rx_in;
>       pos_uart_rx_read = bytUartRead;
>     }
>

Ich würde sagen, das ATOMIC_BLOCK muss vor das "bytUartRead++;", weil 
sonst ein Interrupt dazwischen kommen kann...

von Karl H. (kbuchegg)


Lesenswert?

Daniel V. schrieb:
>>
>>     bytUartRead++;
>>     if (bytUartRead > UART_RX_ISR_BUFFER_SIZE-1) bytUartRead = 0;
>>
>>     ATOMIC_BLOCK(ATOMIC_FORCEON) {
>>       bytUartIn = pos_uart_rx_in;
>>       pos_uart_rx_read = bytUartRead;
>>     }
>>
>
> Ich würde sagen, das ATOMIC_BLOCK muss vor das "bytUartRead++;", weil
> sonst ein Interrupt dazwischen kommen kann...


byteUartRead wird doch im Interrupt gar nicht verändert.

Er hat 2 Sätze Variablen, das hat mich auch eine Zeitlang beschäftigt, 
bis ich das durchschaut habe. In der ISR schreibt er in einen FIFO 
Buffer und ausserhalb kopiert er den FIFO Buffer sukzessive in einen 
anderen Buffer um.

Ich denke, dass stimmt soweit alles. Zumindet ist mir beim Durchspielen 
tatsächlich nichts mehr aufgefallen.

von AVRli (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ich denke, dass stimmt soweit alles.

Ja danke, da bin ich etwas beruhigt. :-) Wenn ich daran denke was Dein 
erstes Kommentar war. ;-)

Ich besorge mir mal eine neue CPU... ich glaube das ist der nächste 
Schritt. Ich habe nur keine mehr hier. :-(

Ich fütter den UART über den PC im 500ms Takt mit 19200 Baud, das sollte 
doch nicht das Problem sein oder?

Betrieben wird die CPU mit einem 11.0592 MHz Quarz.

Kannst Du das mit dem ATOMIC, volatile 8bit, 16bit vlt. nochmal 
erläutern?
8bit volatile ausreichend für Int/Main Zugriff oder generell ALLE Sachen 
die im Main und Int genutzt werden als volatile und im Main mit ATOMIC 
Block ansprechen?

Vielen Dank für die Mühe!

Gruß, AVRli...

von AVRli (Gast)


Lesenswert?

Sorry für den Doppelpost, das war nicht meine Absicht!
Hab ja was vergessen, soory tut mir Leid!!!

Daniel V. schrieb:
> Ich reite jetzt trotzdem mal weiter drauf rum:
>
> Wo werden diese Variablen initialisiert?:
> volatile uint8_t pos_uart_rx_in;
> volatile uint8_t pos_uart_rx_read;

Beim RESET oder Start sind alle 0...

Daniel V. schrieb:
> Eventuell hängt es auch mit dem JTAG-MKII zusammen? Sind die Parameter
> richtig eingestellt? Ist das Kabel zu lang?

Das wäre auch noch ein Möglichkeit!
Also das originale + 25cm Verlängerung, weil das originale hab ich am 
JTAG festgemacht, das ist ja so "fass mich bloß nicht an!"

Daniel V. schrieb:
> ... must be equal or less than 1/4 of the target AVR frequency."

Ähm das stand auf 1MHz, das ist vlt. auch noch ein Grund.
Ich teste das mal.


Gruß AVRli...

von AVRli (Gast)


Lesenswert?

So nun eine Frage an die Profis unter Euch. ;-)

Verwende ich einen ATmega644 (fiel mir ein das doch noch einen größeren 
habe), dann geht es derzeit bereits über mehrere Studen ohne RESET.

Ernsthaft, es scheint tadellos zu funktionieren.

Ich habe den ATmega16 mit der Bemerkung "defekt?" in den Setzkasten 
gelegt.

Ok ein paar Deklarationen mussten angepasst werden, der Kern blieb aber 
gleich. PIN - Kompatibel ist er auch.

Doch der 16er kaputt? Kann man so was noch explizit überprüfen?
Oder hat der generell einen anderen Aufbau als ein 644??

Unterm Strich hat die Diskussion hier für mich einiges gebracht, vielen 
Dank! Auch wenn das RESET Problem nicht restlos aufgeklärt werden 
konnte, sehr schade.

Grüße, schönes WE, AVRli...

von Karl H. (kbuchegg)


Lesenswert?

Kurze Zwischenfrage:
Hattest du CKOPT programmiert um den Oszillator auf Full Swing zu 
stellen?

von AVRli (Gast)


Lesenswert?

Hallo Karl Heinz... nein das Bit war nicht programmiert. Ob ich es 
irgendwann mal programmiert hatte weiß ich nicht, kann man den damit 
zerstören?

Gruß AVRli...

von Karl H. (kbuchegg)


Lesenswert?

Nein.
Dein Mega verbraucht dann ein wenig mehr Strom, aber der Schwingkreis 
der den Quarz am Leben erhält läuft dann stabiler.

von AVRli (Gast)


Lesenswert?

Gratuliere und danke das Du bis zur Klärung am Ball geblieben bist!

Jo mit der Info nun wieder Kommando zurück also 644 wieder raus, 16 
wieder rein. Programm wieder angepasst.

CKOPT nicht gesetzt = RESET wann immer er will
CKOPT gesetzt       = läuft... :-D

Datenblatt sagt dazu:
Bis 8MHz kann es nicht programmiert sein.
Ab mehr als 8 MHz - bis 16 MHz soll man es dann programmieren.

Das ist ja wirklich ein Ding! Doch wer ließt nun immer das ganze 
Datenblatt?

Fazit:
Alles geht nun mit programmierten CKOPT und ich habe was über ++i und 
CKOPT gelernt.

Karl Heinz kannst Du noch kurz was zu meiner Frage schreiben?

AVRli schrieb:
> Kannst Du das mit dem ATOMIC, volatile 8bit, 16bit vlt. nochmal
> erläutern?
> 8bit volatile ausreichend für Int/Main Zugriff oder generell ALLE Sachen
> die im Main und Int genutzt werden als volatile und im Main mit ATOMIC
> Block ansprechen?


Vielen Dank! AVRli...

von Karl H. (kbuchegg)


Lesenswert?

AVRli schrieb:

>> 8bit volatile ausreichend für Int/Main Zugriff oder generell ALLE Sachen
>> die im Main und Int genutzt werden als volatile und im Main mit ATOMIC
>> Block ansprechen?


volatile denke ich ist sowieso vom Tisch.
Da geht es einfach darum, dass du dem Compiler mitteilst, dass er seinen 
eigenen Codeanalysen nicht trauen darf.

    irgendwas = 1;
    while( irgendwas )
      ;

für den Compiler ist die Situation eindeutig. Laut seiner Codeanaylse, 
gibt es für irgendwas innerhalb der Schleife keine Möglichkeit jemals 
den Wert zu verändern. Diese Schleife ist also eine Endlosschleife auf 
Biegen und Brechen.
Wozu daher zuerst eine Variable setzen und bei jedem Schleifendurchlauf 
abfragen?
Der Optimizer wird seine nobelste Aufgabe wahrnehmen und für dich aus 
dem laufenden Programm Zeit rausholen wo er nur kann. Die Abfrage kostet 
Zeit und sie bringt nichts. Denn innerhalb der Schleife KANN irgendwas 
seinen Wert nicht ändern.

Wenn da nicht auch noch Interrupts wären.
Aber von denen weiß der Compiler nichts, wenn er sich dieses Codestück 
vornimmt.

Daher muss man dem Compiler mitteilen: Diese Variable verändert sich auf 
Wegen, die dir nicht zugänglich sind. Deine Datenflussanalyse wird 
fehlerhaft sein und deine Optimierungen sind kontraproduktiv.

Und der Weg das zu tun, ist es die Variable als volatile zu markieren.


Was hat es mit dem sog. atomic Zugriff auf sich.


Stell dir vor du liest ein Buch.
Plötzlich kommt ein Anruf (ein Interrupt), du legst das Buch zur Seite 
und sprichst am Telefon. Während du das tust, kommt dein 
Bruder/Schwester/wer_auch_immer und tauscht dir das Buch gegen ein 
anderes aus. Wenn du dann weiterliest, wird nichts mehr zusammenstimmen.

Dein Buchlesen ist nicht atomic. Das heist es ist nicht sichergestellt, 
dass du nach der Unterbrechung es immer noch mit demselben Basismaterial 
zu tun hast.
Die Lösung dafür ist zb.: Unterbrechungen erst gar nicht zulassen. Dann 
kann dir das nicht passieren.


Liest du einen uint16_t aus, dann geht das auf einem AVR nur in 2 
Schritten, weil es ja eine 8 Bit Maschine ist und es keinen Assebmler 
Befehl gibt, der 16 Bit in einem Rutsch aus dem Speicher holen kann.

schreibst du daher in C

     i = globale_Variable;

dann kann es die Möglichkeit geben, dass 8 Bit von globale_Variable 
bereits ausgelesen sind und dann kommt ein Interrupt. In diesem 
Interrupt wird globale_Variable verändert. Geht die Kontrolle nach dem 
Interrupt wieder zurück an die Aufrufstelle, dann werden die noch 
ausständigen 8 Bit von globale_Variable aus dem Speicher geholt.

Jetzt siehst du aber das Dilemma
 vom 16 Bit Wert stammen 8 Bit vor der Veränderung durch den Interrupt 
und 8 Bit stammen nach der Veränderung durch den Interrupt. Die passen 
daher nicht mehr zusammen. Du hast sozusagen den vorderen Teil von 
'Krieg und Frieden' und den hinteren Teil von 'Buddenbrocks' in einem 
'Buch' vereint und wunderst dich warum die Personen aus dem ersten Teil 
im zweiten Teil nicht mehr vorkommen und wo jetzt eigentlich die neuen 
Personen alle herkommen.


Bei einem 8 Bit ZUgriff kann dir das nicht passieren. Der ist als 
solcher nicht unterbrechbar und läuft auf der CPU in einem Rutsch durch. 
Aber alles was auf mehrmals aus dem Speicher gelesen werden muss UND bei 
dem die Gefahr besteht, dass es sich bei einer Unterbrechung verändert, 
muss atomar abgesichert werden - sprich die Interrupts solange 
Abschalten bis dieser eine Zugriff komplett durchgezogen wurde.

von Walter (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Bei einem 8 Bit ZUgriff kann dir das nicht passieren. Der ist als
> solcher nicht unterbrechbar und läuft auf der CPU in einem Rutsch durch.

der Zugriff selber zwar nicht, aber z.B.
a = a+1
sollte auch nicht durch einen Interrupt zerrupft werden wenn
a auch im Interrupt verändert wird, auch wenn a nur 8 Bit hat

von AVRli (Gast)


Lesenswert?

Besten Dank für die ausführliche Antwort,
Jetzt sind mir die Zusammenhänge klar!

Abschließend noch eine letzte Frage. Diese winzigen ATOMIC Blöcke, nur 
das kopieren der Werte in lokale VAR und das zurückschreiben, 
beeinflussen die Genauigkeit der anderen Interrupts nur so geringfügig 
das man es vernachlässigen kann oder sollte man das im Hinterkopf 
behalten, wenn es da mal Probleme gibt?

Ich meine z.B. einen Timer Interrupt der jede 1 ms aufgerufen wird. 
"Leidet" da die "Genauigkeit" dann?

Gruß AVRli...

von Walter (Gast)


Lesenswert?

Natürlich kann sich der Interrupt dadurch etwas verschieben, sollte man 
beachten wenn der Zeitpunkt des Interrupts wichtig ist.
Es ist aber nur eine Verschiebung, bei durchlaufendem Timer summiert 
sich also kein Fehler auf

von AVRli (Gast)


Lesenswert?

Ja prima, dann hab ich auch das verstanden und bedanke mich für alle 
Antworten!

AVRli, der alte Programmierer - Lehrling... ;-)

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.