4.2.9 周期任务用的延迟--xTaskDelayUntil
接口:BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
形参1:pxPreviousWakeTime,上一次唤醒时间,第一次需要用接口xTaskGetTickCount()获取;
形参2:xTimeIncrement,想要延迟的时间。
返回值:用于判读任务是否确实需要delay。
- 1 BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
- 2 const TickType_t xTimeIncrement )
- 3 {
- 4 TickType_t xTimeToWake;
- 5 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
- 6
- 7 configASSERT( pxPreviousWakeTime );
- 8 configASSERT( ( xTimeIncrement > 0U ) );
- 9
- 10 vTaskSuspendAll();
- 11 {
- 12 /* Minor optimisation. The tick count cannot change in this
- 13 * block. */
- 14 const TickType_t xConstTickCount = xTickCount;
- 15
- 16 configASSERT( uxSchedulerSuspended == 1U );
- 17
- 18 /* Generate the tick time at which the task wants to wake. */
- 19 /* 计算任务下次唤醒的时间 */
- 20 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
- 21
- 22 if( xConstTickCount < *pxPreviousWakeTime )
- 23 {
- 24 /* The tick count has overflowed since this function was
- 25 * lasted called. In this case the only time we should ever
- 26 * actually delay is if the wake time has also overflowed,
- 27 * and the wake time is greater than the tick time. When this
- 28 * is the case it is as if neither time had overflowed. */
- 29 /* tick值已经溢出了, 只有xTimeToWake也溢出并大于xConstTickCount
- 30 * 时, 才需要延迟 */
- 31 /* 假设tick是8位的, 当前值为0x5(从FF加到5), pxPreviousWakeTime为0xFD,
- 32 * 当xTimeIncrement为1时, xTimeToWake未溢出, 当xTimeIncrement为0x15时,
- 33 * xTimeToWake溢出。 显然当xTimeIncrement为1时, xTimeToWake比
- 34 * pxPreviousWakeTime和xConstTickCount都大, 但不需要延迟, 因为tick已过,
- 35 * 当xTimeIncrement为0x15时, xTimeToWake比pxPreviousWakeTime小但比xConstTickCount
- 36 * 大, tick要等到0x12才到延迟时间, 所以需要进行延迟. */
- 37 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
- 38 {
- 39 xShouldDelay = pdTRUE;
- 40 }
- 41 else
- 42 {
- 43 mtCOVERAGE_TEST_MARKER();
- 44 }
- 45 }
- 46 else
- 47 {
- 48 /* The tick time has not overflowed. In this case we will
- 49 * delay if either the wake time has overflowed, and/or the
- 50 * tick time is less than the wake time. */
- 51 /* tick没有溢出, 那么xTimeToWake溢出或比xConstTickCount小,
- 52 * 必然是需要延迟的. */
- 53 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
- 54 {
- 55 xShouldDelay = pdTRUE;
- 56 }
- 57 else
- 58 {
- 59 mtCOVERAGE_TEST_MARKER();
- 60 }
- 61 }
- 62
- 63 /* Update the wake time ready for the next call. */
- 64 *pxPreviousWakeTime = xTimeToWake;
- 65
- 66 if( xShouldDelay != pdFALSE )
- 67 {
- 68 /* prvAddCurrentTaskToDelayedList() needs the block time, not
- 69 * the time to wake, so subtract the current tick count. */
- 70 /* 延迟列表记录的是阻塞时间而不是唤醒时间, 所以需要减去tick. */
- 71 prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
- 72 }
- 73 else
- 74 {
- 75 mtCOVERAGE_TEST_MARKER();
- 76 }
- 77 }
- 78 xAlreadyYielded = xTaskResumeAll();
- 79
- 80 /* Force a reschedule if xTaskResumeAll has not already done so, we may
- 81 * have put ourselves to sleep. */
- 82 if( xAlreadyYielded == pdFALSE )
- 83 {
- 84 taskYIELD_WITHIN_API();
- 85 }
- 86 else
- 87 {
- 88 mtCOVERAGE_TEST_MARKER();
- 89 }
- 90
- 91 return xShouldDelay;
- 92 }
复制代码 xTaskDelayUntil 4.2.10 成对的信息获取接口,一般的和带有FromISR后缀的
这类接口比较简单,主要用于获取TCB中的某些参数,这里挑选任务优先级获取接口为例,重点在于带有FromISR的接口。一般的接口很简单,这里就直接放出来即可。- 1 UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
- 2 {
- 3 TCB_t const * pxTCB;
- 4 UBaseType_t uxReturn;
- 5
- 6 taskENTER_CRITICAL();
- 7 {
- 8 /* If null is passed in here then it is the priority of the task
- 9 * that called uxTaskPriorityGet() that is being queried. */
- 10 pxTCB = prvGetTCBFromHandle( xTask );
- 11 uxReturn = pxTCB->uxPriority;
- 12 }
- 13 taskEXIT_CRITICAL();
- 14
- 15 return uxReturn;
- 16 }
复制代码- 1 UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask )
- 2 {
- 3 TCB_t const * pxTCB;
- 4 UBaseType_t uxReturn;
- 5 UBaseType_t uxSavedInterruptStatus;
- 6
- 7 /* RTOS ports that support interrupt nesting have the concept of a
- 8 * maximum system call (or maximum API call) interrupt priority.
- 9 * Interrupts that are above the maximum system call priority are keep
- 10 * permanently enabled, even when the RTOS kernel is in a critical section,
- 11 * but cannot make any calls to FreeRTOS API functions. If configASSERT()
- 12 * is defined in FreeRTOSConfig.h then
- 13 * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
- 14 * failure if a FreeRTOS API function is called from an interrupt that has
- 15 * been assigned a priority above the configured maximum system call
- 16 * priority. Only FreeRTOS functions that end in FromISR can be called
- 17 * from interrupts that have been assigned a priority at or (logically)
- 18 * below the maximum system call interrupt priority. FreeRTOS maintains a
- 19 * separate interrupt safe API to ensure interrupt entry is as fast and as
- 20 * simple as possible. More information (albeit Cortex-M specific) is
- 21 * provided on the following link:
- 22 * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
- 23 /* 检查调用带有FromISR后缀的中断优先级是否高于
- 24 * configMAX_SYSCALL_INTERRUPT_PRIORITY, 是的话会进入assert */
- 25 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
- 26
- 27 /* MISRA Ref 4.7.1 [Return value shall be checked] */
- 28 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
- 29 /* coverity[misra_c_2012_directive_4_7_violation] */
- 30 /* 获取当前中断屏蔽优先级, 并设置中断屏蔽优先级为configMAX_SYSCALL_INTERRUPT_PRIORITY
- 31 * 相当于进入了临界区并返回了当前中断屏蔽优先级 */
- 32 uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
- 33 {
- 34 /* If null is passed in here then it is the priority of the calling
- 35 * task that is being queried. */
- 36 pxTCB = prvGetTCBFromHandle( xTask );
- 37 uxReturn = pxTCB->uxPriority;
- 38 }
- 39 /* 将保存的中断屏蔽优先级设置回去, 相当于退出临界区 */
- 40 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
- 41
- 42 return uxReturn;
- 43 }
复制代码 4.2.11 设置任务优先级--vTaskPrioritySet
接口虽然较长,但注释较多,且逻辑较为简单,直接看代码里的注释即可。
- 1 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
- 2 {
- 3 TCB_t * pxTCB;
- 4 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
- 5 BaseType_t xYieldRequired = pdFALSE;
- 6
- 7 configASSERT( uxNewPriority < configMAX_PRIORITIES );
- 8
- 9 /* Ensure the new priority is valid. */
- 10 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
- 11 {
- 12 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
- 13 }
- 14 else
- 15 {
- 16 mtCOVERAGE_TEST_MARKER();
- 17 }
- 18
- 19 taskENTER_CRITICAL();
- 20 {
- 21 /* If null is passed in here then it is the priority of the calling
- 22 * task that is being changed. */
- 23 pxTCB = prvGetTCBFromHandle( xTask );
- 24
- 25 #if ( configUSE_MUTEXES == 1 )
- 26 {
- 27 uxCurrentBasePriority = pxTCB->uxBasePriority;
- 28 }
- 29 #else
- 30 {
- 31 uxCurrentBasePriority = pxTCB->uxPriority;
- 32 }
- 33 #endif
- 34
- 35 if( uxCurrentBasePriority != uxNewPriority )
- 36 {
- 37 /* The priority change may have readied a task of higher
- 38 * priority than a running task. */
- 39 if( uxNewPriority > uxCurrentBasePriority )
- 40 {
- 41 /* 提升优先级 */
- 42 #if ( configNUMBER_OF_CORES == 1 )
- 43 {
- 44 if( pxTCB != pxCurrentTCB )
- 45 {
- 46 /* The priority of a task other than the currently
- 47 * running task is being raised. Is the priority being
- 48 * raised above that of the running task? */
- 49 /* 设置的优先级比当前运行的任务高, 需要yield */
- 50 if( uxNewPriority > pxCurrentTCB->uxPriority )
- 51 {
- 52 xYieldRequired = pdTRUE;
- 53 }
- 54 else
- 55 {
- 56 mtCOVERAGE_TEST_MARKER();
- 57 }
- 58 }
- 59 else
- 60 {
- 61 /* The priority of the running task is being raised,
- 62 * but the running task must already be the highest
- 63 * priority task able to run so no yield is required. */
- 64 }
- 65 }
- 66 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 67 }
- 68 else if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
- 69 {
- 70 /* Setting the priority of a running task down means
- 71 * there may now be another task of higher priority that
- 72 * is ready to execute. */
- 73 /* 降低当前运行任务的优先级, 则更高优先级的就绪任务需要抢占 */
- 74 #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
- 75 if( pxTCB->xPreemptionDisable == pdFALSE )
- 76 #endif
- 77 {
- 78 xYieldRequired = pdTRUE;
- 79 }
- 80 }
- 81 else
- 82 {
- 83 /* Setting the priority of any other task down does not
- 84 * require a yield as the running task must be above the
- 85 * new priority of the task being modified. */
- 86 }
- 87
- 88 /* Remember the ready list the task might be referenced from
- 89 * before its uxPriority member is changed so the
- 90 * taskRESET_READY_PRIORITY() macro can function correctly. */
- 91 /* 获取任务当前的优先级, 有可能是继承来的优先级 */
- 92 uxPriorityUsedOnEntry = pxTCB->uxPriority;
- 93
- 94 #if ( configUSE_MUTEXES == 1 )
- 95 {
- 96 /* Only change the priority being used if the task is not
- 97 * currently using an inherited priority or the new priority
- 98 * is bigger than the inherited priority. */
- 99 /* 只有非继承来的优先级, 或提升优先级才可以直接修改pxTCB->uxPriority */
- 100 if( ( pxTCB->uxBasePriority == pxTCB->uxPriority ) || ( uxNewPriority > pxTCB->uxPriority ) )
- 101 {
- 102 pxTCB->uxPriority = uxNewPriority;
- 103 }
- 104 else
- 105 {
- 106 mtCOVERAGE_TEST_MARKER();
- 107 }
- 108
- 109 /* The base priority gets set whatever. */
- 110 pxTCB->uxBasePriority = uxNewPriority;
- 111 }
- 112 #else /* if ( configUSE_MUTEXES == 1 ) */
- 113 {
- 114 pxTCB->uxPriority = uxNewPriority;
- 115 }
- 116 #endif /* if ( configUSE_MUTEXES == 1 ) */
- 117
- 118 /* Only reset the event list item value if the value is not
- 119 * being used for anything else. */
- 120 /* xEventListItem的值未被使用, 才允许更新这个值 */
- 121 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == ( ( TickType_t ) 0U ) )
- 122 {
- 123 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );
- 124 }
- 125 else
- 126 {
- 127 mtCOVERAGE_TEST_MARKER();
- 128 }
- 129
- 130 /* If the task is in the blocked or suspended list we need do
- 131 * nothing more than change its priority variable. However, if
- 132 * the task is in a ready list it needs to be removed and placed
- 133 * in the list appropriate to its new priority. */
- 134 /* 如果任务处于就绪列表, 则需要将其放到修改后的优先级就绪列表 */
- 135 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
- 136 {
- 137 /* The task is currently in its ready list - remove before
- 138 * adding it to its new ready list. As we are in a critical
- 139 * section we can do this even if the scheduler is suspended. */
- 140 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
- 141 {
- 142 /* It is known that the task is in its ready list so
- 143 * there is no need to check again and the port level
- 144 * reset macro can be called directly. */
- 145 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
- 146 }
- 147 else
- 148 {
- 149 mtCOVERAGE_TEST_MARKER();
- 150 }
- 151
- 152 prvAddTaskToReadyList( pxTCB );
- 153 }
- 154 else
- 155 {
- 156 #if ( configNUMBER_OF_CORES == 1 )
- 157 {
- 158 mtCOVERAGE_TEST_MARKER();
- 159 }
- 160 #endif
- 161 }
- 162
- 163 if( xYieldRequired != pdFALSE )
- 164 {
- 165 /* The running task priority is set down. Request the task to yield. */
- 166 /* 开始yield, 但是在退出临界区后才会进入sv中断? */
- 167 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxTCB );
- 168 }
- 169 else
- 170 {
- 171 mtCOVERAGE_TEST_MARKER();
- 172 }
- 173
- 174 /* Remove compiler warning about unused variables when the port
- 175 * optimised task selection is not being used. */
- 176 ( void ) uxPriorityUsedOnEntry;
- 177 }
- 178 }
- 179 taskEXIT_CRITICAL();
- 180 }
复制代码 vTaskPrioritySet 补个流程图
4.2.12 挂起任务--vTaskSuspend
还是直接看代码注释,解释得比较清楚了,接口功能可以顾名思义,逻辑也还好不复杂。
- 1 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
- 2 {
- 3 TCB_t * pxTCB;
- 4
- 5 taskENTER_CRITICAL();
- 6 {
- 7 /* If null is passed in here then it is the running task that is
- 8 * being suspended. */
- 9 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
- 10
- 11 /* Remove task from the ready/delayed list and place in the
- 12 * suspended list. */
- 13 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
- 14 {
- 15 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
- 16 }
- 17 else
- 18 {
- 19 mtCOVERAGE_TEST_MARKER();
- 20 }
- 21
- 22 /* Is the task waiting on an event also? */
- 23 /* 任务挂起, 任务就不管是否在等待事件 */
- 24 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
- 25 {
- 26 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
- 27 }
- 28 else
- 29 {
- 30 mtCOVERAGE_TEST_MARKER();
- 31 }
- 32
- 33 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
- 34
- 35 /* 如果在等待通知, 也直接退出等待 */
- 36 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
- 37 {
- 38 BaseType_t x;
- 39
- 40 for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
- 41 {
- 42 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
- 43 {
- 44 /* The task was blocked to wait for a notification, but is
- 45 * now suspended, so no notification was received. */
- 46 pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
- 47 }
- 48 }
- 49 }
- 50 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
- 51 }
- 52 taskEXIT_CRITICAL();
- 53
- 54 #if ( configNUMBER_OF_CORES == 1 )
- 55 {
- 56 UBaseType_t uxCurrentListLength;
- 57
- 58 if( xSchedulerRunning != pdFALSE )
- 59 {
- 60 /* Reset the next expected unblock time in case it referred to the
- 61 * task that is now in the Suspended state. */
- 62 /* 如果下个解除阻塞的时间对应的任务正好是挂起的任务,
- 63 * 无论如何重置一下下个解除阻塞的时间 */
- 64 taskENTER_CRITICAL();
- 65 {
- 66 prvResetNextTaskUnblockTime();
- 67 }
- 68 taskEXIT_CRITICAL();
- 69 }
- 70 else
- 71 {
- 72 mtCOVERAGE_TEST_MARKER();
- 73 }
- 74
- 75 if( pxTCB == pxCurrentTCB )
- 76 {
- 77 if( xSchedulerRunning != pdFALSE )
- 78 {
- 79 /* The current task has just been suspended. */
- 80 /* 当前运行的任务挂起, 需要yield */
- 81 configASSERT( uxSchedulerSuspended == 0 );
- 82 portYIELD_WITHIN_API();
- 83 }
- 84 else
- 85 {
- 86 /* The scheduler is not running, but the task that was pointed
- 87 * to by pxCurrentTCB has just been suspended and pxCurrentTCB
- 88 * must be adjusted to point to a different task. */
- 89
- 90 /* Use a temp variable as a distinct sequence point for reading
- 91 * volatile variables prior to a comparison to ensure compliance
- 92 * with MISRA C 2012 Rule 13.2. */
- 93 uxCurrentListLength = listCURRENT_LIST_LENGTH( &xSuspendedTaskList );
- 94
- 95 if( uxCurrentListLength == uxCurrentNumberOfTasks )
- 96 {
- 97 /* No other tasks are ready, so set pxCurrentTCB back to
- 98 * NULL so when the next task is created pxCurrentTCB will
- 99 * be set to point to it no matter what its relative priority
- 100 * is. */
- 101 /* 所有创建的任务处于挂起状态, 只能等新任务创建了 */
- 102 pxCurrentTCB = NULL;
- 103 }
- 104 else
- 105 {
- 106 /* 切换下上下文, 因为挂起的是当前任务, 也有可能就绪列表为空,
- 107 * 会导致pxCurrentTCB = idle, 否则会选择就绪列表中优先级最高
- 108 * 任务, 这个接口在这里只是设置了pxCurrentTCB参数, 并pend了
- 109 * yield, 因为当前调度器处于暂停状态 */
- 110 vTaskSwitchContext();
- 111 }
- 112 }
- 113 }
- 114 else
- 115 {
- 116 mtCOVERAGE_TEST_MARKER();
- 117 }
- 118 }
- 119 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 120 }
复制代码 vTaskSuspend
这篇就到这里了,内容也比较多,下篇开始vTaskResume和vTaskStartScheduler。
下篇再见!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |