Forum: Mikrocontroller und Digitale Elektronik Entwicklung eines HAL


von ralf (Gast)


Lesenswert?

Hallo zusammen,

ich bin gerade am überlegen wie ich meine Software am besten so
gestalte, dass ich sie leicht von einem Controller auf den nächsten
portieren kann. Modular und gekapselt habe ich bisher schon
programmiert, aber bei der Hardware hört es bisher immer auf. Jeder
Controller hat ja unterschiedlich viel Funktionalität. Nun habe ich
schon an verschiedenen Stellen etwas über HALs gelesen. Allerdings war
dies nur sehr oberflächlich. Ich habe also nichts darüber gefunden, wie
man an so eine Sache herangehen kann. Vor allem habe ich noch keine
genaue Vorstellung wie man einen HAL optimal programmieren kann, dabei
meine ich zum Beispiel die Verwendung von Interrupts usw.. Wie Schaffe
ich es, die unterschiedlichen Strukturen verschiedener Controller durch
eine einheitliche Schnittstelle zu beschreiben? Hat vielleicht einer ein
paar Tips bzgl. Literatur oder Websites wo etwas zu diesem Thema zu
finden ist? Über Tips aus der Praxis würde ich mich auch freuen.
Zunächst möchte ich sowas auf einem ATMEGA zusammen mit dem GCC
umsetzen.

Viele Grüße,

Ralf

von Hagen (Gast)


Lesenswert?

Ein HAL ist erstmal nur eine Schnittstellen-definition, mehr nicht. Sie
sollte natürlich möglichst portierbar und einheitlich zur
unterschiedlichen Hardware sein, was ja auch der Unterschied zu anderen
Schnittstellen ist. Allerdings lohnt sich ein HAL nur für große CPU's.
Im Falle eines AVR's oder PIC's wäre er softwaretechnische
"überdimensioniert" bzw. viel zu umständlich. Der HAL vom PalmOS zb.
übernimmt einiges an intelligenter Funktion nebst eigenem ausführbarem
Code. Das macht dort auch Sinn da man dort normalerweise keine
Interruptroutinen oder System-Link-Bibliotheken selber programmieren
wird oder kann. Auf einem AVR würde das aber bedeuten das man keine
"Echtzeit-Systeme" mehr programmieren kann. Denn nun würde der HAL
mit einer ziemlich komplizierten IRQ Logik verhindern das man zb. die
Timerspezifischen PWM Eigenschaften der AVR's wirklich ausnutzen kann.
Bedenke der HAL ist ein Abstractionlayer in Software der sich auf einem
gemeinsammen Nenner an Funktionalität einigien muß. D.h. er ist zwar
portable aber auch unspezifisch. Er kann also spezielle Unterschiede
zwischen AVR, PIC oder ARM's nicht eingehen.

Deshalb mache ich sowas immer anders. Alles was HW abhängig ist wird in
einen Mini-HAL als Headerdatei ausgelagert. Je nach Hardware sind dann
nur wenige Sourcedateien betroffen die geändert werden müssen. Ergo,
ist es kein eigenständiger HAL mehr sondern nur noch eine einheitliche
Schnittstellendefinition zur Hardware.

Die HAL's die ich bisher gesehen habe, besonders der vom PalmOS, kann
man sich vorstellen als Library die vergleichbar zum PC das BIOS +
Windows Treiber repräsentieren. Also die unterste Ebene zur Hardware.
Der restliche Programcode muß dann immer über das HAL arbeiten damit er
auch in Punkto Portabilität überhaupt Sinn macht. Damit das funktioniort
kann der HAL aber keine Platformspezifischen Funktionen enthalten und
diese dürfen dann aber auch nicht am HAL vorbei zusätzlich benutzt
werden. Ergo: auf Echtzeitsystemen ist ein HAL eher störend als
sinnvoll.

Nur meine 10 Cent Meinung :=)

Gruß Hagen

von Heinz (Gast)


Lesenswert?

Du könntest in deinem Hauptprogramm eine Variable CPU erstellen und dort
 z.B. über einen int Wert einstellen welchen uC du verwendest.
Dann könntest du in einer oder mehrerer Header Datei/en den
hardwarenahen Code für die jeweiligen uCs schreiben und jeweils in
einer  if(CPU == XYZ) Abfrage kapseln.

von Markus (Gast)


Lesenswert?

Wenn Du etwas portabel machen möchtest, dann gibt es dazu im Prinzip
zwei Ansätze:
a) Man beschränkt sich auf die Gemeinsamkeiten - und verliert dadurch
viel Funktionalität
b) Man bildet fehlene Funktionalität nach - und schleppt einen riesigen
Overhead mit.

Ich schließe mich da Hagen an: Für einen richtigen HAL sind die
üblichen 8-Bit-Microcontroller zu klein.

Markus

von Ralf (Gast)


Lesenswert?

Hallo zusammen,

danke für eure Tips!

@ Heinz:
So in der Art habe ich es bisher gemacht. Der Nachteil den ich darin
sehe ist, dass mit steigender Anzahl von Funktionen und Controller der
Code immer unübersichtlicher und schwer wartbar wird. Aus diesem Grund
möchte ich solche Compilerschalter möglichst auf ein Minimum
reduzieren. Teilweise habe ich dann ja auch noch Schalter für
Debugzwecke im Programm.

@all:
Bei der Ansteuerung der Interrupts und der verschiedenen Timer von
Controllern hatte ich auch die eigentlichen Probleme gesehen. Ich habe
schonmal einen HAL für kleinere Controller gesehen. Dabei gab es
allerdings das Problem, dass verschiedene Routinen zur
Interruptsteuerung relativ lange dauerten wodurch es nicht mehr möglich
war Zeiten sehr genau zu messen. Ich denke mal, dass es bei
Schnittstellen wie CAN oder der seriellen einfacher sein wird eine
gewisse Standardisierung zu erreichen.
Gibt es vielleicht irgentwelche Konzepte wie man am besten festlegt wo
man den Schnitt zwischen hardwarenahem, controllerspezifischem und
allgemeinem Teil der Software macht?
Was mich halt stört ist, dass man immer gezwungen ist relativ viel zu
ändern wenn der Controller gewechselt wird. Wenn man bei den AVRs
bleibt geht das ja noch, aber wenn es dann ein Wechsel auf eine andere
Controllerfamilie ist, dann wird es schon aufwändiger.

Viele Grüße,
Ralf

von OldBug (Gast)


Lesenswert?

Schau Dir mal zB FreeRTOS an, die Mischen die ganze Sache ein wenig.
Es gibt Abstrakte #defines, ISRs werden für jeden Controller neu
geschrieben und halten sich an einen bestimmten Standard. Für die UART
hat man Beispielsweise einfach nur den "Funktionsrumpf" bestimmt,
wodurch gewährleistet ist, daß die aufrufende Funktion überhaupt nichts
von der darunterliegenden, hardwarenahen Funktion wissen muss, ausser
den Parametern, die sie zurückgibt und erwartet.

Wenn man sich da strikt dran hält, kann man das Ganze dann später
wirklich mit nur einem einzigen Symbol beim Compileraufruf für eine
Architektur/CPU oder vielleicht sogar nur ein "Application-Board"
Kompilieren...

von OldBug (Gast)


Lesenswert?

Ausserdem kann man so auch "Testsuites" auf dem PC Programmieren und
die Grundsätzliche Fufnktion einer Applikation nachweisen. Ganz einfach
indem man sich "Ersatzfunktionen", welche die Hardware "Simulieren",
erstellt.

Kann oft sehr hilfreich sein...

von Ralf (Gast)


Lesenswert?

FreeRTOS habe ich mir auch schonmal runtergeladen (allerdings noch nicht
richtig angeschaut)
Wie sieht es denn bei einem RTOS mit den Reaktionszeiten auf Interrupts
aus. Ich meine wenn ich z.B. Zeiten im Bereich von etwa 200us messen
muss und kein Capture mehr frei habe? Bekommt man damit noch gute
Zeiten hin oder ist dann eine Sonderlösung doch besser?

von Ratber (Gast)


Lesenswert?

@Ralf


>Was mich halt stört ist, dass man immer gezwungen ist relativ viel zu
>ändern wenn der Controller gewechselt wird. Wenn man bei den AVRs
>bleibt geht das ja noch, aber wenn es dann ein Wechsel auf eine
andere
>Controllerfamilie ist, dann wird es schon aufwändiger.



Verständlich aber irgendwie doch ein Wiederspruch in sich.

Um einen guten HAL zu schreiben muß man sich schon recht gut mit dem
entsprechenden Controller auskennen.

Hat man diese Kenntnisse dann ist der HAL aber wieder überflüssig weil
man dann ,aufgrund der guten Kentnisse,auch gleich die Anwendung
anpassen kann.


Normalerweise bleibt man bei einer Familie aber das will ich hier nicht
breittreten.

Eine HAL macht im Grunde keinen Sinn da sie die Effektivität eines
jeden Systems nur vermindern kann.

Sie dient nur der Bequemlichkeit der Programierer.

In zeiten wo jeder PC Speicher und Plattenplatz satt hat,wo
Rechenleistung en Mass bereitsteht kann ich nur erahnen zu welchen
Leistungen er eigentlich fäghig wäre wenn man sich seine Software mal
nicht aus bauklötzen zusammenstecken würde.

Den Vorteil der direkten effektiven Programierung willst du wirklich
freiwillig aufgeben ?

von Ralf (Gast)


Lesenswert?

Hallo

@Ratber
Ich habe natürlich nicht vor die flexible Programmierung aufzugeben,
aber ich hatte halt schon ein paar mal das Problem (jobtechnisch), dass
der Controllertyp gewechselt werden soll. Dabei ging es dann darum
möglichst schnell zu entscheiden mit welchem neuen Typ eine Portierung
möglich ist und wie lange eine Portierung braucht bis sie auf dem neuen
Controller läuft. Sowas kommt irgentwie halt schonmal häufiger vor wenn
andere Controller billiger sind. Meine Probleme sind dabei vor allem,
dass ich relativ viele zeitkritische Funktionen in meinem Programm habe
(Motorregelung, d.h. z.B. Drehzahl- Positionserfassung, PWM-Berechnung
usw.) was also eigentlich ein Widerspruch zu einem HAL ist. Ich bin nun
auf der Suche nach Möglichkeiten, diese möglichen Wechsel durch eine
gute Programmierung in Zukunft zu vereinfachen. Dabei bin ich nun auf
HALs gestoßen. Erste Erfahrungen wollte ich nun z.B. auf einem AVR
sammeln (Hobby, vielleicht lässt sich das ganze ja auch hier nutzen
:-)). Ich möchte also in erster Linie Erfahrung sammeln, wie ich an
soetwas herangehe, wie ich die Schnittstellen gestalten muss, wo die
Nachteile sind (da habe ich ja hier schon was erfahren :-)), usw. Im
Moment habe ich nicht so wirklich eine richtige Vorstellung davon wie
sowas in der Realität aussieht (vieleicht habe ich ja schon was
ähnliches in meinem Programm und weiß nicht das es dafür so tolle
Begriffe wie HAL gibt). Ich bin also auf der Suche nach verständlichen
Erklärungen am besten mit Praxisbeispielen. Sowas wie HALs für Dummys
oder so. In den Linux Quelltext zu gucken ist denke ich für eine
Einarbeitung etwas aufwändig.

Trotzdem danke für eure Hinweise!

Bis denne,

Ralf

von OldBug (Gast)


Lesenswert?

Trennt euch doch BITTE von dem Gedanken, einen PC-ähnlichen HAL zu
stricken!

Das kann ja gar nicht Sinn der Sache sein. Eine "minimalistische"
Form eines HALs bringt auch nicht sonderlich viel Overhead mit sich!

Man kann sich ja für den Anfang auf eine Art ucHAL.h begrenzen, da
einige inline-Funktionen und #defines hineinverlagern und Feddisch!
Sowas mache ich sogar schon, wenn ich innerhalb einer Familie bleibe.
Ja, es gibt auch Unterschiede zwischen Tiny26 und Mega128! ;)
Auf letzterem arbeite ich, bis die Applikation "so gut wie Fertig"
ist, auf dem Ersten wird dann die "Release" realisiert...

von Ratber (Gast)


Lesenswert?

@Oldbug

Natürlich will ich das nicht mit einem HAL unter Windows vergleichen
sondern die Richtung aufzeigen.



@Ralf

Ich verstehe schon deine Gründe aber ich persönlich würde mir mal
überlegen ob die häufige Springerei zum billigsten Controller überhaupt
Sinn macht wenn du (Natürlich am Ende die Firma) damit jedesmal Arbeit
und damit auch Kosten hast und sich das überhaupt lohnt.

Es ist ja nunmal so das man sich mit der Zeit auf eine Familie
einschießt und dort erweiterte Kenntnisse erwirbt.
Das macht man sich mit einem Wechsel dann wieder zunichte und artet
instress aus.

Gut,ich weiß nicht wie das bei euch ist aber wir müssten bei jedem
Wechsel das komplete Produkt neu beim Kunden zulassen und das kostet
dann richtig Zeit und Geld.

So,das wars von mir.

Ich kann dir bei deiner Kernfrage leider nicht viel weiterhelfen und
ziehe mich mal wieder zurück aber ich lese noch etwas mit und Fragen
deinerseits beantworte ich auch gerne soweit möglich.

Ratber

von Hagen (Gast)


Lesenswert?

Ich dachte das dies oben schon erklärt wurde.

Also man kann sagen das es zwei Formen von HAL's gibt. Den
durchimplementierten HAL der wie zb. im PalmOS oder Windows aus eigenen
Treibern, ergo eigenem lauffähigem Code besteht. Und den virtuellen HAL
der im Grunde nur aus wenigen Header Dateien mit allerhöchstens par
Makro's besteht.

Der erstere soll den direkten Zugriff auf die Hardwareresourcen durch
Anwendungsprogrammierer möglichst komplett unterbinden und somit
benötigt man für jede neuere Hardware auch einen Treiber der zum HAL
hinzugefügt wird.

Der zweitere Typ ist auf einen einzige Software bezogen nur eine
Sammlung von Schnittstellen und Funktionen die die spezifische Hardware
ansteuert. Wenn, dann würde ich für MCU's nur diesen HAL empfehlen.
Praktisch bedeutet das eine Software zb. aus 50 Quelltextdateien
besteht wovon 1 oder 2 den HAL darstellen. Die restlichen Quelltexte
greifen immer über diesen HAL zu. Dieser HAL ist spezifisch auf ein
Board auf dem eine MCU sitzt. Zb. hat das Board 3 LED's und 1 PWM
gesteuerten Motor und einen AVR. Im HAL sitzt nun der Code um diese
LED's und den Motor zusteuern. Dabei steuert er dann direkt den AVR
an. Wird nun der AVR durch einen PIC ausgetauscht so wird NUR der
Quelltext des HAL's an den PIC angepasst, die restlichen 48
Quelltextdateien deiner Software bleiben unberührt da sie losgelösst
von der eigentlichen Hardware sind.

Im Grunde arbeiten wir tagtäglich mit einem "HAL", zb. die Runtime
Libraries von WinAVR wäre so ein HAL. Das einheitliche Interface dieses
HAL's sind die standardisierten C-Funktionen, wie printf() usw.
Oder, wie es guter Programmierstil ist, benutzen clevere Programmierer
ihre Includes und Header Dateien die in ihrer Funktion ausschließlich
hardware-/nichthardware bezogen sind. Man unterteilt also sauber die
komplette Software in verschiedene Teile wobei eben ein Teil der HAL
ist.

Ein HAL -> Hardware Abstraction Layer -> ist also nur eine
Schnittstelle, eine Definitionssache. Ob diese nun mit eigenen Treibern
oder aus einfachen Header-/Includedateien besteht ist erstmal nicht
entscheidend. In beiden Fällen soll er den Rest der Software oder eben
ganze Programme unabhängig von der Hardware machen.

Ich handhabe es am liebsten so das zu jeder Bibliothek es immer eine
Header/Include Datei gibt die den kompletten HW-nahen Code enthält. Der
Dateiname enthält dann das Kürzel "HW_" oder meinetwegen auch
"HAL_". Will man nun die Software anpassen konzentriert man sich nur
auf diese Dateien.

Gruß Hagen

von OldBug (Gast)


Lesenswert?

Danke, Hagen!
Du sprichs mir wieder mal aus der Seele ;-)

von Markus (Gast)


Lesenswert?

@Hagen:
Aber auch bei einem minimalistischen Hal bist Du doch darauf
angewiesen, daß die MC gleich mächtig sind. Klar, wenn zwei
verschiedene MC jeweils einen Hardware-UART haben, dann kann man dessen
Benutzung schön in ein Headerfile packen. Aber was, wenn einer (weil er
billiger ist) keinen UART hat? Packst Du dann den Software-UART
ebenfalls in den HAL?
Das ganze Spiel gilt natürlich auch für Interruptprioritäten, Anzahl
Timer usw. usf.

Deswegen bringt ein kleiner HAL meiner Meinung nach nicht so furchtbar
viel.

Markus

von Ratber (Gast)


Lesenswert?

@Hagen

Schön,dann hab ich ja mit Bascom mein Hal schon.

LCD-ausgaben erledige ich auch nur per "LCD ........"


Nur hilft mir das bei anderen Sprachen recht wenig da es den Befehl LCD
nicht gibt.

Ich nüßte ihn als Prozedur definieren die den Befehl nur durchreicht
aber da fängt der spaß mit der Zeitverschwendnug schon an und die will
Ralf ja vermeiden.

Eine effektive Programierung ist immernoch "Direkt"

Die Hersteller müßten sich schon im Groben auf einen festen
Grundwortschatz einigen und wie Chancen für diesen Fall stehen brauche
ich ja nicht zu schreiben. gg



Meine  Frage an Ralf wäre dann sowas in der richtung wie
"Wieviel Performance und Reaktionszeit bist du freiwillig bereit
abzutreten ?"

Ohne Kompromiss ist da ja nun wirklich nix zu machen.


Nur mal so als Anmerkung oder so.

von Hagen (Gast)


Lesenswert?

>>billiger ist) keinen UART hat?
>> Packst Du dann den Software-UART ebenfalls in den HAL?

Nein eben nicht. Es würde drei Sourcem geben, Header + C Source für die
UART Funktionen und 1 Header mit Makros die die Hardware anspricht
speziell für die UART Funktionen.

In den UART Source stünde also zb. sowas drinnen:

void UART_Put(char c) {
  UART_DATA_REG = c;
}

und UART_DATA_REG ist in der HAL-Header Datei als Makro/Define etc.
definiert -> #define UART_DATA_REG UDR -> für einen AVR.

Wird nun ein Softare UART draus ist das auch kein Problem, denn nun
würde man den HAL-Header mit anderen Makros/Defines umschreiben.

Der Compiler linkt diese Sachen ja direkt in das Program ein, ergo ist
die Frage von Ratber ebenfalls beantwortet, es wäre genauso effizient
wie eine "direkte" Programmierung.

Wie gesagt es ist doch reine Definitions- bzw. besser
Organsiations-Frage. Nämlich wie sauber und strukturiert man
programmiert. Wichtig ist doch nur das sich die Schnittstellen zur
Hardware namentlich und funktionstechnisch nicht unterscheiden, egal ob
der HAL für den AVR oder den PIC benutzt wird.

Wir alle arbeiten doch "meistens" schon so. Alle Ports/Pins/Register
sind doch schon in separate Dateien gepackt worden und mit diesen
arbeiten wir. Das muß man nur noch konsequenter in seiner täglichen
Arbeit umsetzen, zb. auch die Namensgebung dieser Dateien, und schwups
könnte man sagen alle Dateien die mit "HAL_" beginnen sind die
einzigsten Dateien in meinem Projekt die die Hardwarespezifischen
Sachen enthalten, ergo diese Dateien SIND unser HAL.

Der Sinn eines HAL's ist doch nur eine Verbesserung der Arbeitsabläufe
bei der Programmierung. Einerseits um eine Software schneller portieren
zu können und/oder andererseits damit ein DAU-Programmierer mit unserer
Software arbeiten kann, sozusagen ein Baukastenprogrammierer damit
zurecht kommt.

Gruß Hagen

von Ralf (Gast)


Lesenswert?

Moin moin,

ich denke jetzt habe ich mal wieder etwas mehr verstanden. Bisher habe
ich immer so programmiert, dass ich zum Beispiel ein UART-Modul hatte
das nur in der Lage war einzelne Bytes zu übertragen. Bei der PWM sieht
es ähnlich aus. Das PWM-Modul stellt eigentlich immer nur den Dutycycle
ein und erledigt die Basisinitialisierung der PWM-Timer. Also hatte ich
ja prinzipiell schon einen HAL und wusste nicht, dass es da so tolle
Begriffe für gibt :-). Ich hatte mir da wohl eine größere Sache drunter
vorgestellt (was es auf dem PC ja wahrscheinlich auch ist).
In meiner Software muss ich teilweise auch verschachtelte Interrupts
verwenden da mein Controller diese nicht unterstützt, d.h. ich
deaktiviere zunächst alle nicht benötigten Interrupts und aktiviere
dann die anderen global. Aber ich denke mal, dass ich an dieser Stelle
wohl nichts verbessern kann, sodass dieser Teil allgemeingültiger wird.
Man müsste dann ja grundsätzlich immer alle möglich Interruptquellen
behandeln auch wenn diese in der jew. Software garnicht verwendet
werden was dann wohl eine große Verzögerungszeit mit sich bringt. Ich
habe im Moment die Anforderung, dass ich optimalerweise nur
Verzögerungszeiten von etwa <5us in Kauf nehmen kann, da sonst meine
Zeitmessung nicht genau genug ist was dann wieder andere Nachteile für
mich hat.
@Markus:
>> Aber auch bei einem minimalistischen Hal bist Du doch darauf
>> angewiesen, daß die MC gleich mächtig sind.
Da ist wohl was dran und für mich dann wohl auch ein 'nein' für die
Programmierung eines richtigen HALs. Wenn bei uns der Controller
gewechselt wird, dann ist das im Moment eigentlich nur der Fall, wenn
der andere billiger ist. Dann hat der neue meist auch noch weniger
Funktionen sodass sich da eigentlich nicht so viele Gemeinsamkeiten
feststellen lassen (bei mir war es z.B. der Fall dass ich von einem
C164 auf einen H8Tiny wechseln musste).

Bis denne und viele Grüße,

Ralf

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.