Forum: Mikrocontroller und Digitale Elektronik mein erstes STM32F4 .asm/ .s Program stürzt ab im gdb


von Christoph K. (chriskuku)


Angehängte Dateien:

Lesenswert?

Das angehängte Program stürzt im gdb ab, wenn ich durchsteppe.
Ich habe line-numbers mitgeneriert (-g Schalter im gnu as).
1
(gdb) load
2
`/Users/kuku/myfirst/firmware.elf' has changed; re-reading symbols.
3
Loading section .text, size 0x478 lma 0x0
4
Start address 0x400, load size 1144
5
Transfer rate: 9152 bits in <1 sec, 1144 bytes/write.
6
(gdb) si
7
halted: PC: 0x00000402
8
85    mov r0, HSEON
9
(gdb) 
10
halted: PC: 0x00000404
11
0x00000404  85    mov r0, HSEON
12
(gdb) 
13
halted: PC: 0x00000406
14
86    str r0, [r1]            @ turn on the external clock
15
(gdb) 
16
halted: PC: 0x00000408
17
awaitHSE () at myfirst.s:89
18
89    ldr r0, [r1]
19
(gdb) 
20
halted: PC: 0x0000040a
21
90    ands r0, #HSERDY
22
(gdb) 
23
halted: PC: 0x0000040c
24
0x0000040c  90    ands r0, #HSERDY
25
(gdb) 
26
halted: PC: 0x0000040e
27
91    beq.n awaitHSE  @ hang here until external clock is stable
28
(gdb) 
29
halted: PC: 0x00000410
30
95    ldr r1, = RCC_CFGR
31
(gdb) 
32
halted: PC: 0x00000412
33
97    mov r0, # 1
34
(gdb) 
35
halted: PC: 0xfffffffe
36
0xfffffffe in ?? ()
37
(gdb)

von Johannes S. (Gast)


Lesenswert?

Ich denke da fehlen einige LDR und OR Operationen, mit deinen STR setzt 
du ein Bit und machst alle anderen platt.
Und die Clock Berechnung ist auch nicht gut, normalerweise schaltet man 
die PLL ein und bekommt einen höheren APB Takt, damit wird die Bitrate 
deutlich genauer. Die UART hängen an verschiedenen APB und haben 
wiederum Vorteiler, das kann man sich in CubeMX  ansehen wo es schön 
grafisch dargestellt wird.
Und gdb in VSCode mit Cortex-debug Extension ist Grafisch auch schöner. 
Forth Extensions gibt auch dafür.

von Christoph K. (chriskuku)


Lesenswert?

Johannes S. schrieb:
> Ich denke da fehlen einige LDR und OR Operationen, mit deinen STR setzt
> du ein Bit und machst alle anderen platt.
> Und die Clock Berechnung ist auch nicht gut, normalerweise schaltet man
> die PLL ein und bekommt einen höheren APB Takt, damit wird die Bitrate
> deutlich genauer. Die UART hängen an verschiedenen APB und haben
> wiederum Vorteiler, das kann man sich in CubeMX  ansehen wo es schön
> grafisch dargestellt wird.
> Und gdb in VSCode mit Cortex-debug Extension ist Grafisch auch schöner.
> Forth Extensions gibt auch dafür.

Ad 1) es kommt mir nicht auf den Inhalt an. Es könnte irgendwelcher 
Kokolores im Programm stehen. Denn, meine Frage war:

Ad 2) warum stürzt das Programm ab,

Ad 3) Forth Extensions und gar VS sind das Entfernteste, an das ich hier 
denken würde.

Insofern ist vielleicht der Titel etwas irreführend, daß es "mein 
erstes" Programm ist. Es ist ein Code snippet, das ich aus einem anderen 
Programm isoliert habe und von dem ich wissen will, warum es im GDB 
abstürzt.

Kommt der gdb mit der mov r0, #1 Instruktion nicht klar? Fehlt eine 
Assembler-Direktive?
1
77                    @  Initialize STM32 Clocks
2
  78
3
  79                    @ Ideally, we would just take the defaults to begin with and
4
  80                    @ do nothing.  Because it is possible that HSI is not
5
  81                    @ accurate enough for the serial communication (USART2), we
6
  82                    @ will switch from the internal 8 MHz clock (HSI) to the
7
  83                    @ external 8 MHz clock (HSE).
8
  84 0400 1449                  ldr r1, =RCC_CR
9
  85 0402 4FF48030              mov r0, HSEON
10
  86 0406 0860                  str r0, [r1]            @ turn on the external clock
11
  87
12
  88                    awaitHSE:
13
  89 0408 0868                  ldr r0, [r1]
14
  90 040a 10F40030              ands r0, #HSERDY
15
  91 040e FBD0                  beq.n awaitHSE  @ hang here until external clock is stable
16
  92                                            @ at this point, the HSE is running and
17
  93                                            @ stable but I suppose we have not yet
18
  94                                            @ switched Sysclk to use it.
19
  95 0410 1149                  ldr r1, = RCC_CFGR
20
  96
21
  97 0412 4FF00100              mov r0, # 1

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

Beim Clock versteht der STM32 aber keinen Spass, und du überschreibst im 
RCC_CR alle Bits, auch solche die man lt. Doku auf Initialwert stehen 
lassen soll. Und bei den Periphieclocks genauso, da geht eben gar nix 
mehr und auch das SWD kann sich da verabschieden.

von Christoph K. (chriskuku)


Lesenswert?

Es kommt mir so vor, als sei das, was im memory steht, nicht der code, 
den gdb dazu anzeigt.
1
xPSR: 0x01000000 pc: 0x00003a56 msp: 0x20000330
2
Loading section .text, size 0x478 lma 0x0
3
Start address 0x400, load size 1144
4
Transfer rate: 9152 bits in <1 sec, 1144 bytes/write.
5
(gdb) x/20x 0x0400
6
0x400 <Reset>:  0x04124152  0x040a18b6  0x18800c09  0x3f04414e
7
0x410 <awaitHSE+8>:  0x47706038  0x000004a6  0x75040044  0x002a6d64
8
0x420 <awaitHSE+24>:  0x2400b510  0x6d04f847  0xf847687e  0x693e6d04
9
0x430 <awaitHSE+40>:  0xffc2f7ff  0xcf400031  0xcf400030  0x6d04f847
10
0x440 <awaitHSE+56>:  0xf847683e  0x68fe6d04  0xf7ffb403  0xbc03ffb5
11
(gdb) x/20i 0x0400
12
=> 0x400 <Reset>:  adcs  r2, r2
13
   0x402 <Reset+2>:  lsls  r2, r2, #16
14
   0x404 <Reset+4>:  adds  r6, r6, r2
15
   0x406 <Reset+6>:  lsls  r2, r1, #16
16
   0x408 <awaitHSE>:  lsrs  r1, r1, #16
17
   0x40a <awaitHSE+2>:  adds  r0, r0, r2
18
   0x40c <awaitHSE+4>:  adcs  r6, r1
19
   0x40e <awaitHSE+6>:  subs  r7, #4
20
   0x410 <awaitHSE+8>:  str  r0, [r7, #0]
21
   0x412 <awaitHSE+10>:  bx  lr
22
   0x414 <awaitHSE+12>:  lsls  r6, r4, #18
23
   0x416 <awaitHSE+14>:  movs  r0, r0
24
   0x418 <awaitHSE+16>:  lsls  r4, r0, #1
25
   0x41a <awaitHSE+18>:  strb  r4, [r0, #20]
26
   0x41c <awaitHSE+20>:  ldr  r4, [r4, #84]  ; 0x54
27
   0x41e <awaitHSE+22>:  movs  r2, r5
28
   0x420 <awaitHSE+24>:  push  {r4, lr}
29
   0x422 <awaitHSE+26>:  movs  r4, #0
30
   0x424 <awaitHSE+28>:  str.w  r6, [r7, #-4]!
31
   0x428 <awaitHSE+32>:  ldr  r6, [r7, #4]

von Christoph K. (chriskuku)


Lesenswert?

Johannes S. schrieb:
> Beim Clock versteht der STM32 aber keinen Spass, und du überschreibst im
> RCC_CR alle Bits, auch solche die man lt. Doku auf Initialwert stehen
> lassen soll. Und bei den Periphieclocks genauso, da geht eben gar nix
> mehr und auch das SWD kann sich da verabschieden.

Danke für die Interpretation. Werde das mal mit dem Autor diskutieren.

P.S. ich glaube, ich habe in meinem Source code den vector-Bereich 
vergessen, zu initialisieren. Da stehen im Moment noch die Adressen 
eines älteren Programms drin. Hatte ja meinen Source file gepostet.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Angehängte Dateien:

Lesenswert?

Irgendwas mache ich noch falsch. Ich bekomme nicht das ins flash, was 
ich programmiert habe. Ich lade mal alles hoch. Es geht jetzt um 
simple.s. Weder die Plätze 0 und 4 werden programmiert noch der 
Codebereich
Reset: 0x400:
1
        .global Reset
2
        .syntax unified
3
        .cpu cortex-m4
4
        .thumb
5
        .equ TOS, 0x40000000
6
7
        .data
8
        .org 0
9
10
        .word TOS        @ 00: Stack top address
11
        .word Reset+1    @ 01: Reset Vector +1 wegen des Thumb-Einsprunges
12
13
        .text
14
        .org 0x400
15
16
Reset:
17
        bal Reset
18
        .end
Starte ich dazu den gdb, so bekomme ich dieses:
1
$ ./GDB
2
GNU gdb (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.50.20181213-git
3
Copyright (C) 2018 Free Software Foundation, Inc.
4
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
5
This is free software: you are free to change and redistribute it.
6
There is NO WARRANTY, to the extent permitted by law.
7
Type "show copying" and "show warranty" for details.
8
This GDB was configured as "--host=x86_64-apple-darwin10 --target=arm-none-eabi".
9
Type "show configuration" for configuration details.
10
For bug reporting instructions, please see:
11
<http://www.gnu.org/software/gdb/bugs/>.
12
Find the GDB manual and other documentation resources online at:
13
    <http://www.gnu.org/software/gdb/documentation/>.
14
15
For help, type "help".
16
Type "apropos word" to search for commands related to "word".
17
0x00010100 in ?? ()
18
Unable to match requested speed 2000 kHz, using 1800 kHz
19
Unable to match requested speed 2000 kHz, using 1800 kHz
20
target halted due to debug-request, current mode: Thread 
21
xPSR: 0x01000000 pc: 0x00010100 msp: 0x464c457c
22
Loading section .text, size 0x404 lma 0x0
23
Loading section .data, size 0x8 lma 0x404
24
Start address 0x400, load size 1036
25
Transfer rate: 91 KB/sec, 518 bytes/write.
26
(gdb) x/20x 0
27
0x0:  0x464c457f  0x00010101  0x00000000  0x00000000
28
0x10:  0x00280002  0x00000001  0x00000400  0x00000034
29
0x20:  0x00010d24  0x05000200  0x00200034  0x00280001
30
0x30:  0x000a000b  0x00000001  0x00010000  0x00000000
31
0x40:  0x00000000  0x00000478  0x00000478  0x00000005
32
(gdb) x/10x 0x400
33
0x400 <Reset>:  0x00000000  0x00000000  0x00000000  0x00000000
34
0x410:  0x00000000  0x00000000  0x00000000  0x00000000
35
0x420:  0x00000000  0x00000000

Vielleicht ist memmap falsch? Habe ich so übernommen aus dem 
ursprünglichen Projekt.
1
MEMORY
2
{
3
   rom(RX)   : ORIGIN = 0x00000000, LENGTH = 0x4000
4
   ram(WAIL) : ORIGIN = 0x20000000, LENGTH = 0x4000
5
}
6
7
SECTIONS
8
{
9
   .text : { *(.text*) } > rom
10
   .bss  : { *(.bss*) } > ram
11
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Warum packst du denn die Vektortabelle nach .data (welches du noch dazu 
im Linkerscript nicht einmal erwähnst)?

Die Vektortabelle gehört natürlich an den Anfang des Flashs. 
Üblicherweise reserviert man dafür eine eigene section und platziert 
diese dann im Linkerscript noch vor .text.

.org hat in verschieblichem Assemblercode schon seit CP/M nichts mehr 
verloren …

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Vielleicht solltest du erstmal ein simples C-Blinky-Beispiel durchgehen 
und dir anschauen, was der Compiler als Assemblercode generiert?

Bevor du den ganzen Spaß mit dem GDB in den Flash pumpst, kannst du 
übrigens ruhig mal einen Blick in die ELF-Datei werfern 
(arm-none-eabi-objdump, vor allem -h und -d sind interessant als 
Optionen).

: Bearbeitet durch Moderator
von Christoph K. (chriskuku)


Lesenswert?

Jörg W. schrieb:
> Vielleicht solltest du erstmal ein simples C-Blinky-Beispiel durchgehen
> und dir anschauen, was der Compiler als Assemblercode generiert?
>
> Bevor du den ganzen Spaß mit dem GDB in den Flash pumpst, kannst du
> übrigens ruhig mal einen Blick in die ELF-Datei werfern
> (arm-none-eabi-objdump, vor allem -h und -d sind interessant als
> Optionen).

Gut, werde ich machen.

Was da geladen wurde mit "load" nach 0x00000000, ist übrigens der .ELF 
file selbst:

(gdb) x/20c 0
0x0:  127 '\177'  69 'E'  76 'L'  70 'F'  1 '\001'  1 '\001'  1 '\001' 
0 '\000'
0x8:  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 '\000'  0 
'\0000 '\000'
0x10:  2 '\002'  0 '\000'  40 '('  0 '\000'
(gdb)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Christoph K. schrieb:
> Was da geladen wurde mit "load" nach 0x00000000, ist übrigens der .ELF
> file selbst:

grmpf

Dann ist irgendwas grundlegend flasch gelaufen und der GDB hat das Ding 
als Binärdatei genommen.

Ich denke, es ist wirklich zielführender, ein C-Minimalprogramm 
(möglichst ohne all den Kladderadatsch wie HAL oder dergleichen) mal zu 
analysieren, sowohl hinsichtlich des Aufbaus von Startup-Code und 
Linkerscript als auch hinsichtlich einiger ARM-typischer 
Programmierstrategien (wie eben bspw. das Ablegen von Konstanten 
innerhalb des Codes, die zu groß sind, um als Direktoperanden geladen zu 
werden).

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Das "Reset+1" im Interrupt Vector ist unnötig, wenn man "Reset" korrekt 
als Funktion definiert:
1
  .word TOS           @ 00: Stack top address
2
  .word Reset            @ 01: Reset Vector  +1 wegen des Thumb-Einsprunges
3
4
  .text
5
        .org 0x400
6
7
.type Reset, %function
8
Reset:
9
        bal Reset
10
  .end

Und der Vektor gehört natürlich wie schon gesagt an den Anfang des 
Flash. Wie wäre es mit meinem ARM-ASM-Tutorial?

von Christoph K. (chriskuku)


Lesenswert?

zum .org:

Ich bin ja zunächst von der source des mecrisp-stellaris-forth 
ausgegangen und der Autor hat das Projekt nicht auf .elf basiert, 
sondern .bin Files erzeugt und es sind etliche .org in seiner Source. Da 
habe ich mir jetzt erst mal nichts bei gedacht. Die .data und .text 
statements in meinem Beispiel waren verzweifelte Versuche. Es geht auch 
darum, diese Source noch auf dem discovery-Board unter einem anderen 
UART zum laufen zu kriegen.

Deshalb die .orgs

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Christoph K. schrieb:
> der Autor hat das Projekt nicht auf .elf basiert, sondern .bin Files
> erzeugt

Das glaube ich nicht ernsthaft. Seit mehr als 20 Jahren können die 
entsprechenden Linker (zumindest im hier benutzten Opensource-Umfeld) 
eigentlich nichts anderes als ELF mehr direkt erzeugen. Die .bin-Files 
werden anschließend daraus extrahiert. Es muss also davor schon mal ein 
sinnvoll aufgebautes ELF-File gegeben haben.

Ich glaube, AVRDUDE war damals wohl das letzte derartige Tool, das ich 
darauf umgestellt habe, ELF-Files direkt zu lesen. Das ist nun auch 
schon 8 Jahre her.

Wie ich aber schrieb: .org hatte schon unter CP/M keinen Sinn mehr, wo 
man ähnlich wie hier vorgegangen ist und mit dem Assembler relocatable 
object files (.rel) erzeugt hat, die dann erst der Linker auf absolute 
Adressen mappt.

: Bearbeitet durch Moderator
von Christoph K. (chriskuku)


Lesenswert?

Niklas G. schrieb:
> Das "Reset+1" im Interrupt Vector ist unnötig, wenn man "Reset" korrekt
> als Funktion definiert:
>
>
1
  .word TOS           @ 00: Stack top address
2
>   .word Reset            @ 01: Reset Vector  +1 wegen des 
3
> Thumb-Einsprunges
4
> 
5
>   .text
6
>         .org 0x400
7
> 
8
> .type Reset, %function
9
> Reset:
10
>         bal Reset
11
>   .end
12
>
>
> Und der Vektor gehört natürlich wie schon gesagt an den Anfang des
> Flash. Wie wäre es mit meinem ARM-ASM-Tutorial?

Hatte ich doch auch an den Anfang gesetzt.

ARM-ASM-Tutorial, ja, werde ich mir ansehen.
Danke.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Christoph K. schrieb:
> Hatte ich doch auch an den Anfang gesetzt.

Aber .data ist halt nicht im Flash...

Christoph K. schrieb:
> ARM-ASM-Tutorial, ja, werde ich mir ansehen.

Da sind auch vollständig funktionierende Beispiele und ein 
Projekt-Template drin:

https://github.com/Erlkoenig90/ArmAsmTutorial/tree/master/ProjectTemplate-STM32F103RB

von Johannes S. (Gast)


Lesenswert?

Die gcc toolchain enthält in share/gcc-arm-none-eabi/examples auch 
Beispiele. Aber ein bisschen CMSIS für   die headerfiles und Systeminit 
sollte man auch mitnehmen.

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


Lesenswert?

Warum man die Systeminitialisierung bei einem F4 in Assembler schreibt, 
erschliesst sich mir auch nicht...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Uwe B. schrieb:
> Warum man die Systeminitialisierung bei einem F4 in Assembler schreibt

Christoph hatte seine Motivation doch an anderen Stellen schon 
dargelegt: er hat von einem Verstorbenen einen FORTH-Interpreter 
übernommen und möchte den weiter pflegen.

von Christoph K. (chriskuku)


Lesenswert?

Uwe B. schrieb:
> Warum man die Systeminitialisierung bei einem F4 in Assembler schreibt,
> erschliesst sich mir auch nicht...

Wie schon erwähnt, geht es um ein bereits bestehendes FORTH System, das 
in Assembler geschrieben ist. Warum soll ich da jetzt noch eine weitere 
"Hoch"sprache (C) mit hineinbringen? Die FORTH-Primitiven und der 
FORTH-Inner Interpreter basieren auf Assembler. Da wäre alles andere 
ineffizient.

Das ganze System ist 15KB groß.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Christoph K. schrieb:
> Warum soll ich da jetzt noch eine weitere
> "Hoch"sprache (C) mit hineinbringen? Die FORTH-Primitiven und der
> FORTH-Inner Interpreter basieren auf Assembler. Da wäre alles andere
> ineffizient.

C++ und C werden für ARM schon ziemlich effizient übersetzt. Da holst du 
mit Assembler (sehr) wenig raus.

von Christoph K. (chriskuku)


Lesenswert?

Niklas G. schrieb:
> Christoph K. schrieb:
>> Warum soll ich da jetzt noch eine weitere
>> "Hoch"sprache (C) mit hineinbringen? Die FORTH-Primitiven und der
>> FORTH-Inner Interpreter basieren auf Assembler. Da wäre alles andere
>> ineffizient.
>
> C++ und C werden für ARM schon ziemlich effizient übersetzt. Da holst du
> mit Assembler (sehr) wenig raus.

Der „Inner Interpreter“, der den Threaded Code verarbeitet, sah damals 
auf der PDP-11 so aus:

     .MACRO NEXT
     MOV (IP)+,W
     JMP @(W)+
     .ENDM

Für 68k waren es drei Instruktionen.

IP und W sind CPU-Register.
+ ist postincrement des jew. Registers.

Bilde das in C bzw. ASM ab.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Christoph K. schrieb:
> Bilde das in C bzw. ASM ab.

Ich kann keinen PDP-11-Assembler, keine Ahnung was da passiert. Aber es 
ging überhaupt nicht um den Interpreter, sondern die Initialisierung, 
denn rein zufällig sind sowohl die Cortex-M-Architektur als auch die 
STM32-Peripherie-Register extra auf die Verwendung mit C optimiert.

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.