Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 13: Porting μC/OS-II

Similar presentations


Presentation on theme: "Chapter 13: Porting μC/OS-II"— Presentation transcript:

1 Chapter 13: Porting μC/OS-II

2 Outline Requirements Hardware Software Tasks of Porting µC/OS-II
OS_CPU_C.H OS_CPU_C.C OS_CPU_A.ASM Testing a port

3 μC/OS-II hardware/software architecture
Application Code (test.c) Processor independent implementations Scheduling policy Event flags Semaphores Mailboxes Event queues Task management Time management Memory management Application Specific Configurations OS_CFG.H Max # of tasks Max Queue length μC/OS-II port for processor specific codes Software Hardware CPU Timer

4 Requirements C compiler Interrupt support and a timer
Interrupt can be disabled and enabled by C Support hardware stack The processor can load and store the stack pointer and other registers in memory (stack pointer is stored in TCB)

5 Porting Tasks of µC/OS-II
Setting the value of 2 #define constants (OS_CPU.H) OS_CRITICAL_METHOD OS_STK_GROWTH Declaring 11 data types (OS_CPU.H) OS_STK Declaring 1~3 #define macros (OS_CPU.H) Critical section Writing 10 simple functions in C (OS_CPU_C.C) Hooks OSTaskStkInit Writing 4 assembly language functions (OS_CPU_A.ASM) Context switch (starting, ctx by ISR, ctx by AP) TickISR procedures

6 Development Tools A C compiler that generates reentrant code (each function has its stack space) A linker which is used to combine object files Resolve references within these modules A locator which allow you to place the code and data anywhere in the memory map of the target processor

7 OS_CPU.H Compiler-Specific Data Type
BOOLEAN, INT8U, INT8S… The data type of a task’s stack and the status register typedef unsigned int OS_STK typedef unsigned short OS_CPU_SR

8 OS_CPU.H Critical Method Type 1: enable and disable directly
Type 2: save the interrupt status onto the stack Type 3: save the interrupt status into a local variables

9 OS_CPU.H #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 #if OS_CRITICAL_METHOD == 3 #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR()) #define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr)) X86 port

10 OS_CPU.H OS_TASK_SW() OS_TASK_SW() is called from user program.
a macro that is invoked when µC/OS-II switches from a low-priority task to the highest-priority task. OS_TASK_SW() is called from user program. OSIntExit() is called from ISR In this procedure (OS_Task_SW())… Throw a software trap The interrupt handler should vector to the assembly language function OSCtxSw() X86 port #define OS_TASK_SW() asm INT uCOS

11 OS_CPU.H typedef unsigned short OS_CPU_SR /*define sie of CPU status register*/

12 OS_CPU_C.C OSTaskStkInit() OSTaskCreateHook() OSTaskDelHook()
OSTaskSwHook() OSTaskIdleHook() OSTaskStatHook() OSTimeTickHook() OSInitHookBegin()

13 OSTaskStkInit() This function is called by OSTaskCreate() and OSTAskCreateExt() to initialize the stack frame of a task as an interrupt has just occurred and all the processor registers have been pushed onto that stack.

14 tcb = getHPT() asm {sp = tcb->sp} asm {popa} asm {iret} main()
fun1() os_start() main1() main2() main3() code (Task1) code (Task2) code (Task3) Stack (main) xxx ooo zzz kkk ggg fff qqqqq Regs Regs Regs PSW PC PSW PC PSW PC Stack (Task1) Ret. adrs pdata Stack (Task3) Ret. adrs pdata Stack (Task3) Ret. adrs pdata startHighRdy tcb = getHPT() asm {sp = tcb->sp} asm {popa} asm {iret} sp pc

15 tcb = getHPT() asm {sp = tcb->sp} asm {popa} asm {iret} main1() xxx
code (Task1) code (Task2) code (Task3) Regs Regs local variables PSW PC PSW PC Ret. adrs pdata Stack (Task3) Ret. adrs pdata Stack (Task3) Ret. adrs pdata tcb = getHPT() asm {sp = tcb->sp} asm {popa} asm {iret} startHighRdy Regs sp pc PSW PC

16 Context switch TCB (task2) TCB (task1) Stack (task1) Stack (task2)
main2() { xxx yyy zzz } myFunction() { OSMBoxPost() } OSTCBStkPtr OSTCBStkPtr Regs (1) Mode Change (function call) PSW PC Regs PSW PC OSMboxPost() { //... OS_Sched() OSPrioHighRdy= //Get pointer to HPT ready to run INT 0x80 //OS_TASK_SW } Ret. adrs pdata Ret. adrs pdata (2) Exception (software interrupt) (3) PUSH PSW PUSH PC+4 (4) POP PSW POP PC+4 //(4) ISR (interrupt service routine) PUSHA OSTCBCur->OSTCBStkPtr = SP SP = OSTCBHighRdy->OSTCBStkPtr POPA IRET

17 Pseudo code for OSTaskStkInit()
registers PSW & PC Ret. addr pdata

18 OSTaskStkInit() Under μC/OS-II, a task looks like a C function with one argument. Push the argument onto the stack Pass the argument in one or more registers

19 OSTaskStkInit()- pdata passed to the stack
Regs PSW & PC Ret. adrs pdata

20 BC45 5dc6 0022 0080 5d7A 0031

21 Ret. ADRS bp

22 OSCTXSW

23 OSTaskStkInit()- pdata passed to the stack

24 OSTaskStkInit() – passed in register
Because the compiler passed arguments to a function in registers, we need to find out which register is used to store pData

25 Process Termination

26 Stack layout @OSTaskDelSelf void OSTaskDelSelf() {
OSTaskDel(OS_PRIO_SELF); }

27 Stack layout @OSTaskDel OSTaskDel(OS_PRIO_SELF) { /*…*/ }

28 Stack layout @OSTaskDel 0xFF OSTaskDel(OS_PRIO_SELF) { /*…*/ }

29 Hook Functions If (OS_CPU_HOOK_EN == 1) If (OS_CPU_HOOK_EN == 0)
Hook functions are in OS_CPU_C.C If (OS_CPU_HOOK_EN == 0) In other files

30 OSTaskCreateHook() & OSTaskInitHook()
These functions are called when… After: OS setting up most of OS_TCB Before the OS_TCB is linked to the active task chain and before the task is made ready to run Interrupt has been enabled OSTaskInitHook is called immediately before OSTaskCreateHook

31 OSTaskDelHook() Called by OSTaskDel()
It is called before unlinking the task from OS’s internal linked list of active tasks. This function is called with interrupt disabled

32 OSTaskSwHook() Called by OSCtxSw and OSIntCtxSw
Two variables is meaningful OSTCBCur //old task OSTCBHighRdy //new task This function is called with interrupt disabled

33 OSTaskStatHook() This function is called once every second by OSTaskStat()

34 OSTimeTickHook() This function is called by OSTimeTick()
OSTimeTick() is called before the tick start to process in order to give your port or application first claim to the tick.

35 OSTaskIdleHook() We can bring the processor to the power saving mode by placing “stop” instruction here. void OSTaskIdleHook(void) { asm(“STOP”); }

36 OSInitHookBegin()/ OSInitHookEnd()
OSInitHookBegin() is called immediately upon entering OSInit(). OSInitHookEnd() is called at the end of OSInit().

37 OS_CPU_A.ASM OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR()

38 OSStartHighRdy() This function is called by OSStart() to start the highest priority task ready-to-run. OSStartHighRdy() assumes that OSTCBHighRdy() points to the TCB of the task with the highest priority. OSTCBHighRdy() is set by OSStart() The function only does half a context switch Restoring the registers of the highest priority task Not saving the register of the previous task

39 Pseudocode Call OSTaskSwHook Set OSRunning = true
Get the stack pointer stack pointer = OSTCBHighRdy -> OSTCBStkPtr; Restore all processor registers from the task’s stack Execute “Return from interrupt”

40 OSCtxSw() A task level context switch is accomplished by issuing a software interrupt instruction. The sequence of events that leads µC/OS-II to vector to OSCtxSw() is as follows: The current task calls a system call which causes a higher priority task ready to run. At the end of the service call, the OS calls OSSched(). OSSched() loads the address of the highest priority task into OSTCBHighRdy and then executes the software interrupt or trap instruction by invoking the macro OS_TASK_SW() #define OS_TASK_SW() asm INT uCOS

41 Pseudocode The machine has saved the return address and status word
void OSCtxSw(void) { Save processor registers; Save the current task’s stack pointer into\\ the current task’s OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; }

42 OSTickISR() You MUST enable ticker interrupts AFTER multitasking has started, i.e. after calling OSStart(). You should initialize and tick interrupts in the first task that executes following a call to OSStart().

43 Pseudocode void OSTickISR(void) { Save processor registers;
Call OSIntEnter() or increment OSIntNesting; if (OSIntNesting == 1) OSTCBCur->OSTCBStkPtr = stack pointer Call OSTimeTick(); Call OSIntExit(); Restore processor registers; Execute a return from interrupt instruction; }

44 OSIntExit() void OSIntExit (void) { if (OSIntNesting == 0) { if (OSLockNesting == 0) { OSIntExitY = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]); if (OSPrioHighRdy != OSPrioCur) { OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSIntCtxSw(); } OS_EXIT_CRITICAL();

45 OSIntCtxSw() This function is called by OSIntExit() to perform context switch from ISR. Because it is called from ISR, all registers are properly saved.

46 Pseudocode void OSIntCtxSw(void) { Call user-definable OSTaskSwHook();
OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new task’s stack; Execute a “return from interrupt” instruction; }

47 Pseudocode – an Old Version
void OSIntCtxSw(void) { Adjust the stack pointer to remove calls to: OSIntExit(), OSIntCtxSw() and possibly the push of the processor status word; Save the current task’s stack pointer into the current task’s OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; }

48

49 Testing of a Port Steps Ensure that the code compiles, assembles and links Verify OSTaskStkInit and OSStartHighRdy Verify OSCtxSw Verify OSIntCtxSw and OSTickISR

50 Code Compiling, Assembling and Linking
Ensure that the code compiles, assembles and links void main() { OSInit(); OSStart(); }

51 Verifying of OSTaskStkInit and OSStartHighRdy
Disable the statistic task OS_TASK_STAT_EN = 0 Step over the function OSInit() and then step into the for OSStart() Step into OSStartHighRdy Switch to the “Idle” task? The register order  OSTaskStkInit “Return” to the idle thread  OSStartHighRdy

52 Verifying of OSCtxSw()
void main() { OSInit(); OSTaskCreate(TestTask, NULL, stack, 0); OSStart(); } Void TestTask(void *pData) { while(1) { OSTimeDly(1);

53 Verifying of OSCtxSw()
OSTimeDly()  OS_Sched()  OSCtxSw () When the return from interrupt is executed, the you should be in OS_TaskIdle.

54 Verifying of OSIntCtxSw() and OSTickISR()
Installing of a timer interrupt handler Call OSTimeDly(1) to result in a context switch to the idle thread by using OSIntCtxSw() and OSTickISR()

55 Verifying of OSIntCtxSw() and OSTickISR()
void main(void) { OSInit(); install the clock tick ISR; OSTaskCreate(TestTask); OSStart(); } Void TestTask(void *pData) { disable interrupt initialize the clock tick interrupt; enable interrupt while (1) { OSTimeDly(1); printf(“%d”, OSTimeGet());


Download ppt "Chapter 13: Porting μC/OS-II"

Similar presentations


Ads by Google