From 90a607769708872719da4aefdf8dc0ad4347a732 Mon Sep 17 00:00:00 2001 From: rtel Date: Tue, 29 Mar 2016 11:08:42 +0000 Subject: [PATCH] - Rework the StaticAllocation.c common demo file to reflect the changes to the static allocation object create functions from the previous check-in. - Correct various typos in comments. - Add xTimerGetPeriod() function (feature request). git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2431 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Include/trcKernelHooks.h | 2 +- .../FreeRTOS-Plus-Trace/trcKernelPort.c | 54 +- .../CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c | 55 +- .../main.c | 56 +- .../main.c | 56 +- FreeRTOS/Demo/CORTEX_M4F_CEC1302_Keil/main.c | 56 +- .../Demo/Common/Minimal/StaticAllocation.c | 733 +++++++++++------- .../WIN32-MSVC-Static-Allocation-Only/main.c | 43 +- FreeRTOS/Demo/WIN32-MSVC/main.c | 49 +- FreeRTOS/Source/include/queue.h | 2 +- FreeRTOS/Source/include/semphr.h | 6 +- 11 files changed, 701 insertions(+), 411 deletions(-) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h index 7b94a106f..03145b8e6 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h @@ -187,7 +187,7 @@ #undef trcKERNEL_HOOKS_TASK_RESUME #define trcKERNEL_HOOKS_TASK_RESUME(SERVICE, pxTCB) \ vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); - + #undef trcKERNEL_HOOKS_TIMER_EVENT #define trcKERNEL_HOOKS_TIMER_EVENT(SERVICE, pxTimer) \ vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer)); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c index 38251c40e..722e55341 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c @@ -5,30 +5,30 @@ * trcKernelPort.c * * Kernel-specific functionality for FreeRTOS, used by the recorder library. - * + * * Terms of Use * This software is copyright Percepio AB. The recorder library is free for * use together with Percepio products. You may distribute the recorder library * in its original form, including modifications in trcHardwarePort.c/.h * given that these modification are clearly marked as your own modifications - * and documented in the initial comment section of these source files. - * This software is the intellectual property of Percepio AB and may not be - * sold or in other ways commercially redistributed without explicit written + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written * permission by Percepio AB. * - * Disclaimer - * The trace tool and recorder library is being delivered to you AS IS and - * Percepio AB makes no warranty as to its use or performance. Percepio AB does - * not and cannot warrant the performance or results you may obtain by using the - * software or documentation. Percepio AB make no warranties, express or - * implied, as to noninfringement of third party rights, merchantability, or - * fitness for any particular purpose. In no event will Percepio AB, its - * technology partners, or distributors be liable to you for any consequential, - * incidental or special damages, including any lost profits or lost savings, - * even if a representative of Percepio AB has been advised of the possibility - * of such damages, or for any claim by any third party. Some jurisdictions do - * not allow the exclusion or limitation of incidental, consequential or special - * damages, or the exclusion of implied warranties or limitations on how long an + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * * Tabs are used for indent in this file (1 tab = 4 spaces) @@ -45,7 +45,7 @@ #include "task.h" -/* For classes implemented as FreeRTOS Queues: +/* For classes implemented as FreeRTOS Queues: This translates queue.type to the corresponding trace object class. */ traceObjectClass TraceObjectClassTable[5] = { TRACE_CLASS_QUEUE, @@ -119,14 +119,14 @@ void vTraceInitObjectPropertyTable() RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = NTask; RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = NISR; RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = NTimer; - RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = NEventGroup; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = NEventGroup; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = NameLenQueue; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = NameLenSemaphore; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = NameLenMutex; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = NameLenTask; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = NameLenISR; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = NameLenTimer; - RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = NameLenEventGroup; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = NameLenEventGroup; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex; @@ -163,7 +163,7 @@ void vTraceInitObjectHandleStack() objectHandleStacks.highestIndexOfClass[5] = NQueue + NSemaphore + NMutex + NTask + NISR + NTimer - 1; objectHandleStacks.highestIndexOfClass[6] = NQueue + NSemaphore + NMutex + NTask + NISR + NTimer + NEventGroup - 1; } - + /* Returns the "Not enough handles" error message for this object class */ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass) { @@ -182,7 +182,7 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass) case TRACE_CLASS_TIMER: return "Not enough TIMER handles - increase NTimer in trcConfig.h"; case TRACE_CLASS_EVENTGROUP: - return "Not enough EVENTGROUP handles - increase NEventGroup in trcConfig.h"; + return "Not enough EVENTGROUP handles - increase NEventGroup in trcConfig.h"; default: return "pszTraceGetErrorHandles: Invalid objectclass!"; } @@ -193,7 +193,7 @@ uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType h { TRACE_ASSERT(objectclass < TRACE_NCLASSES, "prvTraceIsObjectExcluded: objectclass >= TRACE_NCLASSES", 1); TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceIsObjectExcluded: Invalid value for handle", 1); - + switch(objectclass) { case TRACE_CLASS_TASK: @@ -205,13 +205,13 @@ uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType h case TRACE_CLASS_QUEUE: return TRACE_GET_QUEUE_FLAG_ISEXCLUDED(handle); case TRACE_CLASS_TIMER: - return TRACE_GET_TIMER_FLAG_ISEXCLUDED(handle); + return TRACE_GET_TIMER_FLAG_ISEXCLUDED(handle); case TRACE_CLASS_EVENTGROUP: - return TRACE_GET_EVENTGROUP_FLAG_ISEXCLUDED(handle); + return TRACE_GET_EVENTGROUP_FLAG_ISEXCLUDED(handle); } - + vTraceError("Invalid object class ID in uiTraceIsObjectExcluded!"); - + /* Must never reach */ return 1; } diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c index b533712c1..0092d9e6b 100644 --- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c +++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c @@ -407,28 +407,53 @@ const uint32_t ulMaxDivisor = 0xff, ulDivisorShift = 0x08; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Idle task as its - stack and to hold its TCB. If these are set to NULL then the buffers will - be allocated dynamically, just as if xTaskCreate() had been called. */ - *ppxIdleTaskTCBBuffer = NULL; - *ppxIdleTaskStackBuffer = NULL; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Timer/RTOS daemon - task as its stack and to hold its TCB. If these are set to NULL then the - buffers will be allocated dynamically, just as if xTaskCreate() had been - called. */ - *ppxTimerTaskTCBBuffer = NULL; - *ppxTimerTaskStackBuffer = NULL; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Giant_Gecko_Simplicity_Studio/main.c b/FreeRTOS/Demo/CORTEX_EFM32_Giant_Gecko_Simplicity_Studio/main.c index 1eb40c1ff..1bef000bf 100644 --- a/FreeRTOS/Demo/CORTEX_EFM32_Giant_Gecko_Simplicity_Studio/main.c +++ b/FreeRTOS/Demo/CORTEX_EFM32_Giant_Gecko_Simplicity_Studio/main.c @@ -222,28 +222,52 @@ void vApplicationTickHook( void ) } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Idle task as its - stack and to hold its TCB. If these are set to NULL then the buffers will - be allocated dynamically, just as if xTaskCreate() had been called. */ - *ppxIdleTaskTCBBuffer = NULL; - *ppxIdleTaskStackBuffer = NULL; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Timer/RTOS daemon - task as its stack and to hold its TCB. If these are set to NULL then the - buffers will be allocated dynamically, just as if xTaskCreate() had been - called. */ - *ppxTimerTaskTCBBuffer = NULL; - *ppxTimerTaskStackBuffer = NULL; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } -/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c index de94bcb9f..369099a1c 100644 --- a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c @@ -229,27 +229,51 @@ void vApplicationTickHook( void ) } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Idle task as its - stack and to hold its TCB. If these are set to NULL then the buffers will - be allocated dynamically, just as if xTaskCreate() had been called. */ - *ppxIdleTaskTCBBuffer = NULL; - *ppxIdleTaskStackBuffer = NULL; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Timer/RTOS daemon - task as its stack and to hold its TCB. If these are set to NULL then the - buffers will be allocated dynamically, just as if xTaskCreate() had been - called. */ - *ppxTimerTaskTCBBuffer = NULL; - *ppxTimerTaskStackBuffer = NULL; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } -/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/CORTEX_M4F_CEC1302_Keil/main.c b/FreeRTOS/Demo/CORTEX_M4F_CEC1302_Keil/main.c index 18db41134..82115564d 100644 --- a/FreeRTOS/Demo/CORTEX_M4F_CEC1302_Keil/main.c +++ b/FreeRTOS/Demo/CORTEX_M4F_CEC1302_Keil/main.c @@ -234,30 +234,54 @@ void vApplicationTickHook( void ) } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Idle task as its - stack and to hold its TCB. If these are set to NULL then the buffers will - be allocated dynamically, just as if xTaskCreate() had been called. */ - *ppxIdleTaskTCBBuffer = NULL; - *ppxIdleTaskStackBuffer = NULL; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Timer/RTOS daemon - task as its stack and to hold its TCB. If these are set to NULL then the - buffers will be allocated dynamically, just as if xTaskCreate() had been - called. */ - *ppxTimerTaskTCBBuffer = NULL; - *ppxTimerTaskStackBuffer = NULL; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ +static StaticTask_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } -/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c index 1433476f2..4b4232b55 100644 --- a/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c +++ b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c @@ -73,6 +73,8 @@ * rather than the normal dynamically allocated memory, and tests objects being * created and deleted with both statically allocated memory and dynamically * allocated memory. + * + * See http://www.FreeRTOS.org/Static_Vs_Dynamic_Memory_Allocation.html */ /* Scheduler include files. */ @@ -130,59 +132,51 @@ static void prvTimerCallback( TimerHandle_t xExpiredTimer ); static void prvStaticallyAllocatedTask( void *pvParameters ); /* - * A function that demonstrates and tests the xTaskCreateStatic() API function - * by creating and then deleting tasks with both dynamically and statically - * allocated TCBs and stacks. + * A function that demonstrates and tests the API functions that create and + * delete tasks using both statically and dynamically allocated TCBs and stacks. */ static void prvCreateAndDeleteStaticallyAllocatedTasks( void ); /* - * A function that demonstrates and tests the xEventGroupCreateStatic() API - * function by creating and then deleting event groups using both dynamically - * and statically allocated event group structures. + * A function that demonstrates and tests the API functions that create and + * delete event groups using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void ); /* - * A function that demonstrates and tests the xQueueCreateStatic() API function - * by creating and then deleting queues with both dynamically and statically - * allocated queue structures and queue storage areas. + * A function that demonstrates and tests the API functions that create and + * delete queues using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedQueues( void ); /* - * A function that demonstrates and tests the xSemaphoreCreateBinaryStatic() API - * macro by creating and then deleting binary semaphores with both dynamically - * and statically allocated semaphore structures. + * A function that demonstrates and tests the API functions that create and + * delete binary semaphores using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void ); /* - * A function that demonstrates and tests the xTimerCreateStatic() API macro by - * creating and then deleting software timers with both dynamically and - * statically allocated timer structures. + * A function that demonstrates and tests the API functions that create and + * delete software timers using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedTimers( void ); /* - * A function that demonstrates and tests the xSemaphoreCreateMutexStatic() API - * macro by creating and then deleting mutexes with both dynamically and - * statically allocated semaphore structures. + * A function that demonstrates and tests the API functions that create and + * delete mutexes using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedMutexes( void ); /* - * A function that demonstrates and tests the xSemaphoreCreateCountingStatic() - * API macro by creating and then deleting counting semaphores with both - * dynamically and statically allocated semaphore structures. + * A function that demonstrates and tests the API functions that create and + * delete counting semaphores using both statically and dynamically allocated + * RAM. */ static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void ); /* - * A function that demonstrates and tests the - * xSemaphoreCreateRecursiveMutexStatic() API macro by creating and then - * deleting recursive mutexes with both dynamically and statically allocated - * semaphore structures. + * A function that demonstrates and tests the API functions that create and + * delete recursive mutexes using both statically and dynamically allocated RAM. */ static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void ); @@ -250,9 +244,8 @@ static volatile BaseType_t xErrorOccurred = pdFALSE; void vStartStaticallyAllocatedTasks( void ) { - /* Create a single task, which then repeatedly creates and deletes the - task implemented by prvStaticallyAllocatedTask() at various different - priorities, and both with and without statically allocated TCB and stack. */ + /* Create a single task, which then repeatedly creates and deletes the other + RTOS objects using both statically and dynamically allocated RAM. */ xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */ "StatCreate", /* Text name for the task - not used by the RTOS, its just to assist debugging. */ staticCREATOR_TASK_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */ @@ -274,16 +267,16 @@ static void prvStaticallyAllocatedCreator( void *pvParameters ) for( ;; ) { - /* Loop, running functions that create and delete the various objects - that can be optionally created using either static or dynamic memory - allocation. */ + /* Loop, running functions that create and delete the various RTOS + objects that can be optionally created using either static or dynamic + memory allocation. */ prvCreateAndDeleteStaticallyAllocatedTasks(); prvCreateAndDeleteStaticallyAllocatedQueues(); - /* Ensure lower priority tasks get CPU time. */ + /* Delay to ensure lower priority tasks get CPU time, and increment the + cycle counter so a 'check' task can determine that this task is still + executing. */ vTaskDelay( prvGetNextDelayTime() ); - - /* Just to show the check task that this task is still executing. */ uxCycleCounter++; prvCreateAndDeleteStaticallyAllocatedBinarySemaphores(); @@ -304,237 +297,6 @@ static void prvStaticallyAllocatedCreator( void *pvParameters ) } /*-----------------------------------------------------------*/ -static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup ) -{ -EventBits_t xEventBits; -const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55; - - /* The event group should not have any bits set yet. */ - xEventBits = xEventGroupGetBits( xEventGroup ); - - if( xEventBits != ( EventBits_t ) 0 ) - { - xErrorOccurred = pdTRUE; - } - - /* Some some bits, then read them back to check they are as expected. */ - xEventGroupSetBits( xEventGroup, xFirstTestBits ); - - xEventBits = xEventGroupGetBits( xEventGroup ); - - if( xEventBits != xFirstTestBits ) - { - xErrorOccurred = pdTRUE; - } - - xEventGroupSetBits( xEventGroup, xSecondTestBits ); - - xEventBits = xEventGroupGetBits( xEventGroup ); - - if( xEventBits != ( xFirstTestBits | xSecondTestBits ) ) - { - xErrorOccurred = pdTRUE; - } - - /* Finally try clearing some bits too and check that operation proceeds as - expected. */ - xEventGroupClearBits( xEventGroup, xFirstTestBits ); - - xEventBits = xEventGroupGetBits( xEventGroup ); - - if( xEventBits != xSecondTestBits ) - { - xErrorOccurred = pdTRUE; - } -} -/*-----------------------------------------------------------*/ - -static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ) -{ -BaseType_t xReturned; -UBaseType_t x; -const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 ); -TickType_t xTickCount; - - /* The binary semaphore should start 'empty', so a call to xSemaphoreTake() - should fail. */ - xTickCount = xTaskGetTickCount(); - xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); - - if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime ) - { - /* Did not block on the semaphore as long as expected. */ - xErrorOccurred = pdTRUE; - } - - if( xReturned != pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - - /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount - times. */ - for( x = 0; x < uxMaxCount; x++ ) - { - xReturned = xSemaphoreGive( xSemaphore ); - - if( xReturned == pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - } - - /* Giving the semaphore again should fail, as it is 'full'. */ - xReturned = xSemaphoreGive( xSemaphore ); - - if( xReturned != pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - - configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount ); - - /* Should now be possible to 'take' the semaphore up to a maximum of - uxMaxCount times without blocking. */ - for( x = 0; x < uxMaxCount; x++ ) - { - xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); - - if( xReturned == pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - } - - /* Back to the starting condition, where the semaphore should not be - available. */ - xTickCount = xTaskGetTickCount(); - xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); - - if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime ) - { - /* Did not block on the semaphore as long as expected. */ - xErrorOccurred = pdTRUE; - } - - if( xReturned != pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - - configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 ); -} -/*-----------------------------------------------------------*/ - -static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue ) -{ -uint64_t ull, ullRead; -BaseType_t xReturned, xLoop; - - /* This test is done twice to ensure the queue storage area wraps. */ - for( xLoop = 0; xLoop < 2; xLoop++ ) - { - /* A very basic test that the queue can be written to and read from as - expected. First the queue should be empty. */ - xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); - if( xReturned != errQUEUE_EMPTY ) - { - xErrorOccurred = pdTRUE; - } - - /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS - times. */ - for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) - { - xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); - if( xReturned != pdPASS ) - { - xErrorOccurred = pdTRUE; - } - } - - /* Should not now be possible to write to the queue again. */ - xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); - if( xReturned != errQUEUE_FULL ) - { - xErrorOccurred = pdTRUE; - } - - /* Now read back from the queue to ensure the data read back matches that - written. */ - for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) - { - xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK ); - - if( xReturned != pdPASS ) - { - xErrorOccurred = pdTRUE; - } - - if( ullRead != ull ) - { - xErrorOccurred = pdTRUE; - } - } - - /* The queue should be empty again. */ - xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); - if( xReturned != errQUEUE_EMPTY ) - { - xErrorOccurred = pdTRUE; - } - } -} -/*-----------------------------------------------------------*/ - -static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore ) -{ -const BaseType_t xLoops = 5; -BaseType_t x, xReturned; - - /* A very basic test that the recursive semaphore behaved like a recursive - semaphore. First the semaphore should not be able to be given, as it has not - yet been taken. */ - xReturned = xSemaphoreGiveRecursive( xSemaphore ); - - if( xReturned != pdFAIL ) - { - xErrorOccurred = pdTRUE; - } - - /* Now it should be possible to take the mutex a number of times. */ - for( x = 0; x < xLoops; x++ ) - { - xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK ); - - if( xReturned != pdPASS ) - { - xErrorOccurred = pdTRUE; - } - } - - /* Should be possible to give the semaphore the same number of times as it - was given in the loop above. */ - for( x = 0; x < xLoops; x++ ) - { - xReturned = xSemaphoreGiveRecursive( xSemaphore ); - - if( xReturned != pdPASS ) - { - xErrorOccurred = pdTRUE; - } - } - - /* No more gives should be possible though. */ - xReturned = xSemaphoreGiveRecursive( xSemaphore ); - - if( xReturned != pdFAIL ) - { - xErrorOccurred = pdTRUE; - } -} -/*-----------------------------------------------------------*/ - static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void ) { SemaphoreHandle_t xSemaphore; @@ -552,7 +314,7 @@ a counting semaphore. http://www.freertos.org/RTOS-task-notifications.html */ StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateCountingStatic() has one more - parameter than the usual xSemaphoreCreateCounting() function. The paraemter + parameter than the usual xSemaphoreCreateCounting() function. The parameter is a pointer to the pre-allocated StaticSemaphore_t structure, which will hold information on the semaphore in an anonymous way. If the pointer is passed as NULL then the structure will be allocated dynamically, just as @@ -568,6 +330,18 @@ StaticSemaphore_t xSemaphoreBuffer; /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Now do the same but using dynamically allocated buffers to ensure the + delete functions are working correctly in both the static and dynamic + allocation cases. */ + xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 ); + configASSERT( xSemaphore != NULL ); + prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount ); + vSemaphoreDelete( xSemaphore ); + } + #endif } /*-----------------------------------------------------------*/ @@ -602,6 +376,18 @@ StaticSemaphore_t xSemaphoreBuffer; /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); + + /* Now do the same using dynamically allocated buffers to ensure the delete + functions are working correctly in both the static and dynamic memory + allocation cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xSemaphore = xSemaphoreCreateRecursiveMutex(); + configASSERT( xSemaphore != NULL ); + prvSanityCheckCreatedRecursiveMutex( xSemaphore ); + vSemaphoreDelete( xSemaphore ); + } + #endif } /*-----------------------------------------------------------*/ @@ -645,6 +431,26 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_ /* Delete the queue again so the buffers can be reused. */ vQueueDelete( xQueue ); + + /* Now do the same using a dynamically allocated queue to ensure the delete + function is working correctly in both the static and dynamic memory + allocation cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */ + sizeof( uint64_t ) ); /* The size of each item. */ + + /* The queue handle should equal the static queue structure passed into the + xQueueCreateStatic() function. */ + configASSERT( xQueue != NULL ); + + /* Ensure the queue passes a few sanity checks as a valid queue. */ + prvSanityCheckCreatedQueue( xQueue ); + + /* Delete the queue again so the buffers can be reused. */ + vQueueDelete( xQueue ); + } + #endif } /*-----------------------------------------------------------*/ @@ -663,7 +469,7 @@ function calls within this function. */ StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateMutexStatic() has one more - parameter than the usual xSemaphoreCreateMutex() function. The paraemter + parameter than the usual xSemaphoreCreateMutex() function. The parameter is a pointer to the pre-allocated StaticSemaphore_t structure, which will hold information on the semaphore in an anonymous way. If the pointer is passed as NULL then the structure will be allocated dynamically, just as @@ -688,11 +494,39 @@ StaticSemaphore_t xSemaphoreBuffer; /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); -} -/*-----------------------------------------------------------*/ -static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void ) -{ + /* Now do the same using a dynamically allocated mutex to ensure the delete + function is working correctly in both the static and dynamic allocation + cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xSemaphore = xSemaphoreCreateMutex(); + + /* The semaphore handle should equal the static semaphore structure + passed into the xSemaphoreCreateMutexStatic() function. */ + configASSERT( xSemaphore != NULL ); + + /* Take the mutex so the mutex is in the state expected by the + prvSanityCheckCreatedSemaphore() function. */ + xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + + /* Delete the semaphore again so the buffers can be reused. */ + vSemaphoreDelete( xSemaphore ); + } + #endif +} +/*-----------------------------------------------------------*/ + +static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void ) +{ SemaphoreHandle_t xSemaphore; /* StaticSemaphore_t is a publicly accessible structure that has the same size @@ -707,7 +541,7 @@ a binary semaphore. http://www.freertos.org/RTOS-task-notifications.html */ StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more - parameter than the usual xSemaphoreCreateBinary() function. The paraemter + parameter than the usual xSemaphoreCreateBinary() function. The parameter is a pointer to the pre-allocated StaticSemaphore_t structure, which will hold information on the semaphore in an anonymous way. If the pointer is passed as NULL then the structure will be allocated dynamically, just as @@ -724,11 +558,21 @@ StaticSemaphore_t xSemaphoreBuffer; /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); + /* Now do the same using a dynamically allocated semaphore to check the + delete function is working correctly in both the static and dynamic + allocation cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xSemaphore = xSemaphoreCreateBinary(); + configASSERT( xSemaphore != NULL ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + vSemaphoreDelete( xSemaphore ); + } + #endif /* There isn't a static version of the old and deprecated vSemaphoreCreateBinary() macro (because its deprecated!), but check it is - still functioning correctly when configSUPPORT_STATIC_ALLOCATION is set to - 1. */ + still functioning correctly. */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) { vSemaphoreCreateBinary( xSemaphore ); @@ -752,7 +596,9 @@ static void prvTimerCallback( TimerHandle_t xExpiredTimer ) UBaseType_t *puxVariableToIncrement; BaseType_t xReturned; - /* Obtain the address of the variable to increment from the timer ID. */ + /* The timer callback just demonstrates it is executing by incrementing a + variable - the address of which is passed into the timer as its ID. Obtain + the address of the variable to increment. */ puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); /* Increment the variable to show the timer callback has executed. */ @@ -762,7 +608,8 @@ BaseType_t xReturned; timer. */ if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS ) { - /* This is called from a timer callback so must not block. */ + /* This is called from a timer callback so must not block. See + http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */ xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK ); if( xReturned != pdPASS ) @@ -838,6 +685,43 @@ StaticTimer_t xTimerBuffer; /* Just to show the check task that this task is still executing. */ uxCycleCounter++; + + /* Now do the same using a dynamically allocated software timer to ensure + the delete function is working correctly in both the static and dynamic + allocation cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xTimer = xTimerCreate( "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, /* The variable incremented by the test is passed into the timer callback using the timer ID. */ + prvTimerCallback ); /* The function to execute when the timer expires. */ + + configASSERT( xTimer != NULL ); + + uxVariableToIncrement = 0; + xReturned = xTimerStart( xTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS ); + + if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS ) + { + xErrorOccurred = pdTRUE; + } + + xReturned = xTimerDelete( xTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + } + #endif } /*-----------------------------------------------------------*/ @@ -871,6 +755,18 @@ StaticEventGroup_t xEventGroupBuffer; /* Delete the event group again so the buffers can be reused. */ vEventGroupDelete( xEventGroup ); + + /* Now do the same using a dynamically allocated event group to ensure the + delete function is working correctly in both the static and dynamic + allocation cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xEventGroup = xEventGroupCreate(); + configASSERT( xEventGroup != NULL ); + prvSanityCheckCreatedEventGroup( xEventGroup ); + vEventGroupDelete( xEventGroup ); + } + #endif } /*-----------------------------------------------------------*/ @@ -896,14 +792,21 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ]; passed as NULL then the respective object will be allocated dynamically as if xTaskCreate() had been called. */ xReturned = xTaskCreateStatic( - prvStaticallyAllocatedTask, /* Function that implements the task. */ - "Static", /* Human readable name for the task. */ - configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ - NULL, /* Parameter to pass into the task. */ - tskIDLE_PRIORITY, /* The priority of the task. */ - &xCreatedTask, /* Handle of the task being created. */ - &( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ - &xTCBBuffer ); /* The variable that will hold that task's TCB. */ + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + uxTaskPriorityGet( NULL ) + 1, /* The priority of the task. */ + &xCreatedTask, /* Handle of the task being created. */ + &( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ + &xTCBBuffer ); /* The variable that will hold that task's TCB. */ + + /* The created task had a higher priority so should have executed and + suspended itself by now. */ + if( eTaskGetState( xCreatedTask ) != eSuspended ) + { + xErrorOccurred = pdTRUE; + } /* Check the task was created correctly, then delete the task. */ configASSERT( xReturned == pdPASS ); @@ -912,6 +815,33 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ]; xErrorOccurred = pdTRUE; } vTaskDelete( xCreatedTask ); + + /* Now do the same using a dynamically allocated task to ensure the delete + function is working correctly in both the static and dynamic allocation + cases. */ + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + xReturned = xTaskCreate( + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + uxTaskPriorityGet( NULL ) + 1, /* The priority of the task. */ + &xCreatedTask ); /* Handle of the task being created. */ + + if( eTaskGetState( xCreatedTask ) != eSuspended ) + { + xErrorOccurred = pdTRUE; + } + + configASSERT( xReturned == pdPASS ); + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + vTaskDelete( xCreatedTask ); + } + #endif } /*-----------------------------------------------------------*/ @@ -919,7 +849,9 @@ static void prvStaticallyAllocatedTask( void *pvParameters ) { ( void ) pvParameters; - /* The created task doesn't do anything - just waits to get deleted. */ + /* The created task just suspends itself to wait to get deleted. The task + that creates this task checks this task is in the expected Suspended state + before deleting it. */ vTaskSuspend( NULL ); } /*-----------------------------------------------------------*/ @@ -957,6 +889,237 @@ const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 ); } /*-----------------------------------------------------------*/ +static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup ) +{ +EventBits_t xEventBits; +const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55; + + /* The event group should not have any bits set yet. */ + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != ( EventBits_t ) 0 ) + { + xErrorOccurred = pdTRUE; + } + + /* Some some bits, then read them back to check they are as expected. */ + xEventGroupSetBits( xEventGroup, xFirstTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != xFirstTestBits ) + { + xErrorOccurred = pdTRUE; + } + + xEventGroupSetBits( xEventGroup, xSecondTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != ( xFirstTestBits | xSecondTestBits ) ) + { + xErrorOccurred = pdTRUE; + } + + /* Finally try clearing some bits too and check that operation proceeds as + expected. */ + xEventGroupClearBits( xEventGroup, xFirstTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != xSecondTestBits ) + { + xErrorOccurred = pdTRUE; + } +} +/*-----------------------------------------------------------*/ + +static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ) +{ +BaseType_t xReturned; +UBaseType_t x; +const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 ); +TickType_t xTickCount; + + /* The binary semaphore should start 'empty', so a call to xSemaphoreTake() + should fail. */ + xTickCount = xTaskGetTickCount(); + xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); + + if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime ) + { + /* Did not block on the semaphore as long as expected. */ + xErrorOccurred = pdTRUE; + } + + if( xReturned != pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + + /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount + times. */ + for( x = 0; x < uxMaxCount; x++ ) + { + xReturned = xSemaphoreGive( xSemaphore ); + + if( xReturned == pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + } + + /* Giving the semaphore again should fail, as it is 'full'. */ + xReturned = xSemaphoreGive( xSemaphore ); + + if( xReturned != pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + + configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount ); + + /* Should now be possible to 'take' the semaphore up to a maximum of + uxMaxCount times without blocking. */ + for( x = 0; x < uxMaxCount; x++ ) + { + xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); + + if( xReturned == pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + } + + /* Back to the starting condition, where the semaphore should not be + available. */ + xTickCount = xTaskGetTickCount(); + xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); + + if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime ) + { + /* Did not block on the semaphore as long as expected. */ + xErrorOccurred = pdTRUE; + } + + if( xReturned != pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + + configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 ); +} +/*-----------------------------------------------------------*/ + +static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue ) +{ +uint64_t ull, ullRead; +BaseType_t xReturned, xLoop; + + /* This test is done twice to ensure the queue storage area wraps. */ + for( xLoop = 0; xLoop < 2; xLoop++ ) + { + /* A very basic test that the queue can be written to and read from as + expected. First the queue should be empty. */ + xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); + if( xReturned != errQUEUE_EMPTY ) + { + xErrorOccurred = pdTRUE; + } + + /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS + times. */ + for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) + { + xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + } + + /* Should not now be possible to write to the queue again. */ + xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); + if( xReturned != errQUEUE_FULL ) + { + xErrorOccurred = pdTRUE; + } + + /* Now read back from the queue to ensure the data read back matches that + written. */ + for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) + { + xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + if( ullRead != ull ) + { + xErrorOccurred = pdTRUE; + } + } + + /* The queue should be empty again. */ + xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); + if( xReturned != errQUEUE_EMPTY ) + { + xErrorOccurred = pdTRUE; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore ) +{ +const BaseType_t xLoops = 5; +BaseType_t x, xReturned; + + /* A very basic test that the recursive semaphore behaved like a recursive + semaphore. First the semaphore should not be able to be given, as it has not + yet been taken. */ + xReturned = xSemaphoreGiveRecursive( xSemaphore ); + + if( xReturned != pdFAIL ) + { + xErrorOccurred = pdTRUE; + } + + /* Now it should be possible to take the mutex a number of times. */ + for( x = 0; x < xLoops; x++ ) + { + xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + } + + /* Should be possible to give the semaphore the same number of times as it + was given in the loop above. */ + for( x = 0; x < xLoops; x++ ) + { + xReturned = xSemaphoreGiveRecursive( xSemaphore ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + } + + /* No more gives should be possible though. */ + xReturned = xSemaphoreGiveRecursive( xSemaphore ); + + if( xReturned != pdFAIL ) + { + xErrorOccurred = pdTRUE; + } +} +/*-----------------------------------------------------------*/ + BaseType_t xAreStaticAllocationTasksStillRunning( void ) { static UBaseType_t uxLastCycleCounter = 0; diff --git a/FreeRTOS/Demo/WIN32-MSVC-Static-Allocation-Only/main.c b/FreeRTOS/Demo/WIN32-MSVC-Static-Allocation-Only/main.c index c3a7d1be3..a14fa4165 100644 --- a/FreeRTOS/Demo/WIN32-MSVC-Static-Allocation-Only/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC-Static-Allocation-Only/main.c @@ -241,35 +241,52 @@ volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { -/* The buffers used by the idle task must be static so they are persistent, and -so exist after this function returns. */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ static StaticTask_t xIdleTaskTCB; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; - /* configSUPORT_STATIC_ALLOCATION is set to 1 and - configSUPPORT_DYNAMIC_ALLOCATION is 0, so the application must supply the - buffers that will be used to hold the Idle task data structure and stack. */ + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ *ppxIdleTaskStackBuffer = uxIdleTaskStack; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { -/* The buffers used by the Timer/Daemon task must be static so they are -persistent, and so exist after this function returns. */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ static StaticTask_t xTimerTaskTCB; static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; - /* configSUPPORT_STATIC_ALLOCATION is set to 1, - configSUPPORT_DYNAMIC_ALLOCATION is set to 1, and configUSE_TIMERS is set - to 1, so the application must supply the buffers that will be used to hold - the Timer task data structure and stack. */ + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ *ppxTimerTaskStackBuffer = uxTimerTaskStack; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 00f67d459..8b3fdf00b 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -329,7 +329,7 @@ volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0; ( void ) ulLine; ( void ) pcFileName; - printf( "ASSERT! Line %d, file %s\r\n", ulLine, pcFileName ); + printf( "ASSERT! Line %d, file %s, GetLastError() %d\r\n", ulLine, pcFileName, GetLastError() ); taskENTER_CRITICAL(); { @@ -410,38 +410,51 @@ const HeapRegion_t xHeapRegions[] = } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { -/* The buffers used by the idle task must be static so they are persistent, and -so exist after this function returns. */ +/* If the buffers to be provided to the Idle task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ static StaticTask_t xIdleTaskTCB; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Idle task as its - stack and to hold its TCB. If these are set to NULL then the buffers will - be allocated dynamically, just as if xTaskCreate() had been called. */ + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ *ppxIdleTaskStackBuffer = uxIdleTaskStack; - *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { -/* The buffers used by the Timer/Daemon task must be static so they are -persistent, and so exist after this function returns. The stack buffer is -not declared here, but globally, as it is checked by a test in a different -file. */ +/* If the buffers to be provided to the Timer task are declared inside this +function then they must be declared static - otherwise they will be allocated on +the stack and so not exists after this function exits. */ static StaticTask_t xTimerTaskTCB; - /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the - opportunity to supply the buffers that will be used by the Timer/RTOS daemon - task as its stack and to hold its TCB. If these are set to NULL then the - buffers will be allocated dynamically, just as if xTaskCreate() had been - called. */ + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ *ppxTimerTaskStackBuffer = uxTimerTaskStack; - *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pusTimerTaskStackSize = configMINIMAL_STACK_SIZE; } diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index a3e55221f..4ff7aa8d5 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -1616,7 +1616,7 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION #endif /* - * The registry is provided as a means for kernel aware debuggers to + * The queue registry is provided as a means for kernel aware debuggers to * locate queues, semaphores and mutexes. Call pcQueueGetQueueName() to look * up and return the name of a queue in the queue registry from the queue's * handle. diff --git a/FreeRTOS/Source/include/semphr.h b/FreeRTOS/Source/include/semphr.h index 29a0f98f5..eff0bfd30 100644 --- a/FreeRTOS/Source/include/semphr.h +++ b/FreeRTOS/Source/include/semphr.h @@ -1152,11 +1152,11 @@ typedef QueueHandle_t SemaphoreHandle_t; /** * semphr.h - *
TaskHandle_t xSemaphoreGetCount( SemaphoreHandle_t xMutex );
+ *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xMutex );
* - * If the semaphore is a counting semaphore then xSemaphoreGetCount() returns + * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns * its current count value. If the semaphore is a binary semaphore then - * xSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the + * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the * semaphore is not available. * */ -- 2.39.5