Add event_groups.c and associated functions in other core files.

Added xTimerPendCallbackFromISR() to provide a centralised deferred interrupt handling mechanism.
Add xPortGetLowestEverFreeHeapSize() to heap_4.c.
This commit is contained in:
Richard Barry
2013-11-21 21:46:08 +00:00
parent faed443e82
commit f54f21b8f6
11 changed files with 1511 additions and 80 deletions

File diff suppressed because it is too large Load Diff

View File

@ -92,9 +92,10 @@ is included as it is used by the port layer. */
conform. */ conform. */
typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
/* The type that holds event bits always matches portTickType - therefore the
number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
32 bits if set to 0. */
typedef portTickType xEventBitsType;
/* /*
* Check all the required application specific macros have been defined. * Check all the required application specific macros have been defined.
@ -190,6 +191,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
#define configUSE_TIMERS 0 #define configUSE_TIMERS 0
#endif #endif
#ifndef configUSE_EVENT_GROUPS
#define configUSE_EVENT_GROUPS 0
#endif
#ifndef configUSE_COUNTING_SEMAPHORES #ifndef configUSE_COUNTING_SEMAPHORES
#define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_COUNTING_SEMAPHORES 0
#endif #endif
@ -218,6 +223,14 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
#define INCLUDE_xTaskResumeFromISR 1 #define INCLUDE_xTaskResumeFromISR 1
#endif #endif
#ifndef INCLUDE_xEventGroupSetBitFromISR
#define INCLUDE_xEventGroupSetBitFromISR 0
#endif
#ifndef INCLUDE_xTimerPendCallbackFromISR
#define INCLUDE_xTimerPendCallbackFromISR 0
#endif
#ifndef configASSERT #ifndef configASSERT
#define configASSERT( x ) #define configASSERT( x )
#define configASSERT_DEFINED 0 #define configASSERT_DEFINED 0

File diff suppressed because it is too large Load Diff

View File

@ -205,7 +205,31 @@ typedef struct xLIST
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList * \ingroup LinkedList
*/ */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->xItemValue ) #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/*
* Return the list item at the head of the list.
*
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
/*
* Return the list item at the head of the list.
*
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
/*
* Return the list item that marks the end of the list
*
* \page listGET_END_MARKER listGET_END_MARKER
* \ingroup LinkedList
*/
#define listGET_END_MARKER( pxList ) ( ( xListItem const * ) ( &( ( pxList )->xListEnd ) ) )
/* /*
* Access macro to determine if a list contains any items. The macro will * Access macro to determine if a list contains any items. The macro will

View File

@ -368,6 +368,7 @@ void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
void vPortFree( void *pv ) PRIVILEGED_FUNCTION; void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
/* /*
* Setup the hardware ready for the scheduler to take control. This generally * Setup the hardware ready for the scheduler to take control. This generally

View File

@ -1,5 +1,5 @@
/* /*
FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -69,6 +69,10 @@
/* Defines the prototype to which task functions must conform. */ /* Defines the prototype to which task functions must conform. */
typedef void (*pdTASK_CODE)( void * ); typedef void (*pdTASK_CODE)( void * );
/* Defines the prototype to which callback functions called from the RTOS/timer
daemon task must conform. */
typedef void (*pdAPPLICATION_CALLBACK_CODE)( void *, unsigned long );
#define pdFALSE ( ( portBASE_TYPE ) 0 ) #define pdFALSE ( ( portBASE_TYPE ) 0 )
#define pdTRUE ( ( portBASE_TYPE ) 1 ) #define pdTRUE ( ( portBASE_TYPE ) 1 )

View File

@ -1378,15 +1378,26 @@ portBASE_TYPE xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
* there be no higher priority tasks waiting on the same event) or * there be no higher priority tasks waiting on the same event) or
* the delay period expires. * the delay period expires.
* *
* The 'unordered' version replaces the event list item value with the
* xItemValue value, and inserts the list item at the end of the list.
*
* The 'ordered' version uses the existing event list item value (which is the
* owning tasks priority) to insert the list item into the event list is task
* priority order.
*
* @param pxEventList The list containing tasks that are blocked waiting * @param pxEventList The list containing tasks that are blocked waiting
* for the event to occur. * for the event to occur.
* *
* @param xItemValue The item value to use for the event list item when the
* event list is not ordered by task priority.
*
* @param xTicksToWait The maximum amount of time that the task should wait * @param xTicksToWait The maximum amount of time that the task should wait
* for the event to occur. This is specified in kernel ticks,the constant * for the event to occur. This is specified in kernel ticks,the constant
* portTICK_RATE_MS can be used to convert kernel ticks into a real time * portTICK_RATE_MS can be used to convert kernel ticks into a real time
* period. * period.
*/ */
void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
/* /*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
@ -1412,13 +1423,23 @@ void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xT
* Removes a task from both the specified event list and the list of blocked * Removes a task from both the specified event list and the list of blocked
* tasks, and places it on a ready queue. * tasks, and places it on a ready queue.
* *
* xTaskRemoveFromEventList () will be called if either an event occurs to * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called
* unblock a task, or the block timeout period expires. * if either an event occurs to unblock a task, or the block timeout period
* expires.
*
* xTaskRemoveFromEventList() is used when the event list is in task priority
* order. It removes the list item from the head of the event list as that will
* have the highest priority owning task of all the tasks on the event list.
* xTaskRemoveFromUnorderedEventList() is used when the event list is not
* ordered and the event list items hold something other than the owning tasks
* priority. In this case the event list item value is updated to the value
* passed in the xItemValue parameter.
* *
* @return pdTRUE if the task being removed has a higher priority than the task * @return pdTRUE if the task being removed has a higher priority than the task
* making the call, otherwise pdFALSE. * making the call, otherwise pdFALSE.
*/ */
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION; signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION;
signed portBASE_TYPE xTaskRemoveFromUnorderedEventList( xListItem * pxEventListItem, portTickType xItemValue ) PRIVILEGED_FUNCTION;
/* /*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
@ -1430,6 +1451,12 @@ signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
*/ */
void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
/*
* THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY
* THE EVENT BITS MODULE.
*/
portTickType uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
/* /*
* Return the handle of the calling task. * Return the handle of the calling task.
*/ */
@ -1479,13 +1506,13 @@ signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed ch
/* /*
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter. * Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
*/ */
unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ); unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ) PRIVILEGED_FUNCTION;
/* /*
* Set the uxTCBNumber of the task referenced by the xTask parameter to * Set the uxTCBNumber of the task referenced by the xTask parameter to
* ucHandle. * ucHandle.
*/ */
void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) PRIVILEGED_FUNCTION;
/* /*
* If tickless mode is being used, or a low power mode is implemented, then * If tickless mode is being used, or a low power mode is implemented, then
@ -1494,7 +1521,7 @@ void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle );
* to date with the actual execution time by being skipped forward by the by * to date with the actual execution time by being skipped forward by the by
* a time equal to the idle period. * a time equal to the idle period.
*/ */
void vTaskStepTick( portTickType xTicksToJump ); void vTaskStepTick( portTickType xTicksToJump ) PRIVILEGED_FUNCTION;
/* /*
* Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port
@ -1509,7 +1536,7 @@ void vTaskStepTick( portTickType xTicksToJump );
* critical section between the timer being stopped and the sleep mode being * critical section between the timer being stopped and the sleep mode being
* entered to ensure it is ok to proceed into the sleep mode. * entered to ensure it is ok to proceed into the sleep mode.
*/ */
eSleepModeStatus eTaskConfirmSleepModeStatus( void ); eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION;
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -83,6 +83,7 @@ extern "C" {
/* IDs for commands that can be sent/received on the timer queue. These are to /* IDs for commands that can be sent/received on the timer queue. These are to
be used solely through the macros that make up the public software timer API, be used solely through the macros that make up the public software timer API,
as defined below. */ as defined below. */
#define tmrCOMMAND_EXECUTE_CALLBACK ( ( portBASE_TYPE ) -1 )
#define tmrCOMMAND_START ( ( portBASE_TYPE ) 0 ) #define tmrCOMMAND_START ( ( portBASE_TYPE ) 0 )
#define tmrCOMMAND_STOP ( ( portBASE_TYPE ) 1 ) #define tmrCOMMAND_STOP ( ( portBASE_TYPE ) 1 )
#define tmrCOMMAND_CHANGE_PERIOD ( ( portBASE_TYPE ) 2 ) #define tmrCOMMAND_CHANGE_PERIOD ( ( portBASE_TYPE ) 2 )
@ -170,7 +171,7 @@ typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer );
* *
* // Optionally do something if the pxTimer parameter is NULL. * // Optionally do something if the pxTimer parameter is NULL.
* configASSERT( pxTimer ); * configASSERT( pxTimer );
* *
* // Which timer expired? * // Which timer expired?
* lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer ); * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer );
* *
@ -293,7 +294,7 @@ void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;
/** /**
* xTimerGetTimerDaemonTaskHandle() is only available if * xTimerGetTimerDaemonTaskHandle() is only available if
* INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h. * INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h.
* *
* Simply returns the handle of the timer service/daemon task. It it not valid * Simply returns the handle of the timer service/daemon task. It it not valid
@ -944,6 +945,95 @@ xTaskHandle xTimerGetTimerDaemonTaskHandle( void );
*/ */
#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) #define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
/**
* portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction,
* void *pvParameter1,
* unsigned long ulParameter2,
* portBASE_TYPE *pxHigherPriorityTaskWoken );
*
*
* Can be used by interrupt service routines to request that a function (the
* callback function) is executed from a task context.
*
* Ideally an interrupt service routine (ISR) is kept as short as possible, but
* sometimes an ISR either has a lot of processing to do, or needs to perform
* processing that is not deterministic. In these cases the processing can be
* deferred to be performed in a task - allowing the ISR to exit. The timer
* daemon service/daemon task is already responsible for executing software
* timer callback functions, so is also used to executed callback functions that
* are pended from interrupts.
*
* A mechanism is provided that allows the interrupt to return directly to the
* task that will subsequently execute the pended callback function. This
* allows the callback function to execute contiguously in time with the
* interrupt - just as if the callback had executed in the interrupt itself.
*
* @param pvCallbackFunction The function to execute from the timer service/
* daemon task. The function must conform to the pdAPPLICATION_CALLBACK_CODE
* prototype.
*
* @param pvParameter1 The value of the callback function's first parameter.
* The parameter has a void * type to allow it to be used to pass any type.
* For example, unsigned longs can be cast to a void *, or the void * can be
* used to point to a structure.
*
* @param ulParameter2 The value of the callback function's second parameter.
*
* @param pxHigherPriorityTaskWoken As mentioned above, calling this function
* will result in a message being sent to the timer daemon task. If the
* priority of the timer daemon task (which is set using
* configTIMER_TASK_PRIORITY in FreeRTOSConfig.h) is higher than the priority of
* the currently running task (the task the interrupt interrupted) then
* *pxHigherPriorityTaskWoken will be set to pdTRUE within
* xTimerPendCallbackFromISR(), indicating that a context switch should be
* requested before the interrupt exits. For that reason
* *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the
* example code below.
*
* Example usage:
* @verbatim
*
* // The callback function that will execute in the context of the daemon task.
* // Note callback functions must all use this same prototype.
* void vProcessInterface( void *pvParameter1, unsigned long ulParameter2 )
* {
* portBASE_TYPE xInterfaceToService;
*
* // The interface that requires servicing is passed in the second
* // parameter. The first parameter is not used in this case.
* xInterfaceToService = ( portBASE_TYPE ) ulParameter2;
*
* // ...Perform the processing here...
* }
*
* // An ISR that receives data packets from multiple interfaces
* void vAnISR( void )
* {
* portBASE_TYPE xInterfaceToService, xHigherPriorityTaskWoken;
*
* // Query the hardware to determine which interface needs processing.
* xInterfaceToService = prvCheckInterfaces();
*
* // The actual processing is to be deferred to a task. Request the
* // vProcessInterface() callback function is executed, passing in the
* // number of the interface that needs processing. The interface to
* // service is passed in the second parameter. The first parameter is
* // not used in this case.
* xHigherPriorityTaskWoken = pdFALSE;
* xTimerPendCallbackFromISR( vProcessInterface, NULL, ( unsigned long ) xInterfaceToService, &xHigherPriorityTaskWoken );
*
* // If xHigherPriorityTaskWoken is now set to pdTRUE then a context
* // switch should be requested. The macro used is port specific and will
* // be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
* // the documentation page for the port being used.
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
*
* }
* @endverbatim
*/
portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction, void *pvParameter1, unsigned long ulParameter2, portBASE_TYPE *pxHigherPriorityTaskWoken );
/* /*
* Functions beyond this part are not part of the public API and are intended * Functions beyond this part are not part of the public API and are intended
* for use by the kernel only. * for use by the kernel only.

View File

@ -134,6 +134,7 @@ static xBlockLink xStart, *pxEnd = NULL;
/* Keeps track of the number of free bytes remaining, but says nothing about /* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */ fragmentation. */
static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
static size_t xMinimumEverFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize /* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
member of an xBlockLink structure is set then the block belongs to the member of an xBlockLink structure is set then the block belongs to the
@ -223,6 +224,11 @@ void *pvReturn = NULL;
xFreeBytesRemaining -= pxBlock->xBlockSize; xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
/* The block is being returned - it is allocated and owned /* The block is being returned - it is allocated and owned
by the application and has no "next" block. */ by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit; pxBlock->xBlockSize |= xBlockAllocatedBit;
@ -295,6 +301,12 @@ size_t xPortGetFreeHeapSize( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void ) void vPortInitialiseBlocks( void )
{ {
/* This just exists to keep the linker quiet. */ /* This just exists to keep the linker quiet. */

View File

@ -169,7 +169,6 @@ typedef struct tskTaskControlBlock
} tskTCB; } tskTCB;
/* /*
* Some kernel aware debuggers require the data the debugger needs access to to * Some kernel aware debuggers require the data the debugger needs access to to
* be global, rather than file scope. * be global, rather than file scope.
@ -1327,7 +1326,9 @@ void vTaskEndScheduler( void )
void vTaskSuspendAll( void ) void vTaskSuspendAll( void )
{ {
/* A critical section is not required as the variable is of type /* A critical section is not required as the variable is of type
portBASE_TYPE. */ portBASE_TYPE. Please read Richard Barry's reply in the following link to a
post in the FreeRTOS support forum before reporting this as a bug! -
http://goo.gl/wu4acr */
++uxSchedulerSuspended; ++uxSchedulerSuspended;
} }
/*----------------------------------------------------------*/ /*----------------------------------------------------------*/
@ -1938,6 +1939,60 @@ portTickType xTimeToWake;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait )
{
portTickType xTimeToWake;
configASSERT( pxEventList );
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
SCHEDULER SUSPENDED. */
/* Store the item value in the event list item. */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue );
/* Place the event list item of the TCB at the end of the appropriate event
list. */
vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
/* The task must be removed from the ready list before it is added to the
blocked list. Exclusive access can be assured to the ready list as the
scheduler is locked. */
if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
{
/* The current task must be in a ready list, so there is no need to
check, and the port reset macro can be called directly. */
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( xTicksToWait == portMAX_DELAY )
{
/* Add the task to the suspended task list instead of a delayed task
list to ensure it is not woken by a timing event. It will block
indefinitely. */
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* Calculate the time at which the task should be woken if the event does
not occur. This may overflow but this doesn't matter. */
xTimeToWake = xTickCount + xTicksToWait;
prvAddCurrentTaskToDelayedList( xTimeToWake );
}
}
#else /* INCLUDE_vTaskSuspend */
{
/* Calculate the time at which the task should be woken if the event does
not occur. This may overflow but this doesn't matter. */
xTimeToWake = xTickCount + xTicksToWait;
prvAddCurrentTaskToDelayedList( xTimeToWake );
}
#endif /* INCLUDE_vTaskSuspend */
}
/*-----------------------------------------------------------*/
#if configUSE_TIMERS == 1 #if configUSE_TIMERS == 1
void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait ) void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait )
@ -2034,6 +2089,56 @@ portBASE_TYPE xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
signed portBASE_TYPE xTaskRemoveFromUnorderedEventList( xListItem * pxEventListItem, portTickType xItemValue )
{
tskTCB *pxUnblockedTCB;
portBASE_TYPE xReturn;
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
SCHEDULER SUSPENDED. It can also be called from within an ISR. */
/* Store the new item value in the event list. */
listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue );
/* Remove the TCB from the delayed list, and add it to the ready list. */
pxUnblockedTCB = ( tskTCB * ) listGET_LIST_ITEM_OWNER( pxEventListItem );
configASSERT( pxUnblockedTCB );
( void ) uxListRemove( pxEventListItem );
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{
( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
prvAddTaskToReadyList( pxUnblockedTCB );
}
else
{
/* Cannot access the delayed or ready lists, so will hold this task
pending until the scheduler is resumed. */
vListInsertEnd( &( xPendingReadyList ), pxEventListItem );
}
if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* Return true if the task removed from the event list has
a higher priority than the calling task. This allows
the calling task to know if it should force a context
switch now. */
xReturn = pdTRUE;
/* Mark that a yield is pending in case the user is not using the
"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
xYieldPending = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
{ {
configASSERT( pxTimeOut ); configASSERT( pxTimeOut );
@ -2973,6 +3078,20 @@ tskTCB *pxNewTCB;
} }
#endif /* configGENERATE_RUN_TIME_STATS */ #endif /* configGENERATE_RUN_TIME_STATS */
/*-----------------------------------------------------------*/
portTickType uxTaskResetEventItemValue( void )
{
portTickType uxReturn;
uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) );
/* Reset the event list item to its normal value - so it can be used with
queues and semaphores. */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
return uxReturn;
}
/*-----------------------------------------------------------*/

View File

@ -1,5 +1,5 @@
/* /*
FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -76,6 +76,10 @@ task.h is included from an application file. */
#include "queue.h" #include "queue.h"
#include "timers.h" #include "timers.h"
#if ( INCLUDE_xTimerPendCallbackFromISR == 1 ) && ( configUSE_TIMERS == 0 )
#error configUSE_TIMERS must be set to 1 to make the INCLUDE_xTimerPendCallbackFromISR() function available.
#endif
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the /* Lint e961 and e750 are suppressed as a MISRA exception justified because the
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
header files above, but not in this file, in order to generate the correct header files above, but not in this file, in order to generate the correct
@ -103,14 +107,41 @@ typedef struct tmrTimerControl
tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */ tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
} xTIMER; } xTIMER;
/* The definition of messages that can be sent and received on the timer /* The definition of messages that can be sent and received on the timer queue.
queue. */ Two types of message can be queued - messages that manipulate a software timer,
and messages that request the execution of a non-timer related callback. The
two message types are defined in two separate structures, xTimerParametersType
and xCallbackParametersType respectively. */
typedef struct tmrTimerParameters
{
portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
} xTimerParametersType;
typedef struct tmrCallbackParameters
{
pdAPPLICATION_CALLBACK_CODE pxCallbackFunction; /* << The callback function to execute. */
void *pvParameter1; /* << The value that will be used as the callback functions first parameter. */
unsigned long ulParameter2; /* << The value that will be used as the callback functions second parameter. */
} xCallbackParametersType;
/* The structure that contains the two message types, along with an identifier
that is used to determine which message type is valid. */
typedef struct tmrTimerQueueMessage typedef struct tmrTimerQueueMessage
{ {
portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */ portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ union
xTIMER * pxTimer; /*<< The timer to which the command will be applied. */ {
} xTIMER_MESSAGE; xTimerParametersType xTimerParameters;
/* Don't include xCallbackParameters if it is not going to be used as
it makes the structure (and therefore the timer queue) larger. */
#if ( INCLUDE_xTimerPendCallbackFromISR == 1 )
xCallbackParametersType xCallbackParameters;
#endif /* INCLUDE_xTimerPendCallbackFromISR */
} u;
} xDAEMON_TASK_MESSAGE;
/*lint -e956 A manual analysis and inspection has been used to determine which /*lint -e956 A manual analysis and inspection has been used to determine which
static variables must be declared volatile. */ static variables must be declared volatile. */
@ -270,7 +301,7 @@ xTIMER *pxNewTimer;
portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
{ {
portBASE_TYPE xReturn = pdFAIL; portBASE_TYPE xReturn = pdFAIL;
xTIMER_MESSAGE xMessage; xDAEMON_TASK_MESSAGE xMessage;
/* Send a message to the timer service task to perform a particular action /* Send a message to the timer service task to perform a particular action
on a particular timer definition. */ on a particular timer definition. */
@ -278,8 +309,8 @@ xTIMER_MESSAGE xMessage;
{ {
/* Send a command to the timer service task to start the xTimer timer. */ /* Send a command to the timer service task to start the xTimer timer. */
xMessage.xMessageID = xCommandID; xMessage.xMessageID = xCommandID;
xMessage.xMessageValue = xOptionalValue; xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.pxTimer = ( xTIMER * ) xTimer; xMessage.u.xTimerParameters.pxTimer = ( xTIMER * ) xTimer;
if( pxHigherPriorityTaskWoken == NULL ) if( pxHigherPriorityTaskWoken == NULL )
{ {
@ -518,77 +549,98 @@ portBASE_TYPE xProcessTimerNow = pdFALSE;
static void prvProcessReceivedCommands( void ) static void prvProcessReceivedCommands( void )
{ {
xTIMER_MESSAGE xMessage; xDAEMON_TASK_MESSAGE xMessage;
xTIMER *pxTimer; xTIMER *pxTimer;
portBASE_TYPE xTimerListsWereSwitched, xResult; portBASE_TYPE xTimerListsWereSwitched, xResult;
portTickType xTimeNow; portTickType xTimeNow;
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */ while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
{ {
pxTimer = xMessage.pxTimer; #if ( INCLUDE_xTimerPendCallbackFromISR == 1 )
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
{ {
/* The timer is in a list, remove it. */ if( xMessage.xMessageID == tmrCOMMAND_EXECUTE_CALLBACK )
( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); {
const xCallbackParametersType * const pxCallback = &( xMessage.u.xCallbackParameters );
/* The timer uses the xCallbackParameters member to request a
callback be executed. Check the callback is not NULL. */
configASSERT( pxCallback );
/* Call the function. */
pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
}
} }
#endif /* INCLUDE_xTimerPendCallbackFromISR */
traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue ); if( xMessage.xMessageID != tmrCOMMAND_EXECUTE_CALLBACK )
/* In this case the xTimerListsWereSwitched parameter is not used, but
it must be present in the function call. prvSampleTimeNow() must be
called after the message is received from xTimerQueue so there is no
possibility of a higher priority task adding a message to the message
queue with a time that is ahead of the timer daemon task (because it
pre-empted the timer daemon task after the xTimeNow value was set). */
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
switch( xMessage.xMessageID )
{ {
case tmrCOMMAND_START : /* The messages uses the xTimerParameters member to work on a
/* Start or restart a timer. */ software timer. */
if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE ) pxTimer = xMessage.u.xTimerParameters.pxTimer;
{
/* The timer expired before it was added to the active timer
list. Process it now. */
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
{
/* The timer is in a list, remove it. */
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
}
traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
/* In this case the xTimerListsWereSwitched parameter is not used, but
it must be present in the function call. prvSampleTimeNow() must be
called after the message is received from xTimerQueue so there is no
possibility of a higher priority task adding a message to the message
queue with a time that is ahead of the timer daemon task (because it
pre-empted the timer daemon task after the xTimeNow value was set). */
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
switch( xMessage.xMessageID )
{
case tmrCOMMAND_START :
/* Start or restart a timer. */
if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE )
{ {
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); /* The timer expired before it was added to the active timer
configASSERT( xResult ); list. Process it now. */
( void ) xResult; pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
{
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
configASSERT( xResult );
( void ) xResult;
}
} }
} break;
break;
case tmrCOMMAND_STOP : case tmrCOMMAND_STOP :
/* The timer has already been removed from the active list. /* The timer has already been removed from the active list.
There is nothing to do here. */ There is nothing to do here. */
break; break;
case tmrCOMMAND_CHANGE_PERIOD : case tmrCOMMAND_CHANGE_PERIOD :
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue; pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
/* The new period does not really have a reference, and can be /* The new period does not really have a reference, and can be
longer or shorter than the old one. The command time is longer or shorter than the old one. The command time is
therefore set to the current time, and as the period cannot be therefore set to the current time, and as the period cannot be
zero the next expiry time can only be in the future, meaning zero the next expiry time can only be in the future, meaning
(unlike for the xTimerStart() case above) there is no fail case (unlike for the xTimerStart() case above) there is no fail case
that needs to be handled here. */ that needs to be handled here. */
( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
break; break;
case tmrCOMMAND_DELETE : case tmrCOMMAND_DELETE :
/* The timer has already been removed from the active list, /* The timer has already been removed from the active list,
just free up the memory. */ just free up the memory. */
vPortFree( pxTimer ); vPortFree( pxTimer );
break; break;
default : default :
/* Don't expect to get here. */ /* Don't expect to get here. */
break; break;
}
} }
} }
} }
@ -664,7 +716,7 @@ static void prvCheckForValidListAndQueue( void )
vListInitialise( &xActiveTimerList2 ); vListInitialise( &xActiveTimerList2 );
pxCurrentTimerList = &xActiveTimerList1; pxCurrentTimerList = &xActiveTimerList1;
pxOverflowTimerList = &xActiveTimerList2; pxOverflowTimerList = &xActiveTimerList2;
xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) ); xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xDAEMON_TASK_MESSAGE ) );
} }
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
@ -698,6 +750,28 @@ xTIMER *pxTimer = ( xTIMER * ) xTimer;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( INCLUDE_xTimerPendCallbackFromISR == 1 )
portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction, void *pvParameter1, unsigned long ulParameter2, portBASE_TYPE *pxHigherPriorityTaskWoken )
{
xDAEMON_TASK_MESSAGE xMessage;
portBASE_TYPE xReturn;
/* Complete the message with the function parameters and post it to the
daemon task. */
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
xMessage.u.xCallbackParameters.pxCallbackFunction = pvCallbackFunction;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
return xReturn;
}
#endif /* INCLUDE_xTimerPendCallbackFromISR */
/*-----------------------------------------------------------*/
/* This entire source file will be skipped if the application is not configured /* This entire source file will be skipped if the application is not configured
to include software timer functionality. If you want to include software timer to include software timer functionality. If you want to include software timer
functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */