Der STM32-Thread

Der chaotische Hauptfaden

Moderatoren: Heaterman, Finger, Sven, TDI, Marsupilami72, duese

Antworten
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Der STM32-Thread

Beitrag von berferd »

Hallo zusammen, nachdem es einen Atmel/Arduino-Thread gibt, muss wohl auch ein STM32-Thread her.

Aktuell arbeite ich mich mal in den STM32 (Nucleo F401RE) ein. Entwickeln möchte ich unter Linux.
Ich arbeite bisher sehr gerne mit Makefile-basierten Umgebungen, mit gdb usw... also eher Kommandozeilig.

Wie steige setze ich die Umgebung am saubersten auf? Wichtig ist mir: möglichst Single Step Build, über Kommandozeile auslösbar. Meinetwegen auch eine GUI, aber der Build soll möglichst auch ohne anstoßbar sein. Für meine Atmels habe ich da bisher immer "make" und "make program" gemacht, das ist recht elegant und schlank.

Es gibt da die STM32CubeIDE, die mir aber ziemlich überladen scheint. Wenn schon der Hauptbildschirm wie eine Webseite mit Facebook- und Instagram- und Wiki-Links loslegt, und schon das "Projekt-Anlegen" Fenster nicht richtig gerendert wird (Text ragt am Rand raus und daher nicht lesbar, Fenster ist nicht größer zu ziehen)... :roll:

Die Makefile-Beispiele, die ich bisher gefunden habe, arbeiten entweder ohne HAL (ich denke es ist wohl sinnvoll, die zu nutzen) oder sind relativ grottig (keine saubere Trennung von BSP-Files, HAL-Files und Projekt-Files.. wir kippen einfach alles in das Projektverzeichnis und bauen dann), haben die Dependencies nicht sauber, oder sind einfach nur Shell-Scripte ohne mit hardcoded Pfaden und ohne jede Fehlerprüfung.

Was ist da die sauberste Lösung für Linux? Wenns sein muss auch mit der GUI, ich will da nicht zu verbohrt sein. Grade die Config des STM32 scheint ja recht komplex zu sein, evtl. ist da doch die Konfiguration via GUI angebracht, anstatt da die Register wie beim Atmel einzeln zusammenzufischen, und bzgl Debugging hat eine integrierte GUI ja auch Vorteile.
Nehme ich da die STM32CubeIDE? Muss man bestimmte Sachen beachten, gibts Fallstricke?
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

berferd hat geschrieben: Mo 27. Mär 2023, 13:02 ich denke es ist wohl sinnvoll, die zu nutzen
Nein, genau das Gegenteil ist der Fall.
Der "HAL" ist ein verbuggter und aufgeblasener obfuscation layer.
Da wird kaum was abstrahiert, zB beim DMA musste immernoch die Channel Nummern reinwerfen anstatt zu sagen "DMA für UART2 bitte", danke für nix.

Was du nutzen kannst sind die CMSIS Headerfiles für die Register- und Bitdefinitionen, die will man nich wirklich selber reinhacken.
Die kannste aus einem erstellten Projekt des STM32 Cube rausziehen (nicht IDE).

Ein makefile mit make und make programm is ja shcnell geschrieben, das nutzt man dann eben imemr weiter.

Ansonsten kauf dir zum Debuggen den J-Link EDU, dann kannste Segger Ozone nutzen.
Das gibts auch für Linux.

Die Config sieht nur im HAL obfuscation layer kompliziert aus.
Es gibt nen Taktbaum mit ein paar Einstellungen für die Taktquelle und PLL, das wars.
Bevor eine Peripherie genutzt werden kann muss im Taktregister der Takt für diese eingestellt werden.
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Der STM32-Thread

Beitrag von berferd »

Gut, dann lasse ich den HAL weg. Ich erinner mich dunkel da schon mal was gehört zu haben.
Zum Flashen wirds wohl openocd mit einem STLink-Klon, den habe ich schon. Bzw auf dem Eval-Board ist ja schon ein entsprechendes Interface (über USB angebunden) dabei.
nux
Beiträge: 83
Registriert: So 31. Jul 2016, 12:53

Re: Der STM32-Thread

Beitrag von nux »

Es gibt noch die STM32LL, die Low Level Library, welche bei einigen Kollegen gerne mal verwendet wird.
Insgesamt leichtgewichtiger und näher an der Hardware als die HAL.

Bei manchen Nucleo Boards kann man den ST-Link auf einen J-Link umflashen:
https://www.segger.com/products/debug-p ... -on-board/

Bei dem STM32CubeMX finde ich persönlich für die Inbetriebnahme der Elektronik die Clock Configuration ganz spannend und hilfreich.

Gruß nux.
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

nux hat geschrieben: Di 28. Mär 2023, 13:45 Bei dem STM32CubeMX finde ich persönlich für die Inbetriebnahme der Elektronik die Clock Configuration ganz spannend und hilfreich.
Sowie um überhaupt den passenden STM32 zu finden und dann gucken an welchen Pin welche Funktion ankommt.
Aber bloß niemals auf Code genererieren klicken von nicht funktionierenden makefiles bis zum falschen Takt kann da alles passieren :mrgreen:

Die LL ist meist nur eine Funktion welche ein Registerzugriff wrapped.
Das kann man auch gleich selber machen.
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Der STM32-Thread

Beitrag von berferd »

Ich habe es via Makefiles zum Bauen bekommen. Zielführend war diese Seite hier: https://avrs.fi/arm/ dort gibts ein entsprechendes Makefile und Vorgehen, wie man sein Projekt-Verzeichnis anlegt.

Allerdings muss ich mich in Kürze auch mal an Komplexeres ranwagen, und da komme ich um die HAL wohl voraussichtlich nicht rum, es da auch um FS-Treiber usw geht.
Idee daher: mit Beispielprojekten aus dem STM32CubeF4-Paket anfangen.
Was empfiehlt sich dafür? STM32CubeIDE? STM32CubeCLT? Oder ist das reine Geschmackssache?
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Der HAL nutzt den elmChan Fat32FS Treiber.
Nur haben die Sp*ck*en den nicht Original gelassen, sondern hier und da etwas verändert.

Nimm lieber das Original, das ist auch sehr gut erklärt wie man das einbaut und nutzt:
http://elm-chan.org/fsw/ff/00index_e.html
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Der STM32-Thread

Beitrag von berferd »

Wenns nur der wäre.. u.a. brauche ich auch USB-Host-Code... :roll: Das alles selber neu zu schreiben dürfte etwas umfangreich werden.
Aber ich behalte das mal im Hinterkopf, dass ich den FAT-Teil ggf. selber neu aufsetze.
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

ja beim USB Horst brauchste leider ein Stückchen HAL.
Das aber so verbuggt, dass sich der STM32 gerne mal aufhängt wenn man dne USb Stick zu langsam reinsteckt :roll:
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Der STM32-Thread

Beitrag von berferd »

Hurra, auf sowas baut man doch gerne auf :lol:
Das klingt ja alles eher nach "STM32 vermeiden" ... gibts da sinnvollere Alternativen?
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Eigentlich nur den HAL.
Datenblätter und die Chips sind recht gut.

Die beileigende Software von Atmel/Microchip ARM Prozessoren is mindestens genauso Müll.
Dafür sind die Datenblätter bei Atmel/Microchip ARM Prozessoren fürn Poppes.
Der DMA hat Prioritäten steht in der Einleitung des Kapitels, dann steht da aber nich ob ID0 oder ID15 die höchste Prio is, das darfste dann selber per Experiment rausfinden...
Benutzeravatar
zauberkopf
Beiträge: 9481
Registriert: So 11. Aug 2013, 15:33
Wohnort: gefährliches Halbwissen

Re: Der STM32-Thread

Beitrag von zauberkopf »

ja beim USB Horst brauchste leider ein Stückchen HAL.
Das aber so verbuggt, dass sich der STM32 gerne mal aufhängt wenn man dne USb Stick zu langsam reinsteckt :roll:
Oh... mir schwarnt böses...
Das gleiche geht mir hier bei einem anderen Controller unter Threat X tierisch auf den Sack.

Ich fange schon langsam an, mich in die USB-Scheisse hineinzuarbeiten.
Virtex7
Beiträge: 2374
Registriert: Di 13. Aug 2013, 21:50
Wohnort: Erlangen

Re: Der STM32-Thread

Beitrag von Virtex7 »

vielleicht nicht unbedingt beliebt, aber wenn es das cube IDE nicht gäbe, würde ich immernoch stm32 kategorisch vermeiden.
Ich hab so etwa vor 8-10 Jahren schonmal versucht, mit den DIngern was zu machen, es ist so grandios gescheitert. Alles nach Datenblatt, wie beim Atmel avr auch.
check ich nicht.. :?

-> cube IDE funktioniert mit dem gekauften stlinkv2 und die Pins tun was sie sollen.. meist zumindest.
Aber ohne das wöre ich stumpf aufgeschmissen.

Also vielleicht auch mal ein Herz für HW Leute. Ohne Arduino und CubeIDE und wie sie alle heißen (und kostenlos sind und NICHT KACK KEIL), wäre mir das Thema versperrt.
Benutzeravatar
zauberkopf
Beiträge: 9481
Registriert: So 11. Aug 2013, 15:33
Wohnort: gefährliches Halbwissen

Re: Der STM32-Thread

Beitrag von zauberkopf »

Naja... also ich habe damals mit 8051 angefangen, mit den Hilfsmitteln : Buch, Epromprogrammer und Epromsimulator.
AVR mit Programmer.. wobei ich sagen muss : Der Bootloader vom Arduino war schon gut.
Herangetastet habe ich mich weniger mit Datenblatt, sondern mit Buch und einfachen beispielen.
Dann klappts auch auf kommandozeilenebene.

Für quick and dirty, nehme ich heute Rasperry Pico unter Python.

Zurrück zur kommandozeilenebene.
Das schöne an make ist, das man aus einem Projekte per parameter verschiedene Versionen ganz einfach erzeugen kann.
z.B. ne Debug version, und dann die endgültige..
Oder noch ne Testversion dazwischenschieben.
Wenn man make nicht hat, muss man im Programmcode irgendwelche Inlcudes etc.. auskommentiereren...
Und wenn ne Versionsverwaltung dahintersteht, wirds dann spassig.

Auch hat man nicht immer volle kontrolle über das Projekt.
z.B. wenn vor 5 Jahren was geschrieben hat, das läuft.. und danach von der IDE immer fleißg updates gezogen hat... mit den ganzen libs... kann es später gut sein,
das nach 5 Jahren plötzlich nicht mehr compiliert.

Deswegen packe ich den dazugehörigen Rotz immer mit in den Projektordner.
bastelheini
Beiträge: 1663
Registriert: So 11. Aug 2013, 13:55

Re: Der STM32-Thread

Beitrag von bastelheini »

Moin,

ich versuche mir gerade ein Beispielprojekt für einen STM32 aufzusetzen.

Ich möchte VScode nutzen. Innerhalb nutze ich das Plugin https://marketplace.visualstudio.com/it ... me=CL.eide . Programmieren möchte ich in C++.

Ich habe das Ganze soweit eingerichtet, dass es baut (nur die main.cpp). Config siehe Anhang, da sollte alles eingestellte ersichtlich sein.

Aber sobald ich eine Klasse instanziieren möchte wirft er mit einen Fehler, bei dem ich nicht so recht weiß wie ich ihn behebe:

Code: Alles auswählen

[ INFO ] start building at 2023-10-03 13:18:15

[ TOOL ] arm-none-eabi-gcc.exe (GNU Arm Embedded Toolchain 10-2020-q4-major) 10.2.1 20201103 (release)

[ INFO ] file statistics (incremental mode)

+---------+-----------+-----------+---------------+--------+
| C Files | Cpp Files | Asm Files | Lib/Obj Files | Totals |
+---------+-----------+-----------+---------------+--------+
| 0       | 2         | 0         | 0             | 2      |
+---------+-----------+-----------+---------------+--------+

[ INFO ] start compilation ...

>> [ 50%] CC 'src/main.cpp'
>> [100%] CC 'src/sample_class.cpp'

[ INFO ] start linking ...

c:/users/username/.eide/tools/gcc_arm/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: ./build/Debug/src/main.o: in function `main':
c:\Users\Stefan\Desktop\project_templates\project_template_stm32/./src/main.cpp:6: undefined reference to `__cxa_end_cleanup'
c:/users/username/.eide/tools/gcc_arm/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: ./build/Debug/src/main.o:(.ARM.extab.text.main+0x0): undefined reference to `__gxx_personality_v0'
Memory region         Used Size  Region Size  %age Used
             RAM:        1664 B         2 KB     81.25%
           FLASH:        1332 B        16 KB      8.13%
collect2.exe: error: ld returned 1 exit status

 ERROR  link failed !, exit code: 1

 ERROR  build failed !, elapsed time 0:0:0


 *  Der Terminalprozess "cmd.exe /C "unify_builder -p c:\Users\Stefan\Desktop\project_templates\project_template_stm32\build\Debug\builder.params"" wurde mit folgendem Exitcode beendet: 1. 
 *  Das Terminal wird von Aufgaben wiederverwendet, drücken Sie zum Schließen eine beliebige Taste. 
Die entsprechende main und Klasse:

main.cpp

Code: Alles auswählen

#include "sample_class.hpp"

int main(void)
{
	sample_class sample_class_instance;

	sample_class_instance.print_test();	
		
	return 0;	
}
sample_class.cpp

Code: Alles auswählen

#include "sample_class.hpp"

sample_class::sample_class(/* args */)
{
}

void sample_class::print_test(void)
{     
}

sample_class::~sample_class()
{
}
sample_class.hpp

Code: Alles auswählen

class sample_class
{
private:
    /* data */
public:
    sample_class(/* args */);
    ~sample_class();
    void print_test(void);
};
Kann mir jemand helfen, wie die Fehler verschwinden? Im Inet findet man was dass man statt gcc g++ erzwingen soll, ich weiß aber nicht so recht an welcher Stelle das passieren soll...
Silvio
Beiträge: 117
Registriert: Mi 21. Sep 2022, 03:18

Re: Der STM32-Thread

Beitrag von Silvio »

Hast du schon mal nach "STM32F401 template git" gesucht? Ich denke, da findet man eine "make clean && make && make flash" Version...
C++ ist Geschmackssache.
virtexultra
Beiträge: 127
Registriert: So 9. Dez 2018, 11:30

Re: Der STM32-Thread

Beitrag von virtexultra »

Ich glaube ein Template für ein Makefile ist hilfreich. Wenn man die nicht genutzte Sektion mit der GCC Option "-Wl,-gc-sections" entfernt sollte es auch bauen. Achtung, der Linker kann so auch Code wegwerfen von dem er denkt das dieser nicht benötigt wird (z.B. Startup Files). Überlicherweise funktioniert das aber weil die Linkerscripts entsprechend angepasst sind.
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Ein Problem ist hier, dass VSKot genutzt wird und das automagisch ein Makefile erzeugt.
Da muss man also in der Javscript geschriebenen Mickeysoft Gammel IDE gucken wo die Einstellungen sind für das Problem.

Das Problem:
Guck dir doch mal den Output genauer an, da meckert der Linker, dass er `__cxa_end_cleanup' und `__gxx_personality_v0' nicht finden kann.
Diese Funktionen werden für C++ Exceptions und RTTI (runtime type information) benötigt.
Braucht man in embedded Umgebungen aber mal so garnicht und bläst sogar nur den Code auf.

2 Dinge müssten im Makefile geändert werden:

1)
Statt "arm-none-eabi-gcc" muss der "arm-none-eabi-g++" als Compiler aufgerufen werden.
Dies ist der C++ Compiler des GCC und er hat schon ein paar Standardlibs drinne für C++.

2)
Als Compiler Optionen/Flags wird übergeben "-fno-exceptions" und "-fno-rtti"
(Willste, aus welchen Gründen auch immer, die Exceptions haben muss stattdessen das hier in die Compilerflags des Makefiles: "-lsupc++")

Jetz musste nurnoch finden wo du das in der GUI einstellen/angeben kannst.
bastelheini
Beiträge: 1663
Registriert: So 11. Aug 2013, 13:55

Re: Der STM32-Thread

Beitrag von bastelheini »

Danke für die Antworten. Das ist aber ein Gefriemel.... :evil:

Ich hab zwischenzeitlich mal angefangen direkt was mit CMake zu schreiben (und ohne das Plugin). Damit sollte ich ja die ganze Kontrolle haben.

Eine vermeintlich gute Anleitung habe ich hier gefunden. https://dev.to/younup/cmake-on-stm32-the-beginning-3766

Was mir dort und mir jetzt fehlt: ich muss ja scheinbar Dinge wie die Architektur übergeben. Für den L011 (M0+) ist das die v6M, da er sich sonst im startupcode über nicht implementierte Befehle beschwert. Wo ist dokumentiert was CMSIS und sonstwas als Parameter alles braucht?

Derzeit übergebe ich nur das (und was mir ggf. später noch an cmd line Fehlermeldungen über den weg läuft):

Code: Alles auswählen

target_compile_definitions(${EXECUTABLE} PRIVATE
        #-DUSE_HAL_DRIVER
        STM32L011x
        __ARM_ARCH_6M
        )

Aktuell beschwert er sich auch über den ARM Kern:

Code: Alles auswählen

[ 20%] Building C object CMakeFiles/STM32L011K4Tx_debug.out.dir/src/main.c.obj
C:\MinGW\mingw32\bin\gcc.exe -DSTM32L011x -D__ARM_ARCH_6M -IC:\Users\Username\Desktop\project_templates\project_template_stm32_cmake\src -IC:\Users\Username\Desktop\project_templates\project_template_stm32_cmake\src\uC_specific\STM32*\Include -IC:\Users\Username\Desktop\project_templates\project_template_stm32_cmake\lib\CMSIS\Core\Include -g -std=c17 -mcpu=cortex-m0plus -fdata-sections -ffunction-sections -Wall -Og -MD -MT CMakeFiles/STM32L011K4Tx_debug.out.dir/src/main.c.obj -MF CMakeFiles\STM32L011K4Tx_debug.out.dir\src\main.c.obj.d -o CMakeFiles\STM32L011K4Tx_debug.out.dir\src\main.c.obj -c C:\Users\Username\Desktop\project_templates\project_template_stm32_cmake\src\main.c
gcc.exe: warning: '-mcpu=' is deprecated; use '-mtune=' or '-march=' instead
cc1.exe: error: bad value 'cortex-m0plus' for '-mtune=' switch
cc1.exe: note: valid arguments to '-mtune=' switch are: i386 i486 i586 pentium lakemont pentium-mmx winchip-c6 winchip2 c3 samuel-2 c3-2 nehemiah c7 esther i686 pentiumpro pentium2 pentium3 pentium3m pentium-m pentium4 pentium4m prescott nocona core2 nehalem corei7 westmere sandybridge corei7-avx ivybridge core-avx-i haswell core-avx2 broadwell skylake skylake-avx512 cannonlake icelake-client rocketlake icelake-server cascadelake tigerlake cooperlake sapphirerapids alderlake bonnell atom silvermont slm goldmont goldmont-plus tremont knl knm intel geode k6 k6-2 k6-3 athlon athlon-tbird athlon-4 athlon-xp athlon-mp x86-64 eden-x2 nano nano-1000 nano-2000 nano-3000 nano-x2 eden-x4 nano-x4 k8 k8-sse3 opteron opteron-sse3 athlon64 athlon64-sse3 athlon-fx amdfam10 barcelona bdver1 bdver2 bdver3 bdver4 znver1 znver2 znver3 btver1 btver2 generic native
Ich habe https://developer.arm.com/downloads/-/a ... -downloads in Version 12.3.Rel1 bei mir drauf. Ich habe die Beschreibung so verstanden, dass das Ganze natürlich schon für ARM Kerne ausgelegt ist als cross compiler. Oder bin ich hier auf dem Holzweg?


Den Schwenk auf C++ in den makefiles mache ich später, erstmal muss die C Variante gehen.
Zuletzt geändert von bastelheini am Di 3. Okt 2023, 22:10, insgesamt 1-mal geändert.
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Warum rufst du einen gcc aus mingw auf?
Der kann doch nur x86(-64) und kein arm.
CMAKE kannste drüberstülpen wenn die Grundlagen verstanden wurden, sonst wird was wie festgestellt friemelig :lol:

CMSIS nimmt man für die Bit und Registerdefinitionen der Prozessor Periph und nicht für mehr.
Der STM32 HAL driver ist nochmal was ganz anderes und ich empfehle dir den nicht zu nutzen, sämtliche Herstellertreiber sind pöse verbuggt und schlecht dokumentiert. Der Versuch eine eierlegende Wollmilchsau zu sein sorgt auch nur für Codebloat.

Ich mach dir morgen maln Minimalprojekt mit makefile fertig.
bastelheini
Beiträge: 1663
Registriert: So 11. Aug 2013, 13:55

Re: Der STM32-Thread

Beitrag von bastelheini »

Darum ist der HAL auch auskommentiert, da ich ihn nicht nutzen werde :)

Das mit dem MinGW ist mir noch garnicht aufgefallen. Das erklärt natürlich auch warum er nicht das richtige gcc nimmt. Vermutlich weil es in der Pfadvariable vor der richtige ARM Version steht...dem spüre ich mal nach. Wird wohl aus dem Beispielskript von der Website kommen.

Das mit dem Minimalprojekt wäre nett. Als Projektstruktur habe ich folgendes vorgesehen (möchte ich für uC und PC Programme gleichermaßen nutzen, möglichs auch Progsprachen übergreifend) falls ganz Grobe Fehler drinne sind bitte melden;) :

Code: Alles auswählen

│   .gitignore
│   arm-none-eabi-gcc.cmake
│   CMakeLists.txt
│   
├───bin
│       .gitignore
│       
├───build
│       .gitignore
│       
├───cmake
│       .gitignore
│       
├───doc
│       .gitignore
│       
├───ide
│   │   launch.json
│   │   project_template_stm32_cmake.code-workspace
│   │   settings.json
│   │   tasks.json
│   │   
│   └───templates
│         .gitignore
│          
├───lib
│   │   .gitignore
│   │   
│   └───CMSIS
│       └───Core
│           └───Include
│                   cachel1_armv7.h
│                   cmsis_armcc.h
│                   cmsis_armclang.h
│                   cmsis_armclang_ltm.h
│                   cmsis_compiler.h
│                   cmsis_gcc.h
│                   cmsis_iccarm.h
│                   cmsis_version.h
│                   core_armv81mml.h
│                   core_armv8mbl.h
│                   core_armv8mml.h
│                   core_cm0.h
│                   core_cm0plus.h
│                   core_cm1.h
│                   core_cm23.h
│                   core_cm3.h
│                   core_cm33.h
│                   core_cm35p.h
│                   core_cm4.h
│                   core_cm55.h
│                   core_cm7.h
│                   core_cm85.h
│                   core_sc000.h
│                   core_sc300.h
│                   core_starmc1.h
│                   mpu_armv7.h
│                   mpu_armv8.h
│                   pac_armv81.h
│                   pmu_armv8.h
│                   tz_context.h
│                   
├───src
│   │   main.c
│   │   
│   └───uC_specific
│       └───STM32L0xx
│           │   STM32L011K4TX_FLASH.ld
│           │   STM32L011K4Tx_MemoryMap.xml
│           │   stm32l011xx_Vectors.s
│           │   STM32L0x1_Registers.xml
│           │   STM32L0xx_Flash.icf
│           │   STM32L0xx_Startup.s
│           │   STM32L0xx_Target.js
│           │   
│           ├───Include
│           │       stm32l010x4.h
│           │       stm32l010x6.h
│           │       stm32l010x8.h
│           │       stm32l010xb.h
│           │       stm32l011xx.h
│           │       stm32l021xx.h
│           │       stm32l031xx.h
│           │       stm32l041xx.h
│           │       stm32l051xx.h
│           │       stm32l052xx.h
│           │       stm32l053xx.h
│           │       stm32l062xx.h
│           │       stm32l063xx.h
│           │       stm32l071xx.h
│           │       stm32l072xx.h
│           │       stm32l073xx.h
│           │       stm32l081xx.h
│           │       stm32l082xx.h
│           │       stm32l083xx.h
│           │       stm32l0xx.h
│           │       system_stm32l0xx.h
│           │       
│           └───Source
│                   system_stm32l0xx.c
│                   
├───test
│       .gitignore
│       
└───tools
        .gitignore
        

Code: Alles auswählen

bin          	<- exe, elf, hex, was halt so rausfällt
build	<- was im Bauprozess so rausfällt, object files etc.
cmake	<- dort sollten eigentlich die cmake dateien alle mal rein, muss noch prüfen ob ich die CMakeList.txt auch dort versenken kann
doc		<- Dokuzeugs
example	<- ggf. notwendige Beispieldaten (iwelche Rohdaten zum verarbeiten etc.)
ide		<- VSCode darf sich hier austoben, dort liegen auch Tiletemplates und sowas
lib		<- Fremdbibliotheken, wie CMSIS
src		<- Eigener Code, .cpp und header im gleichen Ordner (wenn mir das iwann mal gegen das Bein läuft kann ich es immer noch anpassen), Targetspezifischen Code hab ich bis jetzt in einen Unterordner versenkt (
test		<- UnitTest (ka ob ich das jemals privat mache)
tools	<- ggf. notwendige Hilfsprogramme	

Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Das sieht schonmal gut aus, ein paar Sachen gibts aber noch.

Das uC_specific/STM32L0xx/Include muss auch nach lib/CMSIS, weil das die Register/Bit Definitionen sind und die sind per Definition :lol: Teil von CMSIS.

Der Src Ordner ist etwas zu grob.
Man baut sich ja noch Peripherietreiber, also ein Ordner "Periph".
Oben drauf kommen dann Devicetreiber, also was hängt am uC (EEPROM zB), das nutzt dann nen SPI/I2C Periph Treiber.
Dann baut man sich ja meistens noch selber nen HAL (welcher den Dvice Treiber und den periph Treiber abstrahiert), also ein HAL Ordner rein.
Da obendrüber kommt dann die eigentliche Applikation.

Ich würd dir noch eine Headerdatei Namens "cmsis_includer.hpp" empfehlen, diese includet dann erst die passende stm32<blah>.h
Sonst musste bei Änderungen das in jedem anderen Header machen -> MEH

Persönlich mag ich keine ganz große Trennung von Header und Source Datei.
Ich will nich erst über zich Ordner traversieren um vom Source zum Header zu kommen.
Daher liegen die bei mir immer direkt zusammen.
Was man trennen kann sind c++ Interface Header, weil die ne übergreifende Vorgabe sind und im eigentlichen Klassenheader eh nochmal gespiegelt ist.
bastelheini
Beiträge: 1663
Registriert: So 11. Aug 2013, 13:55

Re: Der STM32-Thread

Beitrag von bastelheini »

Fritzler hat geschrieben: Di 3. Okt 2023, 22:04
Ich mach dir morgen maln Minimalprojekt mit makefile fertig.
Hey Fritzler, hast du denn schon Zeit dafür gefunden :mrgreen: ?

Die anderen Tipps arbeite ich dann entsprechend ein...
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Es war ja sogar schon fertig, ich wollte heute noch etwas mit deinem Ordnersystem spielen.
Normalerweise legt man das Makefile ins Toplevel, aber ich wollt mal gucken ob ichs auch in den ide/ Ordner packen kann.
Ja, geht, aber wird ein perverses Dateipfad Yoga. Also hab ichs wieder gelassen, weil man dann nicht mehr durchblickt was das Makefile so tut.

Das Makefile in den src/ Odner packen und die .o/.d Dateien „nach oben schieben“ geht auch (wenn der lib/ Ordner nicht wäre).
Aber nach oben und wieder runter gucken, um die Sourcen zu holen und dann nochmal nach oben zu gehen zum ablegen zerschießt einem erstmal die automatische Abhängigkeitsauflösung und man muss dann Hand anlegen.
Das ist Dateipfadzusammenbautechnisch nicht s einfach machbar, da kommt dann sowas raus:
arm-none-eabi-g++ -MMD -MP -o ../build/../lib/modbus/modbus_discrete.o -c ../lib/modbus/modbus_discrete.cpp
Genauer:
../build/../lib/modbus/modbus_discrete.o
Er geht also erstmal in einen Ordner hoch, in den anderen Ordner und springt dann gleich wieder raus.

Wie zu sehen ist wurde das Projekt auch etwas aufgeblasen um Sourcen im lib/ Ordner zu haben.
Das ist mein Wasserstandssensor über nen Drucksensor an Modbus mit Sleepmodes.

Ab jetzt am Besten den Anhang runterladen und die später erklärten Dateien schonmal in einem Editor der Wahl auf einem zweiten Bildschirm öffnen.

Zur Übersichtlichkeit habe ich es mal in mehrere Posts aufgeteilt.
Dateianhänge
STM32Min_L010.zip
(162.82 KiB) 13-mal heruntergeladen
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Makefile

Z2: Hier wird der Name, ohne Dateiendung, der Ausgangsdateien definiert.

Z3-6: Das sind die wichtigsten Ordner des Ordnersystem von wo was kommt und wohin was hinsoll.

Z7: Das Linkerscript für den Linker, dazu später mehr.

Z9: Der Prefix des Compilers, hier eben der ARM Compiler

Z10: „CXXFLAGS“ die Compiler Flags für C++ Dateien.
Da es keine Exceptions und RTTI geben soll, sind diese deaktiviert.

Z12-16: Die CFLAGS (gelten zusätzlich auch für C++)
Hier steht, dass wir ALLE möglichen Warnings haben wollen, dass wir einen cortex-m0 haben (der nur thumb code kann).
Dazu: „-lm -lc“ das baut die Standard c lib und Mathelib ein.
Dann noch; „-specs=nosys.specs -nostartfiles“ wir haben kein OS, sondern laufen naked.
Das „-Wl,-Map=$(TARGETDIR)/$(TARGET).map“ erzeugt später nach dem linken ein Mapfile, in dem können wir gucken was denn jetzt wie viel Speicher frisst.
Schlussendlich „-mfloat-abi=soft“ cortex-m0 hat keine FPU, also müssen floats in Software gerechnet werden.

Z19: Linker Flags: „--specs=nano.specs“ wir wollen nicht die fette libc, sondern die libnano.
Die libc ist zb Prozess/Thread sicher mit zusätzlichen reentrant Variablen, was wir hier in einem single threaded Programm ohne OS mal so garnicht brauchen. Also raus mit dem Bloat!

Z25: Die angabe möglicher externe libs, die schon compiled sind.

Z28-30: zusätzliche Compilerflags wenn man debuggen will oder nicht.
Beim debuggen brauch der Debugger zB die DWARF Informationen in der elf Datei.
Dazu lässt sich optimierter Code (-O2) nicht debuggen, aber O0 wäre viel zu fett, daher gibts beim GCC/GDB (Segger kanns auch) eine Stufe die optimiert, aber noch (bedingt) debugbar bleibt (-Og).

Z33-34: Hier kommen die Ordner/Pfade zu den Headerdateien hin, welche man icht mit eiem risen langen Pfad includieren möchte, sondern kurz und knackig.

Z38: Pfad zum Stlink, falls man auch per „make programm“ aufs Target schreiben möchte.

Z44-49: Hier werden automatisch die C++, C und asm Dateien gesucht.
Das geht hier im Beispiel auf bis zu 4 Ordnerebenen runter, das Muster sollte klar sein,w enns mal mehr wird.
Alternativ kann man auch jede Datei einzeln angeben, aber neeee…

Z52: Alle gefundenen Dateien zusammenfassen und zu dem gewünschten .o (objectfiles) umbenennen.

Z54: Die objectfiles sollen in einen anderen Ordner, also müssen wir diesen als Prefix ranhexen.

Z56: Damit Änderungen im Header für ein recompile der includierenden Sourcen sorgt brauchen wir .d Dateien, diese kommen auch in den Buildordner und eine pro .o Datei, also nur die Endung ändern.

Z58-62: Die Flageinfügung für Debug oder nicht.

Z65-75: Das sind die Regeln um die objectfiles aus den Sourcen zu compilen.
Eine Regel Pro Dateiendung, damit verschiedene Flags übergeben werden können.

Z73: „$(BUILDDIR)/%.o: %.cpp“
Nimm den Dateipfad zu build/ aus den Sourcen wieder temporär raus, sonst werden die Abhängigkeiten nicht gefunden, aber pack diese trotzdem nach build/
„%.o: %.cpp“ sagt einfach nur: Regel für objectfiles aus cpp erzeugen.

Z74: Erstellt den Ordner in den ein objectfile kommt, sonst würde es nicht gespeichert, das @ sorgt dafür, dass es nicht auf der Konsole ausgegeben wird und diese zuspammt.

Z75: Hier wird jetzt endlich compiled!
„-o $@“ outputs hierhin packen, das $@ ist ein Platzhalter für eine Datei in $(OBJS)
„-c $<“ die Suche nach der passenden Sourcedatei, automatische Auflösung
Beispiel Konsolenausgabe: „arm-none-eabi-g++ -MMD -MP -o build/src/main.o -c src/main.c“

Z78: Endlich die Regel um alles zu bauen ;)
Das PHONY dadrüber sagt dem make nur, dass wir hier keine Datei mit meinen, sonst würde das make versuchen eine „all“ Datei zu finden.
Das „all: $(OBJS)“ sagt erstmal, dass als allererstes die objectfiles erstellt werden müssen mit vordefinierten Regeln. Deshalb stehen die obendrüber, kennt man ja aus C.
Danach erfolgen weitere Aufrufe was erledigt werden muss.

Z79: Aufruf des Linkers nachdem alle objectfiles fertig sind.

Z80: Der Linker spuckt eine elf Datei aus, aber vllt will man ja ein binary.
Hier könnt man auch auf hex umbauen oder zusätzlich hinzufügen.

Z81: Listingdatei, enthält c Code und den daraus resultierenden asm.
Ab und zu ganz interessant, braucht aber ewig. Daher nur Einkommentieren wenn gewünscht.

Z82: Nur asm aus dem elf menschenlesbar in eine Datei packen.
Ab und zu ganz interessant, braucht aber ewig. Daher nur Einkommentieren wenn gewünscht.

Z83: Falls der Debugger eine extra (Debug)symbol Datei braucht.

Z84: Man will ja wissen wie Groß das Ganze grade geworden ist.

Z91-92: Regel zum flashen, benötigt die abgeschlossene Regel „all“ und ruft dann den stlink cli auf.

Z96-100: Regel zum Aufräumen, löschen alle Dateien in build/ und bin/
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Linkerscript

Hier haben viele Angst vor, aber am Ende schiebt man doch nur Speicherblöcke durch die Gegend.

Was für Speicherblöcke (Sections) gibts denn?
Erstmal die vordefinierten:
.text: Programmcode
.rodata: Konstanten (const uint8_t keks = 42U;)
.data: Vorinitialisierte Variablen, die sich im Laufe des Programmablaufs aber ändern (uint8_t keks = 42U;).
.bss: wie .data, aber mit 0 Initialisiert, diese brauchen damit keinen zusätzlichen Speicher für die Inhaltsdefinition, sondern werden zum Startup ausgenullt, dazu später mehr.
.COMMON: Variablen ohne Zuweisung (uint8_t kekse). Keine 0 keine andere Zahl. Sollte aber aus Sicherheitsgründen auch ausgenullt werden.

Dann baut man sich noch eigene Bereiche wie „.text.vectors“ um diese gesondert im Linkerscript behandeln zu können.
Diese können im C Code beim GCC mit „__attribute__ ((section ("<sectName>")))“ vor einer Funktion angegeben werden.
Oder in asm als .section <name> vor dem eigentlichen Code.

Im Linkerscript gibt es den Punkt aka Pointer.
Dieser stellt die momentane Adresse dar.
Diesem Punkt kann man was zuweisen (. = 0x08000000;), aber auch auslesen und in einem Label speichern (_flash_start = .;).
Diese Labels kann man dann später im Code frei nutzen:
extern void (*_flash_start []) (void) __attribute__((weak));

Nun zur eigentlichen Datei:
(src\uC_specific\STM32L0xx\system\linker.lds)

Z18: Dem Linker erklären welche Funktion der Eintrittspunkt des Programms ist.
Nein, das ist nicht main, es braucht ja noch etwas Startup.

Z19ff: Ab hier wird dem Linker vorgeschrieben wie die Speicherblöcke (Sections) angeordnet werden sollen.

Z22: Dem Punkt den Anfang des Flash zuweisen.
Davor könne wir nichts hinpacken, da ist ja nichts.

Z23: Die Zuweisung direkt für etwas im Code herauslesbar gestalten.
Das brauchts nicht unbedingt, das war hier für den Bootloaderteil und ich habs zur Anschauung drinne gelassen.

Z26-30: Es gibt eine Section, die global .text heißen wird.
In diese Section kommen, die oben genannten, Sections .text sowie .text.vectors.
Die Reihenfolge wird auch eingehalten, also .text.vectors kommt zum Flash Anfang, was wichtig ist sonst stimmen die Interruptvektoren nicht. (Offset 0 ist zB der Init Stackpointer und Offset 4 der Reset Vektor!)
Die Sternchen sind Platzhalter für alles Mögliche, also „.text*“ kann auch .text.meow beinhalten.
Was meine ich mit „global .text“? So taucht die Section dann zB im Objectdump auf, ein „.text.vectors“ ist dort dann nicht mehr zu sehen.
Manchmal baut der GCC selber SubSections, daher muss man das so schreiben, sonst gibt das die lustigsten Fehler. Die Klammern drumrum mit dem Sternchen sagen, dass alle so gefunden SubSections auch nochmal einen, wie auch immer, heißenden Prefix haben können.
Damit wird dann auch wirklich alles gefunden!

Z33: Bitte mal den Pointer auf eine 4 Byte Adresse alignen. Sonst könnten alle nachfolgenden Konstanten um 2 Byte verrutscht sein. Der Code ist in 2Byte langem thumb, kann also an einer 2 Byte Adresse aufhören.
Wenn jemand doubles (8 Bytes) im Code nutzen möchte, dann sollte jedesmal auf 8 Bytes aligned werden.

Z34-35: Hier passiert nichts spezielles, die Konstanten liegen im Flash und werden auch von da gelesen.

Z39-44: Statische C++ Konstruktoren müssen beim Startup aufgerufen werden, daher ist der GCC so freundlich uns ein Array aus Funktionspointern zu geben.
Dieses muss natürlich in den Flash und es werden Labels für den Zugriff gebraucht, dazu später mehr.

Z40: Wieder alignment, Variablen (.rodata) können ja nur 1 Byte haben und somit auch an ungeraden Adressen aufhören und Funktionsadressen sind 4 Byte.

Z47: Weil wirs können!

Z48-49: Hier wird es etwas komplizierter. Vorinitialisierten Variablen (.data) enthalten bereits Daten, aber diese sind veränderbar. Daher muss Platz im Flash vorgehalten werden für die Initwerte.
Daher gibts das Label ab dem die Initwete starten dürfen und ein Label wo diese Enden. (Platzhalter).

Z52: Label zum Prüfen ob das Programm in den Flash passt.

Z57: Der SRAM startet.

Z60-65: Die vorinitialisierten Variablen (.data) werden hierher gelinkt, aber die Initwerte werden im Flash abgelegt. Dafür sorgt das „AT( _rom_data_start )“, das Label wurde ja vorher im Flashbereich definiert.

Z67-75: Hier werden alle auszunullenden Variablen gelinkt, aus Sicherheitsgründen kommt hier auch COMMON hin.
Der STM32 HAL ist zB so intelligent globale structs NICHT mit 0 zu initen, aber direkt nach einem structVar.locked != 0 zu fragen (AFFEN!!!)

Z78-79: „end“ ist ein vordefiniertes Symbol für die libc ab wann der Heap starten darf.
Auch wenn malloc und co nicht genutzt werden muss das definiert werden.

Z82: Initialer Stack für die Interruptvektoren (Cortex-M spezifisch) am ende des RAM.

Z86-87: Checken ob alles in den Flash und RAM passt.

Leider sind Linkerscripte sehr Magic Number lastig. Aber mit einem kleinen Trick lässt sich der C Präprozessor nutzen.
Einfach die Datei nach *.lds.S umbenennen, dann wird diese durch den Assembler gejagt und #defines werden aufgelöst. Dann lassen sich diese iwo unter einem schönen Namen speichern.
Benutzeravatar
Fritzler
Beiträge: 12578
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Der STM32-Thread

Beitrag von Fritzler »

Startup

Wie im Linkerscript kennen gelernt gibt es zu kopierende Daten und Daten welche ausgenullt werden müssen. Dafür wurden viele schöne Labels definiert.
Zum Startup muss dies nun durchgeführt werden.

Datei:
src\uC_specific\STM32L0xx\system\startup_stm32l010x8.S

Z5-54: Das sind die (Interrupt)Vektoren des Cortex-M0.
Die Anzahl ist uC spezifisch, das kopiert man sich daher einfach aus dem CMSIS und gut ist.

Z5: Wie angesprochen eine Zuweisung in welche Section dieser Code muss.

Z7: Laut Cortex-M Spezifikation muss hier der Stackpointer stehen, das ist hier „_estack“ aus dem Linkerscript.

Z8: Laut Cortex-M Spezifikation muss hier der Resetvektor stehen, ein Funktionspointer.

Z56-77: Der Startup Code.

Z56: Die Section „zurück“ die .section Angabe gilt ab dem Start bis zum Ende.

Z61-64: Die vorinitialisierten Variablen vom Flash in den RAM kopieren mit memcpy.
Dazu nach ARM calling convention die Übergabeparameter in die Register speichern und dann die Funktion aufrufen.
Die Labels sollten aus dem Linkerscript bekannt sein ;)

Z66-70: Fast das Gleiche nochmal, nur eben mit memset das Ausnullen der .bss Variablen.

Z73: Aufrufen der statischen C++ Konstruktoren, das ist bereits C Code, alle Variablen sind ja nun initialisiert und der Stackpointer steht.
Datei: \src\uC_specific\STM32L0xx\system\cpp_init_caller.c
Diese zieht sich nur die Labels _init_array_start_ und _init_array_end_ aus dem Linkerscript. Dann werden in eienr for Schleife die Funktionspointer aufgerufen, fertig.

Z76: Ab ins Hauptprogramm!

Z82ff: Default IRQ Handler falls nicht im C Code überschrieben.
Ganz wichtig: extern „C“ for die C Funktionen schreiben mit einem das C++ name manfling nicht beim Linken um die Ohren fliegt!
(extern "C" void TIM2_IRQHandler(void){})


Noch was zum Schluss:
In C++ gibt es virtual functions und manche sind „pure virtual functions“.
Da hat wer das Interface nicht komplett implementiert, aber die Funktion trotzdem aufgerufen.
Was soll der Compiler jetz aufrufen?
Das klärt sich in src\uC_specific\STM32L0xx\system\pure_virtual_trap.cpp
ARM Exception Handling ist nochmal ein ganz anderes Thema und ist beim M0 leider ganz anders als bei M3/M4/M7. (Das hat nichts mit den C++ Exceptions zu tun!)
bastelheini
Beiträge: 1663
Registriert: So 11. Aug 2013, 13:55

Re: Der STM32-Thread

Beitrag von bastelheini »

Vielen Dank für die ausführlichen und sicher auch zeitfressenden Beispiele und die dazugehörige Erklärung. Ich werde das Ganze die Tage nach und nach durcharbeiten und mich bei weiteren Fragen melden :)
Jannyboy
Beiträge: 1406
Registriert: So 11. Aug 2013, 14:49
Wohnort: Kreis Augsburg

Re: Der STM32-Thread

Beitrag von Jannyboy »

Schöne Erklärungen magst du die mal im Wiki konservieren. Die sind sogar besser als bei den offiziellen Appnotes.

Grüße Jan
Ollie Garch
Beiträge: 78
Registriert: Di 27. Okt 2020, 01:59

Re: Der STM32-Thread

Beitrag von Ollie Garch »

Ich bin auch ganz Aug' und Ohr!

Muss nur noch (tm) ein anderes Projekt zu Ende bringen (im Guten oder im Bösen), dann geht es dem STM32 auf die Pelle. STM32CubeMX ist von zwei Rechnern (Win10 und Linux) runter geflogen, nachdem (a) der Kram die Platten voll gemüllt hat (abertausende von Dateien, und dort, wo man sie nicht haben will) und (b) nix Gutes drüber zu lesen war, hier und anderswo. Dann ist das Developer-Board wieder in die unterste Schublade gewandert.
Antworten