kopia lustrzana https://github.com/espressif/esp-idf
freertos/backport and test v9.0.0 functions
This commit backports the following features from FreeRTOS v9.0.0 - uxSemaphoreGetCount() - vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime() - xTimerCreateStatic() - xEventGroupCreateStatic() - uxSemaphoreGetCount() Functions backported previously - xTaskCreateStatic() - xQueueCreateStatic() - xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic() - xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic() - pcQueueGetName() - vTaskSetThreadLocalStoragePointer() - pvTaskGetThreadLocalStoragePointer() Unit tests were also written for the functions above (except for pcQueueGetName which is tested in a separate Queue Registry MR). The original tlsp and del cb test case was deleted and integrated into the test cases of this MR.pull/1320/head
rodzic
46673bb6f1
commit
c1d101dd41
|
@ -209,7 +209,7 @@ config SUPPORT_STATIC_ALLOCATION
|
||||||
memory being allocated dynamically:
|
memory being allocated dynamically:
|
||||||
|
|
||||||
- Tasks
|
- Tasks
|
||||||
- Software Timers
|
- Software Timers (Daemon task is still dynamic. See documentation)
|
||||||
- Queues
|
- Queues
|
||||||
- Event Groups
|
- Event Groups
|
||||||
- Binary Semaphores
|
- Binary Semaphores
|
||||||
|
|
|
@ -119,7 +119,11 @@ typedef struct xEventGroupDefinition
|
||||||
UBaseType_t uxEventGroupNumber;
|
UBaseType_t uxEventGroupNumber;
|
||||||
#endif
|
#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;
|
} EventGroup_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,26 +141,83 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
EventGroupHandle_t xEventGroupCreate( void )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
{
|
|
||||||
EventGroup_t *pxEventBits;
|
|
||||||
|
|
||||||
pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );
|
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
|
||||||
if( pxEventBits != NULL )
|
|
||||||
{
|
{
|
||||||
pxEventBits->uxEventBits = 0;
|
EventGroup_t *pxEventBits;
|
||||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
|
||||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
/* A StaticEventGroup_t object must be provided. */
|
||||||
}
|
configASSERT( pxEventGroupBuffer );
|
||||||
else
|
|
||||||
{
|
/* The user has provided a statically allocated event group - use it. */
|
||||||
traceEVENT_GROUP_CREATE_FAILED();
|
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 )
|
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 );
|
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
}
|
}
|
||||||
|
|
||||||
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
|
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||||
vPortFree( pxEventBits );
|
{
|
||||||
|
/* 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();
|
( void ) xTaskResumeAll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -974,18 +974,73 @@ typedef struct xSTATIC_QUEUE
|
||||||
uint8_t ucDummy9;
|
uint8_t ucDummy9;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct {
|
portMUX_TYPE muxDummy; //Mutex required due to SMP
|
||||||
volatile uint32_t ucDummy10;
|
|
||||||
uint32_t ucDummy11;
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
|
||||||
void *pvDummy8;
|
|
||||||
UBaseType_t uxDummy12;
|
|
||||||
#endif
|
|
||||||
} sDummy1;
|
|
||||||
|
|
||||||
} StaticQueue_t;
|
} StaticQueue_t;
|
||||||
typedef StaticQueue_t StaticSemaphore_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -137,7 +137,17 @@ typedef TickType_t EventBits_t;
|
||||||
EventGroupHandle_t xEventGroupCreate( void );
|
EventGroupHandle_t xEventGroupCreate( void );
|
||||||
</pre>
|
</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
|
* 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
|
* 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
|
* \defgroup xEventGroupCreate xEventGroupCreate
|
||||||
* \ingroup EventGroup
|
* \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
|
* event_groups.h
|
||||||
|
|
|
@ -1179,6 +1179,18 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
|
#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 */
|
#endif /* SEMAPHORE_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -135,9 +135,17 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||||
* void * pvTimerID,
|
* void * pvTimerID,
|
||||||
* TimerCallbackFunction_t pxCallbackFunction );
|
* TimerCallbackFunction_t pxCallbackFunction );
|
||||||
*
|
*
|
||||||
* Creates a new software timer instance. This allocates the storage required
|
* Creates a new software timer instance, and returns a handle by which the
|
||||||
* by the new timer, initialises the new timers internal state, and returns a
|
* created software timer can be referenced.
|
||||||
* handle by which the new 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(),
|
* Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
|
||||||
* xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
|
* 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
|
* // Starting the scheduler will start the timers running as they have already
|
||||||
* // been set into the active state.
|
* // been set into the active state.
|
||||||
* xTaskStartScheduler();
|
* vTaskStartScheduler();
|
||||||
*
|
*
|
||||||
* // Should not reach here.
|
* // Should not reach here.
|
||||||
* for( ;; );
|
* for( ;; );
|
||||||
* }
|
* }
|
||||||
* @endverbatim
|
* @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 );
|
* 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 *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 );
|
* BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer );
|
||||||
*
|
*
|
||||||
|
@ -329,6 +495,32 @@ BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||||
*/
|
*/
|
||||||
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
|
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 );
|
* BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||||
*
|
*
|
||||||
|
|
|
@ -165,7 +165,7 @@ typedef struct QueueDefinition
|
||||||
uint8_t ucQueueType;
|
uint8_t ucQueueType;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
portMUX_TYPE mux;
|
portMUX_TYPE mux; //Mutex required due to SMP
|
||||||
|
|
||||||
} xQUEUE;
|
} xQUEUE;
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
#if( configUSE_TRACE_FACILITY == 1 )
|
||||||
UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
|
UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
|
||||||
#endif
|
#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;
|
} xTIMER;
|
||||||
|
|
||||||
/* The old xTIMER name is maintained above then typedefed to the new Timer_t
|
/* 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;
|
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 )
|
BaseType_t xTimerCreateTimerTask( void )
|
||||||
|
@ -257,7 +271,10 @@ BaseType_t xReturn = pdFAIL;
|
||||||
|
|
||||||
if( xTimerQueue != NULL )
|
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
|
/* Create the timer task, storing its handle in xTimerTaskHandle so
|
||||||
it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
|
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. */
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
{
|
|
||||||
Timer_t *pxNewTimer;
|
|
||||||
|
|
||||||
/* Allocate the timer structure. */
|
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
||||||
if( xTimerPeriodInTicks == ( TickType_t ) 0U )
|
const TickType_t xTimerPeriodInTicks,
|
||||||
{
|
const UBaseType_t uxAutoReload,
|
||||||
pxNewTimer = NULL;
|
void * const pvTimerID,
|
||||||
}
|
TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
Timer_t *pxNewTimer;
|
||||||
|
|
||||||
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
|
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
|
||||||
|
|
||||||
if( pxNewTimer != NULL )
|
if( pxNewTimer != NULL )
|
||||||
{
|
{
|
||||||
/* Ensure the infrastructure used by the timer service task has been
|
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
|
||||||
created/initialised. */
|
|
||||||
prvCheckForValidListAndQueue();
|
|
||||||
|
|
||||||
/* Initialise the timer structure members using the function parameters. */
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
pxNewTimer->pcTimerName = pcTimerName;
|
{
|
||||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
/* Timers can be created statically or dynamically, so note this
|
||||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
timer was created dynamically in case the timer is later
|
||||||
pxNewTimer->pvTimerID = pvTimerID;
|
deleted. */
|
||||||
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
|
pxNewTimer->ucStaticallyAllocated = pdFALSE;
|
||||||
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
|
}
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
}
|
||||||
|
|
||||||
traceTIMER_CREATE( pxNewTimer );
|
return pxNewTimer;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
traceTIMER_CREATE_FAILED();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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. */
|
/* 0 is not a valid value for xTimerPeriodInTicks. */
|
||||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
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
|
#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 )
|
const char * pcTimerGetTimerName( TimerHandle_t xTimer )
|
||||||
{
|
{
|
||||||
Timer_t *pxTimer = ( Timer_t * ) xTimer;
|
Timer_t *pxTimer = ( Timer_t * ) xTimer;
|
||||||
|
@ -703,8 +804,29 @@ TickType_t xTimeNow;
|
||||||
|
|
||||||
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 if the memory was dynamically
|
||||||
vPortFree( pxTimer );
|
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;
|
break;
|
||||||
|
|
||||||
default :
|
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 )
|
#if( INCLUDE_xTimerPendFunctionCall == 1 )
|
||||||
|
|
||||||
BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken )
|
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
|
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
|
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
|
of FreeRTOS v8.2.0. This guide outlines the major differences between vanilla
|
||||||
Local Storage Pointers have been backported from later versions of FreeRTOS.
|
FreeRTOS and ESP-IDF FreeRTOS. The API reference for vanilla FreeRTOS can be
|
||||||
This guide outlines the major differences between vanilla FreeRTOS and
|
found via http://www.freertos.org/a00106.html
|
||||||
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
|
:ref:`tasks-and-task-creation`: Use ``xTaskCreatePinnedToCore()`` or
|
||||||
``xTaskCreateStaticPinnedToCore()`` to create tasks in ESP-IDF FreeRTOS. The
|
``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**,
|
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
|
``1`` for **APP_CPU**, or ``tskNO_AFFINITY`` which allows the task to run on
|
||||||
both.
|
both.
|
||||||
|
|
||||||
:ref:`round-robin-scheduling`: The ESP-IDF FreeRTOS scheduler will skip tasks when
|
:ref:`round-robin-scheduling`: The ESP-IDF FreeRTOS scheduler will skip tasks when
|
||||||
implementing Round-Robin scheduling between multiple tasks in the Ready state
|
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
|
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.
|
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
|
:ref:`scheduler-suspension`: Suspending the scheduler in ESP-IDF FreeRTOS will only
|
||||||
affect the scheduler on the the calling core. In other words, calling
|
affect the scheduler on the the calling core. In other words, calling
|
||||||
``vTaskSuspendAll()`` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
|
``vTaskSuspendAll()`` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
|
||||||
vice versa. Use critical sections or semaphores instead for simultaneous
|
vice versa. Use critical sections or semaphores instead for simultaneous
|
||||||
access protection.
|
access protection.
|
||||||
|
|
||||||
:ref:`tick-interrupt-synchronicity`: Tick interrupts of **PRO_CPU** and **APP_CPU**
|
:ref:`tick-interrupt-synchronicity`: Tick interrupts of **PRO_CPU** and **APP_CPU**
|
||||||
are not synchronized. Do not expect to use ``vTaskDelay`` or
|
are not synchronized. Do not expect to use ``vTaskDelay`` or
|
||||||
``vTaskDelayUntil`` as an accurate method of synchronizing task execution
|
``vTaskDelayUntil`` as an accurate method of synchronizing task execution
|
||||||
between the two cores. Use a counting semaphore instead as their context
|
between the two cores. Use a counting semaphore instead as their context
|
||||||
switches are not tied to tick interrupts due to preemption.
|
switches are not tied to tick interrupts due to preemption.
|
||||||
|
|
||||||
:ref:`critical-sections`: In ESP-IDF FreeRTOS, critical sections are implemented using
|
:ref:`critical-sections`: In ESP-IDF FreeRTOS, critical sections are implemented using
|
||||||
mutexes. Entering critical sections involve taking a mutex, then disabling the
|
mutexes. Entering critical sections involve taking a mutex, then disabling the
|
||||||
scheduler and interrupts of the calling core. However the other core is left
|
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
|
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.
|
the calling core has released the mutex by exiting the critical section.
|
||||||
|
|
||||||
:ref:`deletion-callbacks`: ESP-IDF FreeRTOS has
|
:ref:`deletion-callbacks`: ESP-IDF FreeRTOS has
|
||||||
backported the Thread Local Storage Pointers feature. However they have the
|
backported the Thread Local Storage Pointers feature. However they have the
|
||||||
extra feature of deletion callbacks. Deletion callbacks are used to
|
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.
|
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:
|
||||||
|
|
||||||
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()``
|
vanilla FreeRTOS. The vanilla FreeRTOS functions of ``xTaskCreate()``
|
||||||
and ``xTaskCreateStatic()`` have led to the addition of
|
and ``xTaskCreateStatic()`` have led to the addition of
|
||||||
``xTaskCreatePinnedToCore()`` and ``xTaskCreateStaticPinnedToCore()`` in
|
``xTaskCreatePinnedToCore()`` and ``xTaskCreateStaticPinnedToCore()`` in
|
||||||
ESP-IDF FreeRTOS.
|
ESP-IDF FreeRTOS (see :ref:`backported-features`).
|
||||||
|
|
||||||
For more details see :component_file:`freertos/task.c`
|
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
|
In general, it's better to use other RTOS primitives like mutex semaphores to protect
|
||||||
against data shared between tasks, rather than ``vTaskSuspendAll()``.
|
against data shared between tasks, rather than ``vTaskSuspendAll()``.
|
||||||
|
|
||||||
|
|
||||||
.. _tick-interrupt-synchronicity:
|
.. _tick-interrupt-synchronicity:
|
||||||
|
|
||||||
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
|
between tasks in ESP-IDF FreeRTOS. Instead, consider using a counting semaphore
|
||||||
to unblock multiple tasks at the same time.
|
to unblock multiple tasks at the same time.
|
||||||
|
|
||||||
|
|
||||||
.. _critical-sections:
|
.. _critical-sections:
|
||||||
|
|
||||||
Critical Sections & Disabling Interrupts
|
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
|
mutex is provided upon entering and exiting, the type of call should not
|
||||||
matter.
|
matter.
|
||||||
|
|
||||||
|
|
||||||
.. _deletion-callbacks:
|
.. _deletion-callbacks:
|
||||||
|
|
||||||
Thread Local Storage Pointers & 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`
|
For more details see :component_file:`freertos/include/freertos/task.h`
|
||||||
|
|
||||||
|
|
||||||
.. _esp-idf-freertos-configuration:
|
.. _esp-idf-freertos-configuration:
|
||||||
|
|
||||||
Configuring ESP-IDF FreeRTOS
|
Configuring ESP-IDF FreeRTOS
|
||||||
|
|
|
@ -23,3 +23,4 @@ CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS=y
|
||||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7
|
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7
|
||||||
CONFIG_STACK_CHECK_STRONG=y
|
CONFIG_STACK_CHECK_STRONG=y
|
||||||
CONFIG_STACK_CHECK=y
|
CONFIG_STACK_CHECK=y
|
||||||
|
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||||
|
|
Ładowanie…
Reference in New Issue