Forum: Mikrocontroller und Digitale Elektronik Tutorial für Treiberentwicklung


von Max (Gast)


Lesenswert?

Hallo,

ich suche ein gutes Tutorial für die Treiberentwicklung von Embedded 
Geräten.

Ich möchte bei meinem neuen Projekt möglichst abstrakt entwickeln, so 
dass die einzelnen Hardwaretreiber austauschbar sind und der applikative 
Teil nicht geändert werden muss. Ich bin am überlegen, den Treiber (z.B. 
SPI) als Struktur zu implementieren und der jeweiligen Hardware (z.B. 
SPI Slave Device) als Pointer in der Initialisierung mitzugeben.
Nachfolgend ein paar Kurzfragmente:
1
/* Treiberstruktur */
2
typedef struct sSpiDriverStruct SpiDriver;
3
4
typedef struct sSPIDriverStruct
5
{
6
  spidriver_Write     Write;
7
  spidriver_Read      Read;
8
}sSpiDriverStruct_t;
1
/* Implementierung  für SPI Slave*/
2
static SpiDriver* spiDriver = 0;
3
int32_t spislave_Open(const SpiDriver* const driverPtr, ...)
4
{
5
  spiDriver = driverPtr;
6
  ...
7
}
8
9
int32_t spislave_Read(...)
10
{
11
  spiDriver->Read(...);
12
  ...
13
}
14
15
int32_t spislave_Write(...)
16
{
17
  spiDriver->Write(...);
18
  ...
19
}

Wie handhabt ihr das? Greift ihr immer direkt auf die Hardware durch 
oder baut ihr auch "Zwischenschichten" um den Zugriff zu abstrahieren?

Danke

von Arne Maximilian R. (arnemaximilian_r)


Lesenswert?

Dein Treiber wird auch Hardware Abstraction Layer genannt (kurz HAL).

Bis vor kurzem habe ich versucht immer und ueberall eine HAL einzubauen. 
Damit ist jetzt aber schluss.

DU solltest dir folgende Fragen stellen:
Wieviel Zeit brauche ich dafuer?
Wie wahrscheinlich ist ein Hardwarewechsel?
Wieviel Zeit muesste ich bei einem Hardwarewechsel investieren (mit und 
ohne HAL)?

Ich habe bei mir festgestellt, dass ich normal zu viel Zeit in die HAL 
stecke aber keine Wechsel habe. Von daher werde ich es erst wieder bei 
Projekten machen, bei denen es sich wirklich lohnt.

P.S.: Also es ist alles eine Frage der Wirtschaftlichkeit (komischer BWL 
Kram).

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

M.E. fehlt da auf jeden Fall 'Open', 'Close' , Felder für Bufferpointer 
und evtl. ein paar Flags für 'Blocking', 'Capabilities' - wenn man sich 
überhaupt den Spass macht. Eine gute Möglichkeit z.B. ist die 
Erforschung von Linux Treibern.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Max schrieb:
> typedef struct sSpiDriverStruct SpiDriver;

Sowas ist Mumpitz. Wozu soll es denn gut sein, wenn du ein struct 
kreierst, wo die Funktionen drin sind? Das vereinfacht doch garnichts.

Halte dich lieber an vernünftige Schnittstellen (sprich sinnvolle 
Funktionen in den Header-Dateien), die es den aufrufenden Programmteilen 
ermöglichen, die HW-Funktion in Anspruch zu nehmen, OHNE sich um die 
Details kümmern zu müssen.

W.S.

von Kaj (Gast)


Lesenswert?

Max schrieb:
> /* Implementierung  für SPI Slave*/
> static SpiDriver* spiDriver = 0;
> int32_t spislave_Open(const SpiDriver* const driverPtr, ...)
> {
>   spiDriver = driverPtr;
>   ...
> }
>
> int32_t spislave_Read(...)
> {
>   spiDriver->Read(...);
>   ...
> }
>
> int32_t spislave_Write(...)
> {
>   spiDriver->Write(...);
>   ...
> }

Wenn du dir schon so viel mühe machen willst, solltest du es auch 
ordentlich machen -> Wenn eine Funktion einen Rückgabewert hat, solltest 
du diesen auch auswerten, sonst macht der Rückgabewert keinen Sinn. Dann 
kommen wir zur nächsten Frage: Was hast du von dem Rückgabewert/der 
Auswertung?
Mal angenommen deine Read-Funktion gibt eine -1 zurück, weil nicht 
gelesen werden konnte (warum auch immer)... was machst du damit? In der 
Regel hat man bei sowas keine Anzeige, die dir sagt:
Hey ich konnte nicht lesen, was soll ich jetzt machen?
Außerdem würd ich mir das mit dem int32 als return überlegen, wenn du 
das für die kleinen 8bitter machst. Ein int32 braucht erheblich länger 
als ein int8. Mag bei einem einmaligen Aufruf egal sein, aber wenn du 
die Funktion im extrem Fall Hunderte male die Sekunde aufrufst, dann 
geht da auf dauer ganz schön viel Zeit verloren. Und da du von einem 
"Treiber" sprichst, sollte Performance eine hohe Priorität bekommen, 
denn das ist etwas, wodrauf in der Treiberentwicklung geachtet wird.

Ansonsten wie schon gesagt wurde:
Arne Maximilian R. schrieb:
> Wie wahrscheinlich ist ein Hardwarewechsel?
Wenn du innerhalb einer Controllerfamilie bleibst, z.B. Atmel AVR dann 
sind die Anpassungen zwischen den controllern sehr gering (Registernamen 
ändern, und gut ist). Wenn du den Code natürlich von AVR auf 
Cortex(SAM3X) heben willst, oder noch besser von Atmel auf PIC oder 
sonst wohin, dann ist schon mehr arbeit nötig.

Max schrieb:
> Wie handhabt ihr das? Greift ihr immer direkt auf die Hardware durch
> oder baut ihr auch "Zwischenschichten" um den Zugriff zu abstrahieren?
Ich hab mir z.B. eine Klasse (ja, ich benutze auch auf den 8bittern C++) 
für den UART geschrieben, ganz simpel, keine Vererbung oder Templates 
oder sowas.
1
class UART
2
{
3
  public:
4
    UART(uint32_t baudrate);
5
    ~UART();
6
    void TransmitData(char value);
7
    char ReceiveData(void);
8
};
Ganz easy, keine sonderwünsche, reicht für meine Anforderungen. Ist 
momentan noch auf einen bestimmten UART-Port festgenagelt, aber das ist 
für mich nicht so schlimm. Wenn ich den Port wechsel muss ich nur die 
Registernamen anpassen und gut ist. Und die Klasse(C++) erzeugt hier 
auch keinen riesigen Overhaed, wie es hier von so vielen Propagiert 
wird. Das mag durch aus anders aussehen, wenn man von 36 Klassen 
ableitet und dazu noch Container aus der STL, wie "string", 
"stringstream", "vektor" und ähnliches verwendet. Aber das ist ein 
anderes Thema^^

Grüße

von W.S. (Gast)


Lesenswert?

Kaj schrieb:
> Ganz easy..

Na, wohl doch nicht. Das sieht so aus, als ob du schlichtweg blockierend 
programmierst. Was liefert dein "char ReceiveData(void);" denn zurück, 
wenn grad mal nix an Port anliegt? Oder was macht dein TransmitData, 
wenn grad der Sendepuffer voll ist? Blockieren bis es wieder geht?

Sowas mag zwar C++ sein, aber wirklich nützlich ist es für nen µC nicht. 
Vernünftige Funktionalität von Peripherie-Treibern ist eben was anderes. 
Guck mal in die Quellen zur Lernbetty (Codesammlung), wie man sowas ein 
bissel professioneller macht. Besagte Lernbetty ist nämlich genau dazu 
da.

W.S.

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.