Forum: Compiler & IDEs STM32: von HAL nach LL umsteigen


von Ralf (Gast)


Lesenswert?

Hallo,

ich möchte einen STM32L011 (8kB Flash / 2kB SRAM) programmieren. Der 
Einfachheit halber verwende ich Atollic TrueStudio und CubeMX.

Wenn die HAL verwendet wird, bleibt ja nicht mehr wirklich Platz für die 
eigentliche Applikation übrig - aktuell sind nur mit Initialisierung von 
GPIOs, Timer 2 und USART2 schon 5-6kB für den Release-Build weg. Der 
Debug-Build sprengt die 8kB, wenn man nicht weitere Einstellungen 
vornimmt.

Versuchsweise habe ich auch MDK5 von Keil installiert, dafür gibt's ja 
eine kostenfreie Version für STM32x0yy Devices - nur unterstützt die 
wohl keine LinkTimeOptimization, von der ich mir erhofft hatte, dass 
dann weniger Speicher verbraten wird. Da liegt der Verbrauch dann bei 
~7kB.

Aktiviere ich im TrueStudio die LTO, dann passt es mit hängen und würgen 
rein, aber dann kann ich nicht mehr richtig debuggen (trotz 
Optimierungslevel -Og).

Dass die HAL eher was für die dickeren und schnelleren Boliden ist, ist 
mir klar - also bleibt wohl nur der Umstieg auf die LowLevel-Treiber.

Hat jemand einen Tip, wie ich da am besten vorgehen könnte? Vom Ansatz 
her hätt ich mir jetzt jeweils eine Peripherie aus HAL-Sicht angeschaut, 
und dann versucht das, was ich brauche per LL nachzubilden.

Gibt es sonst noch was, was ich bei LL beachten sollte? Also 
beispielsweise, was macht die HAL automatisch, was die LL nicht macht? 
=> Die Aktivierung des SysTick-Timers scheint so ein Kandidat zu sein...

Grüße

von Sebastian E. (sbe_15)


Lesenswert?

IIRC kann CubeMX mittlerweile Init-Code mit LL-Treibern generieren.
Dazu helfen die Examples (z.T. auch von anderen Modellen, wenn für 
deinen L011 keins vorhanden ist. Ging mir mit meinem F091 so, da halfen 
dann idR die F072 Examples). Ansonten schadet auch ein Blick in die 
HAL-Sourcen nicht.

von Bimbo. (Gast)


Lesenswert?

Download mal das Reference Manual.

Schaue dir zuerst die GPIOs an - nur die Registerbeschreibung. Die sind 
äußerst simpel, wie bei vielen anderen Mikrocontrollern auch. Ein 
Register pro Port für Lesen, Schreiben, Modus (analog, Input, Output, 
Alternate Funktion), eines für die Pullups etc.
Am besten schreibst du dir ein Makro, habe ich auch gemacht, das sieht 
dann so aus:
1
#define PINCONFIG(P_PORT, P_PIN, P_MODE, P_TYPE, P_PULLUP, P_AFUNC) [...]

Dann schau dir das RCC Register an. Dort kannst du die Clocks einstellen 
- ist viel einfacher als befürchtet. Ein Bit setzen - HSE ist aktiviert. 
Dann warten bis ein weiteres Bit gesetzt - dann ist die HSE bereit. Dann 
die PLL konfigurieren und aktivieren. So durchschlängeln. Das sind ca. 
10 Zeilen bei mir im Schntt, um die Clock tree zu konfigurieren.

Generell gilt: nach einem Reset sind die meisten Funktionen deaktiviert. 
Das heißt, wenn du z.B. bei einem Timer mit dem ARR Register sagst, bis 
welchen Wert gezählt werden soll, im RCC den Clock für den Timer 
aktivierst (zu jeder Peripherie muss der Clock durchreicht werden - ein 
Bit setzen) und den Timer aktivierst, hast einen ganz simplen Timer, der 
bis zu einem bestmmten Wert zählt. Das wars. Wenn du mehr brauchst 
kannst du es aktivieren, ansonsten belasse es dabei. Einfach mal die 
Register durchgehen und schauen, was man alles schalten und walten kann.

Nimm am Anfang natürlich die Startup.s von Atollic, genauso das 
Linkerscript.

Wenn du RCC, GPIO, Timer und NVIC durchgegangen bist, hast du das 
Grundgerüst geschafft. Achtung, der NVIC tseht im Programming manual 
beschrieben - warum auch immer.

Letztendlich finde ich, dass die Registerebene nicht anders ist, als bei 
z.B. einem Atmega. Nur - wenn man möchte - mit komplexeren 
Einstellmöglichkeiten und alles halt in 32bit.

von CubeMX Hater (Gast)


Angehängte Dateien:

Lesenswert?

Bir vor wenigen Wochen wusste ich es nicht bis ich
hier darauf hingewiesen wurde dass CubeMX auch LL Code
generieren kann.

Ob das schon auch bis zu dir durchgedrungen ist?
Vielleicht geht da was mit einsparen ...

von Ralf (Gast)


Lesenswert?

Hallo sbe_15, Bimbo und CubeMX Hater,

danke für eure Antworten.

@sbe_15:
die Beispiele werd ich mal durchwühlen, das mit dem 072 ist ein guter 
Tipp.

@Bimbo:
Das nimmt mir doch schon mal ein wenig die Sorgen :) Im Prinzip ist es 
doch eigentlich "zu Fuß die Bits konfigurieren", oder? Ich muß mir noch 
klar werden, was mir davon die LL abnimmt bzw. ob es dann nicht auch 
ganz ohne geht.
Soweit ich bisher sehen konnte, werden zumindest auch die 
Interrupthandler installiert, aber ganz ohne Funktion - besser als nix.
Das Bitbeissen dürfte auch kein Problem sein - hab auf nem 8052 die 
Ausbildung gemacht, da waren Bits an der Tagesordnung :) Nur nimmt einem 
die HAL das alles ab und ich könnte das Projekt dann zügiger 
abhandeln... Da ich aber an den F011 gebunden bin, dürfte das mal wieder 
eine gute Übung sein.

@CubeMX Hater:
Ja, wenn ich alles auf LL setze, komme ich bei etwa 2-3kB raus. Das wär 
okay. Nur weiß ich eben nicht, was das an Mehraufwand bedeutet, da man 
dann doch einiges zu Fuß machen muss. Bimbo konnte mir in der Hinsicht 
wie gesagt etwas die Sorgen nehmen, das Konvertieren von HAL nach LL 
scheint nicht ohne Aufwand zu gehen, ist aber auch nicht unlösbar.

Grüße

von Bimbo. (Gast)


Lesenswert?

Ralf schrieb:
> Soweit ich bisher sehen konnte, werden zumindest auch die
> Interrupthandler installiert, aber ganz ohne Funktion - besser als nix.

Wenn du ein Projekt in Atollic erstellst, wird auch eine .s Startup 
Datei erzeugt, in dem die Interrupts alle definiert sind. In deinem 
Programm rufst du den Interrupt nur noch auf durch (Beispiel Timer6 
Überlauf):
1
void TIM6_IRQHandler(){
2
  TIM6->SR &= ~TIM_SR_UIF;
3
}

Musst nur Bedenken:
a) Clock für Timer aktivieren - sonst geht nichts ;)!
b) Interrupt im Timer freigeben für z.B. Überlauf (hat mehrere 
Interruptmöglichkeiten)
c) Im NVIC den Interrupt vom Timer6 priorisieren und freigeben
d) Im void TIM6_IRQHandler(){} werden sämtliche Interrupts vom Timer6 
abgearbeitet. Brauchst also eine If-Abfrage, welcher Interrupt vorliegt 
und musst oftmals das Flag per Software zurücksetzen.

von Ralf (Gast)


Lesenswert?

Hallo Bimbo,

das ist schon mal eine gute Orientierung, besten Dank.

Speziell für Punkt d), das hab ich innerhalb der HAL auch so gesehen, so 
werden dann die verschiedenen Callbacks aufgerufen. Dann kann ich mich 
glaube ich wirklich an der HAL orientieren und Stück für Stück umbauen.

Besten Dank, werd ich so mal in Angriff nehmen.

Gruß

von Zweig (Gast)


Lesenswert?

Ralf schrieb:
> ich möchte einen STM32L011 (8kB Flash / 2kB SRAM) programmieren

schon mal dran gedacht das es auch größere Bausteine gibt?

Je nach Stuckzahl ist die Frage wo man das Geld/Zeit verbuddelt.

von c++ (Gast)


Lesenswert?

Truestudio bietet einen Build Analyzer. Doppelklick auf die .elf und der 
zeigt an wo dein Flash verbraten wird.

Als Release build verstehe ich mal "-Os -flto".
Da bekomme ich z.B. 324Bytes für HAL_GPIO_Init()

von W.S. (Gast)


Lesenswert?

Ralf schrieb:
> ich möchte einen STM32L011 (8kB Flash / 2kB SRAM) programmieren. Der
> Einfachheit halber verwende ich Atollic TrueStudio und CubeMX.

Cube bei so kleinen Ressourcen? Das ist ein schlimmer Fehler.

Wenn du nur 8K an Flash hast, dann lies dir das RefMan und ort das 
Kapitel für das Einstellen der Pin-Funktionalität gut durch, bis du es 
vollkommen verstanden hast. Oft ist das Ganze zweiteilig: erstens die 
Basis-Pinfunktionen, also ob du da einen GPIO oder nen Counter oder I2C 
oder so dran haben willst und zweitens im Falle von GPIO, ob der in, 
out, opendrain usw sein soll.

Dann überlege dir, wie du all die gewünschten Pin-Funktionalitäten in 
einer möglichst sparsamen Tabelle formulieren kannst, so daß du mit 
einer möglichst einfachen Schleife beim Initialisieren anhand der 
Tabelle alle deine Pins richtig konfigurieren kannst. Diese Übung dient 
nämlich dazu, genau folgendes zu vermeiden wie der Teufel das 
Weihwasser:

Bimbo. schrieb:
> #define PINCONFIG(P_PORT, P_PIN, P_MODE, P_TYPE, P_PULLUP, P_AFUNC)
> [...]

Und anschließend sieh zu, daß du dir deine eigenen HW-Treiber schreibst, 
die du dann eben so schreibst, daß sie möglichst sparsam mit den 
Ressourcen umgehen. Das heißt auch, sowas wie printf tunlichst zu 
vermeiden.

Ich geb mal nen Vergleich: Bei dem Minimalsystem, das ich hier schon mal 
für die STM32F103 gepostet habe, braucht die Firmware 11508 Bytes und 
bietet dafür: Konfiguration, gepufferte UART(s), USB-VCP, 
Konvertierungen hex int float In und Out, Kommandoprogramm, 
Event-System, Systemuhr. OK, den Löwenanteil macht da der USB aus.

W.S.

von Bimbo. (Gast)


Lesenswert?

W.S. schrieb:
> Diese Übung dient
> nämlich dazu, genau folgendes zu vermeiden wie der Teufel das
> Weihwasser:

Harte Worte!

von Stefan F. (Gast)


Lesenswert?

Guck mal auf http://stefanfrings.de/stm32 da sind kommentierte 
Codeschnipsel für die ersten Versuche ohne HAL.

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.