pC/OS
Zu den für Anfänger am schnellsten zu verstehenden Echtzeitbetriebssystemen gehört µC/OS von Jean J. Labrosse. Es kann bis zu 63 Applikationstasks mit je unterschiedlichen Prioritäten verwalten und gehört zu den Echtzeitbetriebssystemen mit dem geringsten Speicherbedarf.
Da die Originalversion aus dem Embedded Systems Programming Magazine(1992) FREI ist, habe ich diesen für Interressierte zum Download hinterlegt.
Da die Firma Micrium Ihre Source-Code Distribution Lizenz-Bedingungen auch für die Originalversion aus dem Embedded Systems Programming Magazine(1992) geändert hat, kann ich hier nur noch einen Link zur Download-Seite des Magazins stellen.
Embedded Systems Programming Magazine(1992) - code area
Da in der Originalversion Daten durch direkte Übergabe von Zeigern zwischen den Tasks ausgetauscht werden, und somit keine Garantie für die freie Verwendbarkeit des Absender-buffers nach Übergabe an einen anderen Task besteht und, viel wichtiger, der Empfänger einen Zeiger in das Datenfeld eines anderen Tasks erhält (Pointer-Fehler / Längen-Fehler / Manipulationen u.a.) habe ich die Mechanismen
für Message-Box und Queue entsprechend so geändert, daß nun die Daten über einen Kernel-internen Buffer an den Empfänger übergeben werden. Das bedeutet, daß der Kernel zu übertragende Daten in einen eigenen Buffer kopiert und bei Übergabe an den Empfänger diese auch wieder selber in den durch den Empfänger bereitgestellten Buffer kopiert. Das bringt zwar einen höheren Speicherbedarf je Queue mit sich, sichert aber dafür die Prozesse weitestgehend (für Real-Mode) voneinander ab.
Aus Sicherheitsgründen wurden außerdem Kernel-Konstanten in den CODE-Area verlegt. Desweiteren habe ich den Kernel um die Diente Pipe, Eventgroup und dyn. Memorymanagement erweitert.
Um diese Änderungen eindeutig zu deklarieren habe ich den Namen, angelehnt an dem immer größer werdenden Original "µC/OS", auf pC/OS wie "pico-C.." geändert.
Special zu: Priority Inversion, das Problem und die Lösungsansätze
Um endgültig den Status des pC/OS Kernel basierend auf dem µC/OS 1.00 klarzustellen,
habe ich die alte "V1.00 is FREE" Bestätigungs-email von Jean Labrosse herausgesucht.
Releases:
1.00a | Messagebox und Queue geändert sowie Pipe, Eventgroup und dyn. Memorymanagement hinzugefügt. * Port für Am188ES erstellt |
1.00b | Revision-Info, Tick-counter, Task-Suspension, Task-Delete, History-Table und OS_QueueFrontPost hinzugefügt (Task-Suspension und Task-Delete aus 1.09 importiert). Einige BugFixes aus 1.01 bis 1.09 übernommen. |
1.00c | Beschleunigung der Pipe (bei Taskwechsel auf Grund der Datenübergabe und wenn Pipe leer ist werden die Daten vom Sender-buffer direkt in den Empfänger-buffer kopiert). Vorab-Implementation einer Wartezeit für Sender (OS_.....Post). Nicht-warten für Sender und Empfänger mittels OS_NO_SUSP implementiert. Anlegen von Queue und Pipe (speziell: Zeiger auf Kernel-buffer) überarbeitet. |
1.00d | korrekte Implemenierung "timeout" in OS_...Post-Funktionen und OS_QueueClear hinzugefügt. |
1.00e | Anpassung der Task-Initialisierung und einiger Parameter zur Nutzung der µC/OS-I Port's. OS_QueueInfo und OS_PipeInfo hinzugefügt. |
1.00f | Bugfix innerhalb der Event-Gruppen. OS_SemAccept hinzugefügt. |
1.00g | Dual-Source für MSC-8.00 und Keil-C51 generiert. OS_CFG implementiert. Bugfix in Semaphoren. * Port für 8051 hinzugefügt |
1.00h | MUTEXes hinzugefügt, Eventgruppen richtig implementiert und Code-cleanup. Cleanup der Ports. * Port für Rabbit 2000/3000 hinzugefügt * Port für Philips-XA hinzugefügt |
1.40a | Name auf pC/OS geändert und Revisionsnummer überarbeitet, einige C-fixes. * Port für ATMega128 hinzugefügt * Port für AT91SAM7Sxx hinzugefügt |
1.41a | Implementation von OS_STK_TYPE für Prozessor-konformen Stack incl. Update aller bisherigen Ports. Keil-Variante des AT91SAM7Sxx-Ports (instabil) hinzugefügt |
1.50c | Komplettes Update zu U08..U32 Typen. Implementation von OS_PACKED, OS_PACKED_ATTR und align(x)-Korrekturen. Kleine Korrektur in OS_TaskSuspend(). * Port für LPC214x hinzugefügt * Port für LPC236x hinzugefügt * Port für STR71x hinzugefügt |
1.52b | Split MIN_PRIO und MAX_TASKS um RAM in der Task-Verwaltung bei wenige Tasks einzusparen. Verwendung "NULL" als pointer. Eindeutige Task-ID hinzugefügt, um anderen Modulen eine eindeutige Identifizierung des Tasks zu ermöglichen (siehe ChangePrio und Mutex) und damit auch dort RAM zu sparen. * Port für Cortex-M3 Luminary LM3S811 hinzugefügt |
1.60c | temporären reg-holder hinzugefügt um bei Ab- und Anschalten der Interrupte innerhalb einer ISR gegen "neested interrupts" geschützt zu sein, wenn dies unerwünscht ist * Port für Cortex-M3 STM32 hinzugefügt |
1.61a | der Memory-Manager arbeitet nun immer MPU-spezifisch aligned |
1.65b | Timer-Service implementiert, dessen Timer periodisch oder run-once laufen können. Einige neue API-Funktionen hinzugefügt |
1.66c | einige Checks im Timer-Service implementiert, OS_TimerGetState() und OS_TimerGetRemain() hinzugefügt |
1.67a | Minimierung des RAM-Bedarfs der prio-tables der IPC-Resourcen (SEM/EVG/MUX/Queue/Pipe/..) * Port für PIC32MX hinzugefügt * Port für MSP430 hinzugefügt |
1.68a | OS_EvgPendAbbort() hinzugefügt * Port für AVR32 hinzugefügt |
1.70b | optionaler Debug Stack-End Check hinzugefügt, Kernel Konfiguration restrukturiert |
1.71a | optionaler Stack-Fill zum Debug Stack-End Check hinzugefügt |
1.80c | einige Fixes in allen ...Abbort() Funktionen, einige zusätzliche Checks für "mutex in use", OS_TaskGetID() und OS_TaskGetStatus() hinzugefügt, mit der neuen Funktion OS_TaskDestroy() können nun Tasks - wartend an einer IPC - auch gelöscht werden, Source-File splitted für besseres Handling * Port für ATMega32 hinzugefügt |
1.81b | durch eine Erweiterung in der optionalen Funktion OS_TaskDestroy() können nun auch Mutex geschützte Recoursen reinitialisiert werden, die selbst eine User-Verwaltung basierend auf der unique Task-ID beinhalten (wie zB. ein FileSystem) |
1.82a | OS_TaskDestroy() umbenannt zu OS_TaskIdDestroy(), OS_TaskGetPrio(), OS_TimeDelayIdResume(), OS_TaskIdDelete(), OS_TaskIdGetStatus(), OS_TaskIdSyspend() und OS_TaskIdResume() hinzugefügt plus einige zusätzliche Checks für prio und/oder id |
1.83a | kleiner fix für OS_TaskIdDestroy() in OSIntExit(), wenn der aktuell laufende Task durch eine ISR zerstrört wird * Port für Cortex-M0 NXP LPC11xx hinzugefügt * Port für Cortex-M3 NXP LPC13xx hinzugefügt * Port für Cortex-M3 NXP LPC17xx hinzugefügt * Port für Cortex-M3 Microchip/Atmel AT91SAM3xxx hinzugefügt |
1.83b | mini fix in OSTCBInit(..) für fehlenden Compiler-Switch |
1.84a | Änderung des Event Parameter in Evengruppen zu Pointer für besseres Handling des OR-modes (mit Event return), kleiner Fix in Pipe für schnellen Daten Prozess-Wechsel * Port für Cortex-M4 ST STM32F4xx hinzugefügt |
1.85b | Korrektur in Evengruppen für mehrere wartenden Tasks an einer gemeinsamen Eventgruppe |
1.86a | OS_ID_SELF hinzugefügt für OS_TaskIdDelete() und OS_TaskGetPrio() * Port für Cortex-M0 Microchip/Atmel SAMD21 hinzugefügt |
1.87b | ein Interrupt oder während der sheduler ausgeschalten ist kann ein Sender nicht den fast-mode bei OS_Pipe...Post verwenden, da die Quelle nicht garantiert werden kann. * Ports für Cortex-M23 und Cortex-M33 (ARMv8M baseline & mainline) hinzugefügt (w/o active TZ support) * Port für Cortex-M3 TI Luminary LM3S9B92 hinzugefügt * Port für Cortex-M0 Nuvoton NUC123 hinzugefügt * Port für Cortex-M0 Freescale MKL25Z128 hinzugefügt * Port für Cortex-M0 Freescale MKL26Z64 hinzugefügt * Port für Cortex-M4 Freescale MK20DX256 hinzugefügt * Port für Cortex-M4 Freescale MK60DN512 hinzugefügt * Port für Cortex-M4 Freescale MK66FX1M hinzugefügt * Port für Cortex-M0 Infineon XMC1100 hinzugefügt * Ports für Cortex-M0..7 ST STM32F0xx..7xx erneuert * Port für RISC-V SiFive FE310 hinzugefügt * Port für ARC-EM von Synopsys hinzugefügt (w/o active SecureShield support) * Port für Cortex-M3 Silicon Labs EFM32 hinzugefügt * Ports für MIPS32 M4K Microchip PIC32MX erneuert * Port für MIPS32 M51xx Microchip PIC32MZ hinzugefügt * Ports für Renesas RX210 & RX62N hinzugefügt * Port für Renesas V850 hinzugefügt * Port für Renesas RL78 hinzugefügt * Ports für Cortex-M23 Microchip/Atmel SAML10 & SAML11 hinzugefügt * Port für Cortex-M4 Microchip/Atmel SAMD51 hinzugefügt * Port für Cortex-M23 Nuvoton M2351 hinzugefügt * Port für Cortex-R4 TI TMS570LS04 hinzugefügt * Port für Cortex-M23 GigaDevices GD32E230K hinzugefügt |
1.88c | die IPC 'Pipe' kann nun auch den Memory-Manager für die interne Message Speicherung verwenden anstatt des fest angelegten Arrays, aber Achtung - dies benötigt zusätzliche Laufzeit und kann in einigen Seiteneffekten resultieren * Port für Cortex-M7 Microchip/Atmel SAMS70 hinzugefügt * Port für Cortex-M4 ST STM32L4xx hinzugefügt * Port für Cortex-M4 Nordic Semiconductor nRF52832 hinzugefügt * Port für powerPC NXP/Freescale MPC57xx hinzugefügt |
1.90b | SmartMessageQueue alternativ zur MessageBox hinzugefügt. Die SmartMessageQueue transferiert Messages als reine Pointer. Wenn der Pointer auf einen allokierten Memory-Block zeigt, so wird die Eigentümerschaft dieses Blocks auch übertragen. Zeigt der Pointer nicht auf einen allokierten Memory-Block so bleibt das Risiko beim Anwender, da ein unspezifischer Pointer direkt übergeben wird. * Port für Cortex-M4F Ambiq Micro Apollo3 hinzugefügt |
1.91c | fix in Memory-Manager für Malloc & Free von Kernel Anforderungen * Port für Cortex-M3 GigaDevices GD32F103 hinzugefügt * Port für RISC-V GigaDevices GD32VF103C hinzugefügt * Port für Cortex-M33 ST STM32L5xx hinzugefügt * Port für Cortex-M33 NXP LPC55S69 hinzugefügt |
1.94b | Task Initialisierung restrukturiert und einige kleine Korrekturen eingepflegt |
1.95c | Dual-Core AMP-Pipe als inter-core messaging Pipe (Inter Core Communication) hinzugefügt. * Port für dual-core Cortex-M7/M4 STM STM32H745 hinzugefügt * Port für dual-core Cortex-M4/M0 NXP LPC4337 hinzugefügt * Port für Cortex-M4 STM STM32G4xx hinzugefügt * Port für PIC32MM hinzugefügt * Port für PIC24FJ hinzugefügt * Port für Cortex-M7 STM STM32H750 hinzugefügt * Port für Cortex-M33 GigaDevice GD32E50x hinzugefügt * Ports für Cortex-M4 GigaDevice GD32F303 & GD32F407 hinzugefügt * Port für Cortex-M4 Artery AT32F403A hinzugefügt * Port für Cortex-M0 STM STM32G0xx hinzugefügt * Ports für RISC-V WCH CH32V103 & CH32V307 hinzugefügt * Port für Cortex-M0 Synwit Tech SWM181 hinzugefügt |
Bei Wartezeiten für "OS_...Post" und "OS_...Pend" -Funktionen ist zu Beachten, daß bei einem Aufruf einer Sender-/Empfängerfunktion aus einer ISR heraus NIE mit einer Wartezeit oder sogar Suspendierung gearbeitet werden darf, da dieses die ISR stoppen würde, und somit nichts mehr läuft. Eine Prüfung dieses Zustandes ist integriert worden.
bekannter Bug:
Wenn ein niederpriorisierter Task auf eine Recource wartet, und ein höherpriorisierter Task diese Recource setzt, so wird der schlafende Task in den Ready-state versetzt. Da der höherpriorisierte Task weiterläuft, darf dieser die selbe Recource nicht wieder auslesen, da ansonsten der niederpriorisierte Task bei Ausführung 'vorzeitig' mit dem Return-Code OS_TIMEOUT zurück kommt.
Dienste des pC/OS Version 1.95c (Kurzform)
Die hier aufgeführte Funktionsübersicht dient einzig als Kurzübersicht.
Für detailierte Informationen sehen Sie bitte in Referenz-Manual zu pC/OS nach.
Task-Control: | Description |
OS_Init | Initialisierung des Kernels |
OS_Start | Beginn der Kernelservices |
OS_TaskCreate | Anlegen eines Tasks |
OS_ChangePrio | Änderung der Priorität des aktiven Tasks |
OS_TaskChangePrio | Änderung der Priorität eines aktiven/ready Tasks |
OS_TaskDelete | Löschen eines aktiven/ready Tasks |
OS_TaskIdDelete | Löschen eines aktiven/ready Tasks via unique ID |
OS_TaskGetStatus | Gibt den aktuellen Status eines Tasks zurück |
OS_TaskIdGetStatus | Gibt den aktuellen Status eines Tasks via unique ID zurück |
OS_TaskGetID | Gibt die unique ID eines Tasks zurück |
OS_TaskGetPrio | Gibt die Priorität eines Tasks zurück |
OS_TaskIdDestroy | Löschen eines Tasks via unique ID, auch wenn dieser an einer IPC wartet oder eine Mutex inne hat & freigeben aller Memory Allokationen |
OS_TaskSuspend | Suspendiert einen Task |
OS_TaskIdSuspend | Suspendiert einen Task via unique ID |
OS_TaskResume | Wiederaufwecken eines suspendierten Tasks |
OS_TaskIdResume | Wiederaufwecken eines suspendierten Tasks via unique ID |
OS_TimeDly | Legt laufenden Task für bestimmte Zeit schlafen |
OS_TimeDlyResume | Wiederaufwecken eines schlafenden Tasks vor Ablauf der eingestellten Zeit |
OS_TimeDlyIdResume | Wiederaufwecken eines schlafenden Tasks via unique ID vor Ablauf der eingestellten Zeit |
OS_Lock | Unterdrücken des Shedulers (keine Taskwechsel) |
OS_Unlock | Wiederzuschaltung des Shedulers (Taskwechsel bei Ereignis oder Zeit) |
OS_GetRev | Gibt Zeiger auf Kernel-Revision zurück |
Semaphores: | Description |
OS_SemInit | Anlegen einer Semaphore |
OS_SemAccept | wartet auf Ereignis und gibt Anzahl zurück |
OS_SemPost | Freigabe einer belegten Semaphore / setzt Ereignis |
OS_SemPend | Belegt eine Semaphore / wartet auf Ereignis |
OS_SemPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Semaphore ab |
OS_SemClear | Löscht Semaphoren-Counter |
Mutexes: | Description |
OS_MutexCreate | Anlegen einer Mutex |
OS_MutexPost | gibt Mutex wieder frei |
OS_MutexPend | Besetzt die Mutex |
OS_MutexPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Mutex ab |
Event-Groups: | Description |
OS_EvgInit | Anlegen einer Eventgruppe |
OS_EvgPost | Setzt ein/mehrere Events einer Evengruppe |
OS_EvgPend | Wartet auf das Eintreffen eines oder mehrere Events einer Eventgruppe |
OS_EvgPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Eventgruppe ab |
Mailboxes: | Description |
OS_MboxInit | Anlegen einer Mailbox |
OS_MboxPost | Sendet Daten an höchstpriorisierten Empfänger dieser Mailbox |
OS_MboxPostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Mailbox ab |
OS_MboxPend | Wartet auf Daten aus einer Mailbox |
OS_MboxPendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Mailbox ab |
Queues: | Description |
OS_QueueInit | Anlegen einer Queue |
OS_QueueInfo | Informationen über eine Queue einholen |
OS_QueuePost | Sendet Daten in eine Queue |
OS_QueueFrontPost | Sendet Daten an den Anfang einer Queue |
OS_QueuePostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Queue ab |
OS_QueuePend | Wartet auf Daten aus einer Queue |
OS_QueuePendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Queue ab |
OS_QueueClear | Löscht alle Daten in einer Queue |
SmartMessageQueue: | Description |
OS_SMQueueInit | Anlegen einer SmartMessageQueue |
OS_SMQueueInfo | Informationen über eine SmartMessageQueue einholen |
OS_SMQueueClear | Löscht alle Messages in einer SmartMessageQueue |
OS_SMQueuePost | Sendet eine Message in eine SmartMessageQueue |
OS_SMQueueFrontPost | Sendet eine Message an den Anfang einer SmartMessageQueue |
OS_SMQueuePostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer SmartMessageQueue ab |
OS_SMQueuePend | Wartet auf eine Message aus einer SmartMessageQueue |
OS_SMQueuePendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer SmartMessageQueue ab |
Pipes: | Description |
OS_PipeInit | Anlegen einer Pipe |
OS_PipeInfo | Informationen über eine Pipe einholen |
OS_PipePost | Sendet Daten in eine Pipe |
OS_PipeFrontPost | Sendet Daten an den Anfang einer Pipe |
OS_PipePostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Pipe ab |
OS_PipePend | Wartet auf Daten aus einer Pipe |
OS_PipePendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Pipe ab |
OS_PipeClear | Löscht alle Daten in einer Pipe |
inter-core AMP-Pipes: | Description |
OS_IccInit | Initialisieren des AMP-Pipe Paares |
OS_IccInfo | Informationen über das AMP-Pipe Paar einholen |
OS_IccPost | Sendet Daten zum anderen Core |
OS_IccPend | Wartet auf Daten vom anderen Core |
OS_IccClear | Löscht alle Daten in der AMP-Pipe hin zum anderen Core |
Timer-Service: | Description |
OS_TimerCreate | Anlegen eines Timers |
OS_TimerDelete | Löschen eines angelegten Timers |
OS_TimerStart | (Re-)Starten eines angelegten Timers |
OS_TimerStop | Stoppen eines angelegten Timers |
OS_TimerGetState | gibt den Status eines angelegten Timers zurück |
OS_TimerGetRemain | gibt die verbleibende Zeit eines laufenden Timers zurück |
System-Ticks: | Description |
OS_TimeSet | Setzt Ticker auf übergebenen Wert |
OS_TimeGet | Gibt aktuellen Ticker-Wert zurück |
Interrupts: | Description |
OS_IntEnter | Registrierung einer aufgerufenen ISR |
OS_IntExit | Ende einer aufgerufenen ISR |
Dynamic-Memory: | Description |
OS_MemoryInit | Erzeugen des Speicherpools |
OS_MemAlloc | Allokieren von Speicher |
OS_MemFree | Freigeben von allokiertem Speicher |
OS_MemFreeSize | Gibt den Freispeicher zurück |
OS_MemVerifyPtr | Prüft, ob Zeiger innerhalb des Speicherpools zeigt |
History: | Description |
OS_HistoryPost | Schreibt Eintrag in History |
OS_HistoryRead | Gibt ersten History-Eintrag und löscht diesen in der Tabelle |
Error-Codes:
Name | Decimal_Value |
OS_SUCCESS / OS_NO_ERR | 0 |
OS_PARAM_ERR | 1 |
OS_TIMEOUT | 10 |
OS_PRIO_EXIST | 11 |
OS_TASK_NOT_EXIST | 12 |
OS_TASK_SUSP_PRIO | 13 |
OS_TASK_NOT_SUSP | 14 |
OS_TASK_NOT_RDY | 15 |
OS_SUSPEND_IDLE | 16 |
OS_PRIO_INVALID | 17 |
OS_TIME_NOT_DLY | 18 |
OS_SEM_ERR | 30 |
OS_SEM_NODATA | 31 |
OS_SEM_OVF | 32 |
OS_MUX_ERR | 40 |
OS_MUX_NOACC | 41 |
OS_MUX_USED | 42 |
OS_MBOX_FULL | 50 |
OS_MBOX_NODATA | 51 |
OS_Q_FULL | 60 |
OS_Q_NODATA | 61 |
OS_Q_CLEAR | 62 |
OS_SMQ_ERR | 70 |
OS_SMQ_FULL | 71 |
OS_SMQ_NODATA | 72 |
OS_SMQ_CLEAR | 73 |
OS_P_FULL | 80 |
OS_P_NODATA | 81 |
OS_P_CLEAR | 82 |
OS_P_LEN_ERR | 83 |
OS_EVG_ERR | 90 |
OS_EVG_NOE | 91 |
OS_TMR_NO_TIME | 110 |
OS_TMR_NOT_EXIST | 111 |
OS_TMR_EXIST | 112 |
OS_MEM_ERR | 120 |
OS_MEM_OVF | 121 |
OS_HIS_END | 130 |
OS_ICC_ERR | 140 |
OS_ICC_NODATA | 141 |
OS_ICC_LEN_ERR | 142 |
OS_ICC_FULL | 143 |
Tip zu ASM-ISR's:
Um Assembler-ISR's im pC/OS manuell zu integrieren, muß bei Einsprung in die ISR folgender Startcode implementiert werden: (Beispiel x86)
und am Ende der ISR: