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.
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
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.
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.
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
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 …
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).
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)
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).
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
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.
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.
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.
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.
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ß.
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.
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.
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.