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...
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.
> 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 :-)
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...
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...
#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_tIncOverlapped(uint8_ti,uint8_tmax)
2
{
3
++i;
4
5
if(i<max)
6
returni;
7
8
return0;
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.
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.
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...
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.
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.
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 :)
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.
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...
@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.
@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!
> 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.
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...
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.
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...
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
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...
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...
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!
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.
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;elsed;
So wie beim if nach der Bedingung ein Sequenzpunkt kommt, kommt der auch
bei ?:.
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.
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...
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?
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.
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...
> //--- 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;
}
>> 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...
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.
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...
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...
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...
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...
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...
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.
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
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...
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