一、系统调用OSInit(&err); 初始化内核都做了什么
1、进入初始化函数到这里大致可以分为几个步骤
(1)、初始化数据
OSInitHook(); /* Call port specific initialization code */
OSIntNestingCtr = (OS_NESTING_CTR)0; /* Clear the interrupt nesting counter */
OSRunning = OS_STATE_OS_STOPPED; /* Indicate that multitasking not started */
OSSchedLockNestingCtr = (OS_NESTING_CTR)0; /* Clear the scheduling lock counter */
这里简单来说就是惊醒了一些内容的初始化数值,包括有调用特殊端口的初始化,
清楚终端嵌套计数,不开启多任务、清楚任务调度的锁。
if (OSCfg_ISRStkSize > (CPU_STK_SIZE)0) {
p_stk = OSCfg_ISRStkBasePtr; /* Clear exception stack for stack checking. */
if (p_stk != (CPU_STK *)0) {
size = OSCfg_ISRStkSize;
while (size > (CPU_STK_SIZE)0) {
size--;
*p_stk = (CPU_STK)0;
p_stk++;
}
}
}
这里的话也很简单,简单理解就是通过循环来清除栈空间的内容,全部设置成0,为了后续检查。
void OS_PrioInit (void)
{
CPU_DATA i;
、 /* Clear the bitmap table ... no task is ready */
for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) {
OSPrioTbl[i] = (CPU_DATA)0;
}
}
void OS_RdyListInit (void)
{
OS_PRIO i;
OS_RDY_LIST *p_rdy_list;
for (i = 0u; i < OS_CFG_PRIO_MAX; i++) {
/* Initialize the array of OS_RDY_LIST at each priority */
p_rdy_list = &OSRdyList[i];
p_rdy_list->NbrEntries = (OS_OBJ_QTY)0;
p_rdy_list->HeadPtr = (OS_TCB *)0;
p_rdy_list->TailPtr = (OS_TCB *)0;
}
}
再就是调用这个函数,这个函数大概可以理解为每一个就绪态的任务都会在这个数组中对应优先级的位置去置为1,现在经行初始化,代表没有任务需要被设置为1,所以这里的作用就是清空数组中的内容,代表此时系统正在初始化,代表没有任务就绪。
下方函数就是对于每一个优先级的任务,经行就绪列表的初始化。
void OS_TaskInit (OS_ERR *p_err)
{
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#if OS_CFG_DBG_EN > 0u
OSTaskDbgListPtr = (OS_TCB *)0;
#endif
OSTaskQty = (OS_OBJ_QTY )0; /* Clear the number of tasks */
OSTaskCtxSwCtr = (OS_CTX_SW_CTR)0; /* Clear the context switch counter */
*p_err = OS_ERR_NONE;
}
这个就是初始化系统的任务管理器。说白了也就是去给参数赋值0
(2)、创建空闲任务
接下来来到了比较关键的地方,就是ucos初始化就会创建两个任务出来
OS_IdleTaskInit(p_err); /* Initialize the Idle Task */
if (*p_err != OS_ERR_NONE) {
return;
}
OS_TickTaskInit(p_err); /* Initialize the Tick Task */
if (*p_err != OS_ERR_NONE) {
return;
}
这里就是创建任务的地方,先讲第一个任务(空闲任务)
void OS_IdleTask (void *p_arg)
{
CPU_SR_ALLOC();
p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
while (DEF_ON) {
CPU_CRITICAL_ENTER();
OSIdleTaskCtr++;
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCtr++;
#endif
CPU_CRITICAL_EXIT();
OSIdleTaskHook(); /* Call user definable HOOK */
}
}
这里可以看到空闲任务的实际运行非常的简单,就是不断地对一个变量进行++,OSIdleTaskCtr这个变量,从侧面来说,这个变量自增的快慢也可以反映出我们的系统工作的效率,增加的越快代表系统的利用率越低,(因为系统用都去做这个空闲任务了)
这里面还有一个点:空闲任务是最大优先级-1的优先级位置,这个位置也只允许空闲任务在这里。
(3)、创建时钟基准任务
void OS_TickTask (void *p_arg)
{
OS_ERR err;
CPU_TS ts;
p_arg = p_arg; /* Prevent compiler warning */
while (DEF_ON) {
(void)OSTaskSemPend((OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(CPU_TS *)&ts,
(OS_ERR *)&err); /* Wait for signal from tick interrupt
if (err == OS_ERR_NONE) {
if (OSRunning == OS_STATE_OS_RUNNING) {
OS_TickListUpdate(); /* Update all tasks waiting for time */
}
}
}
}
这个函数是为了去配置ucos的时钟基准。这里面设置的超时时间是0意思也就是一旦时钟基准设置了之后就会无限制的运行下去,这也和实际情况是相符的。
(4)、初始化消息队列的列表
#if (OS_MSG_EN) > 0u /* Initialize the free list of OS_MSGs */
OS_MsgPoolInit(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
#endif