Hallo zusammen, nachdem ich schon reichlich recherchiert habe und inzwischen eher noch verwirrter, möchte ich hier nach Ideen und Wegweisern in die richtige Richtung fragen. Ich habe den STM32F105 RBT6 mit einiger Bechaltung auf einer Platine vorliegen. Der Mikrocontroller soll per USB oder USB/UART mit dem PC kommunizieren. Von einem PC-Programm sollen über diese Verbindung Parameter des Mikrocontrollerprogramms veränderbar sein, unzwar dauerhaft, also auch nach einem Reset die upgedateten Werte gültig bleiben. . Wenn ich nun im Interrupthandler nach Eintreffen der USB-Nachricht einfach eine Variable verändere, wäre das ja nach dem Reset wieder hinfällig. Ich vermute, am ehesten ist ein EEPROM für die Ablage von updatebaren Konstanten üblich. Leider hat meine Platine keins, müsste ich nachträglich irgendwie anschliessen. Gibt es andere sinnvolle Möglichkeiten? Kann ich zur Programmlaufzeit irgendwie schreibend auf den Flash zugreifen? Ist das schwierig zu implementieren? Hat da jemand mit Erfahrung? Ist das mit dem EEPROm eher komplizierter oder das Schreiben auf den Flash? Ein paar erste Hinweise wie es gehen könnte und wo ich mehr Informationen finden kann wäre super. Am besten ein verständlich erklärtes Tutorial (gern auch englisch) oder ein Codebeispiel für STM32. Zum Hintergrund des Projekts: Der Mikrocontroller soll eine Funkbake ansteuern, über einen Transistor und ein Relais werden die entsprechenden Kontakte geschaltet. Also letztlich wird nur ein GPIO-Pin in einem bestimmten zeitlichen raster auf High und Low gesetzt. Und dieses zeitliche Raster (und damit das Erkennungszeichen der Bake) soll von einer einfachen graphischen benutzeroberfläche am PC aus einstellbar sein, die Werte per USB oder UART übertragen werden und dann ab dem Moment das Programm mi den neuen Werten ablaufen. Besten Dank Andreas
Es gibt eine Appnote von ST: www.st.com/resource/en/application_note/CD00165693.pdf Gefunden über google mit "STM32f105 eeprom"
> Gibt es andere sinnvolle Möglichkeiten? Hat der Controller ein Backup RAM? Den Backup RAM kann man mit einer kleinen Batterie versorgen und so übersteht der Inhalt die Resets. > Kann ich zur Programmlaufzeit irgendwie schreibend auf den Flash > zugreifen? ja. > Ist das schwierig zu implementieren? nein. Lese dir mal die "Reference Manual" durch. Da steht das alles drin. > Hat da jemand mit Erfahrung? Ist das mit dem EEPROm eher komplizierter > oder das Schreiben auf den Flash? Das ist beides gleich kompliziert. Ganz grob kann man sagen: Flash hat viel Speicherplatz und weniger Schreibzyklen, EEPROM hat weniger Speicherplatz bei mehr Schreibzyklen.
Ein I2C EEPROM an eine bestehende Schaltung hinzufrickeln ist nun wirklich kein Problem. Der Käfer braucht 2 Pullups, einen Abblock-Kondensator und 4 Leitungen: Vcc, GND, SDA und SCL. Die Adressleitungen einfach auf Masse legen. Kosten tut's auch nix. Wer will da noch jammern? ... hmmm ja ... man müsste was (ein klein wenig) arbeiten ...
Moin, Auf so einen Pipifax muss man einen STM32 loslassen und dann hat der kein Eeprom? Das ist wirklich lächerlich. Nimm einen ATTiny mit ner Uart, die haben alle Eeprom drin. Gruß, Norbert
Datenblätter lesen bildet: STM32F105RB Reference Manual ab Seite 58 zum Schreiben in den Flash Ab Seite 80 für die batteriegestützten Backup Register
Neben I2C-EEPROMs gibt's auch noch SPI-EEPROMs. Preislich und von der Größe her kaum ein Unterschied zu I2C. 8 Beinchen ... Sowohl I2C- als auch SPI-Interfaces sind im F105 drin (sogar mehrfach), wobei das auch problemlos softwaremäßig geht. Was man da nimmt, ist eher Geschmackssache. Außer dass SPI m. E. vielleicht noch etwas simpler und daher einfacher zu debuggen ist.
> Kann ich zur Programmlaufzeit irgendwie schreibend auf den Flash > zugreifen? Ist das schwierig zu implementieren? Je nach Speichergrösse/layout ist es bei vielen STM32 recht störend, dass beim Schreiben auf das interne Flash der jeweilige Speicherbus blockiert ist und man zeitgleich keine Instruktionen daraus ausführen kann. Es lassen sich z.B. während Schreib- und Löschoperationen keine Interrupts bedienen, wenn man nicht explizit den Code der Handler dafür ins RAM verlegt hat (und auch die Vektortabelle). Das kann schon sehr nervig sein, ein richtiges EEPROM macht vieles einfacher, zumindest wenn man mit I2C/SPI dahin umgehen kann. Ungeschlagen wäre ein echtes internes.. aber selbst das angebliche EEPROM bei einigen STM32 ist nur "simuliert" und Zugriffe darauf blockieren ebenfalls den Bus. Aber wenn man mit den Blockaden leben kann, ist der interne Flash-Speicher (IMHO) einfacher zu nutzen. K.
Vielen Dank, da habe ich ja jetzt mehrere Hinweise was alles gehen sollte. - ein reales EEPROm dazubasteln, wahlweise über I2C oder SPI anschliessen - das emulierte EEPROM nach AN2594 - Backup-RAM , noch nie gehört , werde dazu mal recherchieren. Wie soll da eine Batterie dran? Ist dafür ein Pin des Controllers zuständig? - auf den Flash schreiben zur Laufzeit. Was kann denn die genannte kurzzeitige Blockade für Folgen haben? Mir fehlt da Hintergrundwissen. Einfach eine kurzzeitige Verzögerung im Programmablauf? Das stört nicht. Oder könnte ein weiterer Interrupt vom USB oder UART währenddessen verlorengehen? Das wäre in der Tat ein Problem.
Andreas E. schrieb: > Ist dafür ein Pin des Controllers zuständig? Ja, der heißt VBat. u.U. gehen auch Supercaps o.ä. Das Backup-RAM ist am einfachsten zu nutzen - das muss man einmal initialisieren, danach verhält es sich ganz normal wie ein RAM, man kann einfach direkt schreiben & lesen (mit etwas Linker-Script-Magie kann man seine Variablen da hinein legen, dadurch entsprechen die Schreib&Lese-Zugriffe ganz normalen Variablen-Zugriffen), aber die Daten bleiben eben persistent. Das nutzt sich auch nicht ab und hat keine Verzögerung. Nachteil ist eben der Hardware-Aufwand. Andreas E. schrieb: > Einfach eine kurzzeitige Verzögerung im Programmablauf? Das stört nicht. Genau genommen werden Flash-Lesezugriffe blockiert. Läuft das Programm aus dem Flash, bleibt es einfach eine Weile stehen (ein paar ms bis Sekunden je nach Operation). Andreas E. schrieb: > Oder könnte ein weiterer Interrupt vom USB oder UART währenddessen > verlorengehen? Die UART/USB-Peripherie merkt sich ja dass ein Ereignis eingetreten ist. Der Interrupt wird dann erst danach ausgeführt. Wenn jetzt z.B. der UART mehrere Bytes empfangen hat, werden wohl alle bis auf das letzte verloren gehen, weil die ISR verzögert wird und die Bytes nicht abholen kann. Die Lösung wäre hier, das Programm in den RAM zu verlagern und dort auszuführen. Das läuft dann normal weiter. Allerdings ist die Ausführung aus dem RAM etwas langsamer und der RAM ist natürlich auch kleiner. Man könnte sich überlegen während des Speicherns nur ein "Not-Programm" auszuführen. Einige große STM32 haben zwei Speicherbänke, da kann man das Programm aus der einen Bank ausführen während man in die andere schreibt. Es lohnt sich aber kaum nur dafür auf den größeren Controller umzusteigen...
Andreas E. schrieb: > nachdem ich schon reichlich recherchiert habe und inzwischen eher noch > verwirrter Das wiederum finde ich reichlich seltsam. Hättest du reichlich recherchiert, dann müßtest du nicht hier fragen. Also: Entweder bleibst du bei dem STM32 und plazierst einen externen seriellen EEProm auf der LP - oder du benutzt z.B. einen LPC11Exx, denn der hat einen EEPROM bereits intus. Wo also ist das Problem? Von solchen Ratschlägen wie dem Mißbrauch des internen Flash für EEPROM-Zwecke kann ich nur abraten, denn der Flash ist NICHT dafür gedacht, häufig umprogrammiert zu werden. Das macht ihn nur kaputt. Ich hatte sowas mal aus Kostengründen gemacht, hab aber die geänderten Werte nicht gleich, sondern erst nach einigen Sekunden in den Flash zurückgeschrieben - in der Annahme, daß bei Bedienvorgängen zumeist mehrere Änderungen binnen einiger Sekunden stattfinden, so daß ich erst dann zurückschreiben lasse, wenn nach der letzten Änderung ein paar Sekunden Wartezeit vorbei sind. Einfach nur, um die Anzahl der Schreibvorgänge möglichst klein zu halten. W.S.
W.S. schrieb: > Von solchen Ratschlägen wie dem Mißbrauch des internen Flash für > EEPROM-Zwecke kann ich nur abraten, denn der Flash ist NICHT dafür > gedacht, häufig umprogrammiert zu werden. > > Das macht ihn nur kaputt. Halb so schlimm. Der Flash bei den STM32 ist zwar weniger ausdauernd, dafür aber größer (billiger) als EEPROM - das kann man ausnutzen. Wenn man ein Wear-Leveling implementiert und z.B. 10 Speicherstellen sequentiell beschreibt, statt die gleiche Speicherstelle 10x zu beschreiben, hat man die Lebensdauer verzehnfacht. Da ST bei der Herstellung des Chips sich den zusätzlichen Fertigungs- und Integrations-Prozess für einen EEPROM-Die gespart hat, und stattdessen den Flash größer gemacht hat, hat man weniger Overhead und weniger Preis, aber ähnlich viel wiederbeschreibbaren Speicher. Ist halt nur komplizierter zu nutzen, aber nicht prinzipiell verkehrt. Außer zusätzlichem Programmieraufwand gibt es keinen wirklichen Grund, das nicht so zu machen.
Dr. Sommer schrieb: > Wenn > man ein Wear-Leveling implementiert Also jetzt übertreibst du es aber gewaltig. Das mit weitem Abstand sinnvollste wäre, sein Projekt sauberer zu planen und dann den geeigneten Chip dafür zu benutzen. Alles andere ist nur Murks oder neudeutsch "Workaround". W.S.
W.S. schrieb: > Also jetzt übertreibst du es aber gewaltig. > > Das mit weitem Abstand sinnvollste wäre, sein Projekt sauberer zu planen > und dann den geeigneten Chip dafür zu benutzen. Alles andere ist nur > Murks oder neudeutsch "Workaround". Naja, murks würd ich jetzt nicht sagen. Wird in der Industrie zu 10^drölf mal gemacht und verkauft. Schau mal in dein Auto rein, da wirste in keinem aktuellen Auto nen EEPROM finden.
Nachtrag: Wer bitte sehr glaubt ernsthaft daran, daß die Leute hier, die Peter Danneggers Tastenentprellung schon mehrtausendfach benötigt haben, weil sie das Entprellen ihrer Taste aus eigener Kraft nicht zuwege bringen, in der Lage sind, sich mal eben ein kleines und tatsächlich funktionables wear-leveling auszudenken und zu implementieren? ich nicht. W.S.
W.S. schrieb: > Also jetzt übertreibst du es aber gewaltig. Nur weil du kein Wear Leveling implementieren kannst... Je nach Anforderung muss das ja nicht besonders kompliziert sein. W.S. schrieb: > Das mit weitem Abstand sinnvollste wäre, sein Projekt sauberer zu planen > und dann den geeigneten Chip dafür zu benutzen. Top Idee, die Hardware und Chip-Auswahl sind anscheinend schon fertig: Andreas E. schrieb: > Ich habe den STM32F105 RBT6 mit einiger Bechaltung auf einer Platine > vorliegen. Es kann jede Menge Gründe geben, warum genau dieser uC ausgewählt wurde. Die perfekte Wahl gibt es eh nie, irgendwo muss man immer einen Kompromiss machen. Und der genannte Kompromiss ist nicht so schlimm. Da die meisten STM32 keinen EEPROM haben, diese Chip-Familie aber durchaus weit verbreitet ist, scheint die Nutzung des Flash zum Daten Speichern nicht allzu problematisch zu sein.
W.S. schrieb: > Nachtrag: > > Wer bitte sehr glaubt ernsthaft daran, daß die Leute hier, die Peter > Danneggers Tastenentprellung schon mehrtausendfach benötigt haben, weil > sie das Entprellen ihrer Taste aus eigener Kraft nicht zuwege bringen, > in der Lage sind, sich mal eben ein kleines und tatsächlich > funktionables wear-leveling auszudenken und zu implementieren? > > ich nicht. Schließ doch nicht immer von dir auf andere. Man muss nicht immer das Rad bzw. die Tastenentprellung neu erfinden. Oder hast du auch alle deine Elektronik-Geräte komplett selber entwickelt? Nutzt du vielleicht gar von anderen Herstellern produzierte Hardware? Ein einfaches Wear-Leveling wäre: Man reserviert z.B. den 10-fachen Speicher wie benötigt - sinnvollerweise so dass man möglichst wenig Flash-Banks nutzt, und auch so dass diese keine weiteren Daten/Code enthalten. Den Bereich initialisiert man komplett mit '1'. Beim Programmstart sucht man den letzten Block darin, der nicht komplett '1' ist, und liest ihn als aktuellen Zustand. Findet man keinen, nutzt man Default-Werte. Zum Speichern schreibt man in den jeweils nächsten Block (der erste, der komplett '1' ist); sinnvollerweise sorgt man dafür dass mindestens ein Bit '0' ist. Falls sich zum letzten Block nichts geändert hat, braucht man natürlich gar nichts zu schreiben. Falls kein Block mehr frei ist, führt man einen Erase Vorgang auf allen betroffenen Banks aus und schreibt in den 1. Block. Stellt man beim Schreiben fest, dass die geschriebenen Daten nicht korrekt im Flash ankommen, zeigt man an "Flash Kaputt, Gerät bitte austauschen". So hat man die Anzahl der Erase-Vorgänge durch 10 geteilt und die Lebensdauer verzehnfacht.
So, dann melde ich mich hier mal zurück. Unter all den Varianten habe ich mir zuerst das emulierte EEPROm angesehen, aber dann doch entschieden direkt auf den Flash zuzugreifen, schien mir einfacher. Zumindest einfache Fälle von Variablenspeicherung funktionieren schon. Aber da hänge ich dann auch schon. Hier der relevante Codeausschnitt zum "Spielen" mit dem Flash. Was der Code bisher kann: 5 uint32_t Variablenwerte hintereinander abspeichern und alle 5 wieder zurückliefern, auch nach einem Reset des Controllers. Woran es noch hapert: mit char oder uint8_t gehts nicht genauso, und mit Arrays bestehen wohl auch Probleme. IDE ist Coocox CoIDE.
1 | #include "stm32f10x.h" |
2 | #include "morse.h" |
3 | //#include "eeprom.h"
|
4 | #include "semihosting.h" |
5 | #include "string.h" |
6 | |
7 | #include "stm32f10x_flash.h" |
8 | |
9 | void storeToFlash(uint32_t data1, uint32_t data2, uint32_t b, uint32_t c, uint32_t d); |
10 | |
11 | |
12 | int main(void) |
13 | {
|
14 | uint32_t *pdata = 0x08019200; |
15 | |
16 | printf("Erster Eintrag: %d\r\n", *pdata); |
17 | printf("Zweiter Eintrag: %d\r\n", *(pdata+1)); |
18 | printf("Dritter Eintrag: %d\r\n", *(pdata + 2)); |
19 | printf("Vierter Eintrag: %d\r\n", *(pdata+3)); |
20 | printf("Fünfter Eintrag: %d\r\n", *(pdata+4)); |
21 | |
22 | storeToFlash(3, 15, 23, 27, 89); |
23 | |
24 | |
25 | while(1) |
26 | {
|
27 | |
28 | }
|
29 | }
|
30 | |
31 | |
32 | void storeToFlash(uint32_t data1, uint32_t data2, uint32_t b, uint32_t c, uint32_t d) |
33 | {
|
34 | |
35 | FLASH_Unlock(); |
36 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR); |
37 | FLASH_ErasePage(0x08019200); |
38 | |
39 | FLASH_ProgramWord(0x08019200, data1); |
40 | FLASH_ProgramWord(0x08019200 + sizeof(uint32_t), data2); |
41 | FLASH_ProgramWord(0x08019200 + 2 *sizeof(uint32_t), b); |
42 | FLASH_ProgramWord(0x08019200 + 3 * sizeof(uint32_t), c); |
43 | FLASH_ProgramWord(0x08019200 + 4 * sizeof(uint32_t), (uint8_t)d); |
44 | FLASH_Lock(); |
45 | }
|
Das läuft so. Sobald ich jetzt einen der 5 Werte zu einem char oder uint_t verändern will, passt es nicht mehr. Speicheradreese auf ein Byte Breite angepasst , statt FLASH_ProgramWord() FLASH_ProgramOptionByte() versucht, hilft alles nix.
Andreas.E. schrieb: > Sobald ich jetzt einen der 5 Werte zu einem char oder uint_t verändern > will, passt es nicht mehr. Warum zeigst du dann ausgerechnet den Code der funktioniert, und nicht den interessanten, nicht funktionierenden?! FLASH_ProgramWord funktioniert nur mit Adressen die Vielfache von 4 sind.
Damit jetzt Schritt fürSchritt verändert werden kann vom funktionierenden aus.
1 | #include "stm32f10x.h" |
2 | #include "morse.h" |
3 | //#include "eeprom.h"
|
4 | #include "semihosting.h" |
5 | #include "string.h" |
6 | |
7 | #include "stm32f10x_flash.h" |
8 | |
9 | void storeToFlash(uint32_t data1, uint32_t data2, uint32_t b, uint32_t c, char d); |
10 | |
11 | |
12 | int main(void) |
13 | {
|
14 | uint32_t *pdata = 0x08019200; |
15 | |
16 | printf("Erster Eintrag: %d\r\n", *pdata); |
17 | printf("Zweiter Eintrag: %d\r\n", *(pdata+1)); |
18 | printf("Dritter Eintrag: %d\r\n", *(pdata + 2)); |
19 | printf("Vierter Eintrag: %d\r\n", *(pdata+3)); |
20 | printf("Fünfter Eintrag: %c\r\n", *(pdata+4 )); |
21 | |
22 | storeToFlash(3, 15, 23, 27, 'H'); |
23 | |
24 | |
25 | while(1) |
26 | {
|
27 | |
28 | }
|
29 | }
|
30 | |
31 | |
32 | void storeToFlash(uint32_t data1, uint32_t data2, uint32_t b, uint32_t c, char d) |
33 | {
|
34 | |
35 | FLASH_Unlock(); |
36 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR); |
37 | FLASH_ErasePage(0x08019200); |
38 | |
39 | FLASH_ProgramWord(0x08019200, data1); |
40 | FLASH_ProgramWord(0x08019200 + sizeof(uint32_t), data2); |
41 | FLASH_ProgramWord(0x08019200 + 2 *sizeof(uint32_t), b); |
42 | FLASH_ProgramWord(0x08019200 + 3 * sizeof(uint32_t), c); |
43 | FLASH_ProgramOptionByteData(0x08019200 + 4 * sizeof(uint32_t), (uint8_t)d); |
44 | |
45 | FLASH_Lock(); |
46 | }
|
Ausgabe ist: Erster Eintrag: 3 Zweiter Eintrag: 15 Dritter Eintrag: 23 Vierter Eintrag: 27 F�nfter Eintrag: � Ja, genau diese Fragezeichenrauten in Coocox, also irgendwas unbekanntes. Könnte mir natürlich meine chars die ich speichern will vorher in uint32_t werte umrechnen, und später wieder zurück, aber das ist bestimmt nicht im Sinne des Erfinders, also von ST.
:
Bearbeitet durch User
Andreas E. schrieb: > FLASH_ProgramOptionByteData(0x08019200 + 4 * sizeof(uint32_t), > (uint8_t)d); Das Option Byte ist was völlig anderes als der Flash; damit kann man den Watchdog und Reset konfigurieren. Benutze stattdessen FLASH_ProgramHalfWord; da wird dann ein Byte verschwendet. Das kannst du auffüllen mit einem anderen einzelnen Byte falls du noch eines hast. Andreas E. schrieb: > printf("Fünfter Eintrag: %c\r\n", *(pdata+4 )); Hier dereferenzierst du einen Pointer auf uint32_t, und übergibst somit noch irgendwelche anderen Daten an printf. Je nach Implementation macht das dann ggf. Unsinn...
Dr. Sommer schrieb: > Hier dereferenzierst du einen Pointer auf uint32_t, und übergibst somit > noch irgendwelche anderen Daten an printf. Je nach Implementation macht > das dann ggf. Unsinn.. Jetzt habe ich es so: int main(void) { uint32_t *pdata = 0x08019200; uint8_t *smallPointer = 0x08019210; printf("Erster Eintrag: %d\r\n", *pdata); printf("Zweiter Eintrag: %d\r\n", *(pdata+1)); printf("Dritter Eintrag: %d\r\n", *(pdata + 2)); printf("Vierter Eintrag: %d\r\n", *(pdata+3)); printf("Fünfter Eintrag: %c\r\n", *smallPointer); Und in der Flashfunktion steht jetzt als letzter Schreibzugriff: FLASH_ProgramHalfWord(0x08019210, (uint8_t)d); kann es weiterhin mit printf nicht auslesen.
Doch jetzt gehts. !!! Ich bekomm ein H ausgegeben. Lag wohl an dem Flash_ProgramOptionByteData, wo ich dachte das wär die Schreibfunktion für 8 bit Werte. Und dass der Pointer jetzt ein 8 bit-Wert Pointer ist beim Fünften printf.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.