[STM32] HAL vs libopencm vs 'von Hand'

OP #3645391
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
OP #3645425
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.
Gast #3645452
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 });
Gast #3645454
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.
Gast #3645465
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.
OP #3645473
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.
Gast #3645481
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren