Search for posts tagged with: Nucleus

Avatar

在Nucleus中timer的创建函数是NU_Create_Timer,其定义是

#define         NU_Create_Timer                 TMS_Create_Timer

通过其参数我们就可以看出如何设置一个timer。

STATUS  TMS_Create_Timer(NU_TIMER *timer_ptr, CHAR *name,
VOID (*expiration_routine)(UNSIGNED), UNSIGNED id,
UNSIGNED initial_time, UNSIGNED reschedule_time, OPTION enable)

timer -> tm_actual_timer.tm_timer_type =    TM_APPL_TIMER;
CSC_Place_On_List(&TMD_Created_Timers_List, &(timer -> tm_created));
TMD_Total_Timers++;

创建一个timer是很容易看懂的,我们主要分析timer时间到了之后的系统流程。

在TI平台中使用一个硬件晶振产生中断来作为系统的定时器,每次中断间隔时间作为操作系统的一个tick,也就是一个时间片。当中断发生时也就是产生了一个irq,在以前的irq流程中分析中我们可以知道每个irq都有一个自己的处理函数。在ti的平台的这个函数中我们可以发现如下代码

TMT_Timer_Interrupt();

这个函数就是Nucleus timer的接口函数,在这个函数中会检查是否有timer的时间到了,如果有timer active需要进行对应的操作,该函数会激活timer的HISR,这个HISR是在Nucleus初始化时TMI_Initialize函数中创建的。

status =  TCCE_Create_HISR((NU_HISR *) &TMD_HISR, "SYSTEM H",
TMC_Timer_HISR, (OPTION) TMD_HISR_Priority,
TMD_HISR_Stack_Ptr, TMD_HISR_Stack_Size);

在这个HISR的处理函数中,使用timer函数创建的timer的最主要的代码是

/* Determine if the task timer has expired.  */
if (TMD_Timer_State == TM_EXPIRED)

/* Resume the timer task.  */
TMC_Timer_Expiration();

在TMC_Timer_Expiration函数中

id =                  app_timer -> tm_expiration_id;
expiration_routine =  app_timer -> tm_expiration_routine;
//app_timer的tm_expiration_id和tm_expiration_routine就是创建函数TMS_Create_Timer传入的参数。
if (!done)
{

/* Determine which type of timer has expired.  */
if (type == TM_APPL_TIMER)
//类型为TM_APPL_TIMER,也就是task调用timer函数创建的类型。
//调用创建传入的timer超时时需要调用的函数。
/* Call application timer's expiration function.  */
(*(expiration_routine)) (id);
else
//这里是Nucleus进行task的时间片处理的部分。
/* Call the task timeout function in the thread control
function.  */
TCC_Task_Timeout((NU_TASK *) pointer);
}

基本上Nucleus的timer主要流程就是这些了。

Avatar

在Nucleus的等待事件函数EVC_Retrieve_Events中有这么一段函数

if (suspend)
{

/* Suspension is selected.  */

/* Increment the number of tasks waiting.  */
event_group -> ev_tasks_waiting++;

/* Setup the suspend block and suspend the calling task.  */
suspend_ptr =  &suspend_block;
suspend_ptr -> ev_event_group =              event_group;
suspend_ptr -> ev_suspend_link.cs_next =     NU_NULL;
suspend_ptr -> ev_suspend_link.cs_previous = NU_NULL;
task =                            (TC_TCB *) TCT_Current_Thread();
suspend_ptr -> ev_suspended_task =           task;
suspend_ptr -> ev_requested_events =         requested_events;
suspend_ptr -> ev_operation =                operation;

/* Link the suspend block into the list of suspended tasks on this
event group.  */
CSC_Place_On_List((CS_NODE **)
&(event_group -> ev_suspension_list),
&(suspend_ptr -> ev_suspend_link));

/* Finally, suspend the calling task. Note that the suspension call
automatically clears the protection on the event group.  */
TCC_Suspend_Task((NU_TASK *) task, NU_EVENT_SUSPEND,
EVC_Cleanup, suspend_ptr, suspend);

/* Pickup the return status and the actual retrieved events.  */
status =             suspend_ptr -> ev_return_status;
*retrieved_events =  suspend_ptr -> ev_actual_events;

}
else
..........

我们看到当task因为该事件而阻塞的代码

/* Finally, suspend the calling task. Note that the suspension call
automatically clears the protection on the event group.  */
TCC_Suspend_Task((NU_TASK *) task, NU_EVENT_SUSPEND,
EVC_Cleanup, suspend_ptr, suspend);

执行后紧接着的就是将等待事件的状态和接受到消息的变量进行了赋值,这是为什么呢,这样正确吗?
原来是这样的。当TCC_Suspend_Task被调用后当前task被挂起,这个函数以后的代码已经不会再接着执行了。等到这个task恢复时说明这个事件已经等到了,这个事件的值是在EVC_Set_Events函数中被设置的。

if (compare)
{

/* Decrement the number of tasks waiting counter.  */
event_group -> ev_tasks_waiting--;

/* Determine if consumption is requested.  */
if (suspend_ptr -> ev_operation & EV_CONSUME)

/* Keep track of the event flags to consume.  */
consume =  consume | suspend_ptr -> ev_requested_events;

/* Remove the first suspended block from the list.  */
CSC_Remove_From_List((CS_NODE **)
&(event_group -> ev_suspension_list),
&(suspend_ptr -> ev_suspend_link));

/* Setup the appropriate return value.  */
suspend_ptr -> ev_return_status =  NU_SUCCESS;
suspend_ptr -> ev_actual_events =
event_group -> ev_current_events;

/* Resume the suspended task.  */
preempt = preempt |
TCC_Resume_Task((NU_TASK *) suspend_ptr -> ev_suspended_task,
NU_EVENT_SUSPEND);

}

可以看到设置的返回值就是EVC_Retrieve_Events函数中的返回值。

Avatar

Nucleus Task的中断与恢复

以下是以TI的源代码进行的分析
一般来说最有可能中断Task的就是irq中断了。在ARM下到有中断发生时,ARM会自动切换到IRQ模式,此时ARM的寄存器已经是IRQ模式下的寄存器了。

INT_IRQ
STMDB   sp!,{r0-r5}                 ; Save a1-a4 on temporary IRQ stack
MRS     a1,spsr                     ; check for the IRQ bug:
TST     a1,#080h                    ; if the I - flag is set,
BNE     IRQBUG                      ; then postpone execution of this IRQ
SUB     r4,lr,#4                    ; Save IRQ's lr (return address)
注意r4的内容lr-4(被中断的PC,-4是因为ARM放入的是下一条指令+4)
BL      _TCT_Interrupt_Context_Save ; Call context save routine
BL      _IQ_IRQ_isr             ; Call  int. service routine
B       _TCT_Interrupt_Context_Restore

;BUG correction 2nd part  ------------------
IRQBUG: LDMFD  sp!,{r0-r5}                  ; return from interrup. Fix for locosto reset problem. We have pushed 6 regs and popping 4.
SUBS   pc,r14,#4
;BUG correction 2nd part end  --------------

以上就是一个irq的完整的处理过程了,我们慢慢来分析。 Read the rest of this post »

Avatar

Task的创建与调度

Nucleus的系统入口函数是

VOID  INC_Initialize(VOID  *first_available_memory)
{

。。。。。。。。
/* Invoke the application-supplied initialization function.  */
Application_Initialize(first_available_memory);

/* Indicate that initialization is finished.  */
INC_Initialize_State =  INC_END_INITIALIZE;

/* Start scheduling threads of execution.  */
TCT_Schedule();
}

Application_Initialize(first_available_memory);这个函数是留给平台用来初始化系统框架和创建task用的。
Task的创建一般如下

if ( NU_Create_Task (&TaskTable[Handle].TaskCB.TCB, Name, os_TaskEntry,
Handle, (VOID *)NULL,
(void*)(TaskTable[Handle].Stack+1), (ULONG) StackSize, (UCHAR) Priority,
#ifndef _TARGET_
10,
#else
0,
#endif
NU_PREEMPT, NU_NO_START) != NU_SUCCESS )
#define         NU_Resume_Task                  TCCE_Create_Task

最关键的实现是 Read the rest of this post »