Forum: Mikrocontroller und Digitale Elektronik Optimale Programmstruktur bei blockierenden Funktionen?


von Be B. (bebo)


Lesenswert?

Hallo,

bisher sahen meine Mikrocontroller-Programmer immer so aus:

1. In Interrupts wurde alles Hardwarenahe kurz und knapp erledigt. Gab 
es größere Aufgaben, wurden diese über Messages oder Datenstrukturen an 
das Hauptprogramm übergeben.
2. Mainloop: Hier wurde alles verarbeitet, was nicht zeitkritisch war. 
Allerdings habe ich die einzelnen Funktionen im Mainloop auch in 
Ausführungsblöcke aufgeteilt, damit eine Funktion die länger dauerte, 
die anderern Funktionen im Mainloop nicht unnötig lange ausbremste 
(Stichwort: kooperatives Multitasking).

Das hat auch immer alles bestens funktionniert. Da ich auf fremde 
Bibliotheken verzichtet habe, konnte ich darauf achten, daß die 
einzelnen Funktionen sich immer kooperativ verhielten (Multitasking).

Nun aber, da auch Mikrocontrollerbastelleien immer komplexer werden, 
möchte ich auch auf fremde Bibliotheken zugreifen. Insbesondere 
Microchip stellt ja eine ganze Reihe von Bibliotheken zur Verfügung.

Leider ergibt sich daraus nun ein Problem: Einige Funktionen verlangen 
nach einer regelmäßigen Ausführung (sagen wir einmal alle 1ms). Andere 
Funktionen blockieren allerdings den Mainloop mehrere 100ms lang. 
Dummerweise sind die Funktionen aber nicht asynchron ausgelegt (Funktion 
starten, Abarbeitung in Interrupts und Ergebnis später vom Hauptprogramm 
abholbar).

Nun würde ich gerne so etwas konstruieren, wie:
Prio 1: ISRs wie bisher für zeitkritische Aufgaben
Prio 2: Highprio Mainloop (bisheriger Main-Loop, der z.B. 1x pro 
Milisekunde durchlaufen wird)
Prio 3: Standard Mainloop, in dem auch blockierende Funktionen erlaubt 
sind

Dann würden die ISRs zeitunkritische Aufgaben an den Highprio Mainloop 
abgeben. Dieser soll allerdings eine Art kooperatives Multitasking 
bewältigen, d.h. dieser Mainloop darf nicht länger als eine bestimmte 
Zeit (z.B. 1ms oder 10ms) für einen Durchlauf brauchen. Gibt es nun 
Funktionen, die länger brauchen und kein kooperatives Multitasking 
unterstützen, sollten diese vom Highprio Mainloop an den Standard 
Mainloop abgegeben werden können. Dort kann dann die Funktion gern auch 
mal 1 Sekunde rumwerkeln, bis sie das Ergebnis zurückgibt.


Daraus ergibt sich für mich, daß der Inhalt des Highprio Mainloops auch 
in einen Timerinterrupt niedriger Priorität hineinmuß. Frage ist nun, 
wie macht man das am besten. Ich habe bereits eine TIMER-ISR, welche 
alle möglichen Timings erzeugt, von wenigen Mikrosekunden bis hin zu 
Minuten. Fakt ist, daß die Ausführung der gesamten TIMER-ISR nicht 
länger dauern darf, als die Zeit, bis der Timer wieder auslöst, und das 
sind unter umständen nur einige 10µs. Im Grunde könnte diese TIMER-ISR 
für das Timing des Highprio Mainloops sorgen. Nur muß der Timer bereits 
wieder auslösen dürfen, während die Funktionen des Highprio Mainloop 
noch abgearbeitet werden.

Wie löse ich so ein Problem am besten? (Ich verwenden zur Zeit einen 
PIC32 mit dem C32)

Ich bin aber auch gern für andere Vorschläge offen. Mir ist nur wichtig, 
daß solche Funktionen wie Lade_File_von_SD_Karte() den Rest der 
Schaltung nicht für 1s lahmlegen.

Grüße,
Bebo

von Falk B. (falk)


Lesenswert?

Wird wohl oder übel auf ein präemtives RTOS rauslaufen.

von Be B. (bebo)


Lesenswert?

Wieso, gibt es keine Möglichkeit den Interrupt wieder zu enablen? Das 
würde für's erst schon reichen.

von Mark B. (markbrandis)


Lesenswert?

Be Bo schrieb:
> Wieso, gibt es keine Möglichkeit den Interrupt wieder zu enablen? Das
> würde für's erst schon reichen.

Du schriebst doch was von "Priorität ändern" (wenn eine Funktion zu 
lange braucht) und eben auch die Zeitüberwachung, bzw. dass ein 'Task' 
nur soundsoviele Millisekunden Laufzeit bekommt, bevor der andere wieder 
dran ist. Das klingt halt schon ziemlich nach einem Betriebssystem.

von Olaf (Gast)


Lesenswert?

> Leider ergibt sich daraus nun ein Problem: Einige Funktionen verlangen
> nach einer regelmäßigen Ausführung (sagen wir einmal alle 1ms). Andere
> Funktionen blockieren allerdings den Mainloop mehrere 100ms lang.

Dann merkst du jetzt wo der Nachteil liegt wenn man fremden Code 
verwenden will. :-)

Natuerlich kann man einiges machen. Du kannst z.b Interrupts mit 
verschiedenen Prioritaeten verwenden wenn dein Prozessor das kann. Du 
kannst auch einen Interrupt durch einen anderen unterbrechen lassen. Du 
kannst auch viele verschiedene TimerIRQs verwenden.

Aber das aendert nichts daran das du eine ganze Menge Dinge im Auge 
behalten musst. Langfristig faehrt man dann am besten wenn man sich 
seine Funktionen selber schreibt. Oder wenn man etwas uebernehmen will, 
es so anpassen das es gut an den eigenen Programmstil angepasst ist.

Ich denke Faulheit an dieser Stelle muss man sonst wirklich mit einem 
Betriebssystem und entsprechend dicker Hardware bezahlen.

Olaf

von Be B. (bebo)


Lesenswert?

Die Standardsachen würde ich ja auch selber machen, aber warum soll man 
nicht die Bibliotheken des Herstellers verwenden. USB-Firmware, FAT16/32 
Stack, Ethernetstack, im Grunde gibt's das bei Microchip schon fertig. 
Da allerdings Dinge abzuändern würde ich vermeiden wollen. Kommt die 
nächte Version, kann man von vorn beginnen.

Verschiedene Interruptlevel gibt es und mit einem 2. Timer wäre das 
ganze auch nicht schwierig. Ich würde aber gern darauf verzichten einen 
Timer nur für diese Funktion zu opfern. Und da ich mal von Nested 
Interrupts gelesen habe, dachte ich, das wäre das was ich brauche. Ich 
weiß allerdings nicht, wie man das Programmiert.

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.