UART im Interrupt, Daten direkt in EEProm speichern

Gast #2241065
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
Angehängte Dateien:
Gast #2241082
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...
Gast #2242109
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
#2242118
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
#2242154
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
#2242219
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
#2242227
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
#2242277
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
#2242338
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
Gast #2242367
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.
Gast #2242542
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
Angehängte Dateien:
#2242672
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
Gast #2242750
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...
#2242894
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
Gast #2243191
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...
Gast #2243396
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
Gast #2243479
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.
#2243909
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
Persönliche Seite #2244069
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 ;)
#2244098
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren