A simple cooperative multitasking system by Harold Hallikainen.
See "PIC 18C Microcontoller - Preemptive real-time multitasking kernel" /techref/microchip/18c/multitask-rtk-ba.htm for a more complex multutasker for the PIC18C. See "multitasking" /techref/method/multitask.htm for multitasking in general.
// main.c // SIMPLE COOPERATIVE MULTITASKING SYSTEM // Harold Hallikainen // harold@hallikainen.org // December 2006 // This is a test of a SIMPLE cooperative multitasker. For each task, the system keeps a copy of the // stack pointer and a copy of the stack. // Initialization - // Each task starts with a call of InitTask(n) where n is the task number. The task follows the InitTask // call with any other required initialization, then enters a loop. InitTask saves the return address into // the task in the SavedStack array. It then pops the return address off the stack so we return to main() // instead of the function that called InitTask(). This allows us to continue setting up other tasks in main(). // Running- // After each task has been initialized, main calls StartMultiTask(). This loads the stack with the values // stored for task 0 by InitTask(). // Task Switching- // Whenever a task is waiting for something (typically input, perhaps waiting for an output device to be ready), // the loop contains a call of NextTask(). NextTask saves the current stack, loads the stack for the next task, // then returns into that function where IT had called NextTask. Note that this return may be several // function call levels down. It need not be in the original task loop, but, instead, in a function called // by that loop. This is makes multitasking much simpler than use of state machines for each task and function // within that task. // Variables and Function Parameters // If a particular function contains a NextTask call, local variables and parameters to the function MUST // be static. This keeps them from being located on the software stack (as automatic variables would be). // Automatic variables and function parameters are lost during a task switch. In addition, the software stack // may undeflow or overflow if you do a task switch while automatic variables or parameters exist. However, // functions that do NOT include a task switch may use automatic parameters and functions since these are // destroyed before the NextTask is called. #include <p18f8627.h> #include "types.h" #define MaxTask 3 // Function Prototypes void InitTask(static uint8_t TaskNum); // Save return address for this function to continue, // then throw it out, dropping to main() void StartMultiTask(void); // loads stack with initial data for task 0, then returns to task 0. void NextTask(void); // save current stack and load stack for next task void task0(void); void task1(void); void task2(void); void task3(void); uint8_t Task3SubFunction(static uint8_t n); // testing a subfunction uint8_t Task3subSub(uint8_t n); #pragma udata MultiTask // generally requires more than 256 bytes or ram, so put in bigger section union{ uint24_t u24b; // access as 24 bit unsigned int uint8_t u8b[sizeof(uint24_t)]; // or array of bytes }SavedStack[MaxTask+1][31]; // Each stack entry is 3 bytes and there are 31 of them in each stack. // MaxTask is highest task number. Since they start at zero, dimension to MaxTask+1 static uint8_t SavedStackPointer[MaxTask+1]; // stack pointer saved for a particular task #pragma udata // let linker allocate rest of stuff void main(void){ task0(); task1(); task2(); task3(); // init each task StartMultiTask(); // go run multitask } void InitTask(static uint8_t TaskNum){ // Call from within a task. Puts the Saves the return address in SavedStack[TaskNum][1] so a later call // of NextTask will continue from this address. Uses static parameter to avoid use of parameter stack which // would be messed up when we do a return to main instead of calling function. INTCONbits.GIEH=0; // disable high priority interrupts INTCONbits.GIEL=0; // and low priority interrupts while messing with stack SavedStackPointer[TaskNum]=STKPTR; // save the current stack pointer SavedStack[TaskNum][STKPTR & 0b11111].u24b=TOS; // save current tos, which is where this function should start _asm POP _endasm; // remove return address so we drop back to main() INTCONbits.GIEL=1; // interrupts ok now INTCONbits.GIEH=1; } void StartMultiTask(void){ // loads stack with initial data for task 0, then returns to task 0. INTCONbits.GIEH=0; // disable high priority interrupts INTCONbits.GIEL=0; // and low priority interrupts while messing with stack STKPTR=0; // start with clear stack pointer while(STKPTR<=SavedStackPointer[0]){ //TOS=SavedStack[0][STKPTR & 0b11111]; // restore stack value - use below code to avoid movff to tos WREG=SavedStack[0][STKPTR & 0b11111].u8b[0]; TOSL=WREG; WREG=SavedStack[0][STKPTR & 0b11111].u8b[1]; TOSH=WREG; WREG=SavedStack[0][STKPTR & 0b11111].u8b[2]; TOSU=WREG; _asm PUSH _endasm; // and increment stack pointer } _asm POP _endasm; // get rid of extra stack pointer increment at end INTCONbits.GIEL=1; // interrupts ok now INTCONbits.GIEH=1; } void NextTask(void){ // save away the current stack, load the one for the next task, then exit static uint8_t TaskNum=0; INTCONbits.GIEH=0; // disable high priority interrupts INTCONbits.GIEL=0; // and low priority interrupts while messing with stack SavedStackPointer[TaskNum]=STKPTR; // save the current stack pointer while(STKPTR & 0b11111){ // while stuff still on the stack SavedStack[TaskNum][STKPTR & 0b11111].u24b=TOS; // save current tos _asm POP _endasm; // decrement the stack pointer } TaskNum++; // on to next task if(TaskNum>MaxTask) TaskNum=0; // roll over if past last while(STKPTR<=SavedStackPointer[TaskNum]){ //TOS=SavedStack[TaskNum][STKPTR & 0b11111]; // restore stack value - use below code to avoid movff to tos WREG=SavedStack[TaskNum][STKPTR & 0b11111].u8b[0]; TOSL=WREG; WREG=SavedStack[TaskNum][STKPTR & 0b11111].u8b[1]; TOSH=WREG; WREG=SavedStack[TaskNum][STKPTR & 0b11111].u8b[2]; TOSU=WREG; _asm PUSH _endasm; // and increment stack pointer } _asm POP _endasm; // get rid of extra stack pointer increment at end INTCONbits.GIEL=1; // interrupts ok now INTCONbits.GIEH=1; } void task0(void){ static uint8_t n=0; InitTask(0); // set up return address for here while(1){ // task loop ClrWdt(); n++; NextTask(); } // end while } // end function void task1(void){ static uint8_t n=0; InitTask(1); // set up return address for here while(1){ // task loop ClrWdt(); n++; NextTask(); } // end while } void task2(void){ static uint8_t n=0; InitTask(2); // set up return address for here while(1){ // task loop ClrWdt(); n++; NextTask(); } // end while } void task3(void){ static uint8_t n=0; InitTask(3); // set up return address for here while(1){ // task loop ClrWdt(); n++; n=Task3SubFunction(n); ClrWdt(); } // end while } uint8_t Task3SubFunction(static uint8_t n){ // testing a subfunction. Make parameters and local variables static on any functions that include NextTask. ClrWdt(); n=3*n; NextTask(); ClrWdt(); n=Task3subSub(n); return(n); } uint8_t Task3subSub(uint8_t n){ // since this function does not call NextTask, we don't need to use statics uint8_t y=3; uint8_t z; z=n*y; return(z); }
file: /Techref/microchip/language/c/MultiTask.c.htm, 13KB, , updated: 2007/1/24 17:19, local time: 2024/12/25 19:43,
owner: harold-hallikainen-,
3.137.171.71:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/techref/microchip/language/c/MultiTask.c.htm"> Simple C18 Cooperative Multitasking</A> |
Did you find what you needed? |