|
- /*
- ***********************************************************************************************************************
- * uC/OS-III
- * The Real-Time Kernel
- *
- * (c) Copyright 2009-2014; Micrium, Inc.; Weston, FL
- * All rights reserved. Protected by international copyright laws.
- *
- * TICK MANAGEMENT
- *
- * File : OS_TICK.C
- * By : JJL
- * Version : V3.04.04
- *
- * LICENSING TERMS:
- * ---------------
- * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
- * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
- * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
- * application/product. We provide ALL the source code for your convenience and to help you
- * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
- * it commercially without paying a licensing fee.
- *
- * Knowledge of the source code may NOT be used to develop a similar product.
- *
- * Please help us continue to provide the embedded community with the finest software available.
- * Your honesty is greatly appreciated.
- *
- * You can find our product's user manual, API reference, release notes and
- * more information at https://doc.micrium.com.
- * You can contact us at www.micrium.com.
- ************************************************************************************************************************
- */
-
- #define MICRIUM_SOURCE
- #include "os.h"
-
- #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
- const CPU_CHAR *os_tick__c = "$Id: $";
- #endif
-
- /*
- ************************************************************************************************************************
- * FUNCTION PROTOTYPES
- ************************************************************************************************************************
- */
-
- static CPU_TS OS_TickListUpdateDly (void);
- static CPU_TS OS_TickListUpdateTimeout (void);
-
- /*
- ************************************************************************************************************************
- * TICK TASK
- *
- * Description: This task is internal to uC/OS-III and is triggered by the tick interrupt.
- *
- * Arguments : p_arg is an argument passed to the task when the task is created (unused).
- *
- * Returns : none
- *
- * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
- ************************************************************************************************************************
- */
-
- void OS_TickTask (void *p_arg)
- {
- OS_ERR err;
- CPU_TS ts_delta;
- CPU_TS ts_delta_dly;
- CPU_TS ts_delta_timeout;
- CPU_SR_ALLOC();
-
-
- (void)&p_arg; /* Prevent compiler warning */
-
- while (DEF_ON) {
- (void)OSTaskSemPend((OS_TICK )0,
- (OS_OPT )OS_OPT_PEND_BLOCKING,
- (CPU_TS *)0,
- (OS_ERR *)&err); /* Wait for signal from tick interrupt */
- if (err == OS_ERR_NONE) {
- OS_CRITICAL_ENTER();
- OSTickCtr++; /* Keep track of the number of ticks */
- #if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
- TRACE_OS_TICK_INCREMENT(OSTickCtr); /* Record the event. */
- #endif
- OS_CRITICAL_EXIT();
- ts_delta_dly = OS_TickListUpdateDly();
- ts_delta_timeout = OS_TickListUpdateTimeout();
- ts_delta = ts_delta_dly + ts_delta_timeout; /* Compute total execution time of list updates */
- if (OSTickTaskTimeMax < ts_delta) {
- OSTickTaskTimeMax = ts_delta;
- }
- }
- }
- }
-
- /*
- ************************************************************************************************************************
- * INITIALIZE TICK TASK
- *
- * Description: This function is called by OSInit() to create the tick task.
- *
- * Arguments : p_err is a pointer to a variable that will hold the value of an error code:
- *
- * OS_ERR_TICK_STK_INVALID if the pointer to the tick task stack is a NULL pointer
- * OS_ERR_TICK_STK_SIZE indicates that the specified stack size
- * OS_ERR_PRIO_INVALID if the priority you specified in the configuration is invalid
- * (There could be only one task at the Idle Task priority)
- * (Maybe the priority you specified is higher than OS_CFG_PRIO_MAX-1
- * OS_ERR_?? other error code returned by OSTaskCreate()
- *
- * Returns : none
- *
- * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
- ************************************************************************************************************************
- */
-
- void OS_TickTaskInit (OS_ERR *p_err)
- {
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
-
- OSTickCtr = (OS_TICK)0u; /* Clear the tick counter */
-
- OSTickListDly.TCB_Ptr = (OS_TCB *)0;
- OSTickListTimeout.TCB_Ptr = (OS_TCB *)0;
-
- #if OS_CFG_DBG_EN > 0u
- OSTickListDly.NbrEntries = (OS_OBJ_QTY)0;
- OSTickListDly.NbrUpdated = (OS_OBJ_QTY)0;
-
- OSTickListTimeout.NbrEntries = (OS_OBJ_QTY)0;
- OSTickListTimeout.NbrUpdated = (OS_OBJ_QTY)0;
- #endif
-
- /* ---------------- CREATE THE TICK TASK ----------- */
- if (OSCfg_TickTaskStkBasePtr == (CPU_STK *)0) {
- *p_err = OS_ERR_TICK_STK_INVALID;
- return;
- }
-
- if (OSCfg_TickTaskStkSize < OSCfg_StkSizeMin) {
- *p_err = OS_ERR_TICK_STK_SIZE_INVALID;
- return;
- }
-
- if (OSCfg_TickTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) { /* Only one task at the 'Idle Task' priority */
- *p_err = OS_ERR_TICK_PRIO_INVALID;
- return;
- }
-
- OSTaskCreate((OS_TCB *)&OSTickTaskTCB,
- (CPU_CHAR *)((void *)"uC/OS-III Tick Task"),
- (OS_TASK_PTR )OS_TickTask,
- (void *)0,
- (OS_PRIO )OSCfg_TickTaskPrio,
- (CPU_STK *)OSCfg_TickTaskStkBasePtr,
- (CPU_STK_SIZE)OSCfg_TickTaskStkLimit,
- (CPU_STK_SIZE)OSCfg_TickTaskStkSize,
- (OS_MSG_QTY )0u,
- (OS_TICK )0u,
- (void *)0,
- (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
- (OS_ERR *)p_err);
- }
-
- /*
- ************************************************************************************************************************
- * INSERT
- *
- * Description: This task is internal to uC/OS-III and allows the insertion of a task in a tick list.
- *
- * Arguments : p_list is a pointer to the desired list
- *
- * p_tcb is a pointer to the TCB to insert in the list
- *
- * time is the amount of time remaining (in ticks) for the task to become ready
- *
- * Returns : none
- *
- * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
- ************************************************************************************************************************
- */
-
- void OS_TickListInsert (OS_TICK_LIST *p_list,
- OS_TCB *p_tcb,
- OS_TICK time)
- {
- OS_TCB *p_tcb1;
- OS_TCB *p_tcb2;
- OS_TICK remain;
-
-
- if (p_list->TCB_Ptr == (OS_TCB *)0) { /* Is the list empty? */
- p_tcb->TickRemain = time; /* Yes, Store time in TCB */
- p_tcb->TickNextPtr = (OS_TCB *)0;
- p_tcb->TickPrevPtr = (OS_TCB *)0;
- p_tcb->TickListPtr = (OS_TICK_LIST *)p_list; /* Link to this list */
- p_list->TCB_Ptr = p_tcb; /* Point to TCB of task to place in the list */
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries = 1u; /* List contains 1 entry */
- #endif
- } else {
- p_tcb1 = p_list->TCB_Ptr;
- p_tcb2 = p_list->TCB_Ptr; /* No, Insert somewhere in the list in delta order */
- remain = time;
- while (p_tcb2 != (OS_TCB *)0) {
- if (remain <= p_tcb2->TickRemain) {
- if (p_tcb2->TickPrevPtr == (OS_TCB *)0) { /* Insert before the first entry in the list? */
- p_tcb->TickRemain = remain; /* Yes, Store remaining time */
- p_tcb->TickPrevPtr = (OS_TCB *)0;
- p_tcb->TickNextPtr = p_tcb2;
- p_tcb->TickListPtr = (OS_TICK_LIST *)p_list; /* Link TCB to this list */
- p_tcb2->TickRemain -= remain; /* Reduce time of next entry in the list */
- p_tcb2->TickPrevPtr = p_tcb;
- p_list->TCB_Ptr = p_tcb; /* Add TCB to the list */
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries++; /* List contains an extra entry */
- #endif
- } else { /* No, Insert somewhere further in the list */
- p_tcb1 = p_tcb2->TickPrevPtr;
- p_tcb->TickRemain = remain; /* Store remaining time */
- p_tcb->TickPrevPtr = p_tcb1;
- p_tcb->TickNextPtr = p_tcb2;
- p_tcb->TickListPtr = (OS_TICK_LIST *)p_list; /* TCB points to this list */
- p_tcb2->TickRemain -= remain; /* Reduce time of next entry in the list */
- p_tcb2->TickPrevPtr = p_tcb;
- p_tcb1->TickNextPtr = p_tcb;
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries++; /* List contains an extra entry */
- #endif
- }
- return;
- } else {
- remain -= p_tcb2->TickRemain; /* Point to the next TCB in the list */
- p_tcb1 = p_tcb2;
- p_tcb2 = p_tcb2->TickNextPtr;
- }
- }
- p_tcb->TickRemain = remain;
- p_tcb->TickPrevPtr = p_tcb1;
- p_tcb->TickNextPtr = (OS_TCB *)0;
- p_tcb->TickListPtr = (OS_TICK_LIST *)p_list; /* Link the list to the TCB */
- p_tcb1->TickNextPtr = p_tcb;
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries++; /* List contains an extra entry */
- #endif
- }
- }
-
- /*
- ************************************************************************************************************************
- * ADD TASK TO DELAYED TICK LIST
- *
- * Description: This function is called to place a task in a list of task waiting for either time to expire
- *
- * Arguments : p_tcb is a pointer to the OS_TCB of the task to add to the tick list
- * -----
- *
- * time represents either the 'match' value of OSTickCtr or a relative time from the current
- * value of OSTickCtr as specified by the 'opt' argument..
- *
- * relative when 'opt' is set to OS_OPT_TIME_DLY
- * relative when 'opt' is set to OS_OPT_TIME_TIMEOUT
- * match when 'opt' is set to OS_OPT_TIME_MATCH
- * periodic when 'opt' is set to OS_OPT_TIME_PERIODIC
- *
- * opt is an option specifying how to calculate time. The valid values are:
- * ---
- * OS_OPT_TIME_DLY
- * OS_OPT_TIME_TIMEOUT
- * OS_OPT_TIME_PERIODIC
- * OS_OPT_TIME_MATCH
- *
- * p_err is a pointer to a variable that will contain an error code returned by this function.
- * -----
- * OS_ERR_NONE the call was successful and the time delay was scheduled.
- * OS_ERR_TIME_ZERO_DLY if delay is zero or already occurred.
- *
- * Returns : None
- *
- * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
- *
- * 2) This function is assumed to be called with interrupts disabled.
- ************************************************************************************************************************
- */
-
- void OS_TickListInsertDly (OS_TCB *p_tcb,
- OS_TICK time,
- OS_OPT opt,
- OS_ERR *p_err)
- {
- OS_TICK remain;
-
-
-
- if (opt == OS_OPT_TIME_MATCH) { /* MATCH to absolute OSTickCtr value mode */
- remain = time - OSTickCtr;
- if ((remain > OS_TICK_TH_RDY) || /* If delay already occurred, ... */
- (remain == (OS_TICK)0u)) {
- p_tcb->TickRemain = (OS_TICK)0u;
- *p_err = OS_ERR_TIME_ZERO_DLY; /* ... do NOT delay. */
- return;
- }
-
- } else if (opt == OS_OPT_TIME_PERIODIC) { /* PERIODIC mode. */
- if ((OSTickCtr - p_tcb->TickCtrPrev) > time) {
- remain = time; /* ... first time we load .TickCtrPrev */
- p_tcb->TickCtrPrev = OSTickCtr + time;
- } else {
- remain = time - (OSTickCtr - p_tcb->TickCtrPrev);
- if ((remain > OS_TICK_TH_RDY) || /* If delay time has already passed, ... */
- (remain == (OS_TICK)0u)) {
- p_tcb->TickCtrPrev += time + time * ((OSTickCtr - p_tcb->TickCtrPrev) / time); /* Try to recover the period */
- p_tcb->TickRemain = (OS_TICK)0u;
- *p_err = OS_ERR_TIME_ZERO_DLY; /* ... do NOT delay. */
- return;
- }
- p_tcb->TickCtrPrev += time;
- }
-
- } else if (time > (OS_TICK)0u) { /* RELATIVE time delay mode */
- remain = time;
-
- } else { /* Zero time delay; ... */
- p_tcb->TickRemain = (OS_TICK)0u;
- *p_err = OS_ERR_TIME_ZERO_DLY; /* ... do NOT delay. */
- return;
- }
-
- p_tcb->TaskState = OS_TASK_STATE_DLY;
- OS_TickListInsert(&OSTickListDly, p_tcb, remain);
-
- *p_err = OS_ERR_NONE;
- }
-
- /*
- ************************************************************************************************************************
- * REMOVE A TASK FROM THE TICK LIST
- *
- * Description: This function is called to remove a task from the tick list
- *
- * Arguments : p_tcb Is a pointer to the OS_TCB to remove.
- * -----
- *
- * Returns : none
- *
- * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
- *
- * 2) This function is assumed to be called with interrupts disabled.
- ************************************************************************************************************************
- */
-
- void OS_TickListRemove (OS_TCB *p_tcb)
- {
- OS_TICK_LIST *p_list;
- OS_TCB *p_tcb1;
- OS_TCB *p_tcb2;
-
-
- p_list = (OS_TICK_LIST *)p_tcb->TickListPtr;
- p_tcb1 = p_tcb->TickPrevPtr;
- p_tcb2 = p_tcb->TickNextPtr;
- if (p_tcb1 == (OS_TCB *)0) {
- if (p_tcb2 == (OS_TCB *)0) { /* Remove ONLY entry in the list? */
- p_list->TCB_Ptr = (OS_TCB *)0;
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries = (OS_OBJ_QTY )0u;
- #endif
- p_tcb->TickRemain = (OS_TICK )0u;
- p_tcb->TickListPtr = (OS_TICK_LIST *)0;
- } else {
- p_tcb2->TickPrevPtr = (OS_TCB *)0;
- p_tcb2->TickRemain += p_tcb->TickRemain; /* Add back the ticks to the delta */
- p_list->TCB_Ptr = p_tcb2;
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries--;
- #endif
- p_tcb->TickNextPtr = (OS_TCB *)0;
- p_tcb->TickRemain = (OS_TICK )0u;
- p_tcb->TickListPtr = (OS_TICK_LIST *)0;
- }
- } else {
- p_tcb1->TickNextPtr = p_tcb2;
- if (p_tcb2 != (OS_TCB *)0) {
- p_tcb2->TickPrevPtr = p_tcb1;
- p_tcb2->TickRemain += p_tcb->TickRemain; /* Add back the ticks to the delta list */
- }
- p_tcb->TickPrevPtr = (OS_TCB *)0;
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries--;
- #endif
- p_tcb->TickNextPtr = (OS_TCB *)0;
- p_tcb->TickRemain = (OS_TICK )0u;
- p_tcb->TickListPtr = (OS_TICK_LIST *)0;
- }
- }
-
- /*
- ************************************************************************************************************************
- * RESET TICK LIST PEAK DETECTOR
- *
- * Description: This function is used to reset the peak detector for the number of entries in each spoke.
- *
- * Arguments : void
- *
- * Returns : none
- *
- * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
- ************************************************************************************************************************
- */
-
- void OS_TickListResetPeak (void)
- {
- #if OS_CFG_DBG_EN > 0u
- #endif
- }
-
- /*
- ************************************************************************************************************************
- * UPDATE THE LIST OF TASKS DELAYED
- *
- * Description: This function updates the delta list which contains tasks that have been delayed.
- *
- * Arguments : non
- *
- * Returns : none
- *
- * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
- ************************************************************************************************************************
- */
-
- static CPU_TS OS_TickListUpdateDly (void)
- {
- OS_TCB *p_tcb;
- OS_TICK_LIST *p_list;
- CPU_TS ts_start;
- CPU_TS ts_delta_dly;
- #if OS_CFG_DBG_EN > 0u
- OS_OBJ_QTY nbr_updated;
- #endif
- CPU_SR_ALLOC();
-
-
-
- OS_CRITICAL_ENTER();
- ts_start = OS_TS_GET();
- #if OS_CFG_DBG_EN > 0u
- nbr_updated = (OS_OBJ_QTY)0u;
- #endif
- p_list = &OSTickListDly;
- p_tcb = p_list->TCB_Ptr;
- if (p_tcb != (OS_TCB *)0) {
- p_tcb->TickRemain--;
- while (p_tcb->TickRemain == 0u) {
- #if OS_CFG_DBG_EN > 0u
- nbr_updated++; /* Keep track of the number of TCBs updated */
- #endif
- if (p_tcb->TaskState == OS_TASK_STATE_DLY) {
- p_tcb->TaskState = OS_TASK_STATE_RDY;
- OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */
- } else if (p_tcb->TaskState == OS_TASK_STATE_DLY_SUSPENDED) {
- p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
- }
-
- p_list->TCB_Ptr = p_tcb->TickNextPtr;
- p_tcb = p_list->TCB_Ptr; /* Get 'p_tcb' again for loop */
- if (p_tcb == (OS_TCB *)0) {
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries = (OS_OBJ_QTY)0u;
- #endif
- break;
- } else {
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries--;
- #endif
- p_tcb->TickPrevPtr = (OS_TCB *)0;
- }
- }
- }
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrUpdated = nbr_updated;
- #endif
- ts_delta_dly = OS_TS_GET() - ts_start; /* Measure execution time of the update */
- OS_CRITICAL_EXIT();
-
- return (ts_delta_dly);
- }
-
-
- /*
- ************************************************************************************************************************
- * UPDATE THE LIST OF TASKS PENDING WITH TIMEOUT
- *
- * Description: This function updales the delta list which contains tasks that are pending with a timeout.
- *
- * Arguments : non
- *
- * Returns : none
- *
- * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
- ************************************************************************************************************************
- */
-
- static CPU_TS OS_TickListUpdateTimeout (void)
- {
- OS_TCB *p_tcb;
- OS_TICK_LIST *p_list;
- CPU_TS ts_start;
- CPU_TS ts_delta_timeout;
- #if OS_CFG_DBG_EN > 0u
- OS_OBJ_QTY nbr_updated;
- #endif
- #if OS_CFG_MUTEX_EN > 0u
- OS_TCB *p_tcb_owner;
- OS_PRIO prio_new;
- #endif
- CPU_SR_ALLOC();
-
-
-
- OS_CRITICAL_ENTER(); /* ======= UPDATE TASKS WAITING WITH TIMEOUT ======= */
- ts_start = OS_TS_GET();
- #if OS_CFG_DBG_EN > 0u
- nbr_updated = (OS_OBJ_QTY)0u;
- #endif
- p_list = &OSTickListTimeout;
- p_tcb = p_list->TCB_Ptr;
- if (p_tcb != (OS_TCB *)0) {
- p_tcb->TickRemain--;
- while (p_tcb->TickRemain == 0u) {
- #if OS_CFG_DBG_EN > 0u
- nbr_updated++;
- #endif
-
- #if OS_CFG_MUTEX_EN > 0u
- p_tcb_owner = (OS_TCB *)0;
- if (p_tcb->PendOn == OS_TASK_PEND_ON_MUTEX) {
- p_tcb_owner = ((OS_MUTEX *)p_tcb->PendDataTblPtr->PendObjPtr)->OwnerTCBPtr;
- }
- #endif
-
- #if (OS_MSG_EN > 0u)
- p_tcb->MsgPtr = (void *)0;
- p_tcb->MsgSize = (OS_MSG_SIZE)0u;
- #endif
- p_tcb->TS = OS_TS_GET();
- OS_PendListRemove(p_tcb); /* Remove from wait list */
- if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) {
- OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */
- p_tcb->TaskState = OS_TASK_STATE_RDY;
- } else if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) {
-
- p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
- }
- p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */
- p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
-
- #if OS_CFG_MUTEX_EN > 0u
- if(p_tcb_owner != (OS_TCB *)0) {
- if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
- (p_tcb_owner->Prio == p_tcb->Prio)) { /* Has the owner inherited a priority? */
- prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
- prio_new = prio_new > p_tcb_owner->BasePrio ? p_tcb_owner->BasePrio : prio_new;
- if(prio_new != p_tcb_owner->Prio) {
- OS_TaskChangePrio(p_tcb_owner, prio_new);
- #if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
- TRACE_OS_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio)
- #endif
- }
- }
- }
- #endif
-
- p_list->TCB_Ptr = p_tcb->TickNextPtr;
- p_tcb = p_list->TCB_Ptr; /* Get 'p_tcb' again for loop */
- if (p_tcb == (OS_TCB *)0) {
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries = (OS_OBJ_QTY)0u;
- #endif
- break;
- } else {
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrEntries--;
- #endif
- p_tcb->TickPrevPtr = (OS_TCB *)0;
- }
- }
- }
- #if OS_CFG_DBG_EN > 0u
- p_list->NbrUpdated = nbr_updated;
- #endif
- ts_delta_timeout = OS_TS_GET() - ts_start; /* Measure execution time of the update */
- OS_CRITICAL_EXIT(); /* ------------------------------------------------- */
-
- return (ts_delta_timeout);
- }
|