时间:2018.01.27 本人目前是大三学生 电子信息工程专业,在大学前俩年的时间,一直在使用和学习单片机,不过也仅仅是从51到32,马上要面临就业,最近开始学习linux ,驱动方面知识,看了几天视频,感觉看不下去了,昨晚突发奇想,下载了ucos的源码,想要分析一下这个小的嵌入式系统。本人将从头开始,通过调试追踪,对源代码进行细致分析。
希望自己可以坚持下去。开发环境是linux+eclipse 仿真来运行程序。
下面进入正题,大家接触过C语言,单片机的同学都知道,程序的入口是main函数,当然在单片机中会有一些堆栈初始化以及中断向量设置我们现在不关注,
下面是这个程序的main函数;
int main (void)
{
OS_ERR err;
OSInit(&err); /* Initialize "uC/OS-III, The Real-Time Kernel" */
OSTaskCreate((OS_TCB *)&App_TaskStartTCB, /* Create the start task */
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) App_TaskStart,
(void *) 0,
(OS_PRIO ) APP_CFG_TASK_START_PRIO,
(CPU_STK *)&App_TaskStartStk[0],
(CPU_STK )(APP_CFG_TASK_START_STK_SIZE / 10u),
(CPU_STK_SIZE) APP_CFG_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 0,
(OS_TICK ) 0,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
while(DEF_ON){ /* Should Never Get Here */
};
}
OSInit(&err); /* Initialize "uC/OS-III, The Real-Time Kernel" */
osInit(&err); 这是main函数中运行的第一个函数,下面是这个函数的实现 在os_core.c文件中
/*
************************************************************************************************************************
* INITIALIZATION
*
* Description: This function is used to initialize the internals of uC/OS-III and MUST be called prior to
* creating any uC/OS-III object and, prior to calling OSStart().
*
* Arguments : p_err is a pointer to a variable that will contain an error code returned by this function.
*
* OS_ERR_NONE Initialization was successful
* Other Other OS_ERR_xxx depending on the sub-functions called by OSInit().
* Returns : none
************************************************************************************************************************
*/
void OSInit (OS_ERR *p_err)
{
#if (OS_CFG_ISR_STK_SIZE > 0u)
CPU_STK *p_stk;
CPU_STK_SIZE size;
#endif
#ifdef OS_SAFETY_CRITICAL
if (p_err == DEF_NULL) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
OSInitHook(); /* Call port specific initialization code */
OSIntNestingCtr = 0u; /* Clear the interrupt nesting counter */
OSRunning = OS_STATE_OS_STOPPED; /* Indicate that multitasking not started */
OSSchedLockNestingCtr = 0u; /* Clear the scheduling lock counter */
OSTCBCurPtr = DEF_NULL; /* Initialize OS_TCB pointers to a known state */
OSTCBHighRdyPtr = DEF_NULL;
OSPrioCur = 0u; /* Initialize priority variables to a known state */
OSPrioHighRdy = 0u;
#if (OS_CFG_ISR_POST_DEFERRED_EN == DEF_ENABLED)
OSPrioSaved = 0u;
#endif
#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN == DEF_ENABLED)
OSSchedLockTimeBegin = 0u;
OSSchedLockTimeMax = 0u;
OSSchedLockTimeMaxCur = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
OSSafetyCriticalStartFlag = DEF_FALSE;
#endif
#if (OS_CFG_SCHED_ROUND_ROBIN_EN == DEF_ENABLED)
OSSchedRoundRobinEn = DEF_FALSE;
OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;
#endif
#if (OS_CFG_ISR_STK_SIZE > 0u)
p_stk = OSCfg_ISRStkBasePtr; /* Clear exception stack for stack checking. */
if (p_stk != DEF_NULL) {
size = OSCfg_ISRStkSize;
while (size > 0u) {
size--;
*p_stk = 0u;
p_stk++;
}
}
#if (OS_CFG_TASK_STK_REDZONE_EN == DEF_ENABLED) /* Initialize Redzoned ISR stack */
OS_TaskStkRedzoneInit(OSCfg_ISRStkBasePtr, OSCfg_ISRStkSize);
#endif
#endif
#if (OS_CFG_APP_HOOKS_EN == DEF_ENABLED) /* Clear application hook pointers */
#if (OS_CFG_TASK_STK_REDZONE_EN == DEF_ENABLED)
OS_AppRedzoneHitHookPtr = DEF_NULL;
#endif
OS_AppTaskCreateHookPtr = DEF_NULL;
OS_AppTaskDelHookPtr = DEF_NULL;
OS_AppTaskReturnHookPtr = DEF_NULL;
OS_AppIdleTaskHookPtr = DEF_NULL;
OS_AppStatTaskHookPtr = DEF_NULL;
OS_AppTaskSwHookPtr = DEF_NULL;
OS_AppTimeTickHookPtr = DEF_NULL;
#endif
#if (OS_CFG_TASK_REG_TBL_SIZE > 0u)
OSTaskRegNextAvailID = 0u;
#endif
OS_PrioInit(); /* Initialize the priority bitmap table */
OS_RdyListInit(); /* Initialize the Ready List */
#if (OS_CFG_FLAG_EN == DEF_ENABLED) /* Initialize the Event Flag module */
#if (OS_CFG_DBG_EN == DEF_ENABLED)
OSFlagDbgListPtr = DEF_NULL;
OSFlagQty = 0u;
#endif
#endif
#if (OS_CFG_MEM_EN == DEF_ENABLED) /* Initialize the Memory Manager module */
OS_MemInit(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_MSG_EN == DEF_ENABLED) /* Initialize the free list of OS_MSGs */
OS_MsgPoolInit(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_MUTEX_EN == DEF_ENABLED) /* Initialize the Mutex Manager module */
#if (OS_CFG_DBG_EN == DEF_ENABLED)
OSMutexDbgListPtr = DEF_NULL;
OSMutexQty = 0u;
#endif
#endif
#if (OS_CFG_Q_EN == DEF_ENABLED) /* Initialize the Message Queue Manager module */
#if (OS_CFG_DBG_EN == DEF_ENABLED)
OSQDbgListPtr = DEF_NULL;
OSQQty = 0u;
#endif
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED) /* Initialize the Semaphore Manager module */
#if (OS_CFG_DBG_EN == DEF_ENABLED)
OSSemDbgListPtr = DEF_NULL;
OSSemQty = 0u;
#endif
#endif
#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
OS_TLS_Init(p_err); /* Initialize Task Local Storage, before creating tasks */
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
OS_TaskInit(p_err); /* Initialize the task manager */
if (*p_err != OS_ERR_NONE) {
return;
}
#if (OS_CFG_ISR_POST_DEFERRED_EN == DEF_ENABLED)
OS_IntQTaskInit(p_err); /* Initialize the Interrupt Queue Handler Task */
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_TASK_IDLE_EN == DEF_ENABLED)
OS_IdleTaskInit(p_err); /* Initialize the Idle Task */
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_TASK_TICK_EN == DEF_ENABLED)
OS_TickTaskInit(p_err); /* Initialize the Tick Task */
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_STAT_TASK_EN == DEF_ENABLED) /* Initialize the Statistic Task */
OS_StatTaskInit(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_TMR_EN == DEF_ENABLED) /* Initialize the Timer Manager module */
OS_TmrInit(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
#if (OS_CFG_DBG_EN == DEF_ENABLED)
OS_Dbg_Init();
#endif
OSCfg_Init();
OSInitialized = DEF_TRUE; /* Kernel is initialized */
}
代码一长了就没人想看,我也没有看下去的欲望,但是仔细分析,其实都是一些条件编译的东西;
突然想起了一个词,叫做可裁剪,其实,这里的内容就是实现了ucos内核的裁剪功能,根据编译之前对一些功能宏的定义,实现编译我们需要的功能,去掉那些不需要的功能。这个在嵌入式开发中还是比较的重要,在一些嵌入式芯片,无论是ram还是flash都是寸土寸金,有时可能就是因为多定义了一些变量就会导致程序编译失败。
我接下来只会讲参加编译的代码
继续分析我们的这个初始化代码
#if (OS_CFG_ISR_STK_SIZE > 0u) /* 在我的项目 OS_CFG_ISR_STK_SIZE=256 猜测这个宏是一个与堆栈有关*/
CPU_STK *p_stk; /* 而且这个宏确实是大于0 这段代码会被编译 这里是定义可俩个变量*/
CPU_STK_SIZE size; /* 从名字上去看 应该是一个堆栈指针和大小 但是这里并没有赋值 后面应该会继续赋值*/
#endif
OSInitHook(); /* Call port specific initialization code */
/根据官方给出的注释 这里是一个初始化化 下面是这函数的实现*/
*********************************************************************************************************
* OS INITIALIZATION HOOK
*
* Description: This function is called by OSInit() at the beginning of OSInit().
*
* Arguments : None.
*
* Note(s) : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
void OSInitHook (void)
{
struct rlimit rtprio_limits;
ERR_CHK(getrlimit(RLIMIT_RTPRIO, &rtprio_limits));
if (rtprio_limits.rlim_cur != RLIM_INFINITY) {
printf("Error: RTPRIO limit is too low. Set to 'unlimited' via 'ulimit -r' or /etc/security/limits.conf\r\n");
exit(-1);
}
CPU_IntInit(); /* Initialize critical section objects. */
}
上面这个函数的主要内容是 cpu_intinit(); 暂时不去看,后面如果需要在回来看
接着往下分析
这里是对一些变量初始化赋值,根据后面注释可以看出大概的意思
OSIntNestingCtr = 0u; /* Clear the interrupt nesting counter */
OSRunning = OS_STATE_OS_STOPPED; /* Indicate that multitasking not started */
OSSchedLockNestingCtr = 0u; /* Clear the scheduling lock counter */
OSTCBCurPtr = DEF_NULL; /* Initialize OS_TCB pointers to a known state */
OSTCBHighRdyPtr = DEF_NULL;
OSPrioCur = 0u; /* Initialize priority variables to a known state */
OSPrioHighRdy = 0u;
下面也是一个开关 具体意思还不太了解
#if (OS_CFG_SCHED_ROUND_ROBIN_EN == DEF_ENABLED)
OSSchedRoundRobinEn = DEF_FALSE;
OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;
#endif
下面这段有熟悉的地方 有几个变量都在上面出现过了,在上面定义过但是没有赋值,这里开始赋值
#if (OS_CFG_ISR_STK_SIZE > 0u)
p_stk = OSCfg_ISRStkBasePtr; /* 这里给堆栈指针赋值 跟踪过去发现 OSCfg_ISRStkBasePtr是一个数组的首指针*/
if (p_stk != DEF_NULL) {
size = OSCfg_ISRStkSize;
while (size > 0u) { /* 这里是对堆栈初始化,清零 同时 堆栈指针p_stk会指向堆栈数组的尾部*/
size--;
*p_stk = 0u;
p_stk++;
}
}
这里又是一个初始化的部分,是对任务优先级的一个初始化,这里我们先不研究,在之后的任务调度肯定会用到
/*
************************************************************************************************************************
* INITIALIZE THE PRIORITY LIST
*
* Description: This function is called by uC/OS-III to initialize the list of ready priorities.
*
* Arguments : none
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/
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] = 0u;
}
#if (OS_CFG_TASK_IDLE_EN == DEF_DISABLED)
OS_PrioInsert ((OS_CFG_PRIO_MAX - 1u)); /* Insert what would be the idle task */
#endif
}
这个也是一个任务相关数组的初始化 后面会重点关注
************************************************************************************************************************
* INITIALIZATION
* READY LIST INITIALIZATION
*
* Description: This function is called by OSInit() to initialize the ready list. The ready list contains a list of all
* the tasks that are ready to run. The list is actually an array of OS_RDY_LIST. An OS_RDY_LIST contains
* three fields. The number of OS_TCBs in the list (i.e. .NbrEntries), a pointer to the first OS_TCB in the
* OS_RDY_LIST (i.e. .HeadPtr) and a pointer to the last OS_TCB in the OS_RDY_LIST (i.e. .TailPtr).
*
* OS_TCBs are doubly linked in the OS_RDY_LIST and each OS_TCB points pack to the OS_RDY_LIST it belongs
* to.
*
* 'OS_RDY_LIST OSRdyTbl[OS_CFG_PRIO_MAX]' looks like this once initialized:
*
* +---------------+--------------+
* | | TailPtr |-----> 0
* [0] | NbrEntries=0 +--------------+
* | | HeadPtr |-----> 0
* +---------------+--------------+
* | | TailPtr |-----> 0
* [1] | NbrEntries=0 +--------------+
* | | HeadPtr |-----> 0
* +---------------+--------------+
* : :
* : :
* : :
* +---------------+--------------+
* | | TailPtr |-----> 0
* [OS_CFG_PRIO_MAX-1] | NbrEntries=0 +--------------+
* | | HeadPtr |-----> 0
* +---------------+--------------+
*
*
* Arguments : none
*
* Returns : none
*
* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/
void OS_RdyListInit (void)
{
CPU_INT32U 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];
#if (OS_CFG_DBG_EN == DEF_ENABLED)
p_rdy_list->NbrEntries = 0u;
#endif
p_rdy_list->HeadPtr = DEF_NULL;
p_rdy_list->TailPtr = DEF_NULL;
}
}
剩下的部分都是一些条件编译的初始化,就不分析了
这里是本文分析的第一个函数 OS_INIT();
总结一下呢就是对一些数据结构的初始化,我们重点会关注 任务调度时间 以及其他的功能实现 后面会继续分析
第一次写博客 内容有些乱 分析的也很肤浅 应为我本来也不会哈哈哈
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)