📄 os.c
字号:
/* * File: os.c * * uC/OS Real-time multitasking kernel for the ARM processor. * * Kernel functions. * * Created by Jean J. Labrosse. * ARM port by Marco Graziano (marcog@crl.com). * */#include "ucos.h"#include "pid.h"#include "osdefs.h"#pragma no_check_stack/* let's stay on the safe side */#pragma no_optimise_crossjump#pragma no_optimise_multiple_loads#pragma no_optimise_cse/* mapping table to map bit position to bit mask */uint const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };/* priority resolution table */uint const OSUnMapTbl[] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,};/* global variables */uint OSCtxSwCtr; /* context switches counter */uint OSIdleCtr; /* idle counter */uint OSRunning = 0; /* kernel running flag */uint OSIntNesting; /* interrupt nesting level */OS_TCB *OSTCBCur; /* current running TCB pointer */OS_TCB *OSTCBHighRdy; /* highest priority TCB ready to run */OS_TCB *OSTCBPrioTbl[64]; /* table of pointers to created TCBs */ /* local variables */static OS_TCB *OSTCBList; /* TCBs doubled linked list */static uint OSRdyGrp; /* ready list group */static uint OSRdyTbl[8]; /* table of ready to run tasks */static uint OSLockNesting; /* multitasking lock nesting level */static OS_TCB *OSTCBFreeList; /* free TCBs list */static OS_EVENT *OSEventFreeList; /* free EVENT CB list */static OS_Q *OSQFreeList; /* free QUEUE CB list */static uint OSTime; /* system time in ticks */static uint OSIdleStk[OS_IDLE_STK_SIZE]; /* idle task stack */static OS_TCB OSTCBTbl[OS_MAX_TASKS + 1]; /* TCBs table */static OS_EVENT OSEventTbl[OS_MAX_EVENTS]; /* EVENT CBs table */static OS_Q OSQTbl[OS_MAX_QS]; /* QUEUE CBs table *//* idle task */static voidOSTaskIdle(void *data){ for (;;) { ENTER_CRITICAL(); OSIdleCtr++; EXIT_CRITICAL(); }} /* OSTaskIdle *//* process system tick */static voidOSTimeTick(void){ OS_TCB *ptcb = OSTCBList; /* define PIDLED if you would like to see the PID leds */#ifdef PIDLED static int Counter = 0; static int Timer = 0; extern void SetLED(uint);#endif /* PIDLED */ ENTER_CRITICAL(); OSTime++; EXIT_CRITICAL();#ifdef PIDLED /* every second change LEDs */ if (Timer++ == 100) { if (++Counter > 0x0F) Counter= 0; SetLED(Counter); Timer = 0; }#endif /* PIDLED */ /* scan all TCB in list */ ENTER_CRITICAL(); for ( ; ptcb->OSTCBPrio != OS_LO_PRIO; ptcb = ptcb->OSTCBNext) { if (ptcb->OSTCBDly) if (--ptcb->OSTCBDly == 0) { /* task is now ready to run */ OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } } EXIT_CRITICAL(); } /* OSTimeTick *//* initialize uC/OS */void OSInit(void){ static void __swi(OSEnterSWI) OSEnter(void); extern void PIDInit(void); int i; /* initialize PID hardware */ PIDInit(); /* enter supervisor mode and disable interrupts */ OSEnter(); /* initialize variables */ OSTime = 0; OSTCBHighRdy = (OS_TCB *)0; OSTCBCur = (OS_TCB *)0; OSTCBList = (OS_TCB *)0; OSIntNesting = 0; OSLockNesting = 0; OSRunning = FALSE; OSRdyGrp = 0; OSIdleCtr = 0; OSCtxSwCtr = 0; for (i = 0; i < 8; i++) OSRdyTbl[i] = 0; for (i = 0; i < 64; i++) OSTCBPrioTbl[i] = (OS_TCB *)0; for (i = 0; i < OS_MAX_TASKS; i++) OSTCBTbl[i].OSTCBNext = &OSTCBTbl[i + 1]; OSTCBTbl[OS_MAX_TASKS].OSTCBNext = (OS_TCB *)0; OSTCBFreeList = &OSTCBTbl[0]; for (i = 0; i < OS_MAX_EVENTS - 1; i++) OSEventTbl[i].OSEventPtr = &OSEventTbl[i + 1]; OSEventTbl[OS_MAX_EVENTS - 1].OSEventPtr = (OS_EVENT *)0; OSEventFreeList = &OSEventTbl[0]; for (i = 0; i < OS_MAX_QS - 1; i++) OSQTbl[i].OSQPtr = &OSQTbl[i + 1]; OSQTbl[OS_MAX_QS - 1].OSQPtr = (OS_Q *)0; OSQFreeList = &OSQTbl[0]; /* create the idle task */ OSTaskCreate(OSTaskIdle, (void *)0, (void *)&OSIdleStk[OS_IDLE_STK_SIZE], OS_LO_PRIO);} /* OSInit *//* start multitasking */void OSStart(void){ extern void OSStartHighRdy(void); /* defined in subr.s */ extern PFV IRQInstall(int, PFV); uint y, x, p; /* find the highest priority task */ y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; p = (y << 3) + x; OSTCBHighRdy = OSTCBPrioTbl[p]; /* install timer interrupt routine */ IRQInstall(TimerIRQNum, OSTimeTick); OSRunning = 1; /* enable interrupts and run the highest priority task */ OSStartHighRdy();} /* OSStart *//* uC/OS scheduler */static voidOSSched(void){ extern void OSCtxSw(void); /* defined in subr.s */ uint y; ENTER_CRITICAL(); if (OSLockNesting == 0 && OSIntNesting == 0) { /* task scheduling enabled and not interrupt level */ y = OSUnMapTbl[OSRdyGrp]; OSTCBHighRdy = OSTCBPrioTbl[(y << 3) + OSUnMapTbl[OSRdyTbl[y]]]; /* make sure this is not the current running task */ if (OSTCBHighRdy != OSTCBCur) { OSCtxSwCtr++; OSCtxSw(); /* context switch */ } } EXIT_CRITICAL(); } /* OSSched *//* prevent scheduling */void OSSchedLock(void){ ENTER_CRITICAL(); OSLockNesting++; EXIT_CRITICAL();} /* OSSchedLock *//* allow scheduling */void OSSchedUnlock(void){ ENTER_CRITICAL(); if (OSLockNesting == 0) { EXIT_CRITICAL(); return; } OSLockNesting--; if (OSLockNesting == 0 && OSIntNesting == 0) { /* scheduling re-enabled and not an ISR */ EXIT_CRITICAL(); /* check if a higher priority task became ready */ OSSched(); } else EXIT_CRITICAL();} /* OSSchedUnlock *//* find and initialize a TCB */static intOSTCBInit(uint prio, void *pstk){ OS_TCB *ptcb; ENTER_CRITICAL(); if ((ptcb = OSTCBFreeList) == (OS_TCB *)0) { /* no TCB available */ EXIT_CRITICAL(); return(OS_NO_MORE_TCB); } OSTCBFreeList = ptcb->OSTCBNext; /* link to the next free */ OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBStkPtr = pstk; /* top of private stack */ ptcb->OSTCBPrio = prio; /* task priority */ ptcb->OSTCBStat = OS_STAT_RDY; /* task is ready to run */ ptcb->OSTCBDly = 0; ptcb->OSTCBX = prio & 0x07; ptcb->OSTCBBitX = OSMapTbl[prio & 0x07]; ptcb->OSTCBY = prio >> 3; ptcb->OSTCBBitY = OSMapTbl[prio >> 3]; ptcb->OSTCBEventPtr = (OS_EVENT *)0; ptcb->OSTCBNext = OSTCBList; if (OSTCBList) ptcb->OSTCBPrev = ptcb; else ptcb->OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb; OSRdyGrp |= OSMapTbl[prio >> 3]; OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07]; EXIT_CRITICAL(); return(OS_NO_ERR);} /* OSTCBInit *//* create a task */int OSTaskCreate(PTV task, void *pdata, void *ptsk, uint prio){ uint *stk; int Ret; ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* only one task allowed at its priority */ EXIT_CRITICAL(); Ret = OS_PRIO_EXIST; } else { EXIT_CRITICAL(); stk = (uint *)ptsk; /* build a context for the new task */ *--stk = (uint)task; /* lr */ *--stk = 0; /* r12 */ *--stk = 0; /* r11 */ *--stk = 0; /* r10 */ *--stk = 0; /* r9 */ *--stk = 0; /* r8 */ *--stk = 0; /* r7 */ *--stk = 0; /* r6 */ *--stk = 0; /* r5 */ *--stk = 0; /* r4 */ *--stk = 0; /* r3 */ *--stk = 0; /* r2 */ *--stk = 0; /* r1 */ *--stk = (uint)pdata; /* r0 */ *--stk = SVC32MODE; /* spsr YYY+ */ *--stk = SVC32MODE; /* psr */ Ret = OSTCBInit(prio, (void *)stk); if (Ret == OS_NO_ERR && OSRunning) OSSched(); } return(Ret);} /* OSCreateTask *//* delete a task */int OSTaskDel(uint prio){ OS_EVENT *pevent; OS_TCB *ptcb; if (prio == OS_LO_PRIO) return(OS_TASK_DEL_IDLE); ENTER_CRITICAL(); if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { EXIT_CRITICAL(); return(OS_TASK_DEL_ERR); } /* clear old TCB entry */ OSTCBPrioTbl[prio] = (OS_TCB *)0; /* make task not ready */ if ((OSRdyTbl[ptcb->OSTCBY] &= ~(ptcb->OSTCBBitX)) == 0) OSRdyGrp &= ~(ptcb->OSTCBBitY); /* remove from TCB linked list */ if (ptcb->OSTCBPrev == (OS_TCB *)0) { ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb->OSTCBNext; } else { ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; } /* if task waiting on event remove it from event CB */ if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) pevent->OSEventGrp &= ~(ptcb->OSTCBBitY); /* return TCB to the free list */ ptcb->OSTCBNext = OSTCBFreeList; OSTCBFreeList = ptcb; EXIT_CRITICAL(); /* find new highest priority task */ OSSched(); return(OS_NO_ERR);} /* OSTaskDel *//* change task priority */int OSTaskChangePrio(uint oldp, uint newp){ OS_EVENT *pevent; OS_TCB *ptcb; int rdy; ENTER_CRITICAL(); /* check if new priority not in use */ if (OSTCBPrioTbl[newp] != (OS_TCB *)0) { EXIT_CRITICAL(); return(OS_PRIO_EXIST); } /* check if old priority task exists */ if (OSTCBPrioTbl[oldp] == (OS_TCB *)0) { EXIT_CRITICAL(); return(OS_PRIO_ERR); } /* remove TCB from old priority */ OSTCBPrioTbl[oldp] = (OS_TCB *)0; /* if task is ready make it not ready */ if (OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) { if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) OSRdyGrp &= ~(ptcb->OSTCBBitY); rdy = TRUE; } else rdy = FALSE; /* remove from event list */ if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) pevent->OSEventGrp &= ~ptcb->OSTCBBitY; /* remove from TCB linked list */ if (ptcb->OSTCBPrev == (OS_TCB *)0) { ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb->OSTCBNext; } else { ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; } EXIT_CRITICAL(); /* setup task control block with new values */ ptcb->OSTCBPrio = newp; ptcb->OSTCBY = newp >> 3; ptcb->OSTCBBitY = OSMapTbl[newp >> 3]; ptcb->OSTCBX = newp & 0x07; ptcb->OSTCBBitX = OSMapTbl[newp & 0x07]; ENTER_CRITICAL(); /* make new priority ready to run if old one was ready */ if (rdy) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { if (pevent != (OS_EVENT *)0) { /* wait for event if old was waiting */ pevent->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; pevent->OSEventGrp |= ptcb->OSTCBBitY; } } /* place TCB pointer at the new priority */ OSTCBPrioTbl[newp] = ptcb; /* link TCB to the top of the list */ OSTCBList->OSTCBPrev = ptcb; OSTCBList = ptcb; /* at least the idle task is in the list */ EXIT_CRITICAL(); /* run highest priority task ready */ OSSched(); return(OS_NO_ERR);} /* OSTaskChangePrio *//* delay the current task */void OSTimeDly(uint ticks){ ENTER_CRITICAL(); /* suspend the current task */ if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* load number of ticks in TCB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -