mikrocontroller.net

Forum: Compiler & IDEs STM32WB: Mit CubeMX generierter Code wirft HardFault


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe mir ein STM Nucleo Board für den STM32WB Microcontroller 
besorgt und möchte per CubeMX zunächst ein blankes Projekt in CubeIDE 
erstellen, auf den Controller laden und ausführen. Leider bekomme ich 
selbst mit dem unveränderten, in CubeMX speziell für das Board 
generierten Code einen HardFault.

Ich muss dazu sagen, dass ich aus der PC-Software Ecke stamme und bei 
eingebetteten Systemen ziemlicher Einsteiger bin.

Folgendes habe ich versucht:

1. CubeIDE starten und neues Projekt erstellen
2. Bei der Projekterstellung des Board auswählen (Nucleo WB55)
3. An der Konfig in CubeMX nichts verändern
4. Code aus CubeMX heraus generieren
5. Debuggen

Sobald in startup_stm32wb55xx_cm4.s die Funktion "SystemInit" aufgerufen 
wird, tritt ein HardFault auf. Der Fault Analyzer zeigt einen 
IMPRECISERR und STKERR an, PC zeigt jedoch auf 0x0.

Wenn ich im Einzelschritt debugge, sehe ich, dass nach der Anweisung zum 
Aufruf von "SystemInit" folgendes stattfindet, bevor der HardFault 
getriggert wird:

 87         bl  SystemInit
0800270a:   bl      0x80024f0 <SystemInit>
080024f0:   push    {r7}
080024f2:   add     r7, sp, #0               <<<<<<<<<< HardFault
199         SCB->VTOR = VECT_TAB_OFFSET;

Das passiert übrigens bei jedem beliebigen Funktionsaufruf aus dem 
Startup heraus, sobald das "add" ausgeführt wird.

Hat jemand eine Ahnung, warum das so ist? Im Prinzip nutze ich ja ein 
Blanko-Projekt, was speziell für dieses Board vorkonfiguriert ist.

Besten Dank im Voraus!

Autor: ... (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Das ist ja schoen das das so zeitig passiert.
Damit hast du Gelegenheit dich intensiv mit dem Controller
jenseits von HAL zu beschaeftigen.

Lesestoff zu dem Thema 'Hardfault' gibt es u.a. bei TI:
SPMA043.PDF Diagnosing Software Faults...

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ist offenbar der Stack nicht richtig eingestellt. Schau Dir mal im 
resultierenden Hexfile die ersten vier Bytes der ersten Datenzeile an, 
da muß der Stackpointer bei Reset drinstehen.

Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Anregungen!

Prinzipiell stimme ich zu, dass das eine gute Übung für den Einstieg 
ist. Leider sitze ich aber schon eine ganze Weile davor und komme nicht 
weiter. Das Dokument von TI ist zwar hilfreich, allerdings sind bei mir 
alle ansonsten aufschlussreichen register einfach 0.

Der Stackpointer wird mit 0x20040000 initialisiert und zwar mit der 
Anweisung

  ldr   r0, =_estack
  mov   sp, r0          /* set stack pointer */

im Startup (Reset Handler).

Ich habe versucht, herauszufinden, ob das richtig ist. Mir scheint es 
aber so zu sein, dass der Wert im Controller fest hinterlegt ist. Stimmt 
das?

EDIT: Hab gefunden, wo es definiert ist. Laut Kommentar sollte es das 
Ende des RAM sein. Versuche gerade herauszufinden, ob es das auch ist.

EDIT2: Laut Referenz Endet der external RAM an Adresse 0x9FFFFFFF. 
Verstehe ich das richtig? Habe den Wert nun im Linker Script für den RAM 
auf diese Adresse angepasst und nun tritt der HardFault an anderer 
Stelle auf:

Im Startup wird die Funktion "__libc_init_array" aufgerufen. Diese 
wiederum ruft "_init" auf. Im Disassembly von "_init" ist folgender Code 
zu sehen:

0800278c:   push    {r3, r4, r5, r6, r7, lr}
0800278e:   nop
08002790:   pop     {r3, r4, r5, r6, r7}
08002792:   pop     {r3}
08002794:   mov     lr, r3
08002796:   bx      lr                        <<<<< lr = 0x0

lr hat zunächst die richtige Rücksprungadresse, wird dann aber mit r3 = 
0x0 überschrieben (warum?). Mit lr = 0x0 wird dann versucht, an 0x0 zu 
springen, was dann wieder zum HardFault führt.

: Bearbeitet durch User
Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke, ich habe das Problem gelöst:

Der SRAM des Controllers ist 256 KB groß und beginnt bei 0x20000000, 
geht also nur bis 0x20010000. Per Default eingetragen ist aber 
0x20040000, was offenbar zu dem Fehler führt. Ich habe den Wert im 
Linker Script entsprechend auf 0x20010000 angepasst und nun funktioniert 
alles.

Nach wie vor bin ich etwas überrascht, dass die Standardeinstellungen so 
gar nicht zum Board zu passen scheinen...

EDIT: Gerade noch mal nachgerechnet. Was ich oben geschrieben habe passt 
natürlich nicht, 0x20000000 + 256 KB = 0x20040000 ist schon richtig 
gewesen. Dennoch seltsam, warum die Änderung das Problem scheinbar 
behoben hat. Kann das jemand erklären?

: Bearbeitet durch User
Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rem V. schrieb:

> Der Stackpointer wird mit 0x20040000 initialisiert und zwar mit der
> Anweisung
>
>   ldr   r0, =_estack
>   mov   sp, r0          /* set stack pointer */
>
> im Startup (Reset Handler).

Das sollte eigentlich bereits im Hexfile richtig gesetzt sein, manuell 
ist das schon eher ungewöhnlich.

> EDIT2: Laut Referenz Endet der external RAM an Adresse 0x9FFFFFFF.

Das dürfte der Adreßbereich sein, den externes RAM haben kann, sofern 
bestückt. Aber den Stack packt man normalerweise nicht ins externe RAM, 
sondern ins interne. Erstens ist das performanter, und zweitens müßte 
man im externen Fall die Chip-Konfig auch noch in Assembler machen, weil 
C-Funktionen einen bereits funktionierenden Stack erwarten.

> 0800278c:   push    {r3, r4, r5, r6, r7, lr}
> 0800278e:   nop
> 08002790:   pop     {r3, r4, r5, r6, r7}
> 08002792:   pop     {r3}
> 08002794:   mov     lr, r3
> 08002796:   bx      lr                        <<<<< lr = 0x0

Also da werden doch eigentlich nur alle Register einmal gepusht, dann 
gepopt, und am Ende wird das, was vorher als LR gepusht worden ist, in 
R3 gepopt, welches dann in LR kopiert wird. Sinnfrei, aber sieht nicht 
verkehrt aus.

Es sei denn, da ist noch irgendwo die Nullungsschleife fürs RAM drin, 
und das nullt sich u.a. auch den Stack weg. Das ist doof, wenn man dann 
nämlich u.a. LR wieder vom Stack popt, dann kriegt man die beobachtete 
null raus.

Step mal im Einzelschritt durchs Disassembly, da muß irgendwo eine 
Schleife sein, die grob so aussieht:

- ein Register wird mit 0 geladen
- ein anderes Register mit der Startadresse vom RAM
- ein weiteres mit irgendeiner End-Adresse
- und dann wird der Inhalt des genullten Registers in einer Schleife in 
das Register mit der Startadresse geladen. Das letztere wird dann 
typischerweise um 4 erhöht.

Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist so, dass _estack im Linker Script standardmäßig von der IDE auf 
0x20040000 gesetzt wird. Auf diese Weise bekomme ich aber immer diesen 
HardFault. Setze ich diesen Wert auf 0x20030000 funktioniert alles (ist 
auch in den mitgelieferten Beispielen so).

Bei der scheinbar sinnlosen _init Funktion hatte ich noch eine nicht 
vorhandene Speicheradresse für den Stack im Linker Script hinterlegt, 
was beim Laden aus dem Stack dazu geführt hat, dass die Register alle 0 
waren.

Was ich nicht ganz verstehe ist nun, warum es mit einem initialen Stack 
Pointer von 0x20040000 (Ende SRAM) nicht funktioniert. Ich habe mal 
etwas rumprobiert und die letzte funktionierende Speicheradresse ist 
irgendwo in der Nähe von 0x2003df0, etwa 12 kB vor dem Ende des SRAM. 
Alles darüber hinaus führt zum HardFault.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rem V. schrieb:

> Was ich nicht ganz verstehe ist nun, warum es mit einem initialen Stack
> Pointer von 0x20040000 (Ende SRAM) nicht funktioniert.

Was für ein Chip ist überhaupt auf dem Board? Was sagt denn dessen 
Reference Manual zum Thema Speicherbereiche?

> Ich habe mal
> etwas rumprobiert und die letzte funktionierende Speicheradresse ist
> irgendwo in der Nähe von 0x2003df0, etwa 12 kB vor dem Ende des SRAM.
> Alles darüber hinaus führt zum HardFault.

Kann natürlich sein, daß irgendwas in der IDE da noch irgendwas anderes 
hinlegt, was mit der Verwendung kollidiert.

Zudem kennt jedenfalls der Cortex-M3/4 zwei verschiedene Stacks, die für 
Verwendung in einem RTOS gedacht sind: Thread Mode und Handler Mode. 
Wenn Du auch noch ein RTOS drin hast, was schon irgendwas einstellt, 
wäre es möglich, daß Du tatsächlich zwei Stacks hast, die da 
kollidieren.

Siehe hier: 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/ar01s02s06.html

Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Was für ein Chip ist überhaupt auf dem Board? Was sagt denn dessen
> Reference Manual zum Thema Speicherbereiche?

Der Chip ist ein STM32WB55RG mit 256 kB SRAM beginnend bei 0x20000000 
(lt. Reference Manual).

Nop schrieb:
> Wenn Du auch noch ein RTOS drin hast, was schon irgendwas einstellt,
> wäre es möglich, daß Du tatsächlich zwei Stacks hast, die da
> kollidieren.

Das FreeRTOS ist in der Konfiguration deaktiviert. Mein Projekt ist ein 
blanko Projekt aus der Vorlage für genau dieses Board (STM Nucleo WB55), 
ohne jeglichen "Schnickschnack". Fast alle Peripheriekomponenten außer 
GPIO sind deaktiviert.

EDIT: Bin gerade durch Zufall auf die Info gestoßen, dass es 
unterschiedliche Firmware Binaries für den Chip gibt, je nach dem, ob 
ein Wireless Stack benötigt wird. Da eine Wireless-Demo vorgeladen ist, 
ist wahrscheinlich eine entsprechende Wireless-Firmware drauf. Das 
könnte eventuell das Problem sein.

: Bearbeitet durch User
Autor: ... (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
> (lt. Reference Manual).
Ja, mit der falschen Literatur und stuemperhaften Herumprobieren
wird das noch bis zum Sankt Nimmerleinstag dauern.

Die "Memory Map" ist bei ST im allg. im Datasheet.

Und die verraet auch welche Peripherie dort auf dem Speicher
herumzaubert.

So wird das jedenfalls nuex.

Autor: Mw E. (Firma: fritzler-avr.de) (fritzler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei dem Bluetooth STM32 hier is das aber andersrum, also sei leise.

The detailed memory map and the peripheral mapping of the STM32WB55xx 
devices can be found in the reference manual RM0434.

@topic:
Gibts denn eine Doku was die Wireless FW auf dem Cortex M0 macht?
Ansonsten bleibt das hier wirklich ein stochern im dunkeln und der 
SRAM2b sollte nicht vom M4 genutzt werden.

Ansonsten steht beim SRAM2 a/b, dass man den Zugriff durch den M0 (CPU2) 
durch das C2RFD Bit im SYSCFG Register sperren kann.
Wenns dann geht ist klar worans liegt.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... schrieb:

> Die "Memory Map" ist bei ST im allg. im Datasheet.

Üblicherweise sowohl Kapitel 2 Refman als auch Kapitel 4 Datasheet.

Mw E. schrieb:

> Ansonsten steht beim SRAM2 a/b, dass man den Zugriff durch den M0 (CPU2)
> durch das C2RFD Bit im SYSCFG Register sperren kann.

Aber nur code execution aus dem SRAM, nicht jedweden Zugriff. Es gibt 
aber auch noch C2BOOT in PWR_CR4, was man auf 0 setzen kann, dann bootet 
CPU2 nicht und wird nicht dazwischenfunken.

Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe gerade nochmal in das Reference Manual geschaut. SRAM2 beginnt ja 
genau ab 0x20040000, während der (funktionierende) SRAM1 genau ab 
0x20030000 beginnt. So wie ich das verstehe, gibt es zwar eine 
Möglichkeit, den SRAM2 gemeinsam zu nutzen, dafür muss aber scheinbar 
eine entsprechende arbitration Logik implementiert werden. So verstehe 
ich das jedenfalls mit meinem Halbwissen.

Das reicht mir jedenfalls, um mich weiter einarbeiten zu können. Danke 
für eure Hilfe! :)

Autor: Giesser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe auch schon häufig festgedtellt, dass die Standard Cube MX 
Projekte für die ST Boards nie recht  funktionieren. HardFault etc..

Seither erstelle ich immer selbst ein Projekt mit Auswahl des 
Controllers und Config.. Da kann man schön Schritt für Schritt 
vorgehen..

Just my two cents..

Autor: The A. (the_a343)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Remo V.

Wenn du jetzt weißt, was falsch ist, dann mach doch im STM Forum ein 
Bugrepo RT....

Danke und Grüße, Adib.

Autor: Rem V. (veryxrv)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Giesser schrieb:
> Seither erstelle ich immer selbst ein Projekt mit Auswahl des
> Controllers und Config.. Da kann man schön Schritt für Schritt
> vorgehen..

Kannst du das kurz genauer beschreiben, wie du da vorgehst bzw. was du 
verwendest?
Falls du damit meinst, dass du in CubeMX anstatt des Boards nur den 
Controller auswählst: Hab ich schon versucht, funktioniert aber bei dem 
in CubeIDE integrieren MX nicht :-/

The A. schrieb:
> Wenn du jetzt weißt, was falsch ist, dann mach doch im STM Forum ein
> Bugrepo RT....

Mache ich!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.