Presentation is loading. Please wait.

Presentation is loading. Please wait.

國立台灣大學 資訊工程學系 Introduction to uC/OS-II

Similar presentations


Presentation on theme: "國立台灣大學 資訊工程學系 Introduction to uC/OS-II"— Presentation transcript:

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); }


Download ppt "國立台灣大學 資訊工程學系 Introduction to uC/OS-II"

Similar presentations


Ads by Google