Hallo,
ich habe derzeit versucht ein STM32F411RE Nucleo unter Linux mit eclipse
zu programmieren, bin aber im Moment ein bisschen am verzweifeln.
Ich habe Eclipse mit cdt und arm plugin installiert. Habe aus dem
repository den arm-none-eabi-gcc Compiler herunter geladen. Konnte dann
in Eclipse ein Projekt erstellen, wo ich den richtigen Controller
auswählen konnte und das Testprogramm konnte ich auch kompilieren und
die Binary hab ich auch erstellt.
Zum Programmieren habe ich ST-link von hier
https://github.com/texane/stlink heruntergeladen und wie in diesem Video
installiert https://www.youtube.com/watch?v=HKX12hJApZM habe es dann
auch so eingerichtet wie es dort gemacht wurde. Doch aus einem Grund den
ich nicht kenne, kann ich das Programm nicht auf den Controller laden.
Habe versucht die Binary mit st-flash write test.bin 0x8000000 auf das
Board zu laden, leider scheiterte dieser Versuch.
1
2015-02-27T10:03:19 INFO src/stlink-common.c: Loading device parameters....
2
2015-02-27T10:03:19 INFO src/stlink-common.c: Device connected is: F4 device (low power) - stm32f411re, id 0x10006431
3
2015-02-27T10:03:19 INFO src/stlink-common.c: SRAM size: 0x20000 bytes (128 KiB), Flash: 0x80000 bytes (512 KiB) in pages of 16384 bytes
4
2015-02-27T10:03:19 INFO src/stlink-common.c: Attempting to write 5784 (0x1698) bytes to stm32 address: 134217728 (0x8000000)
5
EraseFlash - Sector:0x0 Size:0x4000
6
2015-02-27T10:03:19 INFO src/stlink-common.c: Finished erasing 1 pages of 16384 (0x4000) bytes
7
2015-02-27T10:03:19 INFO src/stlink-common.c: Starting Flash write for F2/F4
8
9
Flash page at addr: 0x08000000 erased2015-02-27T10:03:19 INFO src/stlink-common.c: Successfully loaded flash loader in sram
10
2015-02-27T10:03:22 ERROR src/stlink-common.c: flash loader run error
Verwende Openocd Git Head!
Nach dem Laden und bauen:
~/devel/openocd> src/openocd -s tcl -f tcl/board/st_nucleo_f4.cfg
und in einer anderen Konsole:
arm-none-eabi-gdb xxx.elf
> tar ext :3333
hast du bei openocd auch stlink and stm32f4 als targets angegeben?`
z.b. müsstest du in eine openocd config foglendes mit einbinden:
source [find interface/stlink-v2.cfg]
source [find target/stm32f4_stlink.cfg]
Ich kann von texane stlink generell nur abraten. Lief nie ordentlich.
Buggy und langsam. OpenOCD ist dagegen solide, auch mit dem neuen
ST-Link/V2-1.
Wichtig: das neueste Firmware-Update für das ST-Link einspielen! Geht
leider m.W. auf offiziellen Wegen nur mit Windows.
Vielen Dank für die Antworten,
im Anhang findet ihr einen Screenshoot meiner Einstellungen in Eclipse.
Die openocd.cfg Datei habe ich im Projekt Ordner drin:
source [find interface/stlink-v2.cfg]
muss
source [find interface/stlink-v2-1.cfg]
lauten. V2 sind fast alle Discovery boards, Nucleo und die neuesten
Discovery Boards, wie L0538-Disco sind V2-1.
Martin schrieb:> Habe jetzt mal in Eclipse
Machs doch erst mal von der Kommandozeile bevor Du gleichzeitig noch
eine zweite Front mit Eclipse-Konfigurationsproblen aufmachst.
Mach eins nach dem anderen: Erst wenn Du auf der Kommandozeile mit
openocd einen erfolgreichen connect hinbekommst versuchst Du es mit den
selben Optionen in Eclipse zu reproduzieren.
Die OpenOCD Quellen werden mit GIT verwaltet:
http://openocd.sourceforge.net/repos/
Du arbeitest mit "released" Version, die zu einer Zeit herauskam, als
der F411 noch nicht bekannt war. Du musst also aus den neusten Quellen
(Git Head) bauen, oder mit einer Version, die neuer als 6. November 2014
ist. Zu dem Zeitpunk kamen die Aenderungen fuer den F411 naemlich in den
Baum.
Irgendwas erscheint da noch komisch. Ich erhalte hier:
> src/openocd -s tcl -f tcl/board/st_nucleo_f4.cfg
Open On-Chip Debugger 0.9.0-dev-00314-g90ae846 (2015-02-28-15:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The
results might differ compared to plain JTAG/SWD
adapter speed: 2000 kHz
adapter_nsrst_delay: 100
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : clock speed 1800 kHz
Info : STLINK v2 JTAG v23 API v2 SWIM v7 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 0.007890
Error: target voltage may be too low for reliable debugging
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
...
Warum meldet sich Dein Executable mit 0.8.0 und bei mit mit 0.9.0-dev?
Das mit der Targetspannung hat seine Richtigkeit, ich habe einige
Widerstaende abgeloetet, um den F411 auch mit Batterie zu betreiben.
Welches Repository hast Du verwendet?
> git remote -v
origin git://git.code.sf.net/p/openocd/code (fetch)
Martin M. schrieb:> /usr/local/bin/openocd> /usr/bin/openocd
Schaut nach zwei Binaries aus. Mit absoluten Fileangabe und -version
schauen, welches gebraucht wird. /usr/bin/openocd könnte aus einer
Distribution ein. Wenn nicht benötigt, dann über die Distribution
deinstallieren.
Schaut aus, wie wenn der root eine 0.8 Version zusätzlich installiert.
hat. Bezüglich Versionen nochmal oben lesen, welche für den Controller
benötigt wird.
> root.local/share/Trash/files/openocd-0.8.0/src/openocd
Martin schrieb:> openocd -f /usr/share/openocd/scripts/board/st_nucleo_f4.cfg> Open On-Chip Debugger 0.8.0 (2015-02-27-19:19)> Licensed under GNU GPL v2
Aufräumen.
Es sind zwei openocd installiert und der obige Befehl mischt das Binary
der einen Version mit den Konfig-Dateien der anderen Version.
/usr/bin/openocd -f /usr/share/openocd/scripts/board/st_nucleo_f4.cfg
könnte wieder gültig sein.
noreply@noreply.com schrieb:> /usr/bin/openocd -f /usr/share/openocd/scripts/board/st_nucleo_f4.cfg
Ok das funktioniert mal sehr gut. Vielen Dank! Aber wie bekomm ich das
alte wieder runter, den ich hab die Version 0.8 nicht über den
Paketmanager installiert.
Martin M. schrieb:> Verbindet sich hier der GDB mit openOcd welches mit dem Controller> kommuniziert oder?
Ja, genau so ist es. OpenOCD fungiert hier als sogenannter
gdb-debugserver.
Hättest Du stattdessen zum Beispiel einen Segger Jlink gekauft dann
hättest Du statt openocd den JLinkGDBServerCL gestartet und gdb würde
sich dann mit diesem verbinden, selbes Prinzip.
Jeder Hersteller eines JTag-Adapters sollte entweder einen gdb
debugserver mitliefern oder sicherstellen daß sein Adapter
vollumfänglich mit OpenOCD funktioniert, andernfalls wäre es nicht
möglich mit gdb zu debuggen und der Adapter wäre nicht viel mehr wert
als ein Ziegenstein. Solltest Du Dir irgendwann mal einen eigenständigen
Jtag-Adapter kaufen wollen dann achte bitte auf dieses kleine Detail!
Martin M. schrieb:> Verbindet sich hier der GDB mit openOcd welches mit dem Controller> kommuniziert oder?
Und der Vollständigkeit halber: Du kannst bei OpenOCD auch noch
zusätzlich auf port 4444 mit Telnet connecten (telnet localhost 4444)
und bekommst dann eine Kommandozeile an der Du selbst direkt mit OpenOCD
sprechen kannst.
Probiers mal aus!
Bernd K. schrieb:> Solltest Du Dir irgendwann mal einen eigenständigen> Jtag-Adapter kaufen wollen dann achte bitte auf dieses kleine Detail!
Vielen Dank für den Tipp! ;)
Bernd K. schrieb:> Und der Vollständigkeit halber: Du kannst bei OpenOCD auch noch> zusätzlich auf port 4444 mit Telnet connecten (telnet localhost 4444)> und bekommst dann eine Kommandozeile an der Du selbst direkt mit OpenOCD> sprechen kannst.
Jop hat funktioniert. Aber debuggen kann man doch trotzdem nur über GDB
oder versteh ich da was falsch?
Sepp schrieb:> Versuchs mal so
Hat so nicht in Eclipse funktioniert.
1
/bin/bash: /home/martin/workspace/test2/Debug/test2.elf: Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei
2
/bin/bash: /home/martin/workspace/test2/Debug/test2.elf: Erfolg
Wird durch OpenOcd auch die Software in den Controller geflasht? Diese
ist eine andere als wenn ich die Release flashe, wegen der Nutzung von
Breakpoints,... oder?
1
(gdb) tar ext :3333
2
Remote debugging using :3333
3
0x00000000 in ?? ()
4
(gdb) mon reset halt
5
target state: halted
6
target halted due to debug-request, current mode: Thread
7
xPSR: 0x01000000 pc: 0xfffffffe msp: 0x20020000
8
(gdb)
Es scheint, dass das Programm durchlaufen wird, da mit dem Befehl list
immer ein anderer Codeausschnitt angezeigt wird.
Habe versucht einen Breakpoint zu setzen, doch bei diesem wird nicht
angehalten.
Martin M. schrieb:> Wird durch OpenOcd auch die Software in den Controller geflasht? Diese> ist eine andere als wenn ich die Release flashe, wegen der Nutzung von> Breakpoints,... oder?
Probier es mal mit "load" im gdb. Das flasht den Code. Ich verwende i.A.
diese Initialisierungssequenz für "flashen und dann debuggen":
drama schrieb:> monitor reset halt> load> monitor reset init> thbreak main> continue
es schein so dass es Programmiert wird. aber nur wenn ich load
HelloWorld.elf anstatt nur load schreibe
1
(gdb) tar ext :3333
2
Remote debugging using :3333
3
0x00000000 in ?? ()
4
(gdb) monitor reset halt
5
target state: halted
6
target halted due to debug-request, current mode: Thread
Was brauch ich alles, um auf dem Controller die LED (Port A5)
einzuschalten?
RCC->AHB1ENR |= (1<<0); //Clock für PortA einschalten
GPIOA->MODER |= (1<<10); //PA5 als Ausgang definieren
GPIOA->ODR |= (1<<5); //PA5 auf 1 setzen
Martin M. schrieb:> es schein so dass es Programmiert wird. aber nur wenn ich load> HelloWorld.elf anstatt nur load schreibe
Normalerweise gibt man gdb beim Start als Parameter die elf-Datei mit,
die debuggt, geflasht und/oder ausgeführt werden soll. Versuche das mal.
Keine Ahnung, wie andere Szenarien unterstützt werden.
Martin M. schrieb:> Was brauch ich alles, um auf dem Controller die LED (Port A5)> einzuschalten?
Ja, das sollte eigentlich reichen. Je nachdem, wie dein Board
verschaltet ist, könnte die LED auch invertiert sein, oder einen aktiven
Pullup/Pulldown benötigen. Ansonsten prüfe mal deine Bitmasken, der
CMSIS-Header enthält dafür auch Konstanten.
Schaue mal mit einem Debugger rein, ob du vielleicht im
HardFault-Handler steckst. Das passiert, wenn man nicht ordentlich
Thumb-Code generiert und kann gut verwirren.
> Ich habs jetzt mal nach dieser Anleitung probiert, und da lande ich im
HardFault-Handler.
Dann schau jetzt mal in den Callstack wie Du da hingekommen bist.
Also einen hab ich noch: Bei meinen frühen Versuchen mit einem Nucleo
401 Board hatte ich mal einen Zustand in dem er scheinbar aus heiterem
Himmel einen Sprungbefehl völlig falsch interpretiert und ins Nirvana
gesprungen ist (müsste sogar ein Thread darüber hier irgendwo im Forum
existieren), ein paar Takte später war er dann im Hardfault Handler und
es war nicht einzusehen oder nachzuvollziehen wie er dort auf normalem
Wege jemals hätte hin kommen sollen.
Erst als ich ein paar Breakpoints früh in der Initialisierung gesetzt
und im Einzelschritt durchgegangen bin konnte ich die Stelle einkreisen
an der er plötzlich begann verrückt zu spielen: Es war unmittelbar nach
der Initialisierung der PLL!
Ich hatte versehentlich eine SystemClockInit()-Funktion aus einen
anderen Beispielprogramm für eins der anderen STM32 Boards welches ich
als Grundgerüst genommen hatte in mein Programm eingebaut
(beziehungsweise versehentlich noch nicht aus diesem entfernt und gegen
die richtige ausgetauscht) und der (vermutlich zu hohe) Takt hat ihn
dann beim nächsten Sprungbefehl an eine ungültige Adresse springen
lassen obwohl der besagte Sprungbefehl eigentlich vollkommen korrekt
war.
Nachdem ich die Systemtakt-PLL richtig konfiguriert hatte war der Spuk
vorbei.
Im Terminal habe ich openocd laufen: openocd -f
/usr/share/openocd/scripts/board/st_nucleo_f4.cfg
und in eclipse habe ich nache dieser Anleitung:
http://vedder.se/2012/12/debugging-the-stm32f4-using-openocd-gdb-and-eclipse/
Zylin installiert.
Den Fehler konnte ich leider nicht rekonstruieren. Aber es bleibt immer
im startup hängen (siehe Anhang)
Martin M. schrieb:> Wie kann ich aber vor der _start(void) Funktion einen Breakpoint setzen,> habe es im Assembler Code versucht, doch dieser wird einfach> übersprungen.
Also bei mir klappt das einwandfrei. Ich kann einen Breakpoint irgendwo
in der startup.s Datei nah am Einsprungpunkt setzen und der wird
ordnungsgemäß berücksichtigt. Hab das selbst mal durchexerziert aus ganz
ähnlichen Gründen (oben beschrieben), allerdings an einem
stm32401RE-Nucleo-Board mit openocd, Eclipse, der toolchain von
Launchpad, gnuarm-Plugin und unter Linux.
Allerdings ohne Zylin (was auch immer das ist) denn bei der
arm-none-eabi-* Toolchain und dem GnuARM-Plugin ist eigentlich schon
alles fix und fertig dabei was man zum Debuggen braucht.
Die Toolchain hab ich übrigens installiert indem ich einfach deren PPA
in meine Paketquellen (Ubuntu) aufgenommen habe. So einfach und
unkompliziert hab ich noch keine cross toolchain am Start gehabt wie
diese. Und das verrückteste war daß entgegen aller Unkenrufe der erste
Versuch unter Linux mit diesem Nucleo-Board und openocd auf Anhieb
geklappt hat, am nächsten Tag unter Windows bin ich fast verzweifelt an
den üblichen Windows-Problemen (dort gehts aber mittlerweile auch).
Ich hab auch openocd, das arm plugin, arm-none-eabi- gcc und gdb
installiert. Was hast du für Einstellungen im "GDB OpenOCD Debugging" in
Eclipse eingestellt? Im Anhang findest du meine Einstellungen. Aber nur
mit dem OpenOCD Debugger in Eclipse komm ich noch weniger weiter
$ openocd -v
Open On-Chip Debugger 0.8.0 (2014-05-10-23:20)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.sourceforge.net/doc/doxygen/bugs.html
$ which openocd
/usr/bin/openocd
Oben sieht man wie ich einen Breakpoint direkt im Reset-Handler gesetzt
habe, angehalten hat er eine Instruktion später. Danach kann ich normal
im Einzelschrittmodus weitergehen.
Ich habe auch mal mein eigenes Minimal-Projekt angehängt (genau das aus
dem Screenshot), es ist allerdings für ein STM32F401 Nucleo.
Ich verwende keine HAL-Library und ich habe das startup.s so modifiziert
daß ich den Aufruf von __libc_init_array nicht ausführen muss (weil ich
kein C++ mache). Ich springe dann direkt nach main().
Zu dem angehängten Projekt:
EDIT: Wirf das .d und das .o file aus dem src-Ordner raus, ich weiß
nicht wie die da reingekommen sind, die gehören da nicht hin, lösch die
einfach. Aller Build-Output wird ins build-Verzeichnis gehen.
Das angehängte Projekt sollte sich auf der Konsole mit
make all
bauen lassen und mit
make clean
wieder reinigen. Die Dateien in stm_inc sind alle aus den CubeMX zip
files zusammengesucht und nur die die wirklich absolut notwendig sind
für ein Blinky ohne HAL, evtl kannst Du die austauschen gegen solche für
Deinen Prozessor und das somit passend machen. Du wirst auch das
startup_*.s file austauschen müssen (da sind die Interrupt-Vektoren
definiert) und Du wirst wahrscheinlich auch system_*.c anpassen müssen
für die korrekte PLL Konfiguration für Deinen Prozessor. Ferner musst Du
auch im Makefile evtl. die defines anpassen.
Wenn Du das Projekt in Eclipse importierst dann stell sicher daß Eclipse
es als makefile-Projekt behandelt, also nicht versucht sich on-the-fly
sein eigenes Makefile zu bauen.
Martin M. schrieb:> Ketzt kann ich schon mal Debuggen. Doch er bleibt in einer while> Schleife hängen (Siehe Screenshot).
Setz mal einen Breakpoint eine Zeile tiefer und dann starte ihn (kein
Einzelschritt sondern ungebremst mit dem grünen Pfeil), wenn er aus der
While() draussen ist wird er wieder anhalten.
Der Fehler mit der While Schleife war, da ich den Takt beim erstellen
des Projektes nicht geändert habe, da ich dachte ich müsste die Register
dafür setzten, aber dies hat wahrscheinlich der startup Code für mich
erledigt. Habe jetzt den Takt auf 32.768.000Hz gestellt (Nucleo externer
Quarz)
Kann ich mir über SWD den Inhalt der Register nicht anschauen? Wie sehe
ich, wie viel Speicher das Programm verbraucht? Was ist eigentlich genau
der Unterschied zwischen Release und Debug? Werden beim Realease die
Sachen die der Controller zum debugen braucht nicht mitgeschrieben?
An alle die mir geholfen haben nochmals ein großes Dankeschön
Martin M. schrieb:> Kann ich mir über SWD den Inhalt der Register nicht anschauen?
Doch. Mit dem "Packs-Manager" installierst Du das "Pack" für den
betreffenden Controller:
http://gnuarmeclipse.livius.net/blog/packs-manager/ und danach wird der
Reiter "Peripherals" funktionieren.
> Wie sehe> ich, wie viel Speicher das Programm verbraucht?
Baue noch einen arm-none-eabi-size Aufruf in Deinen Build ein.
> Was ist eigentlich genau> der Unterschied zwischen Release und Debug?
Das sind einfach zwei so benannte Konfigurationen die unterschiedliche
Compilereinstellungen haben. Du kannst auch noch mehr verschiedene
Build-Configurationen erstellen und für jede kannst Du unterschiedliche
Compileroptionen angeben oder unterschiedliche Symbole definieren so daß
Du sogar den selben Code in verschiedenen Varianten bauen könntest.
Im einfachsten Fall hast Du nur die Konfigurationen Release und Debug
und die unterscheiden sich nur geringfügig in den Compilereinstellungen.
> Werden beim Realease die> Sachen die der Controller zum debugen braucht nicht mitgeschrieben?
Der Controller braucht keine "Sachen", der Compiler kann Debug-Symbole
in die .elf-Datei schreiben die der gdb lesen kann und er verzichtet auf
ein paar tiefgreifende, code-umsortierende Optimierungen die das
Debuggen schwierig bis unmöglich machen würden. Das kannst Du auf dem
Reiter "Project properties -> C/C++ build-> Settings" einstellen, oben
kann man auswählen für welche Konfiguration (Debug oder Release) man
jetzt gerade die Einstellungen ändert und unten ändert man sie.
Das obige gilt aber alles nur wenn Du das Projekt von Eclipse bauen
lässt, also der Build-Vorgang von Eclipse gesteuert wird. Wenn Du ein
selbst geschriebenes Makefile hast mach Eclipse nicht anderes als "make
all" aufzurufen und du musst alle Einstellungen im Makefile vornehmen.
Du kannst aber auch in diesem Falle verschiedene Konfigurationen anlegen
und dort dem make-Aufruf noch jeweils andere Argumente übergeben.
Martin M. schrieb:> Danke für die ausführliche Antwort.arm-none-eabi-size> --format=berkeley "STM32_Uart.elf"> text data bss dec hex filename> 7709 160 416 8285 205d STM32_Uart.elf> Sind das 8285 Bytes was das Programm an Flash verbraucht?
text ist all der vom Compiler erzeugte Maschinencode.
bss liegt im RAM, das sind all Deine globalen und statischen Variablen
und data sind die Daten mit denen sie vor Beginn des Programms
initialisiert werden.
Wenn Du sowas hast:
1
uint32_tfoo=0;
2
uint32_tbar=0;
3
uint32_tbaz=42;
4
5
voidfoo(){
6
staticuint32_tbla=0;
7
staticuint32_tblub=23;
8
9
uint32_tlocal_blub=99;// <-- das liegt auf dem Stack, das existiert erst wenn die Funktion aufgerufen wird
10
[...]
Dann wäre bss=40 und data=8 denn bss (also RAM) brauchen alle 5
Variablen aber initialisiert mit anderen Daten als 0 werden nur 2 davon
also insgesamt 8 Byte. Beachte daß die lokale Variable local_blub nicht
dazu zählt, der Platz dafür wird erst später bei Aufruf der Funktion auf
dem Stack reserviert und bei Verlassen der Funktion wieder freigegeben,
das wird auch nicht aus "data" initialisiert sondern von der Funktion
selbst jedesmal wenn sie diese Variable anlegt bei jedem Aufruf.
Die 0 wird im startup mit ner simplen Loop in alle globalen und
statischen Variablen reingeschrieben welche mit 0 initialisiert werden,
die 42 und die 23 werden aus dem Flash ins RAM kopiert. Dazu werden ganz
geschickter weise vom Linker die Variablen so angeordnet dass das in
einem Rutsch geschehen kann, also alle initialisierten Variablen an
aufeinander folgenden Adressen zu liegen kommen so daß er einfach nur
einen Block am Stück aus dem Flash ins RAM kopieren kann, dieser Block
ist "data".
Also wird Dein Programm mindestens text + data im Flash verbrauchen und
darüberhinaus noch evtl ein bisschen mehr weil noch andere Dinge im
Flash liegen, zum Beispiel gibts Controller da beginnt zwar die
Vektortabelle bei 0 aber das Programm erst bei 0x0400 und dazwischen ein
"Loch". Du könntest Dir im Zweifel auch mal die Größe des erzeugten .bin
Files anschauen, das entspricht aufs Byte genau dem Speicherabbild das
letztendlich an einem Stück ins Flash gebrannt wird.