Asynchrones Schreiben in EEPROM

Es gibt Stm32l052 mit eingebautem EEPROM (2k). Es werden 4 ADC-Kanäle verwendet, Daten werden alle 40 Mikrosekunden vom Trigger gesammelt. Daten vom ADC werden im Interrupt verarbeitet (bestimmt durch die Ausgabe von Werten über die Grenzen hinaus). Wenn Sie also die Standard-Hal-Bibliotheken verwenden, gehen während der Aufzeichnung in EEPROM-Punkte verloren (3 Millisekunden Standard-Schreibgeschwindigkeit in EEPROM-Daten), selbst wenn Sie ein Byte aus dem Ringpuffer schreiben. Gibt es eine Möglichkeit, den Controller dazu zu bringen, asynchron in das EEPROM zu schreiben, ohne die ADC-Interrupts zu blockieren?

Was versuchst du hier eigentlich zu erreichen? EEPROM (egal ob intern oder extern) ist wahrscheinlich nicht für Ihren tatsächlichen Bedarf geeignet, es sei denn, es handelt sich um eine ziemlich seltene Verwendung. Möglicherweise möchten Sie die Daten nur im RAM erfassen - entweder und dann in das EEPROM schreiben oder sie nur im RAM behalten, wenn sie nur von kurzer Dauer sind. Sie sollten sich das interne EEPROM im Allgemeinen als Notizblock vorstellen, um kleine Informationsmengen zu speichern, nicht wirklich als Überlaufspeicher oder Ort zum Speichern dynamischer Daten, wie Sie es von einem ADC erhalten würden.
@ChrisStratton Ein Ringpuffer im RAM ist in der Frage impliziert. So wie ich es verstehe, sollten nur Out-of-Bounds-Daten dauerhaft gespeichert werden, dh das Eeprom wird als Fehlerprotokoll verwendet, um mehr oder weniger seltene Ereignisse zu speichern.
Es sieht so aus, als wäre das EEPROM nur ein partitionierter Teil von FLASH, sodass der gesamte Speicher während des Schreibens für 4 ms blockiert. Ich nehme an, das ist das Problem, von dem Sie sprechen. Nicht einfach zu beheben. Sie müssen wahrscheinlich die ISR-Tabelle und den Handler in den RAM verschieben (stellen Sie sicher, dass Sie keine Bibliotheksroutinen in FLASH aufrufen - einschließlich Dinge wie Fließkomma-Mathematik). Die bessere Lösung wäre ein externes EEPROM.

Antworten (1)

STM32L052scheint einen einzigen Bank-NVM-Controller zu haben, daher würde ein Schreibzugriff auf eine beliebige EEPROM-Adresse das Lesen und Abrufen von Daten aus dem Flash blockieren.

Es würde nur funktionieren, wenn Sie den gesamten relevanten Code außer der Initialisierung, aber einschließlich der Vektortabelle, in den RAM verschieben können. Es wäre eine ziemliche Herausforderung, dies in 8 kByte zu tun, aber es könnte funktionieren. Vergessen Sie HAL, es hat zu viel Overhead und Komplexität.

Ich würde empfehlen, es so zu machen:

  • Verschieben Sie NVIC in den RAM
  • ADC-Interrupt-Handler im RAM, legt Daten in den Ringpuffer, ruft PendSV ( SCB->ICSR=SCB_ICSR_PENDSVSET) auf.
  • Der PendSV-Fehlerhandler im RAM legt, solange Daten zu schreiben sind, ein einzelnes 32-Bit-Wort† im EEPROM ab und wartet, bis der Schreibvorgang abgeschlossen ist. Kehren Sie nicht zurück, solange NVM noch beschäftigt ist.
  • Der ADC-Handler sollte eine höhere Priorität als PendSV haben.
  • Der Rest des Codes kann im Flash belassen werden, solange die Verzögerung akzeptabel ist. Interrupt-Handler in Flash sollten niedrigere Prioritäten als PendSV haben.

Diese Anordnung würde verhindern, dass irgendein Code im Flash ausgeführt wird, solange ein EEPROM-Schreibvorgang im Gange ist, lässt jedoch Handler mit höherer Priorität laufen, solange sie nicht den nichtflüchtigen Speicher berühren.

Um eine Funktion in den RAM zu verlagern

Verwenden Sie bei gcc __attribute__((section(".data")))in der Funktionsdeklaration. Führen Sie dies rekursiv mit jeder aufgerufenen Funktion durch. Wird verwendet -ffreestanding, um zu verhindern, dass gcc unerwartet Aufrufe von Bibliotheksfunktionen generiert. Der .dataAbschnitt wird nach dem Zurücksetzen zusammen mit den initialisierten Variablen durch den Startcode vom Flash in den RAM kopiert.

Zum Verschieben der Vektortabelle

Die Vektortabelle des STM32L052ist 192 Bytes lang (Referenzhandbuch 12.3 Unterbrechungs- und Ausnahmevektoren). Ich würde einfach den Beginn des RAM im Linker-Skript um 192 Byte nach oben verschieben

RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 8000 /* 8192 - 192 */

Kopieren Sie die Vektortabelle dorthin und setzen Sie den Vektortabellenzeiger

memcpy((void*)0x20000000, (void*)0x08000000, 192);
SCB->VTOR = 0x20000000;

bevor irgendein Interrupt aktiviert wird.


Stattdessen STM32L072wäre es möglich, das Programm von Bank 1 laufen zu lassen und EEPROM-Daten in Bank 2 zu platzieren , sie würden sich nicht gegenseitig stören. Natürlich würde es immer noch 3 ms dauern (oder 6 ms, wenn es nicht leer ist), um ein 32-Bit-Wort† in das EEPROM zu schreiben. Der Versuch, mehr Daten zu schreiben, bevor der erste Schreibvorgang abgeschlossen ist, würde immer noch die Programmausführung blockieren, bis der erste abgeschlossen ist. Überprüfen Sie das Referenzhandbuch für das Bank-Layout (3.3.1 NVM-Organisation)


† AFAIK EEPROM-Daten werden in 32-Bit-Einheiten geschrieben, das Schreiben von 1 oder 2 Bytes auf einmal dauert genauso lange wie das Schreiben eines vollen 4-Byte-Wortes.