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.



pCOS_195c.zip
download pC/OS 1.95c (as ZIP)


Releases:

1.00aMessagebox und Queue geändert sowie Pipe, Eventgroup und dyn. Memorymanagement hinzugefügt.
* Port für Am188ES erstellt
1.00bRevision-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.00cBeschleunigung 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.00dkorrekte Implemenierung "timeout" in OS_...Post-Funktionen und OS_QueueClear hinzugefügt.
1.00eAnpassung der Task-Initialisierung und einiger Parameter zur Nutzung der µC/OS-I Port's.
OS_QueueInfo und OS_PipeInfo hinzugefügt.
1.00fBugfix innerhalb der Event-Gruppen.
OS_SemAccept hinzugefügt.
1.00gDual-Source für MSC-8.00 und Keil-C51 generiert. OS_CFG implementiert. Bugfix in Semaphoren.
* Port für 8051 hinzugefügt
1.00hMUTEXes 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.40aName auf pC/OS geändert und Revisionsnummer überarbeitet, einige C-fixes.
* Port für ATMega128 hinzugefügt
* Port für AT91SAM7Sxx hinzugefügt
1.41aImplementation von OS_STK_TYPE für Prozessor-konformen Stack incl. Update aller bisherigen Ports.
Keil-Variante des AT91SAM7Sxx-Ports (instabil) hinzugefügt
1.50cKomplettes 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.52bSplit 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.60ctemporä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.61ader Memory-Manager arbeitet nun immer MPU-spezifisch aligned
1.65bTimer-Service implementiert, dessen Timer periodisch oder run-once laufen können.
Einige neue API-Funktionen hinzugefügt
1.66ceinige Checks im Timer-Service implementiert, OS_TimerGetState() und OS_TimerGetRemain() hinzugefügt
1.67aMinimierung 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.68aOS_EvgPendAbbort() hinzugefügt
* Port für AVR32 hinzugefügt
1.70boptionaler Debug Stack-End Check hinzugefügt, Kernel Konfiguration restrukturiert
1.71aoptionaler Stack-Fill zum Debug Stack-End Check hinzugefügt
1.80ceinige 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.81bdurch 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.82aOS_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.83akleiner 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.83bmini 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.85bKorrektur in Evengruppen für mehrere wartenden Tasks an einer gemeinsamen Eventgruppe
1.86aOS_ID_SELF hinzugefügt für OS_TaskIdDelete() und OS_TaskGetPrio()
* Port für Cortex-M0 Microchip/Atmel SAMD21 hinzugefügt
1.87bein 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.88cdie 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.90bSmartMessageQueue 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.91cfix 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.94bTask Initialisierung restrukturiert und einige kleine Korrekturen eingepflegt
1.95cDual-Core AMP-Pipe als inter-core messaging Pipe (Inter Core Communication) hinzugefügt.
* Port für dual-core Cortex-M7/M4 STM ST32H745 hinzugefügt
* Port für dual-core Cortex-M4/M0 NXP LPC4337 hinzugefügt
* Port für Cortex-M4 ST STM32G4xx hinzugefügt
* Port für PIC32MM hinzugefügt
* Port für PIC24FJ hinzugefügt
* Port für Cortex-M7 STM ST32H750 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_InitInitialisierung des Kernels
OS_StartBeginn der Kernelservices
OS_TaskCreateAnlegen eines Tasks
OS_ChangePrioÄnderung der Priorität des aktiven Tasks
OS_TaskChangePrioÄnderung der Priorität eines aktiven/ready Tasks
OS_TaskDeleteLöschen eines aktiven/ready Tasks
OS_TaskIdDeleteLöschen eines aktiven/ready Tasks via unique ID
OS_TaskGetStatusGibt den aktuellen Status eines Tasks zurück
OS_TaskIdGetStatusGibt den aktuellen Status eines Tasks via unique ID zurück
OS_TaskGetIDGibt die unique ID eines Tasks zurück
OS_TaskGetPrioGibt die Priorität eines Tasks zurück
OS_TaskIdDestroyLöschen eines Tasks via unique ID, auch wenn dieser an einer IPC wartet oder eine Mutex inne hat & freigeben aller Memory Allokationen
OS_TaskSuspendSuspendiert einen Task
OS_TaskIdSuspendSuspendiert einen Task via unique ID
OS_TaskResumeWiederaufwecken eines suspendierten Tasks
OS_TaskIdResumeWiederaufwecken eines suspendierten Tasks via unique ID
OS_TimeDlyLegt laufenden Task für bestimmte Zeit schlafen
OS_TimeDlyResumeWiederaufwecken eines schlafenden Tasks vor Ablauf der eingestellten Zeit
OS_TimeDlyIdResumeWiederaufwecken eines schlafenden Tasks via unique ID vor Ablauf der eingestellten Zeit
OS_LockUnterdrücken des Shedulers (keine Taskwechsel)
OS_UnlockWiederzuschaltung des Shedulers (Taskwechsel bei Ereignis oder Zeit)
OS_GetRevGibt Zeiger auf Kernel-Revision zurück



Semaphores:Description
OS_SemInitAnlegen einer Semaphore
OS_SemAcceptwartet auf Ereignis und gibt Anzahl zurück
OS_SemPostFreigabe einer belegten Semaphore / setzt Ereignis
OS_SemPendBelegt eine Semaphore / wartet auf Ereignis
OS_SemPendAbbortBricht Warten eines Tasks (höchste wartende Prio) an einer Semaphore ab
OS_SemClearLöscht Semaphoren-Counter



Mutexes:Description
OS_MutexCreateAnlegen einer Mutex
OS_MutexPostgibt Mutex wieder frei
OS_MutexPendBesetzt die Mutex
OS_MutexPendAbbortBricht Warten eines Tasks (höchste wartende Prio) an einer Mutex ab



Event-Groups:Description
OS_EvgInitAnlegen einer Eventgruppe
OS_EvgPostSetzt ein/mehrere Events einer Evengruppe
OS_EvgPendWartet auf das Eintreffen eines oder mehrere Events einer Eventgruppe
OS_EvgPendAbbortBricht Warten eines Tasks (höchste wartende Prio) an einer Eventgruppe ab



Mailboxes:Description
OS_MboxInitAnlegen einer Mailbox
OS_MboxPostSendet Daten an höchstpriorisierten Empfänger dieser Mailbox
OS_MboxPostAbbortBricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Mailbox ab
OS_MboxPendWartet auf Daten aus einer Mailbox
OS_MboxPendAbbortBricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Mailbox ab



Queues:Description
OS_QueueInitAnlegen einer Queue
OS_QueueInfoInformationen über eine Queue einholen
OS_QueuePostSendet Daten in eine Queue
OS_QueueFrontPostSendet Daten an den Anfang einer Queue
OS_QueuePostAbbortBricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Queue ab
OS_QueuePendWartet auf Daten aus einer Queue
OS_QueuePendAbbortBricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Queue ab
OS_QueueClearLöscht alle Daten in einer Queue



SmartMessageQueue:Description
OS_SMQueueInitAnlegen einer SmartMessageQueue
OS_SMQueueInfoInformationen über eine SmartMessageQueue einholen
OS_SMQueueClearLöscht alle Messages in einer SmartMessageQueue
OS_SMQueuePostSendet eine Message in eine SmartMessageQueue
OS_SMQueueFrontPostSendet eine Message an den Anfang einer SmartMessageQueue
OS_SMQueuePostAbbortBricht Warten eines sendenden Tasks (höchste wartende Prio) an einer SmartMessageQueue ab
OS_SMQueuePendWartet auf eine Message aus einer SmartMessageQueue
OS_SMQueuePendAbbortBricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer SmartMessageQueue ab



Pipes:Description
OS_PipeInitAnlegen einer Pipe
OS_PipeInfoInformationen über eine Pipe einholen
OS_PipePostSendet Daten in eine Pipe
OS_PipeFrontPostSendet Daten an den Anfang einer Pipe
OS_PipePostAbbortBricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Pipe ab
OS_PipePendWartet auf Daten aus einer Pipe
OS_PipePendAbbortBricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Pipe ab
OS_PipeClearLöscht alle Daten in einer Pipe



inter-core AMP-Pipes:Description
OS_IccInitInitialisieren des AMP-Pipe Paares
OS_IccInfoInformationen über das AMP-Pipe Paar einholen
OS_IccPostSendet Daten zum anderen Core
OS_IccPendWartet auf Daten vom anderen Core
OS_IccClearLöscht alle Daten in der AMP-Pipe hin zum anderen Core



Timer-Service:Description
OS_TimerCreateAnlegen eines Timers
OS_TimerDeleteLöschen eines angelegten Timers
OS_TimerStart(Re-)Starten eines angelegten Timers
OS_TimerStopStoppen eines angelegten Timers
OS_TimerGetStategibt den Status eines angelegten Timers zurück
OS_TimerGetRemaingibt die verbleibende Zeit eines laufenden Timers zurück



System-Ticks:Description
OS_TimeSetSetzt Ticker auf übergebenen Wert
OS_TimeGetGibt aktuellen Ticker-Wert zurück



Interrupts:Description
OS_IntEnterRegistrierung einer aufgerufenen ISR
OS_IntExitEnde einer aufgerufenen ISR



Dynamic-Memory:Description
OS_MemoryInitErzeugen des Speicherpools
OS_MemAllocAllokieren von Speicher
OS_MemFreeFreigeben von allokiertem Speicher
OS_MemFreeSizeGibt den Freispeicher zurück
OS_MemVerifyPtrPrüft, ob Zeiger innerhalb des Speicherpools zeigt



History:Description
OS_HistoryPostSchreibt Eintrag in History
OS_HistoryReadGibt 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)

EXTRN C OSIntEnter : NEAR EXTRN C OSIntExit : NEAR ... ISR: pusha ; save all used register push es call OSIntEnter ; C-function to register INT-level ...

und am Ende der ISR:

... call OSIntExit ; C-function to unregister INT-Level ; and perform a context-switch is needed pop es ; restore all used register popa iret ; return