Forum: Compiler & IDEs [AVR] per Interrupt ins EEPROM schreiben


von Bernt H. (bernt)


Lesenswert?

Hallo,

Hat einer schon mal bei einem AVR mit GCC eine Interrupt Routine
geschrieben, um Werte in das EEProm zu beschreiben.

Hintergrund dazu ist:
In meinem Projekt muss ich Daten mit 25kHz Byte-Takt verschicken.
(Das wird per Interrupt gemacht.)
Normales Schreiben ins EEProm dauert laut Datenblatt bis zu 8,5ms.
Daher kann ich die Funktion eeprom_write_byte aus der avrlib nicht
benutzen um konfigurierbare Parameter abzuspeichern.

Ciao,
Bernt

von 2920 (Gast)


Lesenswert?

Und du denkst mit dem interrupt geht es schneller ?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

2920 wrote:

> Und du denkst mit dem interrupt geht es schneller ?

Nein, aber du musst nicht warten, bis das Byte fertig ist, sondern
kannst in der ISR gucken, ob noch mehr zu schreiben ist.

Funktioniert nicht viel anders als eine UART-Senderoutine.

von Bernt H. (bernt)


Lesenswert?

Vor allem wenn ich eine Scene mit DMX-Werten abspeichern will:
512 Werte * 8.5 ms = 4.352 Sekunden.
Soll ich dann Kerzen verteilen damit die Leute was sehen,
während ich eine Scene abspeichere?

daher muss mit dem Interrupt schon sein ... aber bei über 4 Sekunden
werd ich wohl auch ne Rückmeldung aufs LCD brauchen ...
... der nächste Aufbau wird mit externen RAM, 4k sind echt wenig ...

daher die Frage: hat das schon jemand gemacht, oder betrete ich hier
absolutes Neuland? ;-)

von Timmo H. (masterfx)


Lesenswert?

Also ich würde ja einfach Flash-Speicher nehmen. Da kann man dann auch 
schön den internen FiFo beschreiben (z.B. 32 Worte) und ihn dann den 
Rest machen lassen. Und schneller ist er auch als ein EEPROM. Wenn du 
pins sparen willst kannst ja auch ein serielles Flash nehmen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Timmo H. wrote:

> Und schneller ist er auch als ein EEPROM.

Nur durch den Pagemode.

Dafür hat er eine Zehnerpotenz weniger Zyklenlebensdauer.

Wenn die 4 Sekunden insgesamt egal sind, ist die Interruptvariante
sicher so schlecht nicht.  Ich glaube auch, dass die Schreibzeiten
worst-case-Zeiten sind, sodass der Interrupt auch eher triggern
kann (die Gesamtzeit also sinkt).  Das könnte u. U. spannungsabhängig
sein (bei höherer Spannung geht es schneller), weiß nicht, wie das
genau in der Hardware implementiert ist.

von Benedikt K. (benedikt)


Lesenswert?

Jörg Wunsch wrote:
> Timmo H. wrote:
>
>> Und schneller ist er auch als ein EEPROM.
>
> Nur durch den Pagemode.

Nicht unbedingt: Es gibt verschiedene Typen, vergleiche z.B. mal einen 
29Cxxx und einen 29Fxxx. Der 29F wird Byte für Byte beschrieben, mit 
meist um die 10µs Schreibzeit, der 29C im Page Modus mit rund 5-10ms 
Schreibzeit.

von Klaus Falser (Gast)


Lesenswert?

Vielleicht wäre in kleines RTOS ideal.
Eine Task bedient den Benutzer und eine andere (mit niederer Priorität) 
speichert die Werte.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Kanonen und Spatzen?

von holger (Gast)


Lesenswert?

>Vor allem wenn ich eine Scene mit DMX-Werten abspeichern will:
>512 Werte * 8.5 ms = 4.352 Sekunden.

Die Frage ist doch was passiert wenn du einen Schreibzyklus
gestartet hast ? Hast du eine Menge Sachen zu erledigen
bevor der beendet ist und das mit einem Interrupt
gemeldet wird ? Falls nicht bringt es nichts. Du schiebst
das Problem zeitlich nur ein klein wenig vor dir her.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, in 8.5 ms kannste allemal den Leuten das Licht zwischendurch
abdrehen (oder auch zuschalten ;-).

von Falk B. (falk)


Lesenswert?

@ Bernt Hullen (bernt)

>Vor allem wenn ich eine Scene mit DMX-Werten abspeichern will:
>512 Werte * 8.5 ms = 4.352 Sekunden.

Naja, die meisten EPROMS besitzen einen Page Mode, da kann man 16 oder 
32 Bytes gleichzeitig speichern, dauert dann auch nur 8,5ms. Damit 
verringert sich deine Spreicherzeit auf 1/16 bis 1/32, sprich  ca. 270 
bzw 135ms.

>Soll ich dann Kerzen verteilen damit die Leute was sehen,
>während ich eine Scene abspeichere?

???
Ich kenn mich mit DMX nicht aus, aber sollte das Speichern nicht 
parallel zum Normalbetrieb laufen? Das geht auch ohne Interrupt.

MFG
Falk

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner wrote:

> Ich kenn mich mit DMX nicht aus, aber sollte das Speichern nicht
> parallel zum Normalbetrieb laufen?

Genau das ist doch sein Punkt: er möchte den EEPROM-Interrupt
(statt der busy-wait-Routinen aus der avr-libc) benutzen, damit
das Speichern im Hintergrund ablaufen kann.

von Falk B. (falk)


Lesenswert?

@  Jörg Wunsch (dl8dtl)

>Genau das ist doch sein Punkt: er möchte den EEPROM-Interrupt
>(statt der busy-wait-Routinen aus der avr-libc) benutzen, damit
>das Speichern im Hintergrund ablaufen kann.

Schon klar, aber selbst MIT Nutzung der normalen Funktionen der avr-libc 
kann man das praktisch "parallel" erledigen. Klar dass man nicht ohne 
Pause alle 512 Bytes schreiben darf!

MFG
Falk

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, OK, jetzt verstehe ich, was du willst...  Aber das mit dem
EEPROM-Interrupt kann auch nicht der Akt sein.  Wie ich schon schrieb,
ist das doch eigentlich nichts anderes, als eine interruptgesteuerte
UART-Senderoutine.

von Peter D. (peda)


Lesenswert?

Wenn ich in den EEPROM was schreiben muß, benutze ich ne Struktur im 
SRAM, wo die Änderungen gemacht werden.
Das Rückschreiben in den EEPROM erfolgt dann im Hintergrund per Polling 
im Main.
Hier mal ein Programmauszug:
1
void eeprom_changed( void )             // write back needed
2
{
3
  ee_upd = EE_START;
4
}
5
6
7
void eeprom_update( void )              // rewrite changed data
8
{
9
  if( EECR & 1<<EEWE )                  // previous write not finished
10
    return;
11
  EEARL = 0;                            // address outside used data
12
13
  if( ee_upd > EE_END )                 // update done
14
    return;
15
16
  EEARL = ee_upd;
17
  EEARH = 0;
18
  EECR |= 1<<EERE;                              // read
19
  if( EEDR != ((u8*)eedat)[ee_upd-EE_START] ){  // if changed
20
    EEDR = ((u8*)eedat)[ee_upd-EE_START];       // update
21
    cli();
22
    EECR |= 1<<EEMWE;
23
    EECR |= 1<<EEWE;                            // start write
24
    sei();
25
  }
26
  ee_upd++;                                     // next address
27
}


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich verstehe nicht, warum hier nur alle alle möglichen Alternativ-
vorschläge bringen müssen.  Was bitte ist an einem interrupt-
gesteuerten Schreiben denn so schlimm, dass alle das meiden wie
der Teufel das Weihwasser?

von Falk B. (falk)


Lesenswert?

@  Jörg Wunsch (dl8dtl)

>vorschläge bringen müssen.  Was bitte ist an einem interrupt-
>gesteuerten Schreiben denn so schlimm, dass alle das meiden wie
>der Teufel das Weihwasser?

Coitus interruptus?

duckundwech

SCNR
Falk

P.S. Was Wikipedia alles weiss!

http://de.wikipedia.org/wiki/Coitus_interruptus

von holger (Gast)


Lesenswert?

>Was bitte ist an einem interrupt-
>gesteuerten Schreiben denn so schlimm, dass alle das meiden wie
>der Teufel das Weihwasser?

Gar nichts, solange es was bringt. Wie ja bereits 2920 in der
ersten Antwort richtig bemerkte: Das schreiben an sich wird
dadurch nicht schneller. Ob man nun einen Interrupt benutzt
oder die Polling Methode, es bleibt dabei das das reine
schreiben ins EEPROM ca. 4 Sekunden dauert. Vermutlich ist
es wesentlich weniger weil 8,5ms als maximale Schreibzeit
angegeben ist. Bei der Interrupt Methode kann man sicherlich
die Zeit bis zum Ende des Schreibzyklus besser ausnutzen. Bei
der Polling Methode geht das aber auch einigermaßen.
Man fängt halt erst an zu pollen wenn man andere Sachen
erledigt hat.

Wenn die 512 Bytes aber eins nach dem anderen schnell reinkommen
bevor ein EEPROM Schreibzyklus beendet ist, muss er diese
Daten im RAM puffern. Das bleibt ihm einfach nicht erspart.

Das EEPROM ist halt kein RAM-Ersatz.

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:
> Ich verstehe nicht, warum hier nur alle alle möglichen Alternativ-
> vorschläge bringen müssen.  Was bitte ist an einem interrupt-
> gesteuerten Schreiben denn so schlimm, dass alle das meiden wie
> der Teufel das Weihwasser?

Die Frage ist wozu?

EEPROM Schreiben ist meistens was total unwichtiges, warum soll ich mir 
dann damit die Latenz von andern Interupts versauen?

Es reicht, daß es irgendwann fertig ist und daher mache ich es mit 
Polling in der Mainloop.
Durch die nicht benötigte Registerrettung ist auch der Code kleiner.

Es ging ja nur darum, die gesamte Schreibzeit nicht unnötig zu 
verwarten, sondern die Mainloop die Zeit nutzen zu lassen.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

> EEPROM Schreiben ist meistens was total unwichtiges, warum soll ich mir
> dann damit die Latenz von andern Interupts versauen?

Musst du nicht.  Du kannst die Interrupts sofort wieder freigeben.

von Werner B. (Gast)


Lesenswert?

AVR104: Buffered Interrupt Controlled EEPROM Writes

http://www.atmel.com/dyn/resources/prod_documents/doc2540.pdf

Werner

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:
> Musst du nicht.  Du kannst die Interrupts sofort wieder freigeben.

Kannst Du eben nicht, das Interruptflag wird bei Eintritt nicht 
gelöscht!
Ist das gleiche Dilemma, wie bei UART oder I2C.
Nur in Timerinterrupts kann man andere Interrupts freigeben.


Meistens ist es sogar unerwünscht, daß EEPROM-Daten immer sofort 
zurückgeschrieben werden. Es würden nur unnötig viel Schreibzyklen 
verbraten.

Deshalb lege ich für EEPROM-Daten eine Struktur im SRAM an, dort kann 
man dann beliebig rumändern.
Und erst, wenn man die Taste Speichern drückt, wird dann wirklich in den 
EEPROM zurück geschrieben, immer ein Byte nach dem anderen, sobald die 
Mainloop die Schreibroutine pollt.
Und durch das vorherige Lesen, werden auch nur geänderte Bytes 
geschrieben.


Peter

von gast (Gast)


Lesenswert?

sei(); im interrupt! wieso sollte das nicht gehen, peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

>> Musst du nicht.  Du kannst die Interrupts sofort wieder freigeben.

> Kannst Du eben nicht, das Interruptflag wird bei Eintritt nicht
> gelöscht!

Stimmt, ist ja wirklich unschön gelöst.

von Ha Jo (Gast)


Lesenswert?

Peter Dannegger wrote:
> Jörg Wunsch wrote:
>> Musst du nicht.  Du kannst die Interrupts sofort wieder freigeben.
>
> Kannst Du eben nicht, das Interruptflag wird bei Eintritt nicht
> gelöscht!
> Ist das gleiche Dilemma, wie bei UART oder I2C.
> Nur in Timerinterrupts kann man andere Interrupts freigeben.

@Peter und Jörg:
Könnt Ihr mir hier bitte auf die Sprünge helfen? Warum soll das
freigeben der Interrupts nicht funktionieren?
Es gibt doch sogar:
ISR(XXX_vect, ISR_NOBLOCK)

Und warum auch bei UART und I2C?
So verstehe ich das nicht.
Danke für den Tip.

Hajo

von Falk B. (falk)


Lesenswert?

@ Ha Jo (hajo)

>> Ist das gleiche Dilemma, wie bei UART oder I2C.
>> Nur in Timerinterrupts kann man andere Interrupts freigeben.

>Könnt Ihr mir hier bitte auf die Sprünge helfen? Warum soll das
>freigeben der Interrupts nicht funktionieren?

Weil bei UART und TWI der Interrupt nicht beim Anspringen des Interrupts 
automatisch gelöscht wird, sondern erst nach Lesen der Daten vom 
UART/TWI. Dann erst kann man die Interrupts dort wieder freigeben.

MFG
Falk

von Ha Jo (Gast)


Lesenswert?

vor die stirn klatsch

Klaro. Ich bin einfach nicht drauf gekommen. Dachte mir nur,
wiese sollte das nicht gehen? Aber es leuchtet natürlich ein :-)

Danke für den "Schlag auf den Hinterkopf" :-)

Hajo

von ras (Gast)


Lesenswert?

Ja, der Thread ist uralt. Hier aber ein Linkzur Lösung des Problems:

http://avr.15.forumer.com/a/interruptdriven-eeprom-writes-gcc_post251.html

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.