Forum: Mikrocontroller und Digitale Elektronik STM32F105 Parameter im Code zur Laufzeit updaten


von Andreas E. (everest_75)


Lesenswert?

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

von Zweifler (Gast)


Lesenswert?

Es gibt eine Appnote von ST:

www.st.com/resource/en/application_note/CD00165693.pdf

Gefunden über google mit "STM32f105 eeprom"

von egal (Gast)


Lesenswert?

> 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.

von Alter Nativ (Gast)


Lesenswert?

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 ...

von Norbert S. (norberts)


Lesenswert?

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

von Dr. Sommer (Gast)


Lesenswert?

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

von A. B. (Gast)


Lesenswert?

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.

von Kolja W. (kawk)


Lesenswert?

> 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.

von Andreas E. (everest_75)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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...

von W.S. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von ui (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Andreas.E. (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Andreas E. (everest_75)


Lesenswert?

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
von Dr. Sommer (Gast)


Lesenswert?

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...

von Andreas E. (everest_75)


Lesenswert?

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.

von Andreas E. (everest_75)


Lesenswert?

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
Noch kein Account? Hier anmelden.