Skip to content

Commit e1eb15a

Browse files
committed
New API xTaskPeriodicDelay (#1349)
New function to be used for periodic tasks to ensure a constant execution frequency. It is intended to supersede xTaskDelayUntil to overcome its shortcomings, that is: - avoid run away of pxPreviousWakeTime (#1339) - catch up any skipped period immediately (and update pxPreviousWakeTime accordingly), notify the caller of the number of periods skipped (by returning them) and wait until the next period (it could be less than xTimeIncrement if we are close to the next period) - notify the caller when not enough ticks have been elapsed (by returning 0) and handle the situation gracefully (by properly waiting until the next wake time) Signed-off-by: Nicola Fontana <ntd@entidi.it>
1 parent 6cd736c commit e1eb15a

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

include/FreeRTOS.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,14 @@
17661766
#define traceRETURN_vTaskDelete()
17671767
#endif
17681768

1769+
#ifndef traceENTER_xTaskPeriodicDelay
1770+
#define traceENTER_xTaskPeriodicDelay( pxPreviousWakeTime, xTimeIncrement )
1771+
#endif
1772+
1773+
#ifndef traceRETURN_xTaskPeriodicDelay
1774+
#define traceRETURN_xTaskPeriodicDelay( xIncrements )
1775+
#endif
1776+
17691777
#ifndef traceENTER_xTaskDelayUntil
17701778
#define traceENTER_xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement )
17711779
#endif

include/task.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,43 @@ void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
862862
*/
863863
void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION;
864864

865+
/**
866+
* task. h
867+
* @code{c}
868+
* TickType_t xTaskPeriodicDelay( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
869+
* @endcode
870+
*
871+
* INCLUDE_xTaskDelayUntil must be defined as 1 for this function to be available.
872+
* See the configuration section for more information.
873+
*
874+
* Periodic task delay to ensure a constant execution frequency.
875+
*
876+
* This function is similar to xTaskDelayUntil () with a few important differences:
877+
* - pxPreviousWakeTime contains the last past wake time, so it never runs away
878+
* - if you suspend the task, when you resume it pxPreviousWakeTime will instantly
879+
* catch up all skipped increments
880+
* - it returns the number of increments added to pxPreviosWakeTime
881+
*
882+
* @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
883+
* task was last unblocked. The variable must be initialised with the current time
884+
* prior to its first use. Following this the variable is automatically updated.
885+
*
886+
* @param xTimeIncrement The cycle time period. The task will be unblocked at
887+
* time *pxPreviousWakeTime + xTimeIncrement. Passing the same xTimeIncrement
888+
* parameter value will cause the task to execute with a fixed interface period.
889+
*
890+
* @return Number of times xTimeIncrement has been added to pxPreviousWakeTime.
891+
* It is 0 on the first call or if not enough ticks have been elapsed since the
892+
* last call, 1 in normal circumstances or more than 1 if some period has been
893+
* skipped for some reason (e.g. when the caller task is suspended for more than
894+
* xTimeIncrement ticks).
895+
*
896+
* \defgroup xTaskPeriodicDelay xTaskPeriodicDelay
897+
* \ingroup TaskCtrl
898+
*/
899+
TickType_t xTaskPeriodicDelay( TickType_t * const pxPreviousWakeTime,
900+
const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION;
901+
865902
/**
866903
* task. h
867904
* @code{c}

tasks.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,64 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
23742374

23752375
#if ( INCLUDE_xTaskDelayUntil == 1 )
23762376

2377+
TickType_t xTaskPeriodicDelay( TickType_t * const pxPreviousWakeTime,
2378+
const TickType_t xTimeIncrement )
2379+
{
2380+
BaseType_t xAlreadyYielded;
2381+
TickType_t xIncrements, xTicksIncrements, xTicksToWait;
2382+
2383+
traceENTER_xTaskPeriodicDelay( pxPreviousWakeTime, xTimeIncrement );
2384+
2385+
configASSERT( pxPreviousWakeTime );
2386+
configASSERT( xTimeIncrement > 0 );
2387+
2388+
vTaskSuspendAll();
2389+
{
2390+
/* This plays well with overflows */
2391+
const TickType_t xTicksElapsed = xTickCount - *pxPreviousWakeTime;
2392+
2393+
configASSERT( uxSchedulerSuspended == 1U );
2394+
2395+
/* Number of increments to catch up: it could be 0 if
2396+
* not enough ticks have elapsed, 1 in the common case or
2397+
* more than 1 if the task has not been resumed in time */
2398+
xIncrements = xTicksElapsed / xTimeIncrement;
2399+
xTicksIncrements = xIncrements * xTimeIncrement;
2400+
2401+
/* Update to the last wake time */
2402+
*pxPreviousWakeTime += xTicksIncrements;
2403+
2404+
/* Ticks to the next wake time */
2405+
xTicksToWait = xTimeIncrement - ( xTicksElapsed - xTicksIncrements );
2406+
2407+
if( xTicksToWait > 0 )
2408+
{
2409+
prvAddCurrentTaskToDelayedList( xTicksToWait, pdFALSE );
2410+
}
2411+
else
2412+
{
2413+
mtCOVERAGE_TEST_MARKER();
2414+
}
2415+
}
2416+
xAlreadyYielded = xTaskResumeAll();
2417+
2418+
/* Force a reschedule if xTaskResumeAll has not already done so, we may
2419+
* have put ourselves to sleep. */
2420+
if( xAlreadyYielded == pdFALSE )
2421+
{
2422+
taskYIELD_WITHIN_API();
2423+
}
2424+
else
2425+
{
2426+
mtCOVERAGE_TEST_MARKER();
2427+
}
2428+
2429+
traceRETURN_xTaskPeriodicDelay( xIncrements );
2430+
2431+
return xIncrements;
2432+
}
2433+
2434+
23772435
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
23782436
const TickType_t xTimeIncrement )
23792437
{

0 commit comments

Comments
 (0)