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
Hi,
1 | EXT_INT0: |
2 | cli ; Alle Interrupts sperren um Zeit und Energie zu sparen |
3 | |
4 | ldi ZH, high(EEPROMDaten) ; Quell-Adresse im EEPROM |
5 | ldi ZL, low(EEPROMDaten) |
6 | ldi YH, high(RamDat) ; Ziel-Adresse im SRAM |
7 | ldi YL, low(Ramdat) |
8 | ldi r16,112 ; 112 Bytes sind zu kopieren |
9 | |
10 | EEPROM_schreiben: |
11 | |
12 | sbic EECR,EEWE ; prüfen, ob der vorherige Schreibzugriff beendet ist |
13 | rjmp EEPROM_schreiben ; wenn nicht, nochmal prüfen |
14 | |
15 | out EEARH, ZH ; Adresse von EEPROM laden |
16 | out EEARL, ZL |
17 | |
18 | ld r17, Y+ ; r17 mit SRAM-Byte befüllen |
19 | out EEDR, r17 ; r17 ins EEPROM |
20 | |
21 | sbi EECR,EEMWE ; Schreiben vorbereiten |
22 | sbi EECR,EEWE ; Schreiben ausführen |
23 | |
24 | adiw ZH:ZL,1 |
25 | dec r16 ; Byte-Counter |
26 | brne EEPROM_schreiben ; Solange nicht 0 nochmal schreiben |
27 | |
28 | sei ; Interrupts wieder freigeben |
29 | reti |
lg Michi
@ 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
So, hatte da doch noch nen fehler drin! Jetzt ist es richtig! Bis dann MFG Alsastro
Und jetzt gehst du noch her und überlegst dir, wie du wohl die Funktion eeprom_write_block sinnvoll einsetzen könntest.
@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.
@ Läubi .. (laeubi) (Moderator) Benutzerseite >gerade ins EEPROM schreiben ist nicht so dolle wenn der Strom gerade >weg bricht. Muss man aber manchmal machen. Und wenn man es richtg macht (tm), geht das auch. http://www.mikrocontroller.net/articles/Speicher#EEPROM_Schreibzugriffe_minimieren
Schon klar aber größere Blöcke? Dann sollte man sich auf jedenfall nicht darauf Verlassen, dass "eigentlich" noch genug Zeit sein sollte ;)
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
Falk Brunner schrieb: >>Wenn ich es richtig im Kopf habe etwa 8,5ms. > > Ja. über 8000 Zyklen -> 1MHz -> 8.5ms
ok, ich arbeite mit 8MHz; also 1,1ms / Byte= 124 ms in meinem Fall (112 Byte)
@ 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
@Sascha Ja habe ich. Und die Erkennung funktioniert ja korrekt! Nur ist schon nach dem 1. Byte Schluß,.. Der Brown Out ist deaktiviert Michi
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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.