Forum: Mikrocontroller und Digitale Elektronik UART im Interrupt, Daten direkt in EEProm speichern


von Alsastro (Gast)


Angehängte Dateien:

Lesenswert?

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

von coder (Gast)


Lesenswert?

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...

von Michael G. (gorischek)


Lesenswert?

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

von oldmax (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Michael G. (gorischek)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Michael G. (gorischek)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Michael G. (gorischek)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Ralf (Gast)


Lesenswert?

@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.

von Alsastro (Gast)


Angehängte Dateien:

Lesenswert?

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

von Alsastro (Gast)


Angehängte Dateien:

Lesenswert?

So,
hatte da doch noch nen fehler drin!
Jetzt ist es richtig!
Bis dann
MFG Alsastro

von Karl H. (kbuchegg)


Lesenswert?

Und jetzt gehst du noch her und überlegst dir, wie du wohl die Funktion

eeprom_write_block

sinnvoll einsetzen könntest.

von Michael G. (gorischek)


Lesenswert?

@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

von Falk B. (falk)


Lesenswert?

@  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.

von Falk B. (falk)


Lesenswert?

@  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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Schon klar aber größere Blöcke? Dann sollte man sich auf jedenfall nicht 
darauf Verlassen, dass "eigentlich" noch genug Zeit sein sollte ;)

von coder (Gast)


Lesenswert?

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...

von Michael G. (gorischek)


Lesenswert?

@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

von Ralf (Gast)


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

@  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

von Michael G. (gorischek)


Angehängte Dateien:

Lesenswert?

Anbei der vollständige Code,...

lg Michi

von Kurt (Gast)


Lesenswert?

----------------
@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

von Falk B. (falk)


Lesenswert?

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

von Michael G. (gorischek)


Lesenswert?

@ 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

von Lutz (Gast)


Lesenswert?

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.

von Michael G. (gorischek)


Lesenswert?

@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...

von Falk B. (falk)


Lesenswert?

@  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

von Ralf (Gast)


Lesenswert?

Falk Brunner schrieb:
>>Wenn ich es richtig im Kopf habe etwa 8,5ms.
>
> Ja.
über 8000 Zyklen -> 1MHz -> 8.5ms

von Michael G. (gorischek)


Lesenswert?

ok, ich arbeite mit 8MHz; also 1,1ms / Byte= 124 ms in meinem Fall (112 
Byte)

von Falk B. (falk)


Lesenswert?

@  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

von Sascha W. (sascha-w)


Lesenswert?

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

von Michael G. (gorischek)


Lesenswert?

@Sascha
Ja habe ich. Und die Erkennung funktioniert ja korrekt! Nur ist schon 
nach dem 1. Byte Schluß,..
Der Brown Out ist deaktiviert

Michi

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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 ;)

von Sascha W. (sascha-w)


Lesenswert?

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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.