1 / 20

Chapter 13 Porting uC/OS-II

Chapter 13 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.

eze
Download Presentation

Chapter 13 Porting uC/OS-II

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 13Porting uC/OS-II

  2. 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.

  3. uC/OS-II Hardware/Software Architecture u u Setting the value of 2 #define constants (OS_CPU.H) Declaring 11 data types (OS_CPU.H) Declaring 2 #define macros (OS_CPU.H) Writing 10 simple functions in C (OS_CPU_C.C) Writing 4 assembly language functions (OS_CPU_A.ASM) u

  4. 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) 1 #define #define OS_TASK_SW() ??? (5) 10 data types

  5. OS_Enter_Critical() and OS_Exit_Critical() • Be careful to use these two function • Your application will crash if you disable interrupts before calling a uC/OS-II service, such as OSTimeDly. • The task is suspended until time expires, but because interrupts are disabled • 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

  6. 13.04 OS_CPU_C.C A uC/OS-II port requires that you write 10 fairly simple C functions • OSTaskStkInit() • OSTaskCreateHook(): called by OS_TCBInit() whenever a task is created • OSTaskDelHook(): called by OSTaskDel() after removing the task from either the ready list or a wait list. • OSTaskSwHook(): called whenever a task switch occurs. • OSTaskIdleHook(): called by OS_TaskIdel() for bring the CPU into a low-power mode. The CPU exits low-power mode when it receives an interrupt. • OSTaskStatHook(): called once every second by OSTaskStat() • OSTimeTickHook(): called by OSTimetick() at every system tick. • OSInitHookBegin(): called immediately upon entering OSInit() • OSinitHookEnd(): called at the end of OSInit(). • OSTCBinitHook(): called by OS_TCBInit() immediately before it calls OSTaskCreateHook(). • The only necessary functions is OSTaskStkInit()

  7. OSTaskStkInit() • This function is called by OSTaskCreate() and OSTaskCreateExt() to initialize the stack frame of a task • The stack looks as if an interrupt has just occurred and all the processor registers have been pushed onto that stack void MyTask (void *pdata) { /* Do something with argument ‘pdata’ */ for (;;) { /* Task code */ } } • OS_STK *OSTaskStkInit() (void (*task)(void *pd), • void *pdata, • OS_STK *ptos, • INIT16U opt); • { • simulate call to function with an argument (i.e. pdata); • Simulate ISR vector; • Setup stack frame to contain desired initial values of all registers; • Return new top-of-stack pointer to caller; • } • If I were to call MyTask() from another function, the C compiler might push the argument onto the stack followed by the return address of the function calling MyTask()

  8. Figure 9.3 80x86 Stack frame when task is created

  9. Stack frame initialization with pdata passed in register

  10. 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 • Make a ready task to run is to restore all processor registers from the task’s stack and execute a return from interrupt • OS_TASk_SW() is a macro which is always called from task-level code. The OS_TASK_SW() must to simulate an interrupt  It makes a software interrupt (asm INT uCOS) and the interrupt vector points to the OSCtxSw() which is an assembly program. uCOS=80h • 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() Four assembly language functions

  11. OSStartHighRdy() • OSStartHighRdy() is called by OSStart() to start the highest priority task ready to run • Before you can call OSStart(), you must have created at least one of you tasks. 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: }

  12. A task-level context switch is accomplished by issuing a software-interrupt instruction or, depending on the processor, executing a TRAP instruction. • The interrupt service routine, trap, or exception handler must vector to OSCtxSw(). • When the current task calls a service provided by uC/OS-II, which causes a higher priority task to be ready to run • At the end of the service call, uC/OS-II calls OS_Sched() • OS_Sched() loads the address of the highest priority task into OSTCBHighRdy and then calls OS_TASK_SW() to executes the software interrupt. 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(); #define OS_TASK_SW() asm INT uCOS (6) } } OS_EXIT_CRITICAL(); } The ISR is OSCtxSw()

  13. The interrupt vector of INT uCOS points to the OSCtxSw() written by assembly 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; }

  14. OSTickISR() • uC/OS-II requires you to provide a periodic time source to keep track of time delays and timeouts • You must enable ticker interrupts after multitasking has started, that is after calling OSStart(). • if the ticker interrupts are enable before calling OSStart(), the system may crash • You can and should initialize and tick interrupts in the first task that executes following a call to OSStart() • 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 */ }

  15. Pseudocode for tick ISR void OSTickISR(void) { Save processor registers; Call OSIntEnter() or increment OSIntNesting; if (OSIntNexting == 1){ OSTCBCur->OSTCBStkPtr = Stack Pointer; } clear interrupting device; Call OSTimeTick(); Call OSIntExit(); Restore processor registers; Execute a return from interrupt instruction; } Record the SP to avoid SP adjusting in OSIntCtxSw()

  16. 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(); //this is an assembly function (4) } } OS_EXIT_CRITICAL(); }

  17. OSIntCtxSw() • Called by OSIntExit() to perform a context switch from an ISR • Because OSIntCtxSw() is called from an ISR, we assume that all the processor registers are properly saved onto the interrupted task’s stack. 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; } These code is not required after v2.51

  18. OSIntCtxSw() Prior to v2.51 needs to adjust the SP. Stack contents during an ISR

  19. Testing a Port • You should test your port without application code • Four testing steps: • Ensure that the code compiles, assembles, and links • Verify OSTaskStkInit(0 and OSStartHighRdy() • Verify OSCtxSw() • Verify OSIntCtxSw() and OSTickISR()

More Related