Hallo allerseits,
vor kurzem habe ich ein Bastlerprojekt mit einem STM32F7-Nucleo
angefangen und habe jetzt gewisse grundsätzliche Schwierigkeiten mit der
HAL. Das erste Problem war, dass es mir beim Codegenerieren meinen
eigenen Code ohne Vorwarnung gelöscht hat. Gut, anscheinend darf man nur
in den vorgegbenen /* USER CODE */ -Blöcken schreiben. Aber auch das
bringt Probleme mit sich, bspw. verwende ich die UART und den
Netzwerkanschluss. Da die Initialisierung der Netzwerkperipherie den
Verbindungsaufbau mit IP-Vergabe mittels DHCP beinhaltet, dauert das ein
paar Sekunden. Also möchte is sofort nach Initialisierung der UART den
Status an den PC senden und nicht erst auf das LAN warten. Einen
USER-CODE-Abschnitt gibt es aber nicht zwischen beiden Inits. Mein
Workaround war einfach den UART doppelt zu initialisieren, also vorher
im User-Code selber MX_USART3_UART_Init(); aufzurufen. Das Vorgehen
scheint mir aber nicht ideal.
Das nächste Problem ist, dass das Handle für den UART in main.c
definiert ist. Wie kann ich das in anderen Dateien verwenden, ohne das
Handle vorher in eine globale Variable zu kopieren, was mir wieder eher
wie ein Hack vorkommt?
Mir scheint das alles brutal unflexibel, offensichtlich mache ich was
falsch. Andererseits ist die main.c schon ohne mein Zutun recht
aufgebläht, was m.E. schlechter Stil ist.
Wie ist also das richtige Vorgehen im Umgang mit der HAL? Vielleicht
gibt es ja ein paar Tricks, die man verstanden haben muss. Wo legt man
seinen eigenen Code am Besten an, welche Dateien und Bereiche lässt man
lieber unangetastet?
Vielen Dank!
Maxe schrieb:> Wie ist also das richtige Vorgehen im Umgang mit der HAL?
Man nimmt sie bestenfalls zur Initialisierung der diversen PLLs und IO
und schreibt seine eigenen Funktionen in separate Dateien.
Schnell noch Stollen, Lebkuchen, Spekulatius und Glühwein besorgen ;-)
FreeRTOS verwenden, das wird im CubeMX ja per Click & Play angeboten.
Den Ethernet Code dann in eine Task verlagern.
Oder ein OS verwenden das nicht dieses fürchterliche 'hier darst du
schreiben' und 'hier nicht' verwendet.
git hilft auch, nur nicht vergessen vor dem Code generieren einen Commit
zu machen.
Maxe schrieb:> Das nächste Problem ist, dass das Handle für den UART in main.c> definiert ist. Wie kann ich das in anderen Dateien verwenden, ohne das> Handle vorher in eine globale Variable zu kopieren
Kannst ja im main.h einfach eine Vorwärtsdeklaration mit "extern ..."
auf das Handle anlegen und dann in deinen anderen Dateien das main.h
includen.
Hat mit der HAL nichts zu tun, sondern ist eine normale C
Programmiertechnik.
J. S. schrieb:> git hilft auch, nur nicht vergessen vor dem Code generieren einen Commit> zu machen.
Man kann in CubeMX einstellen, dass es vor der Codegenerierung
automatisch ein Backup erstellt; diese Option würde ich immer
aktivieren.
Also wenn man sich konsequent daran hält, den eigenen Code in die
vorgesehenen Blöcke (User Code Begin, User Code End) zu platzieren, dann
gibts in der Regel überhaupt keine Probleme mit überschriebenem Code.
und man kann den Code für die Devices in eigene Dateien legen lassen,
dann werden die includes mit den externals auch automatisch generiert.
das 1. Häkchen in 'Generated files' in dem Screenshot.
@johnny
Das sind gute Tipps, und ohne dein Screenshot wäre es schwierig zu
finden gewesen. Danke!
Mit Extern lässt sich auch gleich noch ein anderes Problem lösen, auf
das ich gestoßen bin :)
@jojos
Ich wollte es nicht noch komplizierter machen und mit einem RTOS eine
weitere 'Abstraktion' einführen.
@m.n.
Das mit den eigenen Dateien mach ich auch so wo möglich, nur braucht man
ja auch irgendwo die Anbindung an den Rest.
Die CubeMX Init Routinen bereiten doch nur die Hardware vor. Ein Init
mit DHCP usw machen die doch gar nicht. Von daher sollet es kein Problem
sein, seine eigenen Applications Init Routinen anderweitig zu verwursten
und auszulagern
Maxe schrieb:> Das mit den eigenen Dateien mach ich auch so wo möglich, nur braucht man> ja auch irgendwo die Anbindung an den Rest.
Rufe nach der Initialisierung Dein 'hauptprogramm()' auf und ignoriere
HAL.
Die STM32 lassen sich bestens auch auf Registerebene programmieren.
Damit sind dann alle Probleme mit HAL abgehakt ;-)
A. B. schrieb:> Die CubeMX Init Routinen bereiten doch nur die Hardware vor. Ein Init> mit DHCP usw machen die doch gar nicht. Von daher sollet es kein Problem> sein, seine eigenen Applications Init Routinen anderweitig zu verwursten> und auszulagern
In meim Testprojekt sieht das wie folgt aus, in MX_LWIP_Init() steckt
die komplette Initialisierung des Ethernet inklusive
Hardwareinitialisierung (netif) als auch DHCP drin. Aber ja, ich versuch
jetzt nur das Nötigste in die Main reinzupacken.
1
/* Initialize all configured peripherals */
2
MX_GPIO_Init();
3
MX_USART3_UART_Init();
4
MX_LWIP_Init();
5
/* USER CODE BEGIN 2 */
6
/* USER CODE END 2 */
m.n. schrieb:> Die STM32 lassen sich bestens auch auf Registerebene programmieren.> Damit sind dann alle Probleme mit HAL abgehakt ;-)
Mir ging es hauptsächlich darum LwIP zum Laufen zu bekommen. Ich versuch
das jetzt mal zu entheddern um aus dem Codegeneratorenzeug rauszukommen.
Ganz unabhängig von Cube HAL bietet sich Git an, um Änderungen zur
protokollieren. Nach der Installation von Git gebe im Projektverzeichnis
folgendes ein:
1
git init
2
git add *
3
git commit -am "Dein Kommentar"
Es ist wirklich so einfach.
Später kannst du den commit Befehl wiederholen, um weitere
Schnappschüsse deiner Dateien zu erstellen. Mit Git kannst du
anschließend alle Änderungen nachvollziehen und ggf. rückgängig machen.
Weitere Git Kommandos, siehe http://stefanfrings.de/git/index.html
Die Schnappschüsse werden in dem Unterverzeichnis ".git" gespeichert,
welches der init Befehl angelegt hat. Wenn du das alles wieder los
werden willst, lösche einfach dieses Verzeichnis.
Natürlich hat deine IDE dafür auch Funktionen in ihrer GUI. Die werden
aber erst nach dem init Befehl benutzbar.
m.n. schrieb:> Die STM32 lassen sich bestens auch auf Registerebene programmieren.> Damit sind dann alle Probleme mit HAL abgehakt ;-)
Tja. Seit wievielen Jahren gibt es dieses Zeug von ST nun schon? Und
immer noch lassen sich die Leute da drannageln. Und wenn sie mal etwas
machen wollen, was von den Konstrukteuren von HAL, CUBE und so nicht
vorgesehen ist, dann stehen sie hilflos da.
Ein jeder hätte sich im Verlaufe der letzten Jahre ein Portfolio von
Treibern, eigener Middleware und Konfigurationsfunktionen machen/zulegen
können und wäre damit in der Lage, ohne viel Aufwand seine Firmware so
zu machen, wie er sie haben will. Aber das hätte anfangs etwas mehr
Arbeit gemacht und die Faulheit hat wie üblich gesiegt.
W.S.
W.S. schrieb:> Tja. Seit wievielen Jahren gibt es dieses Zeug von ST nun schon? Und> immer noch lassen sich die Leute da drannageln. Und wenn sie mal etwas> machen wollen, was von den Konstrukteuren von HAL, CUBE und so nicht> vorgesehen ist, dann stehen sie hilflos da.
Was dann eher daran liegt, daß sie durch die HAL "noch" nicht wirklich
durchblicken.
Die ST-HAL ist nun mal nix, was man "mal eben" an einem Wochenende
durchschaut, aber die Dokumentation kann sich inzw. auch sehen lassen.
W.S. schrieb:> Ein jeder hätte sich im Verlaufe der letzten Jahre ein Portfolio von> Treibern, eigener Middleware und Konfigurationsfunktionen machen/zulegen> können
Bla bla bla...
Soviel Middleware, Treiber etc, wie inzw. zum Cube-Ecosystem gehören
kannst du in deinem ganzen Leben nicht schreiben.
Klar hakts da hier und da auch mal, aber in >99% aller Fälle in denen es
nicht funktioniert sitzt das Problem 50cm vor dem Monitor.
Und wenn ich die Qualität deines Code mit dem der HAL vergleiche, stellt
sich mir die Frage ohnehin nicht mehr.