140 likes | 299 Views
Chapter 8 Porting uC/OS-II. A Processor can run uC/OS-II if it satisfies the following general requirement You must have a C compiler for the processor and the C compiler must be able to produce reentrant code. You must be able to disable and enable interrupts from C.
E N D
A Processor can run uC/OS-II if it satisfies the following general requirement • You must have a C compiler for the processor and the C compiler must be able to produce reentrant code. • You must be able to disable and enable interrupts from C. • The processor must support interrupts and you need to provide an interrupt that occurs at regular intervals (typically between 10 to 100 Hz). • The processor must support a hardware stack, and the processor must be able to store a fair amount of data on the stack (possibly many Kbytes). • The processor must have instructions to load and store the stack pointer and other CPU registers either on the stack or in memory.
uC/OS-II Hardware/Software Architecture u u Setting the value of 1 #define constants (OS_CPU.H) Declaring 10 data types (OS_CPU.H) Declaring 3 #define macros (OS_CPU.H) Writing 6 simple functions in C (OS_CPU_C.C) Writing 4 assembly language functions (OS_CPU_A.ASM) u
OS_CPU.H #ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif /* ********************************************************************************************************* * DATA TYPES * (Compiler Specific) ********************************************************************************************************* */ typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /* Unsigned 8 bit quantity */ (1) typedef signed char INT8S; /* Signed 8 bit quantity */ typedef unsigned int INT16U; /* Unsigned 16 bit quantity */ typedef signed int INT16S; /* Signed 16 bit quantity */ typedef unsigned long INT32U; /* Unsigned 32 bit quantity */ typedef signed long INT32S; /* Signed 32 bit quantity */ typedef float FP32; /* Single precision floating point */ (2) typedef double FP64; /* Double precision floating point */ typedef unsigned int OS_STK; /* Each stack entry is 16-bit wide */ /* ********************************************************************************************************* * Processor Specifics ********************************************************************************************************* */ #define OS_ENTER_CRITICAL() ??? /* Disable interrupts */ (3) #define OS_EXIT_CRITICAL() ??? /* Enable interrupts */ #define OS_STK_GROWTH 1 /* Define stack growth: 1 = Down, 0 = Up */ (4) #define OS_TASK_SW() ??? (5)
OS_Enter_Critical() and OS_Exit_Critical() • Method 1 • If you call the uC/OS-II function with interrupts disabled, on return from uC/OS-II, interrupts would be enabled • Total required four cycles #define OS_ENTER_CRITICAL() asm CLI #define OS_EXIT_CRITICAL() asm STI • Method 2 • OS_enter_Critical() consumes 12 clock cycles • OS_Exit_Critical() use up to 8 clock cycles #define OS_ENTER_CRITICAL() asm PUSHF; CLI #define OS_EXIT_CRITICAL() asm POPF
Context Switch • In uC/OS-II, the stack frame for a ready task always looks as if an interrupt has just occurred and all processor registers were saved onto to it • OS_TASk_SW() is always called from task-level code • OSIntExit() is used to perform a context switch when an ISR makes a higher priority task ready for execution • OS_CPU_A.ASM • OSStartHighRdy() • OSCtxSw() • OSIntCtxSw() • OSTickISR()
OSStartHighRdy() Void OSStartHighRdy(void) { call user definable OSTaskSwHook() Get the stack pointer of the task to resume: stack pointer = OSTCBHighRdy->OSTCBStkPtr; OSRunning = True; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction: }
OSCtxSw() 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; }
OSIntCtxSw() Figure 8.2 Stack contents during an ISR
Pseudocode for OSIntCtxSw() 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; }
OSTickISR() • Incorrect place to start the tick interrupt void main(void) { . . OSInit(); /* Initialize µC/OS-II */ . . /* Application initialization code ... */ /* ... Create at least on task by calling OSTaskCreate() */ . . Enable TICKER interrupts; /* DO NOT DO THIS HERE!!! */ . . OSStart(); /* Start multitasking */ }
Pseudocode 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; }
OSTaskStkInit() void MyTask (void *pdata) { /* Do something with argument ‘pdata’ */ for (;;) { /* Task code */ } } • Stack frame initialization with pdata passed on the stack