Forum: Compiler & IDEs EEprom schneller schreiben


von Lesca (Gast)


Lesenswert?

Guten Morgen,
ich habe hier einen AT90Can128 und betreibe einen Can Open Slave drauf.
Soweit so gut. Ich empfange per SDO Blocktransfer Parameter Blöcke. Die 
Blöcke sind 80 Byte groß.
Diese Empfangenen Blöcke sollen wenn sich was verändert hat ins EEprom 
gesichert werden.
Nutze dazu die Funktion eeprom_write_block.
Auch das funktioniert Grundsätzlich. Mein Problem ist das diese 
eeprom_write_block Funktion anscheinend ziemlich lange dauert und in der 
Zwischenzeit die Empfangs Queue überläuft.
Dies passiert nur während des EEprom schreiben.
Wie könnte ich das schreiben beschleunigen?
Danke Lg

von g457 (Gast)


Lesenswert?

> Wie könnte ich das schreiben beschleunigen?

Selber schreiben und asynchronifizieren.

von Brecher (Gast)


Lesenswert?

Das EEPROM interruptgesteuert beschreiben.

von Hoschti (Gast)


Lesenswert?

Nur die geänderten Bytes ins EEProm schreiben. Das kann, je nach der 
"Änderungsfreudigkeit" der Daten auch helfen.

von Lesca (Gast)


Lesenswert?

Brecher schrieb:
> Das EEPROM interruptgesteuert beschreiben.

Ja das klingt vernünftig. Gibt es dazu ein Beispiel? Oder wo finde ich 
den Quellcode von originalen eeprom_write_block?

Hoschti schrieb:
> Nur die geänderten Bytes ins EEProm schreiben. Das kann, je nach der
> "Änderungsfreudigkeit" der Daten auch helfen.

Ich glaube das das filtern welche Daten sich geändert haben aufwändiger 
ist als den ganzen Block zu schreiben.

Danke

von Brecher (Gast)


Lesenswert?

Lesca schrieb:
> Ich glaube das das filtern welche Daten sich geändert haben aufwändiger
> ist als den ganzen Block zu schreiben.

Nein.
Das Lesen des EEPROMs ist sehr schnell.
if (lese(x) != x) schreibe(x);

Das lohnt sich, wenn z.B. immer mehr als 50% identisch sind.
Im falle von <10% identischen Daten ist es natürlich noch etwas 
langsamer.

> Gibt es dazu ein Beispiel? Oder wo finde ich
> den Quellcode von originalen eeprom_write_block?

Der Quellcode von eeprom_write_block hilft dir nicht bei der Erstellung 
von interruptgesteuerter EEPROM-Bedienung. Aber mit Google wirst du 
sicher fündig.
Außerdem ist es im Datenblatt gut beschrieben.

von M. K. (sylaina)


Lesenswert?

Brecher schrieb:
> Das Lesen des EEPROMs ist sehr schnell.
> if (lese(x) != x) schreibe(x);

Statt einem eeprom_write_word kann man auch ein eeprom_update_word 
benutzen, dass schreibt nur wenn sich auch wirklich was geändert hat ;)

von x^2 (Gast)


Lesenswert?

Falls mehrere Blöcke synchron geschrieben werden, wird viel Zeit auch 
durch den internen Write-Cycle des EEPROM geschluckt. Von der 
Größenordnung her ist dieser ca 5ms. Also ein Vielfaches der Dauer des 
eigentlichen Datentransfers.

Je nachdem wie die Funktion zum Schreiben arbeitet, kann es Sinn machen 
alle Änderungen auf eine Kopie der Page im RAM anzuwenden und diese dann 
einmalig aufs EEPROM zu schreiben, anstatt x-mal die Änderungen direkt 
ans EEPROM zu schreiben.

von Peter D. (peda)


Lesenswert?

Ich arbeite nie direkt im EEPROM, sondern lege eine Kopie im SRAM an und 
bearbeite diese. Bei Bedarf erfolgt dann ein Rückspeichern in den EEPROM 
im Hintergrund.
1
struct
2
{
3
  uint8_t* src;
4
  uint16_t dst;
5
  uint16_t len;
6
  bool busy;
7
} eew;
8
9
void epp_wr_poll(void)                          // called by main loop
10
{
11
  if (eew.busy == false)                        // nothing to do
12
    return;
13
  if (EECR & 1 << EEWE)                         // not ready yet
14
    return;
15
  EEAR = eew.dst;
16
  EECR |= 1 << EERE;                            // read
17
  if (*eew.src != EEDR)
18
  {
19
    EEDR = *eew.src;
20
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
21
    {
22
      EECR |= 1 << EEMWE;                       // Enable Write
23
      EECR |= 1 << EEWE;                        // write
24
    }
25
  }
26
  eew.src++;
27
  eew.dst++;
28
  if (--eew.len == 0)
29
    eew.busy = false;                           // all bytes written
30
}
31
32
static void eep_wr_start(uint8_t* src, uint16_t dst, uint16_t len)
33
{
34
  eew.src = src;
35
  eew.dst = dst;
36
  eew.len = len;
37
  eew.busy = true;
38
}

von Lesca (Gast)


Lesenswert?

Peter D. schrieb:
> Ich arbeite nie direkt im EEPROM, sondern lege eine Kopie im SRAM an und
> bearbeite diese. Bei Bedarf erfolgt dann ein Rückspeichern in den EEPROM
> im Hintergrund.

Dieser Ansatz ist mir sympathisch.
Habe aber dein Beispiel nicht ganz verstanden.
Könntest du mir das Beispiel kurz erklären bzw eine Symbolische main 
einstellen damit ich das Ganze verstehe.
Vielen herzlichen Dank

von Peter D. (peda)


Lesenswert?

Nun, mit eep_wr_start() startet man das Blockwrite. Es wartet aber nicht 
auf das Ende, sondern kehrt sofort zurück.
Das Schreiben führt dann epp_wr_poll() aus, welches zyklisch aufgerufen 
werden muß, z.B. in der Mainloop.
Die Namen src, dst, len dürften selbsterklärend sein.

von Falk B. (falk)


Lesenswert?

Lesca schrieb:
> Nutze dazu die Funktion eeprom_write_block.

Die ist blockierend, denn sie wartet auf das Ende des Schreibvorgangs.

> Wie könnte ich das schreiben beschleunigen?

Indem man es nichtblockierend als Statemachine schreibt und immer 
nur den Schreibvorgang startet, nicht aber direkt auf das Ende wartet. 
Dafür braucht es nicht mal einen Interrupt.

von Oliver S. (oliverso)


Lesenswert?

Das alles ändert aber nichts daran, daß ein Schreibzyklus ins EEPROM 
„endlos“ lange dauert. Und wenn die Daten schneller geschrieben werden 
müssen, als das Schreiben tatsächlich dauert, dann helfen auch die 
genialsten Programmiertipps nicht weiter.

Entweder über das „müssen“ nachdenken, oder andere Hardware einsetzen.

Oliver

von Falk B. (falk)


Lesenswert?

Oliver S. schrieb:
> Das alles ändert aber nichts daran, daß ein Schreibzyklus ins EEPROM
> „endlos“ lange dauert.

Naja, um die 3-4ms pro Byte (Erase and Write).

> Und wenn die Daten schneller geschrieben werden
> müssen, als das Schreiben tatsächlich dauert, dann helfen auch die
> genialsten Programmiertipps nicht weiter.

Unsinn! Das Problem ist die Blockierung der CPU durch die einfache 
EEPROM-Schreibfunktion!

> Entweder über das „müssen“ nachdenken, oder andere Hardware einsetzen.

Erstmal das Problem WIRKLICH verstehen!

von Oliver S. (oliverso)


Lesenswert?

Falk B. schrieb:
> Erstmal das Problem WIRKLICH verstehen!

Eben. Und da außer der Angabe, daß je Block 80 Byte geschrieben werden 
müssen, die über CAn hereinkommen, nichts weiter bekannt ist, fehlen 
alle Fakten zum wirklichen Verstehen des Problems.

Oliver

von MWS (Gast)


Lesenswert?

Falk B. schrieb:
> Naja, um die 3-4ms pro Byte (Erase and Write).

Laut DB 8,5ms.

Oliver S. schrieb:
> fehlen alle Fakten zum wirklichen Verstehen des Problems.

Das Problem ist sehr einfach zu verstehen, die eeprom_write_block aus 
libc wartete eben für jedes Byte, bis es geschrieben ist, daher dauern 
80 Byte 680ms. Diese Wartezeit kann nur durch Interrupts unterbrochen 
werden, die normal Programmausführung ist dagegen blockiert.

Die Lösung ist schwieriger, denn obwohl eine interruptgesteuerte EEProm 
Schreibroutine die normale Programmausführung viel weniger belasten 
würde, so dauert es auch damit noch 680ms bis ein Block geschrieben ist.

Selbst wenn der Controller neue Can-Daten zwischenzeitlich empfangen 
konnte, so hilft das nichts, wenn die alten noch nicht im EEPRom 
abgelegt sind. Das nächste Problem ist zu häufiges Beschreiben des 
EEProms.

Ergo: Das ganze Konzept ist mangelhaft. Also die Daten entweder im SRam 
halten oder auf externen schnellen und nichtflüchtigen Speicher 
auslagern.

von Falk B. (falk)


Lesenswert?

MWS schrieb:
> Falk B. schrieb:
>> Naja, um die 3-4ms pro Byte (Erase and Write).
>
> Laut DB 8,5ms.

Ok, ich hab beim ATmega328 reingeschaut.

> Die Lösung ist schwieriger, denn obwohl eine interruptgesteuerte EEProm
> Schreibroutine die normale Programmausführung viel weniger belasten
> würde, so dauert es auch damit noch 680ms bis ein Block geschrieben ist.

Stimmt.

> Selbst wenn der Controller neue Can-Daten zwischenzeitlich empfangen
> konnte, so hilft das nichts, wenn die alten noch nicht im EEPRom
> abgelegt sind.

Jain. Dafür gibt es FIFOs oder andere Puffermethoden.

von Lesca (Gast)


Lesenswert?

Peter D. schrieb:
> Nun, mit eep_wr_start() startet man das Blockwrite. Es wartet aber nicht
> auf das Ende, sondern kehrt sofort zurück.
> Das Schreiben führt dann epp_wr_poll() aus, welches zyklisch aufgerufen
> werden muß, z.B. in der Mainloop.
> Die Namen src, dst, len dürften selbsterklärend sein.

Werde es probieren Danke

von Peter D. (peda)


Lesenswert?

MWS schrieb:
> Die Lösung ist schwieriger

Nö, die Lösung so einfach, wie bereits beschrieben. Ich hätte es auch 
mit Interrupt machen können, aber das war nicht nötig.
Wenn die EEPROM-Daten mit im RAM liegen, kann man auch viel einfacher 
drauf zugreifen. Man merkt überhaupt keinen Unterschied zu echten 
Variablen. Sie werden nach dem Reset vom EEPROM geladen und bei Bedarf 
im Hintergrund dahin gesichert.
Zur Sicherheit speichere ich im EEPROM 2 Datensätze mit CRC16. Damit ist 
dann auch abgesichert, wenn vor dem Abschalten das Schreiben im 
Hintergrund noch nicht beendet ist.

von Joachim B. (jar)


Lesenswert?

Lesca schrieb:
> Nutze dazu die Funktion eeprom_write_block.

die meisten Routinen warten nach jedem Byte 5ms-10ms, das war für mich 
unerträglich, ich schrieb meine eigene write block Routine (mit Hilfe 
aus dem Netz), nach jedem Byte schreiben teste ich in einer Schleife ob 
das I2C EEPROM ansprechbar ist, wenn ja schreibe ich das nächste Byte, 
das hat meine Geschwindigkeit beim Schreiben mindestens verfünffacht.
1
#define readIIC() Wire.read()
2
3
void my_i2c_eeprom_wait_ready(void) { 
4
  Wire.setClock(I2C_LOW);
5
  // Wait until EEPROM gives ACK again.
6
  // this is a bit faster than the hardcoded 5 milli
7
  do { 
8
    Wire.beginTransmission(MY_I2C_EEPROM_ADDRESS); Wire.requestFrom(MY_I2C_EEPROM_ADDRESS, 1);
9
    readIIC();
10
  }while(Wire.endTransmission());
11
  Wire.setClock(I2C_HIGH);
12
} // void my_i2c_eeprom_wait_ready(void)
13
14
void my_i2c_eeprom_write_buffer( uint16_t eeaddress, char *data, uint16_t length ) { 
15
  uint16_t str_ptr = 0;
16
  while(length--) { 
17
    my_i2c_eeprom_wait_ready();
18
    my_i2c_eeprom_write_byte( (eeaddress+str_ptr++), *data++ );
19
    //DEBUG_PRINTLN(*data++);
20
  };
21
} // void my_i2c_eeprom_write_buffer( uint16_t eeaddress, char *data, uint16_t length )

bei internen EEPROMs kann das busy flag abgefragt werden!

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Peter D. schrieb:
> Nö, die Lösung so einfach, wie bereits beschrieben. Ich hätte es auch
> mit Interrupt machen können

Mir ist wieder eingefallen, warum ich es nicht im EEPROM-Interrupt 
mache.
Wenn sich nur wenige Bytes geändert haben, wird der Interrupt ja sehr 
oft hintereinander aufgerufen. Das kann die Mainloop um mehrere ms 
verzögern und damit Seiteneffekte bewirken. Ein Aufruf im Timerinterrupt 
würde die nötige Updatezeit dagegen unnötig verlängern.
Daher ist der Aufruf in der Mainloop der optimale Platz. Er behindert 
nichts und beendet das Update so schnell wie möglich.

von Lesca (Gast)


Lesenswert?

So Peter ich habe deinen Code getestet, funktioniert einwandfrei!!!

Danke für die Hilfe

von Mitlesa (Gast)


Lesenswert?

Lesca schrieb:
> So Peter ich habe deinen Code getestet, funktioniert einwandfrei!!!

Einfach und schon deshalb ein bisschen genial!

Für die neueren AVRs (328, 644, ....) braucht es leicht
geänderte EEPROM-Registernamen.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Mir ist wieder eingefallen, warum ich es nicht im EEPROM-Interrupt
> mache.
> Wenn sich nur wenige Bytes geändert haben, wird der Interrupt ja sehr
> oft hintereinander aufgerufen. Das kann die Mainloop um mehrere ms
> verzögern und damit Seiteneffekte bewirken. Ein Aufruf im Timerinterrupt
> würde die nötige Updatezeit dagegen unnötig verlängern.
> Daher ist der Aufruf in der Mainloop der optimale Platz. Er behindert
> nichts und beendet das Update so schnell wie möglich.

OMG. Da spricht die geballte Unfähigkeit.

Es ist völlig Ritze, wieviele Bytes sich geändert haben: Der Interrupt 
kann bei korrekter Programmierung natürlich maximal mit der Rate 
auftreten, die die Schreibzeit für ein Byte vorgibt. Also, irgendwas im 
einstelligen ms-Bereich.

Sprich: du kannst einfach nur "Hauptschleife", mit kompetenter 
Interrupt-Programmierung wirst du wohl niemals mehr warm...

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Es ist völlig Ritze, wieviele Bytes sich geändert haben: Der Interrupt
> kann bei korrekter Programmierung natürlich maximal mit der Rate
> auftreten, die die Schreibzeit für ein Byte vorgibt. Also, irgendwas im
> einstelligen ms-Bereich.

Dann hast Du meinen Code nicht gelesen oder nicht verstanden.
Ich prüfe vor dem Schreiben, ob das Byte bereits stimmt. Dann wird 
nämlich nicht nochmal überschrieben. D.h. der Interrupt wird beendet, 
genau ein Befehl der Mainloop ausgeführt und wieder in den Interrupt 
gesprungen.

Es mag Wumpe sein, ob die Mainloop bei nur einem geänderten Byte von 
1024 Byte einige ms Däumchen dreht, aber wenn ich es vermeiden kann, ist 
es die bessere Lösung.
Seiteneffekte zu kennen ist gut, aber Seiteneffekte zu vermeiden, ist 
besser.

von Peter D. (peda)


Lesenswert?

Mitlesa schrieb:
> Einfach und schon deshalb ein bisschen genial!

Danke für die Blumen.
Ich hatte ihn auch als Interrupt probiert. Der Code ist dadurch etwas 
angestiegen, da ja ein Interrupt alles sichern muß, die Mainloop aber 
Register zerstören darf (Call-used registers: r18-r27, r30-r31).
Dann ist mir aber der Seiteneffekt aufgefallen und ich habe die 
Interruptvariante wieder verworfen.

von Ole (Gast)


Lesenswert?

Das ist bestimmt schon patentiert.

von Rolf M. (rmagnus)


Lesenswert?

Peter D. schrieb:
> c-hater schrieb:
>> Es ist völlig Ritze, wieviele Bytes sich geändert haben: Der Interrupt
>> kann bei korrekter Programmierung natürlich maximal mit der Rate
>> auftreten, die die Schreibzeit für ein Byte vorgibt. Also, irgendwas im
>> einstelligen ms-Bereich.
>
> Dann hast Du meinen Code nicht gelesen oder nicht verstanden.
> Ich prüfe vor dem Schreiben, ob das Byte bereits stimmt. Dann wird
> nämlich nicht nochmal überschrieben. D.h. der Interrupt wird beendet,
> genau ein Befehl der Mainloop ausgeführt und wieder in den Interrupt
> gesprungen.

Und warum springst du dann nicht in der ISR weiter zum nächsten Byte, 
das sich geändert hat? Es ist natürlich nicht besonders sinnvoll, aus 
der ISR rauszuspringen, ohne den nächsten Schreibvorgang angestoßen zu 
haben.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Rolf M. schrieb:
> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
> das sich geändert hat? Es ist natürlich nicht besonders sinnvoll, aus
> der ISR rauszuspringen, ohne den nächsten Schreibvorgang angestoßen zu
> haben.

gute Frage aber schrieb PeDa nicht das er es nicht in der ISR macht?

Da ein Schreibvorgang eh um ms dauert könnte man nach dem Anstossen auch 
raus weil keiner solange die ISR blockieren will bis das Byte 
geschrieben ist.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> Rolf M. schrieb:
>> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
>> das sich geändert hat? Es ist natürlich nicht besonders sinnvoll, aus
>> der ISR rauszuspringen, ohne den nächsten Schreibvorgang angestoßen zu
>> haben.
>
> gute Frage aber schrieb PeDa nicht das er es nicht in der ISR macht?

Er schrieb, dass er die ISR-Variante verworfen hat, weil bei wenigen 
Änderungen die ISR mit sehr hoher Rate getriggert wird. Und das liegt 
eben daran, dass er aus ihr zurückspringt, ohne den nächsten 
Schreibvorgang zu starten.

> Da ein Schreibvorgang eh um ms dauert könnte man nach dem Anstossen auch
> raus weil keiner solange die ISR blockieren will bis das Byte
> geschrieben ist.

Ja selbstverständlich. Das ist ja der ganze Sinn davon, es 
interruptgesteuert zu machen. Ist ein Byte fertig geschrieben, wird der 
Interrupt ausgelöst, man stößt den nächsten Schreibvorgang an und geht 
sofort wieder raus.

von Joachim B. (jar)


Lesenswert?

Rolf M. schrieb:
> Ja selbstverständlich. Das ist ja der ganze Sinn davon, es
> interruptgesteuert zu machen

das musst du mal in Code umsetzen, ich verstehe es nicht wirklich

Rolf M. schrieb:
> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
> das sich geändert hat?

?
das nächste Byte kann doch erst nach dem Schreiben vom Vorgänger 
angestoßen werden und das dauert.

also zeige doch wie du dir das vorstellst.

Ich lasse es lieber in der Mainloop, nehme aber mit das man in der 
Schreibroutine nicht warten muss bis fertig, das Prüfen vom Internen EEP 
kann in der ISR bleiben, für I2C busy und I2C EEP lohnt das nicht, der 
Zugriff auf I2C dauert eh länger.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> Rolf M. schrieb:
>> Ja selbstverständlich. Das ist ja der ganze Sinn davon, es
>> interruptgesteuert zu machen
>
> das musst du mal in Code umsetzen, ich verstehe es nicht wirklich

Hmm, der Code wäre doch ziemlich tivial…

> Rolf M. schrieb:
>> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
>> das sich geändert hat?
>
> ?
> das nächste Byte kann doch erst nach dem Schreiben vom Vorgänger
> angestoßen werden und das dauert.

Weißt du, was ein Interrupt ist? Die ISR wird doch erst dadurch 
angetriggert, dass der Vorgänger fertig ist. Sie startet ihre Ausführung 
genau zu dem Zeitpunkt, zu dem das nächste Byte geschrieben werden kann. 
Die ISR muss dann nur das Schreiben anstoßen und zurückspringen. Wenn 
das Byte dann fertig ist, wird die ISR wieder getriggert, und sie kann 
den nächsten Schreibvorgang anstoßen. Warum soll man da irgendwo warten 
müssen?

> Ich lasse es lieber in der Mainloop, nehme aber mit das man in der
> Schreibroutine nicht warten muss bis fertig, das Prüfen vom Internen EEP
> kann in der ISR bleiben,

In der ISR muss man es gar nicht prüfen. Sie wird ja gerade deshalb 
aufgerufen, weil der EEPROM jetzt bereit ist für den nächsten 
Schreibvorgang. Oder was dachtest du, wie die ausgelöst wird?

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Rolf M. schrieb:
> Hmm, der Code wäre doch ziemlich tivial…

ach prosa code liegt mir nicht, wenn es trivial ist, dann zeige bitte 
Code.

von Falk B. (falk)


Lesenswert?

Rolf M. schrieb:

> Er schrieb, dass er die ISR-Variante verworfen hat, weil bei wenigen
> Änderungen die ISR mit sehr hoher Rate getriggert wird. Und das liegt
> eben daran, dass er aus ihr zurückspringt, ohne den nächsten
> Schreibvorgang zu starten.

Im Prinzip ja, aber natürlich muss man bei sowas auch den Fall vorsehen, 
daß keine oder wenige Änderungen vorliegen! Dann muss der Prozess 
pausieren, natürlich nicht in der ISR. Erst wenn wieder ein 
Schreibzugriff auf die EEPROM-Variablen erfolgte, darf die FSM zum 
Update wieder aktiv werden. Und erst dann gibt es wieder 
EEPROM-Interrupts. Ist doch das Gleiche wie beim interruptgesteuerten 
Senden per UART, dort schaltet sich die ISR auch selber ab, wenn keine 
Daten mehr zu senden sind.

Aber am Ende ist es es zweitrangig, ob man das mit einem Timer- oder 
EEPROM-Interrupt macht, die Wirkung ist gleich.

von Falk B. (falk)


Lesenswert?

Joachim B. schrieb:

> Ich lasse es lieber in der Mainloop, nehme aber mit das man in der
> Schreibroutine nicht warten muss bis fertig,

Nicht warten DARF! Denn das wäre ein blockierendes Verhalten und somit 
wäre der Ganze Aufwand für die Katz!

von Peter D. (peda)


Lesenswert?

Rolf M. schrieb:
> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
> das sich geändert hat?

Weil das den Interrupt zu sehr verlängern könnte, z.B. müßte bei 
angenommener Größe der Daten im EEPROM von 1kB die Schleife bis zu 1023 
mal durchlaufen werden. Das könnten wiederum z.B. den UART-Interrupt bei 
115kBaud Daten verlieren lassen usw. Der AVR hat ja keine Prioritäten, 
um andere Interrupts zu unterbrechen.
KISS, Keep It Short and Simple.

von Falk B. (falk)


Lesenswert?

Peter D. schrieb:
> Rolf M. schrieb:
>> Und warum springst du dann nicht in der ISR weiter zum nächsten Byte,
>> das sich geändert hat?
>
> Weil das den Interrupt zu sehr verlängern könnte, z.B. müßte bei
> angenommener Größe der Daten im EEPROM von 1kB die Schleife bis zu 1023
> mal durchlaufen werden. Das könnten wiederum z.B. den UART-Interrupt bei
> 115kBaud Daten verlieren lassen usw. Der AVR hat ja keine Prioritäten,
> um andere Interrupts zu unterbrechen.

Naja, man könnte schon die ISR nach der Prüfung eines einzigen Bytes 
verlassen, auch ohne einen neuen Schreibvorgang auszulösen. Dann hätten 
andere ISRs die Chance, bearbeitet zu werden, denn der EEPROM-Interrupt 
hat in der Interrupt-Liste eine relativ niedrige Priorität.

> KISS, Keep It Short and Simple.

In der Tat. So ein Update-Prozess muss ja keine Rekorde aufstellen, der 
kann mit ein paar Dutzend Hz im Hintergrund laufen.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Weil das den Interrupt zu sehr verlängern könnte, z.B. müßte bei
> angenommener Größe der Daten im EEPROM von 1kB die Schleife bis zu 1023
> mal durchlaufen werden. Das könnten wiederum z.B. den UART-Interrupt bei
> 115kBaud Daten verlieren lassen usw. Der AVR hat ja keine Prioritäten,
> um andere Interrupts zu unterbrechen.
> KISS, Keep It Short and Simple.

OMG, das wird ja immer schlimmer.

Mann, das ist doch trivialste Scheiße. Bei einer UART-Empfangs-Routine 
bekommst du das Grundkonzept der Interruptprogrammierung doch 
offensichtlich auch gebacken.

Der einzige Unterschied bei dieser Sache hier besteht darin, dass das 
Ereignis nicht von außen kommt, sondern aus dem eigenen Programm. Was 
allerdings ganz grundsätzlich für jeden "Ausgabe"-Interrupt zutrifft.
Und, siehe da: auch beim UART-Senden bist du offensichtlich durchaus in 
der Lage, Interruptprogrammierung korrekt umzusetzen. Bei Streams geht's 
also...

D.h.: prinzipiell weisst du offensichtlich bereits alles nötige, um die 
Sache korrekt umzusetzen. Es braucht nur eine Queue für die zu 
schreibenden Bytes, der einzige Unterschied zu einer UART-Sendequeue 
ist, das sie nicht nur Daten, sondern auch Adressen enthalten müsste.

So eine einfache Lösung wäre allerdings nur sinnvoll, wenn sich 
innerhalb einer Byte-Scheibzeit immer nur vergleichsweise (im Verhältnis 
zur Gesamtzahl der EEPROM-Bytes) wenige Bytes ändern werden und diese 
addressmäßig quasi "random" verteilt sind.
Für andere Szenarios gibt es natürlich weitaus bessere 
Queueing-Strategien. Es ist Aufgabe des Programmiers, eine geeignete zu 
wählen, denn nur er kann das Wissen über das Datenaufkommen haben, was 
nötig ist, um eben dies zu tun.

Der eigentliche Kern ist aber: Queues sind IMMER die Lösung für die 
Kommunikation mit ISRs, jedenfalls immer, wenn Daten bewegt werden 
müssen. Aber das weisst du doch selber auch! Also woher, zum Teufel, 
stammt dein Problem speziell bezüglich des EEPROM-Schreibens?

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Also woher, zum Teufel,
> stammt dein Problem speziell bezüglich des EEPROM-Schreibens?

Na von Dir doch. Nur Du versuchst, uns ein Problem einzureden, was nicht 
existiert.
Die Pollingmethode funktioniert bestens und hat eindeutig Vorteile 
gegenüber der Interruptmethode.
Natürlich könnte man in die Interruptmethode nen Haufen Schnulli 
einbauen, um die möglichen Problempunkte zu entschärfen. In diesem Fall 
ist aber die einfachste Methode auch die beste. Niemand hat was davon, 
den Code unnötig aufzublähen.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Die Pollingmethode funktioniert bestens und hat eindeutig Vorteile
> gegenüber der Interruptmethode.

Die da im Detail wären?

Und: warum, zum Teufel, hat der Spender der edlen Hardware diesen 
Interrupt überhaupt vorgesehen, wenn er denn so völlig nutzlos, ja sogar 
kontraproduktiv ist, wie du behauptest?

Hätte er in diesem Fall nicht lieber die dafür nötigen Gatter im Zuge 
der Kostenoptimierung eingespart?

Hat er aber nicht getan. Warum wohl? Könntest du eventuell mal darüber 
nachdenken?

Kanst du das? Nachdenken?

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Die da im Detail wären?

Sie wurden alle bereits genannt (es sind 3), lies sie einfach.

c-hater schrieb:
> Und: warum, zum Teufel, hat der Spender der edlen Hardware diesen
> Interrupt überhaupt vorgesehen, wenn er denn so völlig nutzlos, ja sogar
> kontraproduktiv ist, wie du behauptest?

Ich weiß, Du bist Meister im Worte verdrehen. Es geht hier um einen 
konkreten Anwendungsfall. Niemand hat behauptet, daß der Interrupt 
generell nutzlos ist.

c-hater schrieb:
> Kanst du das? Nachdenken?

Ich schon, aber Du scheinst damit Probleme zu haben, da Du für andere 
Probleme erfinden mußt.

: Bearbeitet durch User
von Lesca (Gast)


Lesenswert?

Ich muss sagen ich bin mit Peter´s Metohde zufrieden.
Aber dies bezieht sich auf meine Anwendung.
Noch mal Danke Peter


Ps Lass dich nicht von @ c-hater  ärgern.Er kann seinen code einfach 
auch veröffentlichen dann sehen wir ja sein können.

von M. K. (sylaina)


Lesenswert?

Lesca schrieb:
> Lass dich nicht von @ c-hater  ärgern.Er kann seinen code einfach
> auch veröffentlichen dann sehen wir ja sein können.

Ich denke, das wird nicht passieren. c-hater steht ja völlig über uns. 
Wir sollen sicher selbst nachdenken um auf die bessere Variante zu 
kommen.

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.