Chapter 13 Porting COSII 1 Outline Requirements Hardware

  • Slides: 56
Download presentation
Chapter 13: Porting μC/OS-II 1

Chapter 13: Porting μC/OS-II 1

Outline • • Requirements Hardware Software Tasks of Porting µC/OS-II OS_CPU_C. H OS_CPU_C. C

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 2

μC/OS-II hardware/software architecture Application Code (test. c) Processor independent implementations • Scheduling policy •

μ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 3

Requirements • • • C compiler Interrupt support and a timer Interrupt can be

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) 4

Porting Tasks of µC/OS-II • Setting the value of 2 #define constants (OS_CPU. H)

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 – OSTask. Stk. Init • Writing 4 assembly language functions (OS_CPU_A. ASM) – Context switch (starting, ctx by ISR, ctx by AP) – Tick. ISR procedures 5

Development Tools • A C compiler that generates reentrant code (each function has its

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 6

OS_CPU. H • Compiler-Specific Data Type – BOOLEAN, INT 8 U, INT 8 S…

OS_CPU. H • Compiler-Specific Data Type – BOOLEAN, INT 8 U, INT 8 S… • The data type of a task’s stack and the status register – typedef unsigned int OS_STK – typedef unsigned short OS_CPU_SR 7

OS_CPU. H • Critical Method – Type 1: enable and disable directly – Type

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 8

OS_CPU. H #if OS_CRITICAL_METHOD == 1 #define OS_ENTER_CRITICAL() asm CLI #define OS_EXIT_CRITICAL() asm STI

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 #endif #if OS_CRITICAL_METHOD == 3 #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSave. SR()) #define OS_EXIT_CRITICAL() (OSCPURestore. SR(cpu_sr)) #endif X 86 port 9

OS_CPU. H • OS_TASK_SW() – a macro that is invoked when µC/OS-II switches from

OS_CPU. H • OS_TASK_SW() – 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. – OSInt. Exit() is called from ISR • In this procedure (OS_Task_SW())… – Throw a software trap – The interrupt handler should vector to the assembly language function OSCtx. Sw() X 86 port #define OS_TASK_SW() asm INT u. COS 10

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

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

OS_CPU_C. C • • OSTask. Stk. Init() OSTask. Create. Hook() OSTask. Del. Hook() OSTask.

OS_CPU_C. C • • OSTask. Stk. Init() OSTask. Create. Hook() OSTask. Del. Hook() OSTask. Sw. Hook() OSTask. Idle. Hook() OSTask. Stat. Hook() OSTime. Tick. Hook() OSInit. Hook. Begin() 12

OSTask. Stk. Init() • This function is called by OSTask. Create() and OSTAsk. Create.

OSTask. Stk. Init() • This function is called by OSTask. Create() and OSTAsk. Create. Ext() 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. 13

main() main 2() fun 1() main 3() os_start() main 1() code (Task 1) xxx

main() main 2() fun 1() main 3() os_start() main 1() code (Task 1) xxx ooo zzz kkk ggg fff qqqqq code (Task 2) code (Task 3) Regs PSW PC Stack Ret. adrs (Task 1) pdata Stack (main) Ret. adrs Stack pdata (Task 3) start. High. Rdy sp pc tcb = get. HPT() asm {sp = tcb->sp} asm {popa} asm {iret} 14

main 1() xxx xxx code (Task 1) local variables Ret. adrs pdata main 2()

main 1() xxx xxx code (Task 1) local variables Ret. adrs pdata main 2() main 3() code (Task 2) code (Task 3) Regs PSW PC Ret. adrs Stack pdata (Task 3) start. High. Rdy sp pc Regs PSW PC tcb = get. HPT() asm {sp = tcb->sp} asm {popa} asm {iret} 15

Context switch TCB (task 2) OSTCBStk. Ptr TCB (task 1) Stack (task 2) OSTCBStk.

Context switch TCB (task 2) OSTCBStk. Ptr TCB (task 1) Stack (task 2) OSTCBStk. Ptr main 2() { my. Function() { xxx OSMBox. Post() yyy zzz } Regs PSW PC (1) Mode Change (function call) OSMbox. Post() { //. . . OS_Sched() OSPrio. High. Rdy= //Get pointer to HPT ready to run INT 0 x 80 //OS_TASK_SW //. . . (2) Exception } (software interrupt) Regs PSW PC Ret. adrs pdata (3) (4) PUSH PSW POP PSW PUSH PC+4 POP PC+4 //(4) ISR (interrupt service routine) PUSHA OSTCBCur->OSTCBStk. Ptr = SP SP = OSTCBHigh. Rdy->OSTCBStk. Ptr POPA IRET 16

Quiz registers PSW & PC Ret. addr pdata 17

Quiz registers PSW & PC Ret. addr pdata 17

Pseudo code for OSTask. Stk. Init() registers PSW & PC Ret. addr pdata 18

Pseudo code for OSTask. Stk. Init() registers PSW & PC Ret. addr pdata 18

OSTask. Stk. Init() • Under μC/OS-II, a task looks like a C function with

OSTask. Stk. Init() • 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

OSTask. Stk. Init()pdata passed to the stack Regs PSW & PC Ret. adrs pdata

OSTask. Stk. Init()pdata passed to the stack Regs PSW & PC Ret. adrs pdata 20

BC 45 5 dc 6 0022 0080 5 d 7 A 0031 21

BC 45 5 dc 6 0022 0080 5 d 7 A 0031 21

Ret. ADRS bp 22

Ret. ADRS bp 22

OSCTXSW 23

OSCTXSW 23

OSTask. Stk. Init()pdata passed to the stack 24

OSTask. Stk. Init()pdata passed to the stack 24

OSTask. Stk. Init() – passed in register • Because the compiler passed arguments to

OSTask. Stk. Init() – passed in register • Because the compiler passed arguments to a function in registers, we need to find out which register is used to store p. Data 25

Process Termination 26

Process Termination 26

Stack layout @OSTask. Del. Self void OSTask. Del. Self() { OSTask. Del(OS_PRIO_SELF); } 27

Stack layout @OSTask. Del. Self void OSTask. Del. Self() { OSTask. Del(OS_PRIO_SELF); } 27

Stack layout @OSTask. Del(OS_PRIO_SELF) { /*…*/ } 28

Stack layout @OSTask. Del(OS_PRIO_SELF) { /*…*/ } 28

Stack layout @OSTask. Del 0 x. FF OSTask. Del(OS_PRIO_SELF) { /*…*/ } 29

Stack layout @OSTask. Del 0 x. FF OSTask. Del(OS_PRIO_SELF) { /*…*/ } 29

Hook Functions • If (OS_CPU_HOOK_EN == 1) – Hook functions are in OS_CPU_C. C

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

OSTask. Create. Hook() & OSTask. Init. Hook() • These functions are called when… –

OSTask. Create. Hook() & OSTask. Init. Hook() • 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 • OSTask. Init. Hook is called immediately before OSTask. Create. Hook 31

OSTask. Del. Hook() • Called by OSTask. Del() • It is called before unlinking

OSTask. Del. Hook() • Called by OSTask. Del() • It is called before unlinking the task from OS’s internal linked list of active tasks. • This function is called with interrupt disabled 32

OSTask. Sw. Hook() • Called by OSCtx. Sw and OSInt. Ctx. Sw • Two

OSTask. Sw. Hook() • Called by OSCtx. Sw and OSInt. Ctx. Sw • Two variables is meaningful – OSTCBCur //old task – OSTCBHigh. Rdy //new task • This function is called with interrupt disabled 33

OSTask. Stat. Hook() • This function is called once every second by OSTask. Stat()

OSTask. Stat. Hook() • This function is called once every second by OSTask. Stat() 34

OSTime. Tick. Hook() • This function is called by OSTime. Tick() • OSTime. Tick()

OSTime. Tick. Hook() • This function is called by OSTime. Tick() • OSTime. Tick() is called before the tick start to process in order to give your port or application first claim to the tick. 35

OSTask. Idle. Hook() • We can bring the processor to the power saving mode

OSTask. Idle. Hook() • We can bring the processor to the power saving mode by placing “stop” instruction here. void OSTask. Idle. Hook(void) { asm(“STOP”); } 36

OSInit. Hook. Begin()/ OSInit. Hook. End() • OSInit. Hook. Begin() is called immediately upon

OSInit. Hook. Begin()/ OSInit. Hook. End() • OSInit. Hook. Begin() is called immediately upon entering OSInit(). • OSInit. Hook. End() is called at the end of OSInit(). 37

OS_CPU_A. ASM • OSStart. High. Rdy() • OSCtx. Sw() • OSInt. Ctx. Sw() •

OS_CPU_A. ASM • OSStart. High. Rdy() • OSCtx. Sw() • OSInt. Ctx. Sw() • OSTick. ISR() 38

OSStart. High. Rdy() • This function is called by OSStart() to start the highest

OSStart. High. Rdy() • This function is called by OSStart() to start the highest priority task ready-to-run. • OSStart. High. Rdy() assumes that OSTCBHigh. Rdy() points to the TCB of the task with the highest priority. – OSTCBHigh. Rdy() 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 1. Call OSTask. Sw. Hook 2. Set OSRunning = true 3. Get the

Pseudocode 1. Call OSTask. Sw. Hook 2. Set OSRunning = true 3. Get the stack pointer = OSTCBHigh. Rdy -> OSTCBStk. Ptr; 4. Restore all processor registers from the task’s stack 5. Execute “Return from interrupt” 40

OSCtx. Sw() • A task level context switch is accomplished by issuing a software

OSCtx. Sw() • 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 OSCtx. Sw() 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 OSTCBHigh. Rdy and then executes the software interrupt or trap instruction by invoking the macro OS_TASK_SW() #define OS_TASK_SW() asm INT u. COS 41

Pseudocode The machine has saved the return address and status word void OSCtx. Sw(void)

Pseudocode The machine has saved the return address and status word void OSCtx. Sw(void) { Save processor registers; Save the current task’s stack pointer into\ the current task’s OS_TCB: OSTCBCur->OSTCBStk. Ptr = Stack pointer; Call user definable OSTask. Sw. Hook(); OSTCBCur = OSTCBHigh. Rdy; OSPrio. Cur = OSPrio. High. Rdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHigh. Rdy->OSTCBStk. Ptr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; } 42

OSTick. ISR() • You MUST enable ticker interrupts AFTER multitasking has started, i. e.

OSTick. ISR() • 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 OSTick. ISR(void) { Save processor registers; Call OSInt. Enter() or increment OSInt.

Pseudocode void OSTick. ISR(void) { Save processor registers; Call OSInt. Enter() or increment OSInt. Nesting; if (OSInt. Nesting == 1) OSTCBCur->OSTCBStk. Ptr = stack pointer Call OSTime. Tick(); Call OSInt. Exit(); Restore processor registers; Execute a return from interrupt instruction; } 44

OSInt. Exit() void OSInt. Exit (void) { if (OSInt. Nesting == 0) { if

OSInt. Exit() void OSInt. Exit (void) { if (OSInt. Nesting == 0) { if (OSLock. Nesting == 0) { OSInt. Exit. Y = OSUn. Map. Tbl[OSRdy. Grp]; OSPrio. High. Rdy = (INT 8 U)((OSInt. Exit. Y << 3) + OSUn. Map. Tbl[OSRdy. Tbl[OSInt. Exit. Y]]); if (OSPrio. High. Rdy != OSPrio. Cur) { OSTCBHigh. Rdy = OSTCBPrio. Tbl[OSPrio. High. Rdy]; OSInt. Ctx. Sw(); } } } OS_EXIT_CRITICAL(); } } 45

OSInt. Ctx. Sw() • This function is called by OSInt. Exit() to perform context

OSInt. Ctx. Sw() • This function is called by OSInt. Exit() to perform context switch from ISR. • Because it is called from ISR, all registers are properly saved. 46

Pseudocode void OSInt. Ctx. Sw(void) { Call user-definable OSTask. Sw. Hook(); OSTCBCur = OSTCBHigh.

Pseudocode void OSInt. Ctx. Sw(void) { Call user-definable OSTask. Sw. Hook(); OSTCBCur = OSTCBHigh. Rdy; OSPrio. Cur = OSPrio. High. Rdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHigh. Rdy->OSTCBStk. Ptr; Restore all processor registers from the new task’s stack; Execute a “return from interrupt” instruction; } 47

Pseudocode – an Old Version void OSInt. Ctx. Sw(void) { Adjust the stack pointer

Pseudocode – an Old Version void OSInt. Ctx. Sw(void) { Adjust the stack pointer to remove calls to: OSInt. Exit(), OSInt. Ctx. Sw() and possibly the push of the processor status word; Save the current task’s stack pointer into the current task’s OS_TCB: OSTCBCur->OSTCBStk. Ptr = Stack pointer; Call user definable OSTask. Sw. Hook(); OSTCBCur = OSTCBHigh. Rdy; OSPrio. Cur = OSPrio. High. Rdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHigh. Rdy->OSTCBStk. Ptr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; } 48

49

49

Testing of a Port • Steps – Ensure that the code compiles, assembles and

Testing of a Port • Steps – Ensure that the code compiles, assembles and links – Verify OSTask. Stk. Init and OSStart. High. Rdy – Verify OSCtx. Sw – Verify OSInt. Ctx. Sw and OSTick. ISR 50

Code Compiling, Assembling and Linking • Ensure that the code compiles, assembles and links

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

Verifying of OSTask. Stk. Init and OSStart. High. Rdy 1. Disable the statistic task

Verifying of OSTask. Stk. Init and OSStart. High. Rdy 1. Disable the statistic task OS_TASK_STAT_EN = 0 2. Step over the function OSInit() and then step into the for OSStart() 3. Step into OSStart. High. Rdy 4. Switch to the “Idle” task? – The register order OSTask. Stk. Init – “Return” to the idle thread OSStart. High. Rdy 52

Verifying of OSCtx. Sw() void main() { OSInit(); OSTask. Create(Test. Task, NULL, stack, 0);

Verifying of OSCtx. Sw() void main() { OSInit(); OSTask. Create(Test. Task, NULL, stack, 0); OSStart(); } Void Test. Task(void *p. Data) { while(1) { OSTime. Dly(1); } } 53

Verifying of OSCtx. Sw() • OSTime. Dly() OS_Sched() OSCtx. Sw () • When the

Verifying of OSCtx. Sw() • OSTime. Dly() OS_Sched() OSCtx. Sw () • When the return from interrupt is executed, the you should be in OS_Task. Idle. 54

Verifying of OSInt. Ctx. Sw() and OSTick. ISR() • Installing of a timer interrupt

Verifying of OSInt. Ctx. Sw() and OSTick. ISR() • Installing of a timer interrupt handler • Call OSTime. Dly(1) to result in a context switch to the idle thread by using OSInt. Ctx. Sw() and OSTick. ISR() 55

Verifying of OSInt. Ctx. Sw() and OSTick. ISR() void main(void) { OSInit(); install the

Verifying of OSInt. Ctx. Sw() and OSTick. ISR() void main(void) { OSInit(); install the clock tick ISR; OSTask. Create(Test. Task); OSStart(); } Void Test. Task(void *p. Data) { disable interrupt initialize the clock tick interrupt; enable interrupt while (1) { OSTime. Dly(1); printf(“%d”, OSTime. Get()); } } 56