Lesson 15: Real-Time OS μC/OS-III
About μC/OS Real-Time Operating System
Micriμm's μC/OS (pronounced "Micro C O S") is a preemptive, highly portable, and scalable real-time kernel. μC/OS has three versions:
μC/OS
- Portable
- ROMable
- Very Scalable
- Preemptive Real-Time
- Multitasking Kernel
- Posted over 45 different CPU architecture
- 6 KB ~ 24 KB RTOS Kernel
μC/OS-II
- Can manage up to 250 application tasks
- Provides the following services:
- Semaphores
- Event Flags
- Mutual-exclusion semaphores
- Message mailboxes and queues
- Task management
- Time management
- Timer management
- Fixed-sized memory block management
μC/OS-III
- Included all features in μC/OS-II
- Additional features:
- Allows multiple tasks to run at the same priority level
- Round Robin Scheduling of tasks at equal priority
- Unlimited number of application tasks
- Unlimited number of kernel objects
- Unlimited number of priorities (32~256)
- The low interrupt disable time (near 0)
- Real-time configurable
Licensing
μC/OS-II is provided in source form, and μC/OS-III is a linkable library for a FREE evaluation, educational use, or peaceful research. If you plan on using μC/OS-II or μC/OS-III in a commercial product, you need to contact Micriμm to properly license its use in your product.
Create μC/OS-III Project
- Create a new Project in PSoC Creator.
- Download RTOS_uCOS-III_V3.03.01.zip, and unzip it into the project folder.
- Add RTOS path into the Project
- From the Project menu, select Build Setting...
- Expand the tree under ARM GCC XXXX, and click Compiler
- Add the following directories into the Additional Include Directories item:
.\RTOS; .\RTOS\uC-CPU; .\RTOS\uC-CPU\ARM-Cortex-M3\GNU; .\RTOS\uC-LIB; .\RTOS\uCOS-III\Source; .\RTOS\uCOS-III\Ports\ARM-Cortex-M3\Generic\GNU; .\RTOS\PSoC5\BSP; .\RTOS\PSoC5\BSP\OS\uCOS-III
- Add RTOS Library to the Project
- Expand the tree under ARM GCC XXXX, and click Linker
- Add the following libraries to the Additional Libraries item:
m; :uCOS-III-ARM-Cortex-M3.a
- Add the following directory to the Additional Libraries Directories item:
.\RTOS\PSoC5\LIB
- Create Folders and add RTOS files to your project
- Right-click on the Project in the Workspace Explorer window, then type RTOS as the folder name.
- Select Add ➤ New Folder. Add the following folders under the RTOS folder
- Right-click on the RTOS folder just created, and select Add ➤ Existing Item. Add the following files into the folders as shown as blows:
- Right-click on the Project in the Workspace Explorer window, then type RTOS as the folder name.
- Copy and paste the content from RTOS_main.c into your main.c
- Modify or create the AppTask_xxx based on the project design
- Modify the App_TaskCreate() to create all tasks
Application Code
main.c
The startup code for the compiler will bring the CPU to the main() function, which is the entry point for the application. In the main() function, you need to initialize the operating system, create the primary application task (App_TaskStart() function), begin multitasking.
Listing 1: main.c Code
int main (void) { OS_ERR os_err; BSP_PreInit(); // Perform BSP pre-initialization CPU_Init(); // Initialize the uC/CPU services OSInit(&os_err); // Init uC/OS-III OSTaskCreate((OS_TCB *)&App_TaskStartTCB, // Create the start task (CPU_CHAR *)"Start", (OS_TASK_PTR )App_TaskStart, (void *)0, (OS_PRIO )APP_CFG_TASK_START_PRIO, (CPU_STK *)&App_TaskStartStk[0], (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE_LIMIT, (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE, (OS_MSG_QTY )0u, (OS_TICK )0u, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&os_err); OSStart(&os_err); // Start multitasking (i.e. give control to uC/OS-III) }
- Line 5: BSP_PreInit()
It is a Board Support Package pre-initialization function. This function will perform all the hardware initialization required before the OS is initialized. Most of the time, this function will disable all interrupts to make sure the application does not get interrupted until it is fully initialized. - Line 7: CPU_Init()
Initializes μC/CPU. μC/CPU contains CPU-related code to enable/disable interrupts and enter/exit to/from critical sections, among other functions. - Line 9: OSInit()
Initialize the μC/OS-III. This function must be called before creating a task or any other kernel object. - Line 11: OSTaskCreate()
At least one task must be created. OSTaskCreate() will create the startup task. - Line 25: OSStart()
You need to call this function to let μC/OS-III start the multitasking and give control to μC/OS-III. At this point, there should be either 4 to 6 tasks created depending on configuration option: OS_IdleTask(), OS_TickTask(), OS_StatTask(), OS_TmrTask() (optional), OS_IntQTask() (optional) and now AppTaskStart().
You can create as many tasks as you want before calling OSStart(). However, it is recommended to only create one task, AppTaskStart(). Because having a single application task allows μC/OS-III to determine the relative speed of the CPU. This allows μC/OS-III to calculate the percentage of CPU usage at run-time.
If the application needs other kernel objects, such as semaphores and message queues, then it is recommended that these be created prior to calling OSStart().
Finally, notice that interrupts are not enabled.
Single Task Application
- Line 1: We will be creating an application task, and it is necessary to allocate a task control block (OS_TCB) for this task
- Line 2: Each task created requires its own stack. A stack must be declared using the CPU_STK data type as shown. The stack can be allocated statically, as shown here, or dynamically from the heap using malloc().
Create Other Tasks
The listing below shows how to create other tasks once multitasking has started.
static void App_TaskCreate (void) { OS_ERR err; OSTaskCreate((OS_TCB *)&AppTask1_TCB, (CPU_CHAR *)"App Task 1", (OS_TASK_PTR )AppTask1, (void *)0, (OS_PRIO )5, (CPU_STK *)&AppTask1_Stk[0], (CPU_STK_SIZE )0, (CPU_STK_SIZE )128, (OS_MSG_QTY )0, (OS_TICK )0, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); OSTaskCreate((OS_TCB *)&AppTask2_TCB, (CPU_CHAR *)"App Task 2", (OS_TASK_PTR )AppTask2, (void *)0, (OS_PRIO )6, (CPU_STK *)&AppTask2_Stk[0], (CPU_STK_SIZE )0, (CPU_STK_SIZE )128, (OS_MSG_QTY )0, (OS_TICK )0, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); }
Interrupts in μC/OS-III
In the PSoC Creator, the interrupts are managed by the Interrupt component . To integrate the interrupt with μC/OS-III, the following code must be added to the Interrupt Service Routine (ISR) code.
Cy_ISR( MyISR ) { CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); OSIntEnter(); CPU_CRITICAL_EXIT(); // Your ISR Code Here OSIntExit(); }
- Line 3: CPU_SR_ALLOC()
This function allocates storage for a local variable to hold the value of the current interrupt disable status of the CPU. - Line 5: OSIntEnter()
Notify μC/OS-III that an ISR is being processed, which allows μC/OS-III to keep track of interrupt nesting. - Line 10: OSIntExit()
Notify μC/OS-III that the ISR is complete, which allows μC/OS-III to keep track of track of interrupt nesting. When the last nested interrupt completes OSIntExit() determines if a higher priority task is ready to run. If so, the interrupt return to the higher priority task instead of the interrupt task.