Download presentation
Presentation is loading. Please wait.
1
國立台灣大學 資訊工程學系 Introduction to uC/OS-II http://www.micrium.com/
2
資工系網媒所 NEWS 實驗室 11:01 /271 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
3
資工系網媒所 NEWS 實驗室 11:01 /272 Real-Time Systems Concepts Multitasking Kernel Scheduling Mutual Exclusion Message Passing Interrupt
4
資工系網媒所 NEWS 實驗室 11:01 /273 Foreground/Background Systems Task Level Interrupt Level
5
資工系網媒所 NEWS 實驗室 11:01 /274 Multitasking A process of scheduling and switching CPU between several tasks. Related issues Context Switch (Task Switch) Resource Sharing Critical Section
6
資工系網媒所 NEWS 實驗室 11:01 /275 Multitasking
7
資工系網媒所 NEWS 實驗室 11:01 /276 Task A task, or called a thread, a simple program that thinks it has the CPU all to itself. Each task is assigned a priority, its own set of CPU registers, and its own stack area. Each task typically is an infinite loop that can be in any one of five states. Ready, Running, Waiting, ISR, Dormant
8
資工系網媒所 NEWS 實驗室 11:01 /277 Task States
9
資工系網媒所 NEWS 實驗室 11:01 /278 Kernel Kernel is the part of a multitasking system responsible for the management of tasks. Context switching is the fundamental service of a kernel. Non-Preemptive Kernel v.s. Preemptive Kernel
10
資工系網媒所 NEWS 實驗室 11:01 /279 Non-Preemptive Kernel Cooperative multitasking A non-preemptive kernel allows each task to run until it voluntarily gives up control of the CPU. An ISR can make a higher priority task ready to run, but the ISR always returns to the interrupted task. Linux 2.4 is non-preemptive. Linux 2.6 is preemptive.
11
資工系網媒所 NEWS 實驗室 11:01 /2710 Non-Preemptive Kernel
12
資工系網媒所 NEWS 實驗室 11:01 /2711 Preemptive Kernel A preemptive kernel always executes the highest priority task that is ready to run. µC/OS-II and most commercial real-time kernels are preemptive. Much better response time. Should not use non-reentrant functions, unless the functions are mutual exclusive.
13
資工系網媒所 NEWS 實驗室 11:01 /2712 Preemptive Kernel
14
資工系網媒所 NEWS 實驗室 11:01 /2713 Function Reentrancy A reentrant function is a function that can be used by more than one task without fear of data corruption. Reentrant functions either use local variables or protected global variables. OS_ENTER_CRITICAL() OS_EXIT_CRITICAL()
15
資工系網媒所 NEWS 實驗室 11:01 /2714 Function Reentrancy Non-Reentrant Function static static int Temp; void swap(int *x, int *y) { Temp = *x; *x = *y; *y = Temp; } Reentrant Function void strcpy(char *dest, char *src) { while (*dest++ = *src++) { ; } *dest = NULL; }
16
資工系網媒所 NEWS 實驗室 11:01 /2715 Scheduling Round-Robin Scheduling Tasks executed sequentially Task Priority Assignment Static priority Rate Monotonic (RM) Dynamic priority Earliest-Deadline First (EDF) Time-Driven Scheduling Pinwheel
17
資工系網媒所 NEWS 實驗室 11:01 /2716 Round-Robin Kernel gives control to next task if the current task has no work to do completes reaches the end of time-slice Not supported in uC/OS-II O(1) priority preemptive scheduling
18
資工系網媒所 NEWS 實驗室 11:01 /2717 Priority Inversion Problem
19
資工系網媒所 NEWS 實驗室 11:01 /2718 Priority Inheritance
20
資工系網媒所 NEWS 實驗室 11:01 /2719 Mutual Exclusion Protected shared data of processes. Exclusive access implementation Disabling and enabling interrupts Test-and-Set Disabling and enabling scheduler Semaphores Simple Semaphore Counting Semaphore Deadlock – set timeout for a semaphore
21
資工系網媒所 NEWS 實驗室 11:01 /2720 Using Semaphore
22
資工系網媒所 NEWS 實驗室 11:01 /2721 Synchronization Synchronization mechanism is used between tasks or task to ISR. Unilateral rendezvous Bilateral rendezvous
23
資工系網媒所 NEWS 實驗室 11:01 /2722 Unilateral rendezvous
24
資工系網媒所 NEWS 實驗室 11:01 /2723 Bilateral rendezvous
25
資工系網媒所 NEWS 實驗室 11:01 /2724 Event Flags
26
資工系網媒所 NEWS 實驗室 11:01 /2725 Message Passing Intertask Communication Using global variables or sending messages Only communicate to ISR through global variables Tasks are not aware when the global variables is changed unless task polls the content.
27
資工系網媒所 NEWS 實驗室 11:01 /2726 Message Mailboxes A Message Mailbox, also called a message exchange, is typically a pointer size variable. Operations Initial POST PEND necessary to wait for the message being deposited ACCEPT Acknowledgement
28
資工系網媒所 NEWS 實驗室 11:01 /2727 Message Queues A message queue is used to send one or more messages to a task. A message queue is an array of message mailboxes. Generally, FIFO is used. µC/OS-II allows a task to get messages Last-In-First-Out (LIFO).
29
資工系網媒所 NEWS 實驗室 11:01 /2728 Interrupt An interrupt is a hardware mechanism used to inform the CPU that an asynchronous event has occurred. Interrupt Latency Interrupt Response Interrupt Recovery
30
資工系網媒所 NEWS 實驗室 11:01 /2729 Interrupt Nesting
31
資工系網媒所 NEWS 實驗室 11:01 /2730 Interrupt Latency Disabling interrupts affects interrupt latency. All real-time systems disable interrupts to manipulate critical sections of code. Re-enable interrupts when the critical section has executed. Interrupt latency = Maximum time to disable interrupts + Time to start the first instruction in ISR.
32
資工系網媒所 NEWS 實驗室 11:01 /2731 Interrupt Response Interrupt Response means time between the reception of the interrupt and the start of the user code which will handle the interrupt. Interrupt response = Interrupt latency + Time to save CPU context The worst case for interrupt response is adopted.
33
資工系網媒所 NEWS 實驗室 11:01 /2732 Interrupt Recovery Interrupt recovery is defined as the time required for the processor to return to the interrupted code. Interrupt recovery = Time to determine if a high priority task is ready + Time to restore the CPU context of the highest priority task + time of executing return- from-interrupt.
34
資工系網媒所 NEWS 實驗室 11:01 /2733 Non-preemptive Kernel
35
資工系網媒所 NEWS 實驗室 11:01 /2734 Preemptive Kernel
36
資工系網媒所 NEWS 實驗室 11:01 /2735 Non-Maskable Interrupts (NMIs) Service the most important time-critical ISR Can not be disabled Interrupt latency = Time to execution the longest instruction + Time to start execution the NMI ISR Interrupt response = Interrupt latency + Time to save CPU context Interrupt recovery = Time to restore CPU context + time of executing return-from- interrupt
37
資工系網媒所 NEWS 實驗室 11:01 /2736 Clock Tick A periodical interrupt Be viewed as heartbeat Application specific and is generally between 10ms and 200ms Faster timer causes higher overhead Delay problem should be considered in real-time kernel.
38
資工系網媒所 NEWS 實驗室 11:01 /2737 Delaying a Task for 1 Tick Tick Interrupt Tick ISR All higher priority tasks Delayed Task t1 t2 t3 20 mS (6 mS) (19 mS) (27 mS) Call to delay 1 tick (20 mS)
39
資工系網媒所 NEWS 實驗室 11:01 /2738 Clock Tick Solve the problem Increase the clock rate of your microprocessor. Increase the time between tick interrupts. Rearrange task priorities. Avoid using floating-point math. Get a compiler that performs better code optimization. Write time-critical code in assembly language. If possible, upgrade to a faster microprocessor in the same family.
40
資工系網媒所 NEWS 實驗室 11:01 /2739 Memory Requirement Be careful to avoid large RAM requirement Large local arrays Nested/Recursive function Interrupt nesting Stack used by libraries Too many function arguments
41
資工系網媒所 NEWS 實驗室 11:01 /2740 Real-Time Kernels Real-time OS allows real-time application to be designed and expanded easily. The use of an RTOS simplifies the design process by splitting the application into separate tasks. Real-time kernel requires more ROM/RAM and 2 to 4 percent overhead.
42
資工系網媒所 NEWS 實驗室 11:01 /2741 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
43
資工系網媒所 NEWS 實驗室 11:01 /2742 Kernel Structure Task Control Blocks Ready List Task Scheduling Interrupt under uC/OS-II
44
資工系網媒所 NEWS 實驗室 11:01 /2743 Critical Sections Archive this by disabling interrupt OS_CPU.H OS_ENTER_CRITICAL() OS_EXIT_CRITICAL()
45
資工系網媒所 NEWS 實驗室 11:01 /2744 Tasks Up to 64 tasks Two tasks for system use(idle and statistic) Priorities 0, 1, 2, 3, OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO for future use The lower the priority number, the higher the priority of the task. The task priority is also the task identifier.
46
資工系網媒所 NEWS 實驗室 11:01 /2745 Task States
47
資工系網媒所 NEWS 實驗室 11:01 /2746 Task Control Blocks typedef struct os_tcb { OS_STK *OSTCBStkPtr; #if OS_TASK_CREATE_EXT_EN void *OSTCBExtPtr; OS_STK *OSTCBStkBottom; INT32U OSTCBStkSize; INT16U OSTCBOpt; INT16U OSTCBId; #endif struct os_tcb *OSTCBNext; struct os_tcb *OSTCBPrev; #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN OS_EVENT *OSTCBEventPtr; #endif #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN void *OSTCBMsg; #endif INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; #if OS_TASK_DEL_EN BOOLEAN OSTCBDelReq; #endif } OS_TCB;
48
資工系網媒所 NEWS 實驗室 11:01 /2747 OS_TCB Lists TCBs store in OSTCBTbl[] All TCBs are initialized and linked when uC/OS-II is initialized
49
資工系網媒所 NEWS 實驗室 11:01 /2748 Ready List
50
資工系網媒所 NEWS 實驗室 11:01 /2749 OSRdyGrp and OSRdyTbl[] Bit 0 in OSRdyGrp is 1 when any bit in OSRdyTbl[0] is 1. Bit 1 in OSRdyGrp is 1 when any bit in OSRdyTbl[1] is 1. Bit 2 in OSRdyGrp is 1 when any bit in OSRdyTbl[2] is 1. Bit 3 in OSRdyGrp is 1 when any bit in OSRdyTbl[3] is 1. Bit 4 in OSRdyGrp is 1 when any bit in OSRdyTbl[4] is 1. Bit 5 in OSRdyGrp is 1 when any bit in OSRdyTbl[5] is 1. Bit 6 in OSRdyGrp is 1 when any bit in OSRdyTbl[6] is 1. Bit 7 in OSRdyGrp is 1 when any bit in OSRdyTbl[7] is 1.
51
資工系網媒所 NEWS 實驗室 11:01 /2750 Making a Task Ready to Run IndexBit mask (Binary) 000000001 100000010 200000100 300001000 400010000 500100000 601000000 710000000 Task’s Priority 00YYYXXX OSRdyGrp |= OSMapTbl[prio >> 3]; OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
52
資工系網媒所 NEWS 實驗室 11:01 /2751 Removing a Task from the Ready List if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) OSRdyGrp &= ~OSMapTbl[prio >> 3];
53
資工系網媒所 NEWS 實驗室 11:01 /2752 Finding the Highest Priority Task y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; prio = (y << 3) + x; INT8U const OSUnMapTbl[] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; 76543210OSUnMapTbl[] 00000000 0 00000001 0 00000010 1 00000011 0 00000100 2 00000101 0 00000110 1 00000111 0 00001000 3 00001001 0 00001010 1 00001011 0 00001100 2 00001101 0 00001110 1 00001111 0 …
54
資工系網媒所 NEWS 實驗室 11:01 /2753 Task Scheduler void OSSched (void) { INT8U y; OS_ENTER_CRITICAL(); if ((OSLockNesting | OSIntNesting) == 0) { (1) y = OSUnMapTbl[OSRdyGrp]; (2) OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); (2) if (OSPrioHighRdy != OSPrioCur) { (3) OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (4) OSCtxSwCtr++; (5) OS_TASK_SW(); (6) } OS_EXIT_CRITICAL(); }
55
資工系網媒所 NEWS 實驗室 11:01 /2754 Locking The Scheduler void OSSchedLock (void) { if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); OSLockNesting++; OS_EXIT_CRITICAL(); } }
56
資工系網媒所 NEWS 實驗室 11:01 /2755 Unlocking The Scheduler void OSSchedUnlock (void) { if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); if (OSLockNesting > 0) { OSLockNesting--; if ((OSLockNesting | OSIntNesting) == 0) { (1) OS_EXIT_CRITICAL(); OSSched(); (2) } else { OS_EXIT_CRITICAL(); } } else { OS_EXIT_CRITICAL(); } } }
57
資工系網媒所 NEWS 實驗室 11:01 /2756 Idle Task OSTaskIdle() Lowest priority, OS_LOWEST_PRIO void OSTaskIdle (void *pdata) { pdata = pdata; for (;;) { OS_ENTER_CRITICAL(); OSIdleCtr++; OS_EXIT_CRITICAL(); } }
58
資工系網媒所 NEWS 實驗室 11:01 /2757 Statistics Task
59
資工系網媒所 NEWS 實驗室 11:01 /2758 Initializing the Statistic Task void main (void) { OSInit(); /* Initialize uC/OS-II (1)*/ /* Install uC/OS-II's context switch vector */ /* Create your startup task (for sake of discussion, TaskStart()) (2)*/ OSStart(); /* Start multitasking (3)*/ } void TaskStart (void *pdata) { /* Install and initialize µ C/OS-II ’ s ticker (4)*/ OSStatInit(); /* Initialize statistics task (5)*/ /* Create your application task(s) */ for (;;) { /* Code for TaskStart() goes here! */ } }
60
資工系網媒所 NEWS 實驗室 11:01 /2759 Initializing the Statistic Task void OSStatInit (void) { OSTimeDly(2); OS_ENTER_CRITICAL(); OSIdleCtr = 0L; OS_EXIT_CRITICAL(); OSTimeDly(OS_TICKS_PER_SEC); OS_ENTER_CRITICAL(); OSIdleCtrMax = OSIdleCtr; OSStatRdy = TRUE; OS_EXIT_CRITICAL(); }
61
資工系網媒所 NEWS 實驗室 11:01 /2760 Statistics Task void OSTaskStat (void *pdata) { INT32U run; INT8S usage; pdata = pdata; while (OSStatRdy == FALSE) { (1) OSTimeDly(2 * OS_TICKS_PER_SEC); } for (;;) { OS_ENTER_CRITICAL(); OSIdleCtrRun = OSIdleCtr; run = OSIdleCtr; OSIdleCtr = 0L; OS_EXIT_CRITICAL(); if (OSIdleCtrMax > 0L) { usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); (2) if (usage > 100) { OSCPUUsage = 100; } else if (usage < 0) { OSCPUUsage = 0; } else { OSCPUUsage = usage; } } else { OSCPUUsage = 0; } OSTaskStatHook(); (3) OSTimeDly(OS_TICKS_PER_SEC); }
62
資工系網媒所 NEWS 實驗室 11:01 /2761 Interrupts under uC/OS-II Be written in assembly language or C code with in-line assembly. YourISR: Save all CPU registers; (1) Call OSIntEnter() or, increment OSIntNesting directly; (2) Execute user code to service ISR; (3) Call OSIntExit(); (4) Restore all CPU registers; (5) Execute a return from interrupt instruction;
63
資工系網媒所 NEWS 實驗室 11:01 /2762 Servicing an Interrupt
64
資工系網媒所 NEWS 實驗室 11:01 /2763 Beginning an ISR void OSIntEnter (void) { OS_ENTER_CRITICAL(); OSIntNesting++; OS_EXIT_CRITICAL(); }
65
資工系網媒所 NEWS 實驗室 11:01 /2764 Leaving an ISR void OSIntExit (void) { OS_ENTER_CRITICAL(); (1) if ((--OSIntNesting | OSLockNesting) == 0) { (2) OSIntExitY = OSUnMapTbl[OSRdyGrp]; (3) OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]); if (OSPrioHighRdy != OSPrioCur) { OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSCtxSwCtr++; OSIntCtxSw(); (4) } OS_EXIT_CRITICAL(); }
66
資工系網媒所 NEWS 實驗室 11:01 /2765 Pseudo Code for Tick ISR void OSTickISR(void) { Save processor registers; Call OSIntEnter() or increment OSIntNesting; Call OSTimeTick(); Call OSIntExit(); Restore processor registers; Execute a return from interrupt instruction; }
67
資工系網媒所 NEWS 實驗室 11:01 /2766 Service a Tick void OSTimeTick (void) { OS_TCB *ptcb; OSTimeTickHook(); (1) ptcb = OSTCBList; (2) while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { (3) OS_ENTER_CRITICAL(); if (ptcb->OSTCBDly != 0) { if (--ptcb->OSTCBDly == 0) { if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { (5) OSRdyGrp |= ptcb->OSTCBBitY; (4) OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { ptcb->OSTCBDly = 1; } } } ptcb = ptcb->OSTCBNext; OS_EXIT_CRITICAL(); } OS_ENTER_CRITICAL(); (7) OSTime++; (6) OS_EXIT_CRITICAL(); }
68
資工系網媒所 NEWS 實驗室 11:01 /2767 uC/OS-II Initialization Initialize variables and data structures Create the idle task OSTaskIdle() Create the statistic task OSTaskStat()
69
資工系網媒所 NEWS 實驗室 11:01 /2768 After calling OSInit()
70
資工系網媒所 NEWS 實驗室 11:01 /2769 Starting uC/OS-II void main (void) { OSInit(); /* Initialize uC/OS-II */.. Create at least 1 task using either OSTaskCreate() or OSTaskCreateExt();.. OSStart(); /* Start multitasking! OSStart() will not return */ } void OSStart (void) { INT8U y; INT8U x; if (OSRunning == FALSE) { y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; OSPrioHighRdy = (INT8U)((y << 3) + x); OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (1) OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); (2) } }
71
資工系網媒所 NEWS 實驗室 11:01 /2770 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
72
資工系網媒所 NEWS 實驗室 11:01 /2771 Task Management Task prototype Create a task Task stacks Stack checking Delete a task Change a task’s priority Suspend a task Resume a task Query task information
73
資工系網媒所 NEWS 實驗室 11:01 /2772 Task Prototype void YourTask (void *pdata) { for (;;) { /* USER CODE */ Call one of uC/OS-II’s services: /* USER CODE */ } } void YourTask (void *pdata) { /* USER CODE */ OSTaskDel(OS_PRIO_SELF); }
74
資工系網媒所 NEWS 實驗室 11:01 /2773 OSTaskCreate() Check that the task priority is valid Check that the task is unique Set up the task stack OSTaskStkInit() Obtain and initialize OS_TCB from TCB pool OSTCBInit() Call OSTaskCreateHook() to extend the functionality Call OSSched() when OSTaskCreate() is called from a task
75
資工系網媒所 NEWS 實驗室 11:01 /2774 OSTaskCreate() INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) { void *psp; INT8U err; if (prio > OS_LOWEST_PRIO) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { (2) OSTCBPrioTbl[prio] = (OS_TCB *)1; (3) OS_EXIT_CRITICAL(); (4) psp = (void *)OSTaskStkInit(task, pdata, ptos, 0); (5) err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); (6) if (err == OS_NO_ERR) { (7) OS_ENTER_CRITICAL(); OSTaskCtr++; (8) OSTaskCreateHook(OSTCBPrioTbl[prio]); (9) OS_EXIT_CRITICAL(); if (OSRunning) { (10) OSSched(); (11) } } else { OSTCBPrioTbl[prio] = (OS_TCB *)0; (12) } return (err); } else { OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST); }
76
資工系網媒所 NEWS 實驗室 11:01 /2775 OSTaskCreateExt() More flexibility, at the expense of overhead The first four arguments are the same as OSTaskCreate() id, assign a unique identifier for the task pbos, a pointer that can perform stack checking stk_size, specifies the size of the stack pext, a pointer to extend the OS_TCB opt, specifies whether stack checking is performed
77
資工系網媒所 NEWS 實驗室 11:01 /2776 OSTaskCreateExt() INT8U OSTaskCreateExt (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio, INT16U id, OS_STK *pbos, INT32U stk_size, void *pext, INT16U opt) { void *psp; INT8U err; INT16U i; OS_STK *pfill; if (prio > OS_LOWEST_PRIO) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { (2) OSTCBPrioTbl[prio] = (OS_TCB *)1; (3) OS_EXIT_CRITICAL(); (4) … return (err); } else { OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST); }
78
資工系網媒所 NEWS 實驗室 11:01 /2777 Task Stacks Static OS_STK MyTaskStack[stack_size]; OS_STK MyTaskStack[stack_size]; or Using malloc() to allocate stack space OS_STK *pstk; pstk = (OS_STK *)malloc(stack_size); if (pstk != (OS_STK *)0) { /* Make sure malloc() had enough space */ Create the task; }
79
資工系網媒所 NEWS 實驗室 11:01 /2778 Fragmentation
80
資工系網媒所 NEWS 實驗室 11:01 /2779 OSTaskStkChk() Computes the amount of free stack space by “walking” from the bottom of the stack until a nonzero value is found
81
資工系網媒所 NEWS 實驗室 11:01 /2780 Stack Checking
82
資工系網媒所 NEWS 實驗室 11:01 /2781 OSTaskDel() Return to the DORMANT state The code for the task will not be deleted Procedures Prevent from deleting and idle task Prevent from deleting a task from within an ISR Verify that the task to be deleted does exist Remove the OS_TCB Remove the task from ready list or other lists Set.OSTCBStat to OS_STAT_RDY Call OSDummy() Call OSTaskDelHook() Remove the OS_TCB from priority table Call OSSched()
83
資工系網媒所 NEWS 實驗室 11:01 /2782 OSTaskDelReq() Tell the task that owns memory buffers or semaphore to delete itself Procedures Check the task’s priority If the task’s priority is OS_PRIO_SELF Return the flag of OSTCBDelReq Otherwise Set OSTCBDelReq of the task to OS_TASK_DEL_REQ
84
資工系網媒所 NEWS 實驗室 11:01 /2783 OSTaskDelReq() Example void RequestorTask (void *pdata) { for (;;) { /* Application code */ if (‘TaskToBeDeleted()’ needs to be deleted) { while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) { OSTimeDly(1); } } /* Application code */ } } void TaskToBeDeleted (void *pdata) { for (;;) { /* Application code */ if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) { Release any owned resources; De-allocate any dynamic memory; OSTaskDel(OS_PRIO_SELF); } else { /* Application code */ } } }
85
資工系網媒所 NEWS 實驗室 11:01 /2784 OSTaskChangePrio() Cannot change the priority of any idle task Procedures Reserve the new priority by OSTCBPrioTbl[newprio] = (OS_TCB *) 1; Remove the task from the priority table Insert the task into new location of the priority table Change the OS_TCB of the task Call OSSched()
86
資工系網媒所 NEWS 實驗室 11:01 /2785 OSTaskSuspend() Procedures Check the input priority Remove the task from the ready list Set the OS_STAT_SUSPEND flag in OS_TCB Call OSSched()
87
資工系網媒所 NEWS 實驗室 11:01 /2786 OSTaskResume() Procedures Check the input priority Clear the OS_STAT_SUSPEND bit in the OSTCBStat field Set OSTCBDly to 0 Call OSSched()
88
資工系網媒所 NEWS 實驗室 11:01 /2787 OSTaskQuery() INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata) { OS_TCB *ptcb; if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (prio == OS_PRIO_SELF) { (2) prio = OSTCBCur->OSTCBPrio; } if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { (3) OS_EXIT_CRITICAL(); return (OS_PRIO_ERR); } *pdata = *ptcb; (4) OS_EXIT_CRITICAL(); return (OS_NO_ERR); }
89
資工系網媒所 NEWS 實驗室 11:01 /2788 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
90
資工系網媒所 NEWS 實驗室 11:01 /2789 Time Management OSTimeDly() OSTimeDlyHMSM() OSTimeDlyResume() OSTimeGet() OSTimeSet()
91
資工系網媒所 NEWS 實驗室 11:01 /2790 OSTimeDly() void OSTimeDly (INT16U ticks) { if (ticks > 0) { if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBDly = ticks; OSSched(); } }
92
資工系網媒所 NEWS 實驗室 11:01 /2791 OSTimeDlyHMSM() INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli) { { INT32U ticks; INT16U loops; if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) { if (minutes > 59) { return (OS_TIME_INVALID_MINUTES); } if (seconds > 59) { return (OS_TIME_INVALID_SECONDS); } if (milli > 999) { return (OS_TIME_INVALID_MILLI); } ticks = (INT32U)hours * 3600L * OS_TICKS_PER_SEC + (INT32U)minutes * 60L * OS_TICKS_PER_SEC + (INT32U)seconds) * OS_TICKS_PER_SEC + OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L; loops = ticks / 65536L; ticks = ticks % 65536L; OSTimeDly(ticks); while (loops > 0) { OSTimeDly(32768); loops--; } return (OS_NO_ERR); } else { return (OS_TIME_ZERO_DLY); } }
93
資工系網媒所 NEWS 實驗室 11:01 /2792 OSTimeDlyResume() INT8U OSTimeDlyResume (INT8U prio) { ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; if (ptcb != (OS_TCB *)0) { if (ptcb->OSTCBDly != 0) { ptcb->OSTCBDly = 0; if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OSSched(); } return (OS_NO_ERR); } else { return (OS_TIME_NOT_DLY); } } else { return (OS_TASK_NOT_EXIST); } }
94
資工系網媒所 NEWS 實驗室 11:01 /2793 OSTimeGet() & OSTimeSet() INT32U OSTimeGet (void) { ticks = OSTime; return (ticks); } void OSTimeSet (INT32U ticks) { OSTime = ticks; }
95
資工系網媒所 NEWS 實驗室 11:01 /2794 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
96
資工系網媒所 NEWS 實驗室 11:01 /2795 Intertask Communication & Synchronization OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() OSSchedLock() OSSchedUnlock() Semaphore Message mailbox Message queue
97
資工系網媒所 NEWS 實驗室 11:01 /2796 OS_ENTER_CRITICAL() & OS_EXIT_CRITICAL() #define OS_CRITICAL_METHOD 2 #if OS_CRITICAL_METHOD == 1 #define OS_ENTER_CRITICAL() asm CLI #define OS_EXIT_CRITICAL() asm STI #endif #if OS_CRITICAL_METHOD == 2 #define OS_ENTER_CRITICAL() asm {PUSHF; CLI} #define OS_EXIT_CRITICAL() asm POPF #endif CLI … CLI … STI … STI …
98
資工系網媒所 NEWS 實驗室 11:01 /2797 Linux Example /* include/asm-i386/system.h */ /* interrupt control.. */ #define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x):) #define __restore_flags(x) __asm__ __volatile__("pushl %0; popfl": /* no output */ :"g" (x):"memory", "cc") #define __cli() __asm__ __volatile__("cli": : :"memory") #define __sti() __asm__ __volatile__("sti": : :"memory") /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__("pushfl; popl %0; cli":"=g" (x): :"memory") #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti()
99
資工系網媒所 NEWS 實驗室 11:01 /2798 Locking and Unlocking the Scheduler void OSSchedLock (void) { if (OSRunning == TRUE) { OSLockNesting++; } } void OSSchedUnlock (void) { if (OSRunning == TRUE) { if (OSLockNesting > 0) { OSLockNesting--; if ((OSLockNesting | OSIntNesting) == 0) { OSSched(); } }
100
資工系網媒所 NEWS 實驗室 11:01 /2799 ECB (Event Control Block)
101
資工系網媒所 NEWS 實驗室 11:01 /27100 Event Control Block typedef struct { void *OSEventPtr; /* Ptr to message or queue structure */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Wait list for event to occur */ INT16U OSEventCnt; /* Count (when event is a semaphore) */ INT8U OSEventType; /* Event type */ INT8U OSEventGrp; /* Group for wait list */ } OS_EVENT;
102
資工系網媒所 NEWS 實驗室 11:01 /27101 List of Free ECBs
103
資工系網媒所 NEWS 實驗室 11:01 /27102 Wait Queue Functions void OSEventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) { y = OSUnMapTbl[pevent->OSEventGrp]; bity = OSMapTbl[y]; x = OSUnMapTbl[pevent->OSEventTbl[y]]; bitx = OSMapTbl[x]; prio = (INT8U)((y << 3) + x); if ((pevent->OSEventTbl[y] &= ~bitx) == 0) { pevent->OSEventGrp &= ~bity; } ptcb = OSTCBPrioTbl[prio]; ptcb->OSTCBDly = 0; ptcb->OSTCBEventPtr = (OS_EVENT *)0; ptcb->OSTCBMsg = msg; ptcb->OSTCBStat &= ~msk; if (ptcb->OSTCBStat == OS_STAT_RDY) { OSRdyGrp |= bity; OSRdyTbl[y] |= bitx; } }
104
資工系網媒所 NEWS 實驗室 11:01 /27103 Wait Queue Functions void OSEventTaskWait (OS_EVENT *pevent) { OSTCBCur->OSTCBEventPtr = pevent; if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; } void OSEventTO (OS_EVENT *pevent) { if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; }
105
資工系網媒所 NEWS 實驗室 11:01 /27104 Semaphore
106
資工系網媒所 NEWS 實驗室 11:01 /27105 Creating a Semaphore OS_EVENT *OSSemCreate (INT16U cnt) { pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_SEM; pevent->OSEventCnt = cnt; OSEventWaitListInit(pevent); } return (pevent); }
107
資工系網媒所 NEWS 實驗室 11:01 /27106 Waiting for a Semaphore void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { if (pevent->OSEventCnt > 0) { pevent->OSEventCnt--; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_SEM; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { OSEventTO(pevent); } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } }
108
資工系網媒所 NEWS 實驗室 11:01 /27107 Signaling a Semaphore INT8U OSSemPost (OS_EVENT *pevent) { if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventCnt < 65535) { pevent->OSEventCnt++; return (OS_NO_ERR); } else { return (OS_SEM_OVF); } }
109
資工系網媒所 NEWS 實驗室 11:01 /27108 Getting a Semaphore without Waiting INT16U OSSemAccept (OS_EVENT *pevent) { cnt = pevent->OSEventCnt; if (cnt > 0) { pevent->OSEventCnt--; } return (cnt); }
110
資工系網媒所 NEWS 實驗室 11:01 /27109 Obtaining the Status of a Semaphore INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata) { pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSCnt = pevent->OSEventCnt; return (OS_NO_ERR); }
111
資工系網媒所 NEWS 實驗室 11:01 /27110 Message Mailbox
112
資工系網媒所 NEWS 實驗室 11:01 /27111 Creating a Mailbox OS_EVENT *OSMboxCreate (void *msg) { pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_MBOX; pevent->OSEventPtr = msg; OSEventWaitListInit(pevent); } return (pevent); }
113
資工系網媒所 NEWS 實驗室 11:01 /27112 Waiting for a Message to Arrive at a Mailbox void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_MBOX; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) { OSEventTO(pevent); } else { msg = pevent->OSEventPtr; pevent->OSEventPtr = (void *)0; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } return (msg); }
114
資工系網媒所 NEWS 實驗室 11:01 /27113 Depositing a Message in a Mailbox INT8U OSMboxPost (OS_EVENT *pevent, void *msg) { if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_MBOX); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventPtr != (void *)0) { return (OS_MBOX_FULL); } else { pevent->OSEventPtr = msg; return (OS_NO_ERR); } }
115
資工系網媒所 NEWS 實驗室 11:01 /27114 Getting a Message without Waiting void *OSMboxAccept (OS_EVENT *pevent) { msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } return (msg); }
116
資工系網媒所 NEWS 實驗室 11:01 /27115 Obtaining the Status of a Mailbox INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) { pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSMsg = pevent->OSEventPtr; return (OS_NO_ERR); }
117
資工系網媒所 NEWS 實驗室 11:01 /27116 Using a Mailbox as a Binary Semaphore void Task1 (void *pdata) { for (;;) { OSMboxPend(MboxSem, 0, &err); /* Obtain access to resource(s) */.. /* Task has semaphore, access resource(s) */. OSMboxPost(MboxSem, (void )1); /* Release access to resource(s) */ }
118
資工系網媒所 NEWS 實驗室 11:01 /27117 Using a Mailbox as a Time Delay void Task1 (void *pdata) { for (;;) { OSMboxPend(MboxTimeDly, TIMEOUT, &err); /* Delay task */.. /* Code executed after time delay */. } void Task2 (void *pdata) { for (;;) { OSMboxPost(MboxTimeDly, (void *)1); /* Cancel delay for Task1 */. }
119
資工系網媒所 NEWS 實驗室 11:01 /27118 Message Queues OSQCreate() OSQPend() OSQPost() OSQPostFront() OSQAccept() OSQFlush() OSQQuery()
120
資工系網媒所 NEWS 實驗室 11:01 /27119 Message Queues A message queue Allows a task or an ISR to send pointer size variables to another task. Each pointer points a specific data structure containing a ‘message’. Looks like a mailbox with multiple entries. Is like an array of mailboxes except that there is only one wait list.
121
資工系網媒所 NEWS 實驗室 11:01 /27120 Message Queues (Cont.)
122
資工系網媒所 NEWS 實驗室 11:01 /27121 Data Structures in a Message Queue
123
資工系網媒所 NEWS 實驗室 11:01 /27122 Queue Control Block A queue control block contains following fields OSQPtr OSQStart OSQEnd OSQIn OSQOut OSQSize OSQEntries
124
資工系網媒所 NEWS 實驗室 11:01 /27123 List of Free Queue Control Blocks
125
資工系網媒所 NEWS 實驗室 11:01 /27124 Message Queue Is a Circular Buffer
126
資工系網媒所 NEWS 實驗室 11:01 /27125 Creating a Queue Specify the number of entries. OSQCreate() requires that you allocate an array of pointers that hold the message. The array must be declared as an array of pointers to void. Once a message queue has been created, it cannot be deleted.
127
資工系網媒所 NEWS 實驗室 11:01 /27126 OSQCreate() OS_EVENT *OSQCreate (void **start, INT16U size) { pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pq = OSQFreeList; if (OSQFreeList != (OS_Q *)0) { OSQFreeList = OSQFreeList->OSQPtr; } if (pq != (OS_Q *)0) { pevent->OSEventType = OS_EVENT_TYPE_Q; pevent->OSEventPtr = pq; OSEventWaitListInit(pevent); } else { pevent->OSEventPtr = (void *)OSEventFreeList; OSEventFreeList = pevent; pevent = (OS_EVENT *)0; } return (pevent); }
128
資工系網媒所 NEWS 實驗室 11:01 /27127 OSQPend() (1) void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } *err = OS_NO_ERR; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_Q; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR;
129
資工系網媒所 NEWS 實驗室 11:01 /27128 OSQPend() (2) } else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { OSEventTO(pevent); msg = (void *)0; *err = OS_TIMEOUT; } else { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR; } return (msg); }
130
資工系網媒所 NEWS 實驗室 11:01 /27129 OSQPost() INT8U OSQPost (OS_EVENT *pevent, void *msg) { if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { *pq->OSQIn++ = msg; pq->OSQEntries++; if (pq->OSQIn == pq->OSQEnd) { pq->OSQIn = pq->OSQStart; } return (OS_NO_ERR); }
131
資工系網媒所 NEWS 實驗室 11:01 /27130 OSQPostFront() Is basically identical to OSQPost(). Uses OSQOut instead of OSQIn as the pointer to the next entry.
132
資工系網媒所 NEWS 實驗室 11:01 /27131 OSQPostFront() (Cont.) INT8U OSQPostFront (OS_EVENT *pevent, void *msg){ if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { if (pq->OSQOut == pq->OSQStart) { pq->OSQOut = pq->OSQEnd; } pq->OSQOut--; *pq->OSQOut = msg; pq->OSQEntries++; } return (OS_NO_ERR); }
133
資工系網媒所 NEWS 實驗室 11:01 /27132 OSQAccept () void *OSQAccept (OS_EVENT *pevent) { pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } } else { msg = (void *)0; } return (msg); }
134
資工系網媒所 NEWS 實驗室 11:01 /27133 OSQFlush() INT8U OSQFlush (OS_EVENT *pevent) { pq = pevent->OSEventPtr; pq->OSQIn = pq->OSQStart; pq->OSQOut = pq->OSQStart; pq->OSQEntries = 0; return (OS_NO_ERR); }
135
資工系網媒所 NEWS 實驗室 11:01 /27134 OSQQuery() Pass a OS_Q_DATA structure to query. OS_Q_DATA contains following fields OSMsg OSNMsgs OSQSize OSEventTbl[] OSEventGrp
136
資工系網媒所 NEWS 實驗室 11:01 /27135 OSQQuery() (Cont.) INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata){ pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pq = (OS_Q *)pevent->OSEventPtr; if (pq->OSQEntries > 0) { pdata->OSMsg = pq->OSQOut; } else { pdata->OSMsg = (void *)0; } pdata->OSNMsgs = pq->OSQEntries; pdata->OSQSize = pq->OSQSize; return (OS_NO_ERR); }
137
資工系網媒所 NEWS 實驗室 11:01 /27136 Using a Message Queue When Reading Analog Inputs
138
資工系網媒所 NEWS 實驗室 11:01 /27137 Using a Queue as a Counting Semaphore void main (void){ OSInit(); … QSem = OSQCreate(&QMsgTbl[0], N_RESOURCES); for (i = 0; i < N_RESOURCES; i++) { OSQPost(Qsem, (void *)1); } … OSTaskCreate(Task1,..,..,..); … OSStart(); } void Task1 (void *pdata) { for (;;) { OSQPend(&QSem, 0, &err); /* Obtain access to resource(s) */ Task has semaphore, access resource(s) OSMQPost(QSem, (void )1); /* Release access to resource(s) */ }
139
資工系網媒所 NEWS 實驗室 11:01 /27138 uC/OS-II Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management
140
資工系網媒所 NEWS 實驗室 11:01 /27139 Memory Management Overview Memory Control Blocks OSMemCreate() OSMemGet() OSMemPut() OSMemQuery() Examples
141
資工系網媒所 NEWS 實驗室 11:01 /27140 ANSI C malloc() and free() Dangerous in an embedded real-time system. Fragmentation. Non-deterministic.
142
資工系網媒所 NEWS 實驗室 11:01 /27141 µ C/OS-II malloc() and free() Obtain a contiguous memory area. Memory blocks are the same size. Partition contains an integral number of blocks. Allocation and de-allocation is deterministic. More than one memory partition can exist. Application can obtain memory blocks of different sizes. Memory block must always be returned to the partition from which it came from.
143
資工系網媒所 NEWS 實驗室 11:01 /27142 Multiple Memory Partitions
144
資工系網媒所 NEWS 實驗室 11:01 /27143 Memory Control Blocks Keeps track of memory partitions through MCB. Each memory partition requires its own memory control block. Initialization is done by OSMemInit(). Number of memory partitions must be set to at least 2.
145
資工系網媒所 NEWS 實驗室 11:01 /27144 Memory Control Block Data Structure typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; } OS_MEM;
146
資工系網媒所 NEWS 實驗室 11:01 /27145 List of Free Memory Control Blocks
147
資工系網媒所 NEWS 實驗室 11:01 /27146 OSMemCreate() (1)
148
資工系網媒所 NEWS 實驗室 11:01 /27147 OSMemCreate() (2) OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err) { pmem = OSMemFreeList; if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList>OSMemFreeList; } if (pmem == (OS_MEM *)0) { *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); } plink = (void **)addr; pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; pmem->OSMemAddr = addr; pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; *err = OS_NO_ERR; return (pmem); }
149
資工系網媒所 NEWS 實驗室 11:01 /27148 OSMemGet() void *OSMemGet (OS_MEM *pmem, INT8U *err) { if (pmem->OSMemNFree > 0) { pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = *(void **)pblk; pmem->OSMemNFree--; *err = OS_NO_ERR; return (pblk); } else { *err = OS_MEM_NO_FREE_BLKS; return ((void *)0); }
150
資工系網媒所 NEWS 實驗室 11:01 /27149 Returning a Memory Block INT8U OSMemPut (OS_MEM *pmem, void *pblk) { if (pmem->OSMemNFree >= pmem->OSMemNBlks) return (OS_MEM_FULL); *(void **)pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; return (OS_NO_ERR); }
151
資工系網媒所 NEWS 實驗室 11:01 /27150 Obtaining Status about Memory Partition Pass a OS_MEM_DATA structure to query. OS_MEM_DATA contains following fields OSAddr OSFreeList OSBlkSize OSNBlks OSNFree OSNUsed
152
資工系網媒所 NEWS 實驗室 11:01 /27151 OSMemQuery() INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata) { pdata->OSAddr = pmem->OSMemAddr; (1) pdata->OSFreeList = pmem->OSMemFreeList; pdata->OSBlkSize = pmem->OSMemBlkSize; pdata->OSNBlks = pmem->OSMemNBlks; pdata->OSNFree = pmem->OSMemNFree; pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2) return (OS_NO_ERR); }
153
資工系網媒所 NEWS 實驗室 11:01 /27152 Using Dynamic Memory Allocation
154
資工系網媒所 NEWS 實驗室 11:01 /27153 Waiting for Memory Blocks (1) Sometimes it’s useful to have a task wait for a memory block in case a partition runs out of blocks. µC/OS-II doesn’t support ‘pending’ on a partitions. Can support this requirement by adding a counting semaphore.
155
資工系網媒所 NEWS 實驗室 11:01 /27154 Waiting for Memory Blocks (2) void main (void) { … SemaphorePtr = OSSemCreate(100); PartitionPtr = OSMemCreate(Partition, 100, 32, &err); … OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); … OSStart(); }
156
資工系網媒所 NEWS 實驗室 11:01 /27155 Waiting for Memory Blocks (3) void Task (void *pdata) { INT8U err; INT8U *pblock; for (;;) { OSSemPend(SemaphorePtr, 0, &err); pblock = OSMemGet(PartitionPtr, &err); /* Use the memory block */ OSMemPut(PartitionPtr, pblock); OSSemPost(SemaphorePtr); }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.