ucosii is scheduled according to priority. For tasks, there are two states, ready state and not ready state. In many cases, tasks will be in non ready state, such as semaphore, message queue, mailbox, delay, task suspension, scheduling lock, etc., which will make the program enter into non ready state. At this time, tasks can be switched according to priority.
In general, our task code is a business + delay mode. When our code goes into the delay function of the task, it will first clear the status of the task ready table and make it a non running state, then call the scheduling function -OS_Sched() to cut the task.
void OS_Sched (void) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); if (OSIntNesting == 0u) { /* Schedule only if all ISRs done and ... */ if (OSLockNesting == 0u) { /* ... scheduler is not locked */ OS_SchedNew(); OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ #if OS_TASK_PROFILE_EN > 0u OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSCtxSwCtr++; /* Increment context switch counter */ OS_TASK_SW(); /* Perform a context switch */ } } } OS_EXIT_CRITICAL(); }
To view the above scheduling code, first call the OS_SchedNew function to get the highest priority task of the ready state, then use the OS_TASK_SW function to store the address of the current task and the information of R0-R14 to the stack, push the highest priority task from the stack to the register, then call the R13 PSP register to switch to the next task to run. The OS_SchedNew function is implemented as follows:
static void OS_SchedNew (void) 2 { 3 #if OS_LOWEST_PRIO <= 63u /* See if we support up to 64 tasks */ 4 INT8U y; 5 6 7 y = OSUnMapTbl[OSRdyGrp]; 8 OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]); 9 #else /* We support up to 256 tasks */ 10 INT8U y; 11 OS_PRIO *ptbl; 12 13 14 if ((OSRdyGrp & 0xFFu) != 0u) { 15 y = OSUnMapTbl[OSRdyGrp & 0xFFu]; 16 } else { 17 y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u; 18 } 19 ptbl = &OSRdyTbl[y]; 20 if ((*ptbl & 0xFFu) != 0u) { 21 OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]); 22 } else { 23 OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u); 24 } 25 #endif 26 }
Where: 7 y = OSUnMapTbl[OSRdyGrp];
8 OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);
The two rows obtain the highest priority by looking up tables. First, the group with the highest priority is obtained, and then the value of the highest priority is obtained from the reorganization. The combination of the group and the value returns the highest priority.
For the amount of delay we have in the function, it is not obtained from the tick, but in the task structure, there is a delay value specially used for management, which is PTCB - > ostcbdly. His time cycle is changed according to the time granularity of our initial tick timer. Each tick timer will trigger the OSTimeTick function as follows:
void OSTimeTick (void) { OS_TCB *ptcb; if (OSRunning == OS_TRUE) { ptcb = OSTCBList; /* Point at first TCB in TCB list */ while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) { /* Go through all TCBs in TCB list */ OS_ENTER_CRITICAL(); if (ptcb->OSTCBDly != 0u) { /* No, Delayed or waiting for event with TO */ ptcb->OSTCBDly--; /* Decrement nbr of ticks to end of delay */ if (ptcb->OSTCBDly == 0u) { /* Check for timeout */ if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) { ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY; /* Yes, Clear status flag */ ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */ } else { ptcb->OSTCBStatPend = OS_STAT_PEND_OK; } if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */ OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } } } ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */ OS_EXIT_CRITICAL(); } } }
Question the 0-63 priority task to see if OSTCBDly is reduced to 0, then judge whether it is ready, and then enable the priority task.
This is mainly used to schedule tasks. It is possible that the OSTCBDly value of multiple tasks is 0 at the same time, so multiple tasks can be triggered, but at this time it depends on priority, who has higher priority, who has limited operation. So the priority of the task cannot be set to the same. There will be problems.