Getting Started with Micriμm’s μC/OS-III Kernel
Renesas Technology & Solution Portfolio In the session 110C, Renesas Next Generation Microcontroller and Microprocessor Technology Roadmap, Ritesh Tyagi introduces this high level image of where the Renesas Products fit. The big picture. <Click> NOTE For Reviewer, the below notes are from the 110C presentation so you can better understand this slide ___________________________________________________________________________________________________________________________________ The wealth of technology you see here is a direct result of the fact that Renesas Electronics Corporation was formed on April 1, 2010 as a joint venture between Renesas Technology and NEC Electronics — Renesas Technology having been launched seven years ago by Hitachi, Ltd. and Mitsubishi Electric Corporation. There are four major areas where Renesas offers distinct technology advantage. --The Microcontrollers and Microprocessors are the back bone of the new company. Renesas is the undisputed leader in this area with 31% of W/W market share. --We do have a rich portfolio of Analog and power devices. Renesas has the #1 market share in low voltage MOSFET solutions. --We have a rich portfolio of ASIC solution with an advanced 90nm, 65nm, 40nm and 28nm processes. The key solutions are for the Smart Grid, Integrated Power Management and Networking --ASSP: Industry leader for USB 2.0 and USB 3.0. Solutions for the cell phone market -- Memory: #1 in the Networking Memory market Company Logo HERE
Agenda Introduction Lab 1 Foreground/Background Systems Kernel-Based Applications Initiating Multitasking Lab 2 Scheduling and Context Switches Lab 3 Additional Kernel Services Lab 4 Conclusion
Introduction
Class Objectives Understand what services a real-time kernel provides Learn how to make use of kernel services Learn how kernels are implemented Gain experience with an actual kernel
Labs Based on µC/OS-III Real-time kernel from Micriµm Concepts underlying the labs are not µC/OS-III-specific Step-by-step instructions are provided for each lab
A µC/OS-III-Based Application Application Code Micriµm’s Modules (Portable Code) Micriµm’s Modules (Hardware-Specific Code) Hardware
A µC/OS-III-Based Application (Cont.) Application Code µC/OS-III µC/CPU µC/LIB µC/OS-III µC/CPU BSP Hardware
Directory Structure Workspace files
e2 Studio IDE supporting Renesas MCUs Based on Eclipse A variety of debugging features
Lab 1
Lab 1 Summary The kernel is built alongside application code A kernel-based application looks much like any other C program Application code interacts with the kernel through API functions
Foreground/Background Systems
A Foreground/Background Example int main (void) { Perform initializations; while (1) { ADC_Read(); SPI_Read(); USB_Packet(); LCD_Update(); Audio_Decode(); File_Write(); } void USB_ISR (void) { Clear interrupt; Read packet; }
Foreground/Background Benefits No upfront cost Minimal training required Developers don’t need to learn a kernel’s API No need to set aside memory resources to accommodate a kernel There is a small amount of overhead associated with a kernel
Foreground/Background Drawbacks Difficult to ensure that each operation will meet its deadline All code in the background essentially has the same importance, or priority while (1) { ADC_Read(); SPI_Read(); USB_Packet(); Service other devices; } void ADC_Read (void) { Initialize ADC; while (conv_rdy == 0) { ; } Process converted value; Potential to delay entire application
Foreground/Background Drawbacks (Cont.) High-priority code must be placed in the foreground (in an ISR) Lengthy ISRs can negatively impact system responsiveness while (1) { ADC_Read(); SPI_Read(); USB_Packet(); LCD_Update(); Audio_Decode(); File_Write(); } void USB_ISR (void) { Clear interrupt; Read packet; } If a USB packet is received immediately after this function returns, the response time will be lengthy.
Foreground/Background Drawbacks (Cont.) Problems with multiple developers Developers’ efforts must be closely coordinated Difficult expansion, even with one developer Changes to one portion of the application may negatively impact the remainder of the code
Kernel-Based Applications
A Kernel-Based Example Tasks ISRs void AppTaskADC (void *p_arg) { while (1) { ADC_Read(); Sleep for 1 ms; } void AppTaskUSB (void *p_arg) Wait for signal from ISR; USB_Packet(); void AppISRUSB (void) { Clear interrupt; Signal USB Task; }
Kernel Basics Application is divided into tasks Kernel shares CPU amongst tasks Developer may assign importance, or priority, to each task
Template Task static void AppTaskExample (void *p_arg) { Perform initializations; while (1) { Work toward task’s goals; }
Initiating Multitasking
Initializing and Starting the Kernel Application code must initialize the kernel µC/OS-III is typically initialized in main() Initialization accomplished through kernel API functions
OSInit() Must be invoked before any kernel services are used Initializes data structures Creates internal tasks Number of tasks depends on configuration
µC/OS-III Internal Tasks Always present Idle Task Automatically given lowest priority Tick Task Synchronized with a periodic interrupt Allows µC/OS-III to provide time delays Optional Statistics Task Monitors resource usage ISR Handler Task Facilitates deferred interrupt scheme Timer Task Manages software timers
Creating a Task void OSTaskCreate (OS_TCB *p_tcb, CPU_CHAR *p_name, OS_TASK_PTR p_task, void *p_arg, OS_PRIO prio, CPU_STK *p_stk_base, CPU_STK *p_stk_limit, OS_STK_SIZE stk_size, OS_MSG_QTY q_size, OS_TICK time_quanta, void *p_ext, OS_OPT opt, OS_ERR *p_err); The task itself The task’s priority A pointer to the task’s stack
A Task Control Block (TCB) Contains information on the task’s status StkPtr ExtPtr StkLimitPtr NextPtr 23 - 51 fields PrevPtr
Stacks Each task has a stack Context is stored on stacks Stack growth conventions vary across platforms Higher memory addresses PSW (0x00010000) PC (p_task) R15 (0x15151515) R14 (0x14141414) R13 (0x13131313) R12 (0x12121212) R11 (0x11111111) R10 (0x10101010) R9 (0x09090909) R8 (0x08080808) R7 (0x07070707) R6 (0x06060606) R5 (0x05050505) R4 (0x04040404) R3 (0x03030303) R2 (0x02020202) p_stk R1 (p_arg) Lower memory addresses
OSStart() Runs highest priority task Initializes CPU registers Should be the last function called from main()
Lab 2
Lab 2 Summary Application code creates tasks by calling kernel API functions Each task has its own stack A priority must be assigned to each task
Scheduling and Context Switches
Two Types of Multitasking Scheduling differs from kernel to kernel There are two common approaches to scheduling multiple tasks Cooperative scheduling Preemptive scheduling
Cooperative Scheduling Interrupt signals the availability of Task A’s data ISR Task A Task A cannot run until Task B completes Task B Time
Preemptive Scheduling Interrupt signals the availability of the high-priority task’s data ISR The high-priority task is scheduled by the kernel High-Priority Task Low-Priority Task Time
Round-Robin Scheduling Task A Task B Task C Time Quantum Time
Scheduling in µC/OS-III µC/OS-III is preemptive Finds highest-priority, ready task Scheduling can be optimized Assembly language, tables Round-robin scheduling is performed only when enabled
OSTCBCurPtr->StkPtr Context Switch Switch from Task A to Task B Load new stack pointer Pop registers from stack Update kernel variables Save stack pointer Push registers onto stack OSPrioCur OSTCBCurPtr->StkPtr OSTCBCurPtr PSW R0 (SP) PSW PC PC R1 R1 R1 R2 R2 R2 R3 R3 R3 R4 R4 R4 R5 R5 R5 R6 R6 R6 PSW R7 R7 R7 PC R8 R8 R8 R9 R9 R9 R10 R10 R10 R11 R11 R11 R12 R12 R12 R13 R13 R13 R14 R14 R14 R15 R15 R15 Task A’s stack Task B’s stack
Interrupts In a preemptive kernel, interrupt handlers are capable of triggering context switches ExampleISR: Save CPU registers; OSIntEnter(); AppISR(); OSIntExit(); Restore CPU registers; Return from interrupt; void AppISR (void) { /* Clear interrupt */ /* Signal task */ } Determine whether a context switch is needed
The Tick Interrupt Most kernels keep track of time via a periodic interrupt, often called a “tick” A kernel can use its tick interrupt to implement a number of useful features: Time delays Software timers Timeouts for blocking API functions
Time Delays void OSTimeDly (OS_TICK dly, OS_OPT opt, OS_ERR *p_err); void OSTimeDlyHMSM (CPU_INT16U hours, CPU_INT16U minutes, CPU_INT16U seconds, CPU_INT32U milli,
Lab 3
Lab 3 Summary Most µC/OS-III ISRs are written at least partially in assembly language ISRs must perform a few kernel-specific operations An interrupt can be set up with a fairly small amount of code
Additional Kernel Services
Beyond Task Management A kernel does more than just switch between tasks Synchronization Inter-task communication Resource protection
Synchronization Can be thought of as signaling Tasks can be signaled by ISRs or other tasks While one tasks waits for a signal, the kernel runs other tasks
Semaphores A means of synchronization Based on a counter Counter value indicates whether or not an event has occurred Two basic operations Pend: wait for event Post: signal occurrence of event
Semaphore API void OSSemCreate (OS_SEM *p_sem, CPU_CHAR *p_name, OS_SEM_CTR cnt, OS_ERR *p_err); OS_SEM_CTR OSSemPend (OS_SEM *p_sem, OS_TICK timeout, OS_OPT opt, CPU_TS *p_ts, OS_SEM_CTR OSSemPost (OS_SEM *p_sem,
Semaphore Example Statistics Task Display Task OS_SEM AppSemDisp; /* Initialization Code */ OSSemCreate((OS_SEM *)&AppSemDisp, (CPU_CHAR *)”Disp Sem”, (OS_SEM_CTR)0, (OS_ERR *)&err); void AppTaskStat (void *p_arg) { Perform initializations; while (1) { Read signals; Calculate statistics; OSSemPost((OS_SEM *)&AppSemDisp, (OS_OPT )OS_OPT_POST_1, (OS_ERR *)&err); Delay for 5 ms; } Statistics Task Display Task void AppTaskDisp (void *p_arg) { while (1) { OSSemPend((OS_SEM *)&AppSemDisp, (OS_TICK )100, (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err); Update display; }
Task Semaphores An alternative to standard semaphores in µC/OS-III Lower overhead Type SemCtr NamePtr TCB SemPendTime OS_SEM PendList SemPendTimeMax Ctr TS
Event Flags Another means of synchronization Each event represented by a bit Pend and post operations Pend for multiple events
Event Flag API void OSFlagCreate (OS_FLAG_GRP *p_grp, CPU_CHAR *p_name, OS_FLAGS flags, OS_ERR *p_err); OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp, OS_TICK timeout, OS_OPT opt, CPU_TS *p_ts, OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp,
Shared Resources Peripheral devices, buffer pools, or simple global variables Accessed by more than one task or by at least one task and one ISR Can cause race conditions
Shared Resource Example void AppTaskUART (void *p_arg) { Perform initializations; while (1) { Write message to UART; Delay for 1s; } void AppTaskFS (void *p_arg) { Perform initializations; while (1) { Read file; Write status to UART; }
Protecting Shared Resources Disabling and enabling interrupts Locking and unlocking the scheduler Semaphores Mutexes
Mutexes Implemented much like semaphores Manipulated through pend and post functions Offer protection against priority inversion
Mutex API void OSMutexCreate (OS_MUTEX *p_mutex, CPU_CHAR *p_name, OS_ERR *p_err); void OSMutexPend (OS_MUTEX *p_mutex, OS_TICK timeout, OS_OPT opt, CPU_TS *p_ts, void OSMutexPost (OS_MUTEX *p_mutex,
Mutex Example Pressure Task Error Task OS_MUTEX AppMutexSD; /* Initialization Code */ OSMutexCreate((OS_MUTEX *)&AppMutexSD, (CPU_CHAR *)”SDCard Mutex”, (OS_ERR *)&err); void AppTaskError (void *p_arg) { while (1) { Check for errors; OSMutexPend((OS_MUTEX *)&AppMutexSD, (OS_TICK )50, (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err); Write errors to SD card; OSMutexPost((OS_MUTEX *)&AppMutexSD, (OS_OPT )OS_OPT_POST_NONE, } void AppTaskPressure (void *p_arg) { while (1) { Read pressure; OSMutexPend((OS_MUTEX *)&AppMutexSD, (OS_TICK )50, (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err); Write pressure to SD card; OSMutexPost((OS_MUTEX *)&AppMutexSD, (OS_OPT )OS_OPT_POST_NONE, } Pressure Task Error Task
Inter-Task Communication Sending and receiving messages Tasks can send or receive ISRs can send Messages stored in a queue managed by the kernel While one task waits for a message, other tasks run
Message Queue API void OSQCreate (OS_Q *p_q, CPU_CHAR *p_name, OS_MSG_QTY max_qty, OS_ERR *p_err); void *OSQPend (OS_Q *p_q, OS_TICK timeout, OS_OPT opt, OS_MSG_SIZE *p_msg_size, CPU_TS *p_ts, void OSQPost (OS_Q *p_q, void *p_void, OS_MSG_SIZE msg_size,
Message Queue Example ADC Task ISR ADC OS_Q AppQADC; /* Initialization Code */ OSQCreate((OS_Q *)&AppQADC, (CPU_CHAR *)”ADC Queue”, (OS_MSG_QTY)20, (OS_ERR *)&err); ADC Task ISR void AppISRADC (void) { Read new value; Clear ADC interrupt; OSQPost((OS_Q *)&AppQADC, (void *)adc_val, (OS_MSG_SIZE)msg_size, (OS_OPT )OS_OPT_POST_FIFO, (OS_ERR *)&err); } void AppTaskADC (void *p_arg) { while (1) { adc_val = (CPU_INT32U)OSQPend((OS_Q *)&AppQADC, (OS_TICK )0, (OS_OPT )OS_OPT_PEND_BLOCKING, (OS_MSG_SIZE *)&msg_size, (CPU_TS *)&ts, (OS_ERR *)&err); Process value; } ADC Note that it is possible to use queues for resource protection: a single task manages a particular I/O device and receives requests to manipulate that device from other tasks via a queue.
Task Message Queue Message queue included in TCB Less overhead than standard message queue Can be used whenever only one task will be receiving messages
Additional Services Multi-pend Dynamic memory allocation Timers Pend on multiple queues and semaphores Dynamic memory allocation Timers One-shot and periodic software timers with callbacks
Lab 4
Lab 4 Summary In general, it is desirable to keep interrupt handlers as short as possible Using semaphores, interrupt handlers can signal tasks The two primary semaphore operations are pend and post
Conclusion
Summary Today we discussed… The differences between foreground/background systems and kernel-based applications How a kernel is initialized The contents of a task How a kernel schedules tasks
Summary (Cont.) Today we discussed… What happens during a context switch The structure of ISRs in kernel-based applications Synchronization, mutual exclusion, and inter-task communication services
Questions? Company Logo HERE