Forum: Mikrocontroller und Digitale Elektronik STM32F031 Wann blockiert CPU beim Flash programmieren/löschen


von stm32user (Gast)


Lesenswert?

Guten Tag,

ich besitze einen STM32F031 und möchte zur Laufzeit in eine freie 
Flashseite etwas programmieren bzw. diese löschen. Aufgrund der 
Löschzeit von max. 40ms möchte ich aber parallel weiter meine 
Main-Funktion / andere Funktionen und Interrupts abarbeiten und auf ein 
Flash-Interrupt warten, also kein Busywait.

Meine Frage: Ist das so direkt umsetzbar, dass gelöscht/programmiert 
wird und ich parallel andere Programmteile ausführen kann (inkl. 
Interruptroutinen)?

Die Frage stelle ich, weil ich Zweifel aufgrund folgender Textzeilen im 
Datenblatt habe:
1
during a program/erase operation to the Flash memory, any attempt to read the Flash memory will stall the bus. The read operation will proceed correctly once the program/erase operation has completed. This means that code or data fetches cannot be made while a program/erase operation is ongoing.

Ich verstehe darunter, dass ich KEIN Code (Code fetch) aus dem Flash 
holen und ausführen darf, während Löschen/Programmieren. Ist es dann 
notwendig, dass ich mein Linkerfile anpassen muss um den Code in den 
SRAM zu bekommen?

Mein Linkerfile:
1
.isr_vector :
2
  {
3
    . = ALIGN(4);
4
    KEEP(*(.isr_vector)) /* Startup code */
5
    . = ALIGN(4);
6
  } >FLASH
7
8
  /* The program code and other data goes into FLASH */
9
  .text :
10
  {
11
    . = ALIGN(4);
12
    *(.text)           /* .text sections (code) */
13
    *(.text*)          /* .text* sections (code) */
14
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
15
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
16
    *(.glue_7)         /* glue arm to thumb code */
17
    *(.glue_7t)        /* glue thumb to arm code */
18
  *(.eh_frame)
19
20
    KEEP (*(.init))
21
    KEEP (*(.fini))
22
23
    . = ALIGN(4);
24
    _etext = .;        /* define a global symbols at end of code */
25
  } >FLASH




-------------------------------
In diesem Beitrag ist das Problem auch schon geschildert worden:

STM32 : internen Flash löschen/schreiben - CPU stall mit STLINK 
detektieren?
Beitrag "STM32 : internen Flash löschen/schreiben - CPU stall mit STLINK detektieren?"

In diesem Beitrag
https://stackoverflow.com/questions/36244319/why-cant-write-internal-flash-of-same-address-twice

heisst es auch in einem Kommentar:
1
normally you can read one page while writing/erasing another, but in STM32 the entire flash bus stalls, so no no code in flash runs - stalling execution for significant periods (tens of milliseconds)

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Um waehrend des Flashzugriffes bei den Single Bank STM32 Bauteilen 
weiterarbeiten zu koennen, wirst Du wie ein Fuchs darauf aufpassen 
muessen , dass Dein Code im Ram nicht irgendetwas aus dem Flash braucht: 
Code, Daten, Literal, Interrupt Vektoren etc.

von Jim M. (turboj)


Lesenswert?

stm32user schrieb:
> Aufgrund der
> Löschzeit von max. 40ms möchte ich aber parallel weiter meine
> Main-Funktion / andere Funktionen und Interrupts abarbeiten und auf ein
> Flash-Interrupt warten, also kein Busywait.

Dann hol Dir einen dicken µC, der entweder 2 kompltt getrennte Flash 
Bereiche hat (z.B. EFM32GG) oder den kompletten Code aus dem RAM 
ausführen kann.

von Jim M. (turboj)


Lesenswert?

stm32user schrieb:
> Ist es dann
> notwendig, dass ich mein Linkerfile anpassen muss um den Code in den
> SRAM zu bekommen?

Nicht nur das Linker File. Auch den Startup Code müsstest Du dann 
anpassen, denn es muss ja mindestens so etwas wie memcpy() im Flash 
verbleiben zuzüglich einer Kopie der Interrupt Vektor Tabelle.

von Curby23523 N. (Gast)


Lesenswert?

Mir gefällt die Speicheraufteilung der STM32 für nichtflüchtige Daten 
generell nicht - der wohl größte Minuspunkt an diesen Controllern. Ich 
verwende daher immer ein externes EEPROM, auch wenn das etwas mehr Platz 
und Geld kostet.

Ansonsten ist das wichtigste gesagt. Aufpassen, dass dein Code keinen 
Flashzugriff benötigt. Mit einem SPI EEPROM passiert mir sowas aber 
nicht ;).

von stm32user (Gast)


Lesenswert?

Eine Ergänzung von mir die meine Zweifel bestärkt, scheint als ob der 
ganze Controller ausser Gefecht gesetzt wird:
https://community.st.com/thread/30821

>wirst Du wie ein Fuchs darauf aufpassen
>muessen , dass Dein Code im Ram nicht irgendetwas aus dem Flash braucht

Sprich: Mit meinem aktuellen Linkerfile (ganzer Code im Flash) kann ich 
mein Vorhaben in die Tonne kloppen?

Ich hab > 5k Code im Flash, aber nur ein 4k RAM. Damit ist also dieses 
"Parallele abarbeiten der main / andere Unterfunktionen" wohl 
Wunschdenken und verdammt kompliziert.


Ich muss also mit sowas arbeiten, richtig?
1
__attribute__( ( section(".data") ) ) void 
2
TIM3_IRQHandler .....


1
Dann hol Dir einen dicken µC
Ich kann die Hardware nicht wechseln.

von Jim M. (turboj)


Lesenswert?

stm32user schrieb:
> Ich muss also mit sowas arbeiten, richtig?

Ich hätte die Section ".data.TIM3_IRQHandler" genannt, aber ungefähr 
richtig.

Du musst aber auch zwingend die Vektor-Tabelle ins RAM schieben, und ich 
weiss grade nicht ob der Cortex-M0 überhaupt das dafür notwendige VTOR 
Register kennt. War das nicht ein optionales Feature...?

von stm32user (Gast)


Lesenswert?

Ich hab kurz in die Headerfiles geschaut und konnte nichts finden beim 
M0.

core_cm0.h:
1
typedef struct
2
{
3
  __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
4
  __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
5
       uint32_t RESERVED0;
6
  __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
7
  __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
8
  __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
9
       uint32_t RESERVED1;
10
  __IO uint32_t SHP[2];                  /*!< Offset: 0x01C (R/W)  System Handlers Priority Registers. [0] is RESERVED   */
11
  __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
12
} SCB_Type;


core_cm4.h:
1
typedef struct
2
{
3
  __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
4
  __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
5
  __IO uint32_t VTOR;                    /*!< Offset: 0x008 (R/W)  Vector Table Offset Register                          */
6
  __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
7
  __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
8
  __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
9
  __IO uint8_t  SHP[12];                 /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */
10
  __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
11
  __IO uint32_t CFSR;                    /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register                    */
12
  __IO uint32_t HFSR;                    /*!< Offset: 0x02C (R/W)  HardFault Status Register                             */
13
  __IO uint32_t DFSR;                    /*!< Offset: 0x030 (R/W)  Debug Fault Status Register                           */
14
  __IO uint32_t MMFAR;                   /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register                      */
15
  __IO uint32_t BFAR;                    /*!< Offset: 0x038 (R/W)  BusFault Address Register                             */
16
  __IO uint32_t AFSR;                    /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register                       */
17
  __I  uint32_t PFR[2];                  /*!< Offset: 0x040 (R/ )  Processor Feature Register                            */
18
  __I  uint32_t DFR;                     /*!< Offset: 0x048 (R/ )  Debug Feature Register                                */
19
  __I  uint32_t ADR;                     /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register                            */
20
  __I  uint32_t MMFR[4];                 /*!< Offset: 0x050 (R/ )  Memory Model Feature Register                         */
21
  __I  uint32_t ISAR[5];                 /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register                   */
22
       uint32_t RESERVED0[5];
23
  __IO uint32_t CPACR;                   /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register                   */
24
} SCB_Type;

Anscheinend hat M0 im Vergleich zu M4 die Funktion nicht.



Was ist eigentlich mit diesem Codeausschnitt von ST aus der StdLib?
1
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
2
{ 
3
  FLASH_Status status = FLASH_COMPLETE;
4
   
5
  /* Check for the FLASH Status */
6
  status = FLASH_GetStatus();
7
  
8
  /* Wait for a FLASH operation to complete or a TIMEOUT to occur */
9
  while((status == FLASH_BUSY) && (Timeout != 0x00))
10
  {
11
    status = FLASH_GetStatus();
12
    Timeout--;
13
  }
14
  
15
  if(Timeout == 0x00 )
16
  {
17
    status = FLASH_TIMEOUT;
18
  }
19
  /* Return the operation status */
20
  return status;
21
}

Wird die while-Schleife ueberhaupt ausgefuehrt waehrend des Loeschens 
einer Seite und wie?

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Jim M. schrieb:
> Du musst aber auch zwingend die Vektor-Tabelle ins RAM schieben, und ich
> weiss grade nicht ob der Cortex-M0 überhaupt das dafür notwendige VTOR
> Register kennt. War das nicht ein optionales Feature...?

Die STM32F0 Serie hat kein VTOR. Um das zu umgehen mappe ich mit SYSCFG 
das Ram an Adresse 0. Dann ist die Interrupttabelle im Ram aktiv.

von Dr. Sommer (Gast)


Lesenswert?

stm32user schrieb:
> Ich hab > 5k Code im Flash, aber nur ein 4k RAM.

Kannst du den Code, der parallel zum schreiben läuft, nicht eingrenzen 
sodass nur ein "Notprogramm" in den RAM passen muss? Kannst du einfach 
nach dem Abschalten des Geräts schreiben indem du einen Kondensator als 
Puffer verbaust? Reduziert auch die Flash Abnutzung.

von TriHexagon (Gast)


Lesenswert?

Wäre es denn in der Zeit möglich auf die Ereignisse mit DMA zu 
reagieren?

von stm32user (Gast)


Lesenswert?

Danke, für die Antworten.

Ich wünschte ich hätte dieses Dokument früher gefunden und mir die 
Sucharbeit erspart:

AN4808

Writing to non-volatile memory without disrupting code execution
 on microcontrollers of the STM32L0 and STM32L1 Series

http://www.st.com/content/ccc/resource/technical/document/application_note/group0/7c/6a/88/d1/27/04/46/2f/DM00260799/files/DM00260799.pdf/jcr:content/translations/en.DM00260799.pdf

Schade das im Reference Manual dieser ganze Sachverhalt nur in paar 
Sätzen kurz nebenbei erläutert wird.

>Kannst du den Code, der parallel zum schreiben läuft,
>nicht eingrenzen sodass nur ein "Notprogramm" in den RAM passen muss

Das werd ich wohl machen müssen, da ich heute rausgefunden habe, dass 
sogar (hochpriorisierte) Interrupts nicht bearbeitet werden während 
dieser Zeit - was fatal ist ... sogar Watchdogs.

>Wäre es denn in der Zeit möglich auf die Ereignisse mit DMA zu
reagieren?

Ich hatte eher die Idee an eine komplette quasi-Multitaskanwendung 
gedacht, also mit mehreren Tasks ...


Kann mir jemand noch vielleicht verraten, was der Sinn hinter der 
Funktion ist, die ja im Flash ausgefuehrt wird:
1
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)

von S. R. (svenska)


Lesenswert?

stm32user schrieb:
> Kann mir jemand noch vielleicht verraten, was der Sinn hinter der
> Funktion ist, die ja im Flash ausgefuehrt wird:

Wenn ein Not-Programm aus dem RAM ausgeführt wird, dann muss es 
irgendwie rauskriegen können, ob es seinen Zweck erfüllt hat und wieder 
an das Hauptprogramm abgeben darf.

von ProgNix (Gast)


Lesenswert?

Die Löschzeit ist im Verhältnis zur Schreibzeit von zwei Byte ja recht 
lang.
(ms v. µS)

Vielleicht kannst du das Löschen auf unkritische Zeitpunkte legen (z.B. 
Startup)

von stm32user (Gast)


Lesenswert?

>Wenn ein Not-Programm aus dem RAM ausgeführt wird

Diese ganzen Funktionen wie EraseFlash, ProgramHalfWord, .. SOLLTEN also 
aus dem RAM aufgerufen werden. Weil ja sonst die nächste Programmzeile 
nach dem Funktionsaufruf die CPU Blockade hervorrufen würde.

Schade das diese Empfehlung mit der Auslagerung in den RAM gar nicht im 
Code/StdLib dokumentiert ist. Wenn ich mich irre, bitte Bescheid sagen. 
Alles sehr mager beschrieben

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.