Forum: Mikrocontroller und Digitale Elektronik [STM32] HAL vs libopencm vs 'von Hand'


von Lukas K. (carrotindustries)


Lesenswert?

Hallo Zusammen,

In den Vorüberlegungen für ein vmtl. doch recht umfangreich werdendes 
Projekt mit nem STM32 hat sich mir die Frage aufgeworfen, ob man besser 
die HAL (aus dem STM32Cube-Bündel) oder libopencm verwendet oder direkt 
in den Registern rumstochert.

HAL
 + Umfassende Unterstützung aller Peripherieeinheiten
 - gewöhnungsbedürftige API (wenn man POSIX gewöhnt ist)
1
GPIO_InitTypeDef GPIO_InitStruct;
2
GPIO_InitStruct.Pin = GPIO_PIN_0;
3
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
4
GPIO_InitStruct.Pull = GPIO_NOPULL;
5
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 - Fragwürdige Lizenz im Zusammenhang mit OSS-Projekten (auf einigen
   Seiten von ST steht was von wegen BSD, in den Quellen selber nicht)
 - Nur mit dem CubeMX-Codegenerator gut zu verwenden
 - Abstraktion, ein Problem mehr (Feature im Datenblatt gefunden,
   wie mach ich's mit der HAL?)

libopencm
 + schöne API
 - eigene Registerdefinitionen
 - nicht vollständige Unterstützung aller Peripherieeinheiten

Registerzugriff
 + sehr gute Dokumentation (Reference Manual)
 - umständlich

Für große Peripherieeinheiten, wie z.B. USB führt natürlich kein Weg an 
der HAL und der Middleware von ST vorbei.

Was sind eure Meinungen und Erfahrungen dazu?

Lukas

von holger (Gast)


Lesenswert?

Wird libopencm überhaupt noch gepflegt?
Selbst die einfachsten Sachen sind da ja noch rot markiert.

von Lukas K. (carrotindustries)


Lesenswert?

holger schrieb:
> Wird libopencm überhaupt noch gepflegt?
> Selbst die einfachsten Sachen sind da ja noch rot markiert.

Der letzte Commit war vor 3 Monaten, ganz tot isses wohl noch nicht, 
aber lebendig sieht auch anders aus.

von Kindergärtner (Gast)


Lesenswert?

Lukas K. schrieb:
> - gewöhnungsbedürftige API (wenn man POSIX gewöhnt ist)
Wie sieht denn das POSIX-API zum Konfigurieren von Pins aus? Wie sähe 
denn ein nicht-gewöhnungsbedürftiges API aus (ernst gemeinte Frage)?

von Lukas K. (carrotindustries)


Lesenswert?

Kindergärtner schrieb:
> Lukas K. schrieb:
>> - gewöhnungsbedürftige API (wenn man POSIX gewöhnt ist)
> Wie sieht denn das POSIX-API zum Konfigurieren von Pins aus? Wie sähe
> denn ein nicht-gewöhnungsbedürftiges API aus (ernst gemeinte Frage)?

libopencm macht's richtig:
http://libopencm3.github.io/docs/latest/stm32f4/html/group__gpio__file.html#ga733d745a0b6840f22b516979ce7a92c9
1
void gpio_mode_setup (   uint32_t    gpioport,
2
            uint8_t    mode,
3
            uint8_t    pull_up_down,
4
            uint16_t    gpios 
5
)

Keine Structs mit bescheuerten Namen (GPIO_InitTypeDef ?!) ausfüllen und 
an eine Funktion übergeben. Principle of least surprise und so
Beim API-Design sollte man sich IMO an vorhandenem orientieren und nicht 
mit was vollkommenem anderen anfangen (oder machen das mit structs als 
kwargs für arme noch andere so?)

Wahrschein's wollte ST damit das Fehlen von keyword-args in C 
kompensieren, denn Funktionen wie die oben von libopencm sind sehr 
anfällig gegen vertauschen von Parametern.

von Dr. Sommer (Gast)


Lesenswert?

Lukas K. schrieb:
> denn Funktionen wie die oben von libopencm sind sehr
> anfällig gegen vertauschen von Parametern.
In der Tat, beim CAN zB wären es schlappe 11 Parameter - da ist der 
struct doch lesbarer, weil immerhin Namen dranstehen und man halbwegs 
erahnen kann was die Parameter bedeuten?! Und wenn du mit C++11 
kompilierst kannst du immerhin sowas machen:
1
GPIO_Init (GPIOD, { GPIO_Pin_0, GPIO_Speed_10MHz, GPIO_Mode_Out_PP });

von Dr. Sommer (Gast)


Lesenswert?

PS: Oohps, kann man nicht, die Funktionen wollen Pointer.
Aber man kann 1 struct an mehrere Aufrufe der jeweiligen Funktion 
übergeben, um zB 10 Pins mit den selben Einstellungen zu initialisieren. 
Spart auch etwas Code.

von W.S. (Gast)


Lesenswert?

Lukas K. schrieb:
> Für große Peripherieeinheiten, wie z.B. USB führt natürlich kein Weg an
> der HAL und der Middleware von ST vorbei.

Wiebitte???
Ich halte das für Unsinn. Den Gegenbeweis hatte ich mir vor einiger Zeit 
selbst gegönnt und mir einen virtuellen COM (als device) selber 
geschrieben. Das ist auf lange Sicht wesentlich angenehmer und 
praktikabler als das von ST vorgefertigte Zeugs. Letzteres ist nämlich 
keine echte Erleichterung für den Programmierer, weil es keine echten 
Treiber sind, sondern nur ein die Hardware umschreibendes Zeug ist, so 
daß man als Programmierer zuletzt ja doch wieder alles selber machen 
muß.

Gleiches gilt auch für das SD-Karten Interface.

Lukas K. schrieb:
> Registerzugriff
>  + sehr gute Dokumentation (Reference Manual)
>  - umständlich

Ich halte das überhaupt nicht für umständlich, allerdings stehe ich auch 
auf dem Standpunkt, daß man sich selbst seine Low-Level-Treiber 
schreiben sollte, in deren Interface (also der zugehörigen .h) kein 
Hardwarebezug mehr stehen darf. Also nicht ein Treiber, der Port1.Pin7 
auf Hi setzt, sondern einer der "Maschine_kleine_Fahrt_vorwärts" macht, 
also sein Interface auf der logischen Anwendungsebene hat.

W.S.

von W.S. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> GPIO_Init (GPIOD, { GPIO_Pin_0, GPIO_Speed_10MHz, GPIO_Mode_Out_PP });

Hmm.. merkst du noch was?

W.S.

von Lukas K. (carrotindustries)


Lesenswert?

Dr. Sommer schrieb:
> um zB 10 Pins mit den selben Einstellungen zu initialisieren.

Kann libopencm auch. gpios ist ne bitmaske

Dr. Sommer schrieb:
> In der Tat, beim CAN zB wären es schlappe 11 Parameter

Bei komplexeren Peripherieeinheiten hat libopencm dann mehrere 
Funktionen, um diese zu initialisieren.

Auch wenig schön an der HAL ist, dass es nicht vorgesehen ist, einzelne 
Parameter der Peripherie zu ändern. Entweder alles initialisieren, oder 
gar nichts.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Hmm.. merkst du noch was?
Ja, vergessen dass die Funktionen Pointer wollen und keine "const T&" 
(dann würde es gehen). Ist halt C. egal.

Lukas K. schrieb:
> Dr. Sommer schrieb:
>> um zB 10 Pins mit den selben Einstellungen zu initialisieren.
>
> Kann libopencm auch. gpios ist ne bitmaske
Na hoffentlich gilt das für alle anderen Periphals auch, also alle 3 
SDADC's mit einem Befehl initialisieren oder Pins aus GPIOA und GPIOB 
ohne alle Parameter zigmal hinzuschreiben etc.

von Uwe Bonnes (Gast)


Lesenswert?

Wenn Du experiementierfreudig bist, kannst Du NUT/OS 
http://www.ethernut.de/ einsetzen. Im Sourceforge Trunk habe ich einiges 
fuer STM32 gemacht und verwende es fuer Projekte bei der Arbeit.

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.