Hallo Leute,
Ich verzweifel gerade ein bißchen,
versuche seit längerem schon eine Interruptroutine zu schreiben, welche
beim Empfangen von daten bei der UART (immer 8Byte) diese direkt als
einzelne byte in den EEProm speichert.
bei einem Byte klappt das super.
aber sobalt ich mehrere Bytes empfangen und speichern will, funzt das
nicht so wie ich möchte.
Controller ist der ATmega32
Sprache ist C
Das ist so zimlich der ganze mist was ich ausprobiert habe:
ISR(USART_RXC_vect)
{
cli();
a = UDR;
eeprom_write_byte(&wert1,a);
// while ( !( UCSRA & (1<<RXC)) ) ; // solange warten bis
Empfangspuffer leer ist,
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert2,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert3,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert4,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert5,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert6,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert7,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
a = UDR;
eeprom_write_byte(&wert8,a);
// while ( !( UCSRA & (1<<RXC)) )
// while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer
daten hat,
_delay_ms(1);
sei();
}
Das ausgeklammerte habe ich mal eingeklammert und mal ausgeklammert
gehabt, aber es geht nicht so wie ich möchte.
Im Main ist eigentlich alles richtig inizialisiert. Ganze programm steht
im Anhang.
Mache im momen mit den werten nichts besonderes weil ich zur zeit nur
teste.
Kann mir bitte einer einen vernünftigen weg zeigen?
Danke.
MFG Alsastro
du machst in deinem programm viele unschöne sachen.
- Wenn Du einen interruptgesteuerten Empfang möchtest, benutze einen
Ringpuffer.
- aus deinem Hauptprogramm liest du die Daten aus deinem Ringprogramm
und beschreibts das Eeprom.
Verwende mal die Suchfunktion des Forums...
Hi,
auch wenn es dir momentan nicht weiterhilft, aber ich habe ein ähnliches
Problem. Ich möchte bei Auslösen eines Interrupts einen Block von Daten
ins EEPROM schreiben. Auch hier scheitert es nach dem ersten Byte,...
Bislang habe ich keine Lösung gefunden...
lg Michi
Hi
Nun, die Lösung ist bereits genannt. Ein Ringpuffer. Du mußt die ISR vom
UART für sich betrachten. Soweit ich weiß, darf die Schreibroutine auf
den EEProm nicht durch einen Interrupt gestört werden, daher sollte
diese für die Zeit des Schreibens blockiert sein. Dies könnte dem UARt
aber nicht gefallen, da er möglicherweise nicht weiß, wohin mit den
Daten. Ein Ringpuffer sollte das Problem lösen. Irgendwie weiß man ja,
wieviele Daten in einem Rutsch an den Controller gesendet werden.
Dementsprechend baut mn die Größe des Ringpuffers auf. Alle ankommenden
Daten werden dann erst mal ins RAM geschrieben. Sind sie vollständig,
geht es dann ab in den EEProm. Andere Alternative ist die Baudrate
herabsetzen. Da sollte zwischen den Zeichen ausreichend Zeit für's
Speichern im EEProm sein. Ich hab mal so was in Assembler auf einem
Atmega8 gemacht. Der sollte sich Telefonnummern merken. Das gab auch
keine Probleme, kann aber sein, das ich immer ein Quittungssignal
zurückgeschickt habe, um einen neuen Datensatz anzufordrn. Kann es von
hier aus leider nicht prüfen.
Gruß oldmax
@ Alsastro (Gast)
>Das ist so zimlich der ganze mist was ich ausprobiert habe:
Ein wahres Wort. Soviel Dung in eine ISR zu packen ist nicht wirklich
zielführend. Vor allem weil du das Konzpet einer ISR nicht verstanden
hast. Und dass man in einer ISR nicht nennenswert warten darf. 1ms IST
nennenswert.
Wie man es richtig macht, siehe Interrupt.
MFG
Falk
Hi,
das mag im Falle des UART schon stimmen, aber in meinem Fall wird die
Spannungsversorgung mittels INT0 überwacht. Sobald die Spannung weg ist
wird der Interrupt ausgelöst und die Daten sollten im EEPROM landen.
(Andere Interrupts sind gesperrt und spielen in der Situation auch keine
Rolle mehr) Aber genau da ist nach 1 Byte Schluss,... Die gepufferte
Spannung würde aber locker für 10 Sekunden reichen.
lg Michi
@ Michael Gorischek (gorischek)
>Spannungsversorgung mittels INT0 überwacht. Sobald die Spannung weg ist>wird der Interrupt ausgelöst und die Daten sollten im EEPROM landen.
Quelltext?
MFg
Falk
@ Michael Gorischek (gorischek)
>EXT_INT0:> cli ; Alle Interrupts sperren um Zeit und Energie zu sparen
Unsinn, die sind hier längst gesperrt.
> ldi ZH, high(EEPROMDaten) ; Quell-Adresse im EEPROM> ldi ZL, low(EEPROMDaten)> ldi YH, high(RamDat) ; Ziel-Adresse im SRAM> ldi YL, low(Ramdat)> ldi r16,112 ; 112 Bytes sind zu kopieren>EEPROM_schreiben:
Sieht OK aus.
> sei ; Interrupts wieder freigeben
Ist ebenfalls Unsinn, das macht reti automatisch.
> reti
Wie stellst du fest, dass das Schreiben nicht klappt?
MFG
Falk
Hi,
einfach daran, dass die Daten im EEPROM nicht geändert sind.
Grundprinzip: Beim Start lese ich aus dem EEPROM die Daten ins SRAM.
Beim Abschalten sollen sie ins EEPROM zurückgeschrieben werden. Während
dem "Normal"-Lauf sehe ich die geänderten Daten im SRAM über die
Schnittstelle bzw ändere sie über die Schnittstelle. Aber es wird nur
das erste Byte ins EEPROM zurückgeschrieben.
Das habe ich sowohl durch Auslesen des EEPROM mit dem SVR Studio, wie
auch beim Neustart des Systems verifizieren können.
Die Software an sich scheint ja zu funktionieren, weil es im Simulator
vom Studio so tut wie ich es möchte. Nur im µP nicht mehr,...
lg Michi
@ Michael Gorischek (gorischek)
>Schnittstelle bzw ändere sie über die Schnittstelle. Aber es wird nur>das erste Byte ins EEPROM zurückgeschrieben.
Wahrscheinlich schlägt der Brown Out Detector zu. Versuch mal die Daten
im normalen Programmablauf per Kommando zu schreiben. Dann weißt du dass
es prinzipiell geht.
MFG
Falk
@Alsastro
Ich will dir mal erklären was hier passiert:
Alsastro schrieb:> ISR(USART_RXC_vect)
= Auslösen eines Interrupts beim Empfang eines Bytes
> {> cli();
= siehe 'Falk Brunner'
> a = UDR;
= Übernahme des Zeichens
> eeprom_write_byte(&wert1,a);
= Ich hoffe, ich habe das Datenblatt richtig interpretiert: so ein
Schreibzugriff dauert über 8000 Zyklen, da geht vom Rest der Daten 'ne
Menge flöten, wenn der|die|das UART sich überhaupt wieder fängt!
> // while ( !( UCSRA & (1<<RXC)) ) ; // solange warten bis> Empfangspuffer leer ist,> // while (UCSRA & (1<<RXC)); //solange warten bis Empfangspuffer> daten hat,> _delay_ms(1);
= und da wird's dann noch schlimmer.
So ich melde mich mal wieder,
ich weiß das das großer mist war warteschleifen in die ISR zu packen.
Hatte da ja nur mal ausprobiert. :-)
Habe jetzt auch mal ein Lauffähigesprogramm von mir hineingestellt.
Das ist das was ich wollte. Wuste nur irgendwie nicht das ich das wollte
:-)
warum einfach wenn es am anfang auch kompliziert nicht geht.
Habe das jetzt mit einem Arrey gemacht welches die werte erstmal
einspeichert und dann wenn 8 werte drin sind wird es dann erst im
hauptprogramm in das eeprom geschrieben.
Klappt super, das kann ich euch sagen.
Damit wäre dann auch mein problem gelöst.
Bis dann und danke an alle beteiligten.
MFG Alsastro
@Falk
Wenn ich die Routine ausserhalb des Interrupts ausführe funktioniert
sie. Sobald ich sie im Zuge des INT0 ausführe steckt sie nach dem 1.
Byte. Ich hatte schon den Watchdog in Verdacht, aber selbst dessen
Deaktivierung änderte nichts. Der Brown Out Detector ist übrigens
deaktiviert,...
Ich versteh es einfach nicht mehr,...
lg Michi
@ Karl Heinz Buchegger (kbuchegg) (Moderator)
>eeprom_write_block>sinnvoll einsetzen könntest.
Dazu muss man Grundlagen von Arrays beherrschen, eine überaus komplexe
Programmiertechnik, die es noch nicht so lange gibt.
@ Michael Gorischek (gorischek)
>Ich versteh es einfach nicht mehr,...
Löse mal den EXT INT0 aus, ohne die Stromversorgung zu kappen.
Vielleicht bricht die schneller zusammen als du denkst.
MFG
Falk
gerade ins EEPROM schreiben ist nicht so dolle wenn der Strom gerade
weg bricht. Genau deshalb gibt es ja die Schutzmechanismen und die etwas
komplizierte Schreibroutine, damit dies nicht zufällig geschieht, wenn
sich die Daten nicht so arg oft ändern würde ich das ganze eher zyklisch
schreiben.
Na mann kennt seine Hardwareschaltung nicht. Wenn er einen großen
Kondensator zum Puffern des uC (und nur des Mikrocontrollers) verwendet
und eine externe Spannungsüberwachung benutzt, sollte es prinzipiell
funktionieren...
@Falk: Habe ich gemacht! Leider selbes Ergebnis: Es wird nur Byte 1 ins
EEPROM geschrieben. Dann steht er.
@Läubi: Da ein nicht-Speichern der Daten beim nächsten Programmstart
eher unangenehme Folgen hat bleibt mir nichts anderes übrig,... Ob man
112 Byte jetzt als groß bezeichnet lasse ich dahinestellt, aber es
scheitert ja shcon an Byte 2!
@Coder: ich habe einen 1F Goldcap der NUR den µP versorgt. Der hat nach
ca. 1 Minute noch immer >4,5V! An der Leistung sollte es also nicht
liegen. (Abgesehen davon habe ih bei aufrechter Versorgungsspannung den
Interrupteingang auf MAsse gezogen und damit den Interrupt manuell
ausgelöst. Leider selbiges Problem.)
Es scheint so, als würde das Beschreiben des EEPROMS innerhalb der
Interruptroutine nicht korrekt quittiert werden. Warum auch immer,...
Ich habe jetzt mal zu Testzwecken an einem Port eine LED angeschlossen.
Die lasse ich abhängig vom Fortschritt des Zurückschreibens leuchten.
Erkenntnis: Der Schreibzugriff wird nie als beendet gemeldet. Nur warum?
lg Michi
Vielleicht eine Möglichkeit:
In der ISR_INT0 nur das Flag setzen (i=1) und dann in der main() den
EPROM beschreiben. Das wäre dann sozusagen eine Mischung aus deinen zwei
Versuchen. Dann wären die ISRs schön kurz, wie es sich gehört. Wobei ich
mir nicht vorstellen kann, warum eine ISR 'mit Überlänge', wenn
hinterher sowieso nichts mehr passiert, Schwierigkeiten machen sollte...
@ Michael Gorischek (gorischek)
>@Falk: Habe ich gemacht! Leider selbes Ergebnis: Es wird nur Byte 1 ins>EEPROM geschrieben. Dann steht er.
Poste VOLLSTÄNDIGEN Code als Anhang.
MFG
Falk
----------------
@Coder: ich habe einen 1F Goldcap der NUR den µP versorgt. Der hat nach
ca. 1 Minute noch immer >4,5V! An der Leistung sollte es also nicht
liegen. (Abgesehen davon habe ih bei aufrechter Versorgungsspannung den
Interrupteingang auf MAsse gezogen und damit den Interrupt manuell
ausgelöst. Leider selbiges Problem.)
---------------
Der Goldige ist aber ziemlich hochohmig.
Wenn du den µP nur damit versorgst dann kann es ev. auch bei
"Netzbetrieb"
beim EE-Schreiben zum Spannungseinbruch kommen.
Häng mal die 5V direkt an den AVR.
Gruss Kurt
Hab den Code nur überflogen. Kann es sein, dass du dein Daten nicht an
die Stelle im RAM schreibst, die du glaubst? Denn dann landen die bei
Schreiben auch nicht im EEPROM.
MFG
Falk
@ Falk
hmm...
Da der Code im Simulator funktioniert und auch, wenn ich ihn im µP
ausserhalb des Interrupts verwende, gehe ich mal davon aus, dass die
Daten dort stehen, wo sie sollen,...
Und ich lese sie ja (natürlich mit umgekehrter Logik) am Programmstart
aus dem EEPROM aus.
lg Michi
Wie lange dauert es eigentlich laut Datenblatt, 1 byte ins EEPROM zu
schreiben?
Ich habe den Code jetzt nicht angeschaut, aber gerade bei Blöcken macht
es zeitlich Sinn, ganze Pages zu schreiben, auch wenn man weniger Platz
benötigt.
@Lutz
Wenn ich es richtig im Kopf habe etwa 8,5ms.
Wie realisiert man es in asm eine ganze Page ins EEPROM zu schreiben?
Ich habe keine ander Variante gefunden als Byte-weise...
@ Michael Gorischek (gorischek)
>Wenn ich es richtig im Kopf habe etwa 8,5ms.
Ja.
>Wie realisiert man es in asm eine ganze Page ins EEPROM zu schreiben?
Gar nicht, das kann der AVR nicht. Nur externe EEPROMs ala 24Cxx
MFG
Falk
@ Michael Gorischek (gorischek)
>ok, ich arbeite mit 8MHz; also 1,1ms / Byte= 124 ms in meinem Fall (112>Byte)
Nö, die Schreibgeschwindigkeit ist UNABHÄNGIG von deinem CPU-Takt. Es
sind IMMER 8,5ms. Aber der Takt wird vom internen RC-Oszillator
abgeleitet, wenn man den per OSCCAL zu hoch stellt kann es zu
Schreibfehlern kommen. Sollte bei dir aber nicht das Problem, denn
ausserhalb des Interrupts funktioniert es ja.
MfG
Falk
Hast du mal getestet den INT0 auszulösen ohne die Spannung abzuschalten?
Wie ist der INT-Eingang beschaltet um ein ausfallen der
Spannungsversorgung zu messen?
Hast du den Brownout aktiviert?
Sascha
Mal was mir am Code auffällt:
- Das Datenbank sagt als zweiten Schritt: 'Wait until SPMEN in SPMCR
becomes zero' das fehlt bei dir.
- Du kannst 2 Takte sparen, wenn du die neuen Daten vor dem Warten auf
den Schreibvorgang in r17 lädst.
- 5. Schritt im DB: 'Write a logical one to the EEMWE bit while writing
a zero to EEWE in EECR' du schreibst nur eine 1 in das Register, ich
interpretiere dass auch so als solle dies gleichzeitig geschehen.
- Ist der Watchdog definitiv aus? Datenblatt sagt: 'If a reset occurs
while a write operation is in progress, the write
operation will be completed provided that the power supply voltage is
sufficient'
Michael Gorischek schrieb:> Da der Code im Simulator funktionier
Der Unterschied zwischen Theorie und Praxis ist in der Praxis größer als
in der Theorie ;)
Läubi .. schrieb:> Mal was mir am Code auffällt:> - Das Datenbank sagt als zweiten Schritt: 'Wait until SPMEN in SPMCR> becomes zero' das fehlt bei dir.
aber nur wenn er irgendwas in den Flash schreiben würde
> - 5. Schritt im DB: 'Write a logical one to the EEMWE bit while writing> a zero to EEWE in EECR' du schreibst nur eine 1 in das Register, ich> interpretiere dass auch so als solle dies gleichzeitig geschehen.
gleich weiter unten kommt der Beispielcode und der sieht genauso aus wie
seiner
Sascha
Atmel ist nicht gerade dafür berühmt immer und überall fehlerfreien
Beispielcode zu liefern.
Sascha Weber schrieb:> aber nur wenn er irgendwas in den Flash schreiben würde
Schon klar, aber warum nicht diese eine Abfrage noch zusätzlich
einbringen? Kostet Initial max 2 Takte...