mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/freertos_backported_functions' into 'master'
freertos/backport and test v9.0.0 functions See merge request !1515
This commit is contained in:
commit
02304ad83e
@ -209,7 +209,7 @@ config SUPPORT_STATIC_ALLOCATION
|
||||
memory being allocated dynamically:
|
||||
|
||||
- Tasks
|
||||
- Software Timers
|
||||
- Software Timers (Daemon task is still dynamic. See documentation)
|
||||
- Queues
|
||||
- Event Groups
|
||||
- Binary Semaphores
|
||||
|
@ -119,7 +119,11 @@ typedef struct xEventGroupDefinition
|
||||
UBaseType_t uxEventGroupNumber;
|
||||
#endif
|
||||
|
||||
portMUX_TYPE eventGroupMux;
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
|
||||
#endif
|
||||
|
||||
portMUX_TYPE eventGroupMux; //Mutex required due to SMP
|
||||
} EventGroup_t;
|
||||
|
||||
|
||||
@ -137,26 +141,83 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
EventGroup_t *pxEventBits;
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );
|
||||
if( pxEventBits != NULL )
|
||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
|
||||
{
|
||||
pxEventBits->uxEventBits = 0;
|
||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEVENT_GROUP_CREATE_FAILED();
|
||||
EventGroup_t *pxEventBits;
|
||||
|
||||
/* A StaticEventGroup_t object must be provided. */
|
||||
configASSERT( pxEventGroupBuffer );
|
||||
|
||||
/* The user has provided a statically allocated event group - use it. */
|
||||
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
|
||||
|
||||
if( pxEventBits != NULL )
|
||||
{
|
||||
pxEventBits->uxEventBits = 0;
|
||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Both static and dynamic allocation can be used, so note that
|
||||
this event group was created statically in case the event group
|
||||
is later deleted. */
|
||||
pxEventBits->ucStaticallyAllocated = pdTRUE;
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
|
||||
vPortCPUInitializeMutex(&pxEventBits->eventGroupMux);
|
||||
|
||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEVENT_GROUP_CREATE_FAILED();
|
||||
}
|
||||
|
||||
return ( EventGroupHandle_t ) pxEventBits;
|
||||
}
|
||||
|
||||
vPortCPUInitializeMutex(&pxEventBits->eventGroupMux);
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
return ( EventGroupHandle_t ) pxEventBits;
|
||||
}
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
EventGroup_t *pxEventBits;
|
||||
|
||||
/* Allocate the event group. */
|
||||
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
|
||||
|
||||
if( pxEventBits != NULL )
|
||||
{
|
||||
pxEventBits->uxEventBits = 0;
|
||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Both static and dynamic allocation can be used, so note this
|
||||
event group was allocated statically in case the event group is
|
||||
later deleted. */
|
||||
pxEventBits->ucStaticallyAllocated = pdFALSE;
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
vPortCPUInitializeMutex(&pxEventBits->eventGroupMux);
|
||||
|
||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEVENT_GROUP_CREATE_FAILED();
|
||||
}
|
||||
|
||||
return ( EventGroupHandle_t ) pxEventBits;
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
|
||||
@ -600,8 +661,29 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
}
|
||||
|
||||
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
|
||||
vPortFree( pxEventBits );
|
||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||
{
|
||||
/* The event group can only have been allocated dynamically - free
|
||||
it again. */
|
||||
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
|
||||
vPortFree( pxEventBits );
|
||||
}
|
||||
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||
{
|
||||
/* The event group could have been allocated statically or
|
||||
dynamically, so check before attempting to free the memory. */
|
||||
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
|
||||
{
|
||||
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); //Exit mux of event group before deleting it
|
||||
vPortFree( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
}
|
||||
|
@ -974,18 +974,73 @@ typedef struct xSTATIC_QUEUE
|
||||
uint8_t ucDummy9;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
volatile uint32_t ucDummy10;
|
||||
uint32_t ucDummy11;
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
void *pvDummy8;
|
||||
UBaseType_t uxDummy12;
|
||||
#endif
|
||||
} sDummy1;
|
||||
portMUX_TYPE muxDummy; //Mutex required due to SMP
|
||||
|
||||
} StaticQueue_t;
|
||||
typedef StaticQueue_t StaticSemaphore_t;
|
||||
|
||||
/*
|
||||
* In line with software engineering best practice, especially when supplying a
|
||||
* library that is likely to change in future versions, FreeRTOS implements a
|
||||
* strict data hiding policy. This means the event group structure used
|
||||
* internally by FreeRTOS is not accessible to application code. However, if
|
||||
* the application writer wants to statically allocate the memory required to
|
||||
* create an event group then the size of the event group object needs to be
|
||||
* know. The StaticEventGroup_t structure below is provided for this purpose.
|
||||
* Its sizes and alignment requirements are guaranteed to match those of the
|
||||
* genuine structure, no matter which architecture is being used, and no matter
|
||||
* how the values in FreeRTOSConfig.h are set. Its contents are somewhat
|
||||
* obfuscated in the hope users will recognise that it would be unwise to make
|
||||
* direct use of the structure members.
|
||||
*/
|
||||
typedef struct xSTATIC_EVENT_GROUP
|
||||
{
|
||||
TickType_t xDummy1;
|
||||
StaticList_t xDummy2;
|
||||
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxDummy3;
|
||||
#endif
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucDummy4;
|
||||
#endif
|
||||
|
||||
portMUX_TYPE muxDummy; //Mutex required due to SMP
|
||||
|
||||
} StaticEventGroup_t;
|
||||
|
||||
/*
|
||||
* In line with software engineering best practice, especially when supplying a
|
||||
* library that is likely to change in future versions, FreeRTOS implements a
|
||||
* strict data hiding policy. This means the software timer structure used
|
||||
* internally by FreeRTOS is not accessible to application code. However, if
|
||||
* the application writer wants to statically allocate the memory required to
|
||||
* create a software timer then the size of the queue object needs to be know.
|
||||
* The StaticTimer_t structure below is provided for this purpose. Its sizes
|
||||
* and alignment requirements are guaranteed to match those of the genuine
|
||||
* structure, no matter which architecture is being used, and no matter how the
|
||||
* values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in
|
||||
* the hope users will recognise that it would be unwise to make direct use of
|
||||
* the structure members.
|
||||
*/
|
||||
typedef struct xSTATIC_TIMER
|
||||
{
|
||||
void *pvDummy1;
|
||||
StaticListItem_t xDummy2;
|
||||
TickType_t xDummy3;
|
||||
UBaseType_t uxDummy4;
|
||||
void *pvDummy5[ 2 ];
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxDummy6;
|
||||
#endif
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucDummy7;
|
||||
#endif
|
||||
|
||||
} StaticTimer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -137,7 +137,17 @@ typedef TickType_t EventBits_t;
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group. This function cannot be called from an interrupt.
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
* block of memory, in which the event group's structure is stored. If an event
|
||||
* groups is created using xEventGropuCreate() then the required memory is
|
||||
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||
* using xEventGropuCreateStatic() then the application writer must instead
|
||||
* provide the memory that will get used by the event group.
|
||||
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||
* without using any dynamic memory allocation.
|
||||
*
|
||||
* Although event groups are not related to ticks, for internal implementation
|
||||
* reasons the number of bits available for use in an event group is dependent
|
||||
@ -173,7 +183,62 @@ typedef TickType_t EventBits_t;
|
||||
* \defgroup xEventGroupCreate xEventGroupCreate
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
* block of memory, in which the event group's structure is stored. If an event
|
||||
* groups is created using xEventGropuCreate() then the required memory is
|
||||
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||
* using xEventGropuCreateStatic() then the application writer must instead
|
||||
* provide the memory that will get used by the event group.
|
||||
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||
* without using any dynamic memory allocation.
|
||||
*
|
||||
* Although event groups are not related to ticks, for internal implementation
|
||||
* reasons the number of bits available for use in an event group is dependent
|
||||
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
|
||||
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
|
||||
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
|
||||
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
|
||||
* event bits within an event group.
|
||||
*
|
||||
* @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type
|
||||
* StaticEventGroup_t, which will be then be used to hold the event group's data
|
||||
* structures, removing the need for the memory to be allocated dynamically.
|
||||
*
|
||||
* @return If the event group was created then a handle to the event group is
|
||||
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// StaticEventGroup_t is a publicly accessible structure that has the same
|
||||
// size and alignment requirements as the real event group structure. It is
|
||||
// provided as a mechanism for applications to know the size of the event
|
||||
// group (which is dependent on the architecture and configuration file
|
||||
// settings) without breaking the strict data hiding policy by exposing the
|
||||
// real event group internals. This StaticEventGroup_t variable is passed
|
||||
// into the xSemaphoreCreateEventGroupStatic() function and is used to store
|
||||
// the event group's data structures
|
||||
StaticEventGroup_t xEventGroupBuffer;
|
||||
|
||||
// Create the event group without dynamically allocating any memory.
|
||||
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
</pre>
|
||||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
|
@ -1179,6 +1179,18 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
||||
*/
|
||||
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
|
||||
|
||||
/**
|
||||
* semphr.h
|
||||
* <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre>
|
||||
*
|
||||
* If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns
|
||||
* its current count value. If the semaphore is a binary semaphore then
|
||||
* uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the
|
||||
* semaphore is not available.
|
||||
*
|
||||
*/
|
||||
#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
#endif /* SEMAPHORE_H */
|
||||
|
||||
|
||||
|
@ -135,9 +135,17 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
* void * pvTimerID,
|
||||
* TimerCallbackFunction_t pxCallbackFunction );
|
||||
*
|
||||
* Creates a new software timer instance. This allocates the storage required
|
||||
* by the new timer, initialises the new timers internal state, and returns a
|
||||
* handle by which the new timer can be referenced.
|
||||
* Creates a new software timer instance, and returns a handle by which the
|
||||
* created software timer can be referenced.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, software timers use a block
|
||||
* of memory, in which the timer data structure is stored. If a software timer
|
||||
* is created using xTimerCreate() then the required memory is automatically
|
||||
* dynamically allocated inside the xTimerCreate() function. (see
|
||||
* http://www.freertos.org/a00111.html). If a software timer is created using
|
||||
* xTimerCreateStatic() then the application writer must provide the memory that
|
||||
* will get used by the software timer. xTimerCreateStatic() therefore allows a
|
||||
* software timer to be created without using any dynamic memory allocation.
|
||||
*
|
||||
* Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
|
||||
* xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
|
||||
@ -250,14 +258,151 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
*
|
||||
* // Starting the scheduler will start the timers running as they have already
|
||||
* // been set into the active state.
|
||||
* xTaskStartScheduler();
|
||||
* vTaskStartScheduler();
|
||||
*
|
||||
* // Should not reach here.
|
||||
* for( ;; );
|
||||
* }
|
||||
* @endverbatim
|
||||
*/
|
||||
TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TimerHandle_t xTimerCreateStatic(const char * const pcTimerName,
|
||||
* TickType_t xTimerPeriodInTicks,
|
||||
* UBaseType_t uxAutoReload,
|
||||
* void * pvTimerID,
|
||||
* TimerCallbackFunction_t pxCallbackFunction,
|
||||
* StaticTimer_t *pxTimerBuffer );
|
||||
*
|
||||
* Creates a new software timer instance, and returns a handle by which the
|
||||
* created software timer can be referenced.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, software timers use a block
|
||||
* of memory, in which the timer data structure is stored. If a software timer
|
||||
* is created using xTimerCreate() then the required memory is automatically
|
||||
* dynamically allocated inside the xTimerCreate() function. (see
|
||||
* http://www.freertos.org/a00111.html). If a software timer is created using
|
||||
* xTimerCreateStatic() then the application writer must provide the memory that
|
||||
* will get used by the software timer. xTimerCreateStatic() therefore allows a
|
||||
* software timer to be created without using any dynamic memory allocation.
|
||||
*
|
||||
* Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
|
||||
* xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
|
||||
* xTimerChangePeriodFromISR() API functions can all be used to transition a
|
||||
* timer into the active state.
|
||||
*
|
||||
* @param pcTimerName A text name that is assigned to the timer. This is done
|
||||
* purely to assist debugging. The kernel itself only ever references a timer
|
||||
* by its handle, and never by its name.
|
||||
*
|
||||
* @param xTimerPeriodInTicks The timer period. The time is defined in tick
|
||||
* periods so the constant portTICK_PERIOD_MS can be used to convert a time that
|
||||
* has been specified in milliseconds. For example, if the timer must expire
|
||||
* after 100 ticks, then xTimerPeriodInTicks should be set to 100.
|
||||
* Alternatively, if the timer must expire after 500ms, then xPeriod can be set
|
||||
* to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or
|
||||
* equal to 1000.
|
||||
*
|
||||
* @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will
|
||||
* expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter.
|
||||
* If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and
|
||||
* enter the dormant state after it expires.
|
||||
*
|
||||
* @param pvTimerID An identifier that is assigned to the timer being created.
|
||||
* Typically this would be used in the timer callback function to identify which
|
||||
* timer expired when the same callback function is assigned to more than one
|
||||
* timer.
|
||||
*
|
||||
* @param pxCallbackFunction The function to call when the timer expires.
|
||||
* Callback functions must have the prototype defined by TimerCallbackFunction_t,
|
||||
* which is "void vCallbackFunction( TimerHandle_t xTimer );".
|
||||
*
|
||||
* @param pxTimerBuffer Must point to a variable of type StaticTimer_t, which
|
||||
* will be then be used to hold the software timer's data structures, removing
|
||||
* the need for the memory to be allocated dynamically.
|
||||
*
|
||||
* @return If the timer is created then a handle to the created timer is
|
||||
* returned. If pxTimerBuffer was NULL then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
*
|
||||
* // The buffer used to hold the software timer's data structure.
|
||||
* static StaticTimer_t xTimerBuffer;
|
||||
*
|
||||
* // A variable that will be incremented by the software timer's callback
|
||||
* // function.
|
||||
* UBaseType_t uxVariableToIncrement = 0;
|
||||
*
|
||||
* // A software timer callback function that increments a variable passed to
|
||||
* // it when the software timer was created. After the 5th increment the
|
||||
* // callback function stops the software timer.
|
||||
* static void prvTimerCallback( TimerHandle_t xExpiredTimer )
|
||||
* {
|
||||
* UBaseType_t *puxVariableToIncrement;
|
||||
* BaseType_t xReturned;
|
||||
*
|
||||
* // Obtain the address of the variable to increment from the timer ID.
|
||||
* puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );
|
||||
*
|
||||
* // Increment the variable to show the timer callback has executed.
|
||||
* ( *puxVariableToIncrement )++;
|
||||
*
|
||||
* // If this callback has executed the required number of times, stop the
|
||||
* // timer.
|
||||
* if( *puxVariableToIncrement == 5 )
|
||||
* {
|
||||
* // This is called from a timer callback so must not block.
|
||||
* xTimerStop( xExpiredTimer, staticDONT_BLOCK );
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* void main( void )
|
||||
* {
|
||||
* // Create the software time. xTimerCreateStatic() has an extra parameter
|
||||
* // than the normal xTimerCreate() API function. The parameter is a pointer
|
||||
* // to the StaticTimer_t structure that will hold the software timer
|
||||
* // structure. If the parameter is passed as NULL then the structure will be
|
||||
* // allocated dynamically, just as if xTimerCreate() had been called.
|
||||
* xTimer = xTimerCreateStatic( "T1", // Text name for the task. Helps debugging only. Not used by FreeRTOS.
|
||||
* xTimerPeriod, // The period of the timer in ticks.
|
||||
* pdTRUE, // This is an auto-reload timer.
|
||||
* ( void * ) &uxVariableToIncrement, // A variable incremented by the software timer's callback function
|
||||
* prvTimerCallback, // The function to execute when the timer expires.
|
||||
* &xTimerBuffer ); // The buffer that will hold the software timer structure.
|
||||
*
|
||||
* // The scheduler has not started yet so a block time is not used.
|
||||
* xReturned = xTimerStart( xTimer, 0 );
|
||||
*
|
||||
* // ...
|
||||
* // Create tasks here.
|
||||
* // ...
|
||||
*
|
||||
* // Starting the scheduler will start the timers running as they have already
|
||||
* // been set into the active state.
|
||||
* vTaskStartScheduler();
|
||||
*
|
||||
* // Should not reach here.
|
||||
* for( ;; );
|
||||
* }
|
||||
* @endverbatim
|
||||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
/**
|
||||
* void *pvTimerGetTimerID( TimerHandle_t xTimer );
|
||||
@ -281,6 +426,27 @@ TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTi
|
||||
*/
|
||||
void *pvTimerGetTimerID( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
|
||||
*
|
||||
* Sets the ID assigned to the timer.
|
||||
*
|
||||
* IDs are assigned to timers using the pvTimerID parameter of the call to
|
||||
* xTimerCreated() that was used to create the timer.
|
||||
*
|
||||
* If the same callback function is assigned to multiple timers then the timer
|
||||
* ID can be used as time specific (timer local) storage.
|
||||
*
|
||||
* @param xTimer The timer being updated.
|
||||
*
|
||||
* @param pvNewID The ID to assign to the timer.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* See the xTimerCreate() API function example usage scenario.
|
||||
*/
|
||||
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer );
|
||||
*
|
||||
@ -329,6 +495,32 @@ BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
*/
|
||||
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
|
||||
|
||||
/**
|
||||
* TickType_t xTimerGetPeriod( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the period of a timer.
|
||||
*
|
||||
* @param xTimer The handle of the timer being queried.
|
||||
*
|
||||
* @return The period of the timer in ticks.
|
||||
*/
|
||||
TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the time in ticks at which the timer will expire. If this is less
|
||||
* than the current tick count then the expiry time has overflowed from the
|
||||
* current time.
|
||||
*
|
||||
* @param xTimer The handle of the timer being queried.
|
||||
*
|
||||
* @return If the timer is running then the time in ticks at which the timer
|
||||
* will next expire is returned. If the timer is not running then the return
|
||||
* value is undefined.
|
||||
*/
|
||||
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||
*
|
||||
|
@ -165,7 +165,7 @@ typedef struct QueueDefinition
|
||||
uint8_t ucQueueType;
|
||||
#endif
|
||||
|
||||
portMUX_TYPE mux;
|
||||
portMUX_TYPE mux; //Mutex required due to SMP
|
||||
|
||||
} xQUEUE;
|
||||
|
||||
|
253
components/freertos/test/test_freertos_backported_functions.c
Normal file
253
components/freertos/test/test_freertos_backported_functions.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Test features that are backported from version FreeRTOS 9.0.0.
|
||||
*
|
||||
* 1) Test backported timer functions
|
||||
* - xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
* 2) Test backported queue/semaphore functions
|
||||
* - xQueueCreateStatic()
|
||||
* - xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic(), uxSemaphoreGetCount()
|
||||
* - xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* 3) Test static allocation of tasks
|
||||
* - xTaskCreateStaticPinnedToCore()
|
||||
* 4) Test static allocation of event group
|
||||
* - xEventGroupCreateStatic()
|
||||
* 5) Test Thread Local Storage Pointers and Deletion Callbacks
|
||||
* - vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* - pvTaskGetThreadLocalStoragePointer()
|
||||
*
|
||||
* Note: The *pcQueueGetName() function is also backported, but is not tested in
|
||||
* the following test cases (see Queue Registry test cases instead)
|
||||
* For more details please refer the the ESP-IDF FreeRTOS changes documentation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
|
||||
/* ---------------------Test 1: Backported Timer functions-----------------------
|
||||
* Test xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
*
|
||||
* This test creates a one-shot static timer, sets/checks the timer's id and period. Then ensures
|
||||
* the timer cb is executed in a timely fashion.
|
||||
*/
|
||||
#define TMR_PERIOD_TICKS 10
|
||||
#define TIMER_ID 0xFF
|
||||
#define TICK_DELTA 5
|
||||
|
||||
static StaticTimer_t timer_buffer;
|
||||
static TickType_t tmr_ideal_exp;
|
||||
|
||||
static void tmr_cb(TimerHandle_t xtimer)
|
||||
{
|
||||
//Check cb is called in timely fashion
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTaskGetTickCount());
|
||||
}
|
||||
|
||||
//No need for smp test as Timer Task always runs on core 0
|
||||
TEST_CASE("Test FreeRTOS backported timer functions", "[freertos]")
|
||||
{
|
||||
//Create one shot static timer with period TMR_PERIOD_TICKS
|
||||
TimerHandle_t tmr_handle = xTimerCreateStatic("static_tmr", TMR_PERIOD_TICKS, pdFALSE, NULL, tmr_cb, &timer_buffer);
|
||||
TEST_ASSERT_EQUAL(TMR_PERIOD_TICKS, xTimerGetPeriod(tmr_handle)); //Test xTimerGetPeriod()
|
||||
|
||||
vTimerSetTimerID(tmr_handle, (void *)TIMER_ID);
|
||||
TEST_ASSERT_EQUAL(TIMER_ID, (uint32_t)pvTimerGetTimerID(tmr_handle)); //Test vTimerSetTimerID()
|
||||
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTimerStart(tmr_handle, 1)); //Start Timer
|
||||
tmr_ideal_exp = xTaskGetTickCount() + TMR_PERIOD_TICKS; //Calculate ideal expiration time
|
||||
vTaskDelay(2); //Need to yield to allow daemon task to process start command, or else expiration time will be NULL
|
||||
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTimerGetExpiryTime(tmr_handle)); //Test xTimerGetExpiryTime()
|
||||
|
||||
vTaskDelay(2*TMR_PERIOD_TICKS); //Delay until one shot timer has triggered
|
||||
TEST_ASSERT_EQUAL(pdPASS, xTimerDelete(tmr_handle, portMAX_DELAY)); //Clean up
|
||||
|
||||
}
|
||||
|
||||
/* ---------------Test backported queue/semaphore functions-------------------
|
||||
* xQueueCreateStatic()
|
||||
* xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic()
|
||||
* xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* uxSemaphoreGetCount() is also tested on the static counting semaphore
|
||||
*
|
||||
* This test creates various static queue/semphrs listed above and tests them by
|
||||
* doing a simple send/give and rec/take.
|
||||
*/
|
||||
|
||||
#define ITEM_SIZE 3
|
||||
#define NO_OF_ITEMS 3
|
||||
#define DELAY_TICKS 2
|
||||
|
||||
static StaticQueue_t queue_buffer; //Queues, Semaphores, and Mutex use the same queue structure
|
||||
static uint8_t queue_storage_area[(ITEM_SIZE*NO_OF_ITEMS)]; //Queue storage provided in separate buffer to queue struct
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported Queue and Semphr functions", "[freertos]")
|
||||
{
|
||||
//Test static queue
|
||||
uint8_t queue_item_to_send[ITEM_SIZE];
|
||||
uint8_t queue_item_received[ITEM_SIZE];
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
queue_item_to_send[i] = (0xF << i);
|
||||
}
|
||||
QueueHandle_t handle = xQueueCreateStatic(NO_OF_ITEMS, ITEM_SIZE,(uint8_t*) &queue_storage_area, &queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueSendToBack(handle, &queue_item_to_send, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(handle, queue_item_received, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
TEST_ASSERT_EQUAL(queue_item_to_send[i], queue_item_received[i]); //Check received contents are correct
|
||||
}
|
||||
vQueueDelete(handle); //Technically not needed as deleting static queue/semphr doesn't clear static memory
|
||||
|
||||
//Test static binary semaphore
|
||||
handle = xSemaphoreCreateBinaryStatic(&queue_buffer); //Queue and Semphr handles are the same
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static counting semaphore and uxSemaphoreGetCount()
|
||||
handle = xSemaphoreCreateCountingStatic(NO_OF_ITEMS, 0, &queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(NO_OF_ITEMS, uxSemaphoreGetCount(handle)); //Test uxSemaphoreGetCount()
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(0, uxSemaphoreGetCount(handle));
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex
|
||||
handle = xSemaphoreCreateMutexStatic(&queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should now hold mutex
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex recursive
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTakeRecursive(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should hold mutex
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGiveRecursive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
}
|
||||
|
||||
/* -----------------Test backported static task allocation -------------------
|
||||
* Test xTaskCreateStaticPinnedToCore() but creating static task on each core
|
||||
* and checking the task cb has run successfully.
|
||||
*/
|
||||
|
||||
#define STACK_SIZE 2048 //Task stack size
|
||||
|
||||
static StackType_t task_stack[STACK_SIZE]; //Static buffer for task stack
|
||||
static StaticTask_t task_buffer; //Static buffer for TCB
|
||||
static bool has_run[portNUM_PROCESSORS];
|
||||
|
||||
static void task(void *arg)
|
||||
{
|
||||
has_run[xPortGetCoreID()] = true; //Signify static task cb has run
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS static task allocation", "[freertos]")
|
||||
{
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
has_run[core] = false; //Clear has_run flag
|
||||
TaskHandle_t handle = xTaskCreateStaticPinnedToCore(task, "static task", STACK_SIZE, NULL,
|
||||
UNITY_FREERTOS_PRIORITY + 1, (StackType_t *)&task_stack,
|
||||
(StaticTask_t *)&task_buffer, core);
|
||||
vTaskDelay(5); //Allow for static task to run, delete, and idle to clean up
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, handle); //Check static task was successfully allocated
|
||||
TEST_ASSERT_TRUE(has_run[core]) //Check static task has run
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- Test backported static event group allocation -------------------
|
||||
* Test xEventGroupCreateStatic() but creating static event group then waiting
|
||||
* for an event.
|
||||
*/
|
||||
|
||||
#define WAIT_BITS 0x01 //Wait for first bit
|
||||
|
||||
static StaticEventGroup_t event_group;
|
||||
static EventGroupHandle_t eg_handle;
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
|
||||
{
|
||||
eg_handle = xEventGroupCreateStatic((StaticEventGroup_t *)&event_group);
|
||||
xEventGroupSetBits(eg_handle, WAIT_BITS);
|
||||
TEST_ASSERT_EQUAL(WAIT_BITS, xEventGroupWaitBits(eg_handle, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY));
|
||||
//Cleanup static event
|
||||
vEventGroupDelete(eg_handle);
|
||||
}
|
||||
|
||||
/* --------Test backported thread local storage pointer and deletion cb feature----------
|
||||
* vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* pvTaskGetThreadLocalStoragePointer(),
|
||||
*
|
||||
* This test creates a task and set's the task's TLSPs. The task is then deleted
|
||||
* which should trigger the deletion cb.
|
||||
*/
|
||||
|
||||
#define NO_OF_TLSP configNUM_THREAD_LOCAL_STORAGE_POINTERS
|
||||
#define TLSP_SET_BASE 0x0F //0b1111 to be bit shifted by index
|
||||
#define TLSP_DEL_BASE 0x05 //0b0101 to be bit shifted by index
|
||||
|
||||
//The variables pointed to by Thread Local Storage Pointer
|
||||
static uint32_t task_storage[portNUM_PROCESSORS][NO_OF_TLSP] = {0};
|
||||
|
||||
static void del_cb(int index, void *ptr)
|
||||
{
|
||||
*((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value
|
||||
}
|
||||
|
||||
static void task_cb()
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
task_storage[core][i] = (TLSP_SET_BASE << i); //Give each element of task_storage a unique number
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, i, (void *)&task_storage[core][i], del_cb); //Set each TLSP to point to a task storage element
|
||||
}
|
||||
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
uint32_t * tlsp = (uint32_t *)pvTaskGetThreadLocalStoragePointer(NULL, i);
|
||||
TEST_ASSERT_EQUAL(*tlsp, (TLSP_SET_BASE << i)); //Check if TLSP points to the correct task storage element by checking unique value
|
||||
}
|
||||
|
||||
vTaskDelete(NULL); //Delete Task to Trigger TSLP deletion callback
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS thread local storage pointers and del cb", "[freertos]")
|
||||
{
|
||||
//Create Task
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
xTaskCreatePinnedToCore(task_cb, "task", 1024, NULL, UNITY_FREERTOS_PRIORITY+1, NULL, core);
|
||||
}
|
||||
vTaskDelay(10); //Delay long enough for tasks to run to completion
|
||||
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
TEST_ASSERT_EQUAL((TLSP_DEL_BASE << i), task_storage[core][i]); //Check del_cb ran by checking task storage for unique value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
|
||||
static void tskdelcb(int no, void *arg)
|
||||
{
|
||||
ets_printf("Delete callback: %d = %p!\n", no, arg);
|
||||
}
|
||||
|
||||
|
||||
static void tska(void *pvParameters)
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xAAAAAAAA, tskdelcb);
|
||||
while (1) {
|
||||
vTaskDelay(10000000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskb(void *pvParameters)
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xBBBBBBBB, tskdelcb);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TaskHandle_t a = (TaskHandle_t)pvParameters;
|
||||
printf("Killing task A\n");
|
||||
vTaskDelete(a);
|
||||
while (1) {
|
||||
vTaskDelay(10000000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Freertos TLS delete cb", "[freertos]")
|
||||
{
|
||||
TaskHandle_t a, b;
|
||||
|
||||
xTaskCreatePinnedToCore(tska , "tska" , 2048, NULL, 3, &a, 0);
|
||||
xTaskCreatePinnedToCore(tskb , "tska" , 2048, a, 3, &b, 0);
|
||||
|
||||
// Let stuff run for 20s
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
printf("Killing task B\n");
|
||||
//Shut down b
|
||||
vTaskDelete(b);
|
||||
}
|
||||
|
@ -113,6 +113,10 @@ typedef struct tmrTimerControl
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
|
||||
#endif
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */
|
||||
#endif
|
||||
} xTIMER;
|
||||
|
||||
/* The old xTIMER name is maintained above then typedefed to the new Timer_t
|
||||
@ -239,6 +243,16 @@ static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIV
|
||||
*/
|
||||
static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Called after a Timer_t structure has been allocated either statically or
|
||||
* dynamically to fill in the structure's members.
|
||||
*/
|
||||
static void prvInitialiseNewTimer( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xTimerCreateTimerTask( void )
|
||||
@ -257,7 +271,10 @@ BaseType_t xReturn = pdFAIL;
|
||||
|
||||
if( xTimerQueue != NULL )
|
||||
{
|
||||
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
||||
/* Although static allocation has been backported from FreeRTOS v9.0.0,
|
||||
the timer task is still allocated dynamically. The actual timers
|
||||
however can be allocated statically.*/
|
||||
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
||||
{
|
||||
/* Create the timer task, storing its handle in xTimerTaskHandle so
|
||||
it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
|
||||
@ -280,44 +297,108 @@ BaseType_t xReturn = pdFAIL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
Timer_t *pxNewTimer;
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
|
||||
/* Allocate the timer structure. */
|
||||
if( xTimerPeriodInTicks == ( TickType_t ) 0U )
|
||||
{
|
||||
pxNewTimer = NULL;
|
||||
}
|
||||
else
|
||||
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
Timer_t *pxNewTimer;
|
||||
|
||||
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
|
||||
|
||||
if( pxNewTimer != NULL )
|
||||
{
|
||||
/* Ensure the infrastructure used by the timer service task has been
|
||||
created/initialised. */
|
||||
prvCheckForValidListAndQueue();
|
||||
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
|
||||
|
||||
/* Initialise the timer structure members using the function parameters. */
|
||||
pxNewTimer->pcTimerName = pcTimerName;
|
||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
||||
pxNewTimer->pvTimerID = pvTimerID;
|
||||
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
|
||||
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Timers can be created statically or dynamically, so note this
|
||||
timer was created dynamically in case the timer is later
|
||||
deleted. */
|
||||
pxNewTimer->ucStaticallyAllocated = pdFALSE;
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
}
|
||||
|
||||
traceTIMER_CREATE( pxNewTimer );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceTIMER_CREATE_FAILED();
|
||||
}
|
||||
return pxNewTimer;
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
Timer_t *pxNewTimer;
|
||||
|
||||
#if( configASSERT_DEFINED == 1 )
|
||||
{
|
||||
/* Sanity check that the size of the structure used to declare a
|
||||
variable of type StaticTimer_t equals the size of the real timer
|
||||
structures. */
|
||||
volatile size_t xSize = sizeof( StaticTimer_t );
|
||||
configASSERT( xSize == sizeof( Timer_t ) );
|
||||
}
|
||||
#endif /* configASSERT_DEFINED */
|
||||
|
||||
/* A pointer to a StaticTimer_t structure MUST be provided, use it. */
|
||||
configASSERT( pxTimerBuffer );
|
||||
pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
|
||||
|
||||
if( pxNewTimer != NULL )
|
||||
{
|
||||
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Timers can be created statically or dynamically so note this
|
||||
timer was created statically in case it is later deleted. */
|
||||
pxNewTimer->ucStaticallyAllocated = pdTRUE;
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
}
|
||||
|
||||
return pxNewTimer;
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInitialiseNewTimer( const char * const pcTimerName,
|
||||
const TickType_t xTimerPeriodInTicks,
|
||||
const UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
/* 0 is not a valid value for xTimerPeriodInTicks. */
|
||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
||||
|
||||
return ( TimerHandle_t ) pxNewTimer;
|
||||
if( pxNewTimer != NULL )
|
||||
{
|
||||
/* Ensure the infrastructure used by the timer service task has been
|
||||
created/initialised. */
|
||||
prvCheckForValidListAndQueue();
|
||||
|
||||
/* Initialise the timer structure members using the function
|
||||
parameters. */
|
||||
pxNewTimer->pcTimerName = pcTimerName;
|
||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
||||
pxNewTimer->pvTimerID = pvTimerID;
|
||||
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
|
||||
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
|
||||
traceTIMER_CREATE( pxNewTimer );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
@ -375,6 +456,26 @@ DaemonTaskMessage_t xMessage;
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
|
||||
{
|
||||
Timer_t *pxTimer = ( Timer_t * ) xTimer;
|
||||
|
||||
configASSERT( xTimer );
|
||||
return pxTimer->xTimerPeriodInTicks;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
|
||||
{
|
||||
Timer_t * pxTimer = ( Timer_t * ) xTimer;
|
||||
TickType_t xReturn;
|
||||
|
||||
configASSERT( xTimer );
|
||||
xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
const char * pcTimerGetTimerName( TimerHandle_t xTimer )
|
||||
{
|
||||
Timer_t *pxTimer = ( Timer_t * ) xTimer;
|
||||
@ -703,8 +804,29 @@ TickType_t xTimeNow;
|
||||
|
||||
case tmrCOMMAND_DELETE :
|
||||
/* The timer has already been removed from the active list,
|
||||
just free up the memory. */
|
||||
vPortFree( pxTimer );
|
||||
just free up the memory if the memory was dynamically
|
||||
allocated. */
|
||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||
{
|
||||
/* The timer can only have been allocated dynamically -
|
||||
free it again. */
|
||||
vPortFree( pxTimer );
|
||||
}
|
||||
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||
{
|
||||
/* The timer could have been allocated statically or
|
||||
dynamically, so check before attempting to free the
|
||||
memory. */
|
||||
if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
|
||||
{
|
||||
vPortFree( pxTimer );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
break;
|
||||
|
||||
default :
|
||||
@ -847,6 +969,20 @@ Timer_t * const pxTimer = ( Timer_t * ) xTimer;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID )
|
||||
{
|
||||
Timer_t * const pxTimer = ( Timer_t * ) xTimer;
|
||||
|
||||
configASSERT( xTimer );
|
||||
|
||||
//taskENTER_CRITICAL(); //Atomic instruction, critical not necessary
|
||||
//{
|
||||
pxTimer->pvTimerID = pvNewID;
|
||||
//}
|
||||
//taskEXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( INCLUDE_xTimerPendFunctionCall == 1 )
|
||||
|
||||
BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken )
|
||||
|
@ -12,11 +12,13 @@ run tasks interchangeably between them.
|
||||
|
||||
The ESP-IDF FreeRTOS is a modified version of vanilla FreeRTOS which supports
|
||||
symmetric multiprocessing (SMP). ESP-IDF FreeRTOS is based on the Xtensa port
|
||||
of FreeRTOS v8.2.0, however features such as static task creation and Thread
|
||||
Local Storage Pointers have been backported from later versions of FreeRTOS.
|
||||
This guide outlines the major differences between vanilla FreeRTOS and
|
||||
ESP-IDF FreeRTOS. The API reference for vanilla FreeRTOS can be found
|
||||
via http://www.freertos.org/a00106.html
|
||||
of FreeRTOS v8.2.0. This guide outlines the major differences between vanilla
|
||||
FreeRTOS and ESP-IDF FreeRTOS. The API reference for vanilla FreeRTOS can be
|
||||
found via http://www.freertos.org/a00106.html
|
||||
|
||||
:ref:`backported-features`: Although ESP-IDF FreeRTOS is based on the Xtensa
|
||||
port of FreeRTOS v8.2.0, a number of FreeRTOS v9.0.0 features have been backported
|
||||
to ESP-IDF.
|
||||
|
||||
:ref:`tasks-and-task-creation`: Use ``xTaskCreatePinnedToCore()`` or
|
||||
``xTaskCreateStaticPinnedToCore()`` to create tasks in ESP-IDF FreeRTOS. The
|
||||
@ -24,30 +26,30 @@ last parameter of the two functions is ``xCoreID``. This parameter specifies
|
||||
which core the task is pinned to. Acceptable values are ``0`` for **PRO_CPU**,
|
||||
``1`` for **APP_CPU**, or ``tskNO_AFFINITY`` which allows the task to run on
|
||||
both.
|
||||
|
||||
|
||||
:ref:`round-robin-scheduling`: The ESP-IDF FreeRTOS scheduler will skip tasks when
|
||||
implementing Round-Robin scheduling between multiple tasks in the Ready state
|
||||
that are of the same priority. To avoid this behavior, ensure that those tasks either
|
||||
enter a blocked state, or are distributed across a wider range of priorities.
|
||||
|
||||
|
||||
:ref:`scheduler-suspension`: Suspending the scheduler in ESP-IDF FreeRTOS will only
|
||||
affect the scheduler on the the calling core. In other words, calling
|
||||
``vTaskSuspendAll()`` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
|
||||
vice versa. Use critical sections or semaphores instead for simultaneous
|
||||
access protection.
|
||||
|
||||
|
||||
:ref:`tick-interrupt-synchronicity`: Tick interrupts of **PRO_CPU** and **APP_CPU**
|
||||
are not synchronized. Do not expect to use ``vTaskDelay`` or
|
||||
``vTaskDelayUntil`` as an accurate method of synchronizing task execution
|
||||
between the two cores. Use a counting semaphore instead as their context
|
||||
switches are not tied to tick interrupts due to preemption.
|
||||
|
||||
|
||||
:ref:`critical-sections`: In ESP-IDF FreeRTOS, critical sections are implemented using
|
||||
mutexes. Entering critical sections involve taking a mutex, then disabling the
|
||||
scheduler and interrupts of the calling core. However the other core is left
|
||||
unaffected. If the other core attemps to take same mutex, it will spin until
|
||||
the calling core has released the mutex by exiting the critical section.
|
||||
|
||||
|
||||
:ref:`deletion-callbacks`: ESP-IDF FreeRTOS has
|
||||
backported the Thread Local Storage Pointers feature. However they have the
|
||||
extra feature of deletion callbacks. Deletion callbacks are used to
|
||||
@ -64,6 +66,61 @@ configured using ``make meunconfig`` such as running ESP-IDF in Unicore Mode,
|
||||
or configuring the number of Thread Local Storage Pointers each task will have.
|
||||
|
||||
|
||||
.. _backported-features:
|
||||
|
||||
Backported Features
|
||||
-------------------
|
||||
|
||||
The following features have been backported from FreeRTOS v9.0.0 to ESP-IDF.
|
||||
|
||||
Static Alocation
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
This feature has been backported from FreeRTOS v9.0.0 to ESP-IDF. The
|
||||
:ref:`CONFIG_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig`
|
||||
in order for static allocation functions to be available. Once enabled, the
|
||||
following functions can be called...
|
||||
|
||||
- ``xTaskCreateStatic()`` See :ref:`backporting-notes` below
|
||||
- ``xQueueCreateStatic()``
|
||||
- ``xSemaphoreCreateBinaryStatic()``
|
||||
- ``xSemaphoreCreateCountingStatic()``
|
||||
- ``xSemaphoreCreateMutexStatic()``
|
||||
- ``xSemaphoreCreateRecursiveMutexStatic()``
|
||||
- ``xTimerCreateStatic()`` See :ref:`backporting-notes` below
|
||||
- ``xEventGroupCreateStatic()``
|
||||
|
||||
Other Features
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- ``vTaskSetThreadLocalStoragePointer()`` See :ref:`backporting-notes` below
|
||||
- ``pvTaskGetThreadLocalStoragePointer()`` See :ref:`backporting-notes` below
|
||||
- ``vTimerSetTimerID()``
|
||||
- ``xTimerGetPeriod()``
|
||||
- ``xTimerGetExpiryTime()``
|
||||
- ``pcQueueGetName()``
|
||||
- ``uxSemaphoreGetCount()``
|
||||
|
||||
.. _backporting-notes:
|
||||
|
||||
Backporting Notes
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
**1)** ``xTaskCreateStatic`` has been made SMP compatible in a similar
|
||||
fashion to ``xTaskCreate`` (see :ref:`tasks-and-task-creation`). Therefore
|
||||
``xTaskCreateStaticPinnedToCore()`` can also be called.
|
||||
|
||||
**2)** Although vanilla FreeRTOS allows the Timer feature's daemon task to
|
||||
be statically allocated, the daemon task is always dynamically allocated in
|
||||
ESP-IDF. Therefore ``vApplicationGetTimerTaskMemory`` **does not** need to be
|
||||
defined when using statically allocated timers in ESP-IDF FreeRTOS.
|
||||
|
||||
**3)** The Thread Local Storage Pointer feature has been modified in ESP-IDF
|
||||
FreeRTOS to include Deletion Callbacks (see :ref:`deletion-callbacks`). Therefore
|
||||
the function ``vTaskSetThreadLocalStoragePointerAndDelCallback()`` can also be
|
||||
called.
|
||||
|
||||
|
||||
.. _tasks-and-task-creation:
|
||||
|
||||
Tasks and Task Creation
|
||||
@ -75,7 +132,7 @@ appending ``PinnedToCore`` to the names of the task creation functions in
|
||||
vanilla FreeRTOS. The vanilla FreeRTOS functions of ``xTaskCreate()``
|
||||
and ``xTaskCreateStatic()`` have led to the addition of
|
||||
``xTaskCreatePinnedToCore()`` and ``xTaskCreateStaticPinnedToCore()`` in
|
||||
ESP-IDF FreeRTOS.
|
||||
ESP-IDF FreeRTOS (see :ref:`backported-features`).
|
||||
|
||||
For more details see :component_file:`freertos/task.c`
|
||||
|
||||
@ -234,6 +291,7 @@ protecting shared resources in ESP-IDF FreeRTOS.
|
||||
In general, it's better to use other RTOS primitives like mutex semaphores to protect
|
||||
against data shared between tasks, rather than ``vTaskSuspendAll()``.
|
||||
|
||||
|
||||
.. _tick-interrupt-synchronicity:
|
||||
|
||||
Tick Interrupt Synchronicity
|
||||
@ -266,6 +324,7 @@ Therefore, task delays should **NOT** be used as a method of synchronization
|
||||
between tasks in ESP-IDF FreeRTOS. Instead, consider using a counting semaphore
|
||||
to unblock multiple tasks at the same time.
|
||||
|
||||
|
||||
.. _critical-sections:
|
||||
|
||||
Critical Sections & Disabling Interrupts
|
||||
@ -315,6 +374,7 @@ called as they are all defined to call the same function. As long as the same
|
||||
mutex is provided upon entering and exiting, the type of call should not
|
||||
matter.
|
||||
|
||||
|
||||
.. _deletion-callbacks:
|
||||
|
||||
Thread Local Storage Pointers & Deletion Callbacks
|
||||
@ -351,6 +411,7 @@ Other indexes can be used for any purpose, provided
|
||||
|
||||
For more details see :component_file:`freertos/include/freertos/task.h`
|
||||
|
||||
|
||||
.. _esp-idf-freertos-configuration:
|
||||
|
||||
Configuring ESP-IDF FreeRTOS
|
||||
|
@ -23,3 +23,4 @@ CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7
|
||||
CONFIG_STACK_CHECK_STRONG=y
|
||||
CONFIG_STACK_CHECK=y
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
|
Loading…
Reference in New Issue
Block a user