diff --git a/.github/scripts/check-header.py b/.github/scripts/check-header.py index a374112125..f7273bbbd5 100755 --- a/.github/scripts/check-header.py +++ b/.github/scripts/check-header.py @@ -369,7 +369,7 @@ FREERTOS_IGNORED_PATTERNS = [ FREERTOS_HEADER = [ '/*\n', - ' * FreeRTOS V202011.00\n', + ' * FreeRTOS V202012.00\n', ' * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n', ' *\n', ' * Permission is hereby granted, free of charge, to any person obtaining a copy of\n', diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h index a698bd9808..386c0492b7 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h @@ -38,48 +38,78 @@ * * See https://www.freertos.org/a00110.html *----------------------------------------------------------*/ - -#define configASSERT_DEFINED 1 + +#define configASSERT_DEFINED 1 extern void vAssertCalled( void ); #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( ) +#define configQUEUE_REGISTRY_SIZE 20 -#define configUSE_PREEMPTION 1 -#define configUSE_TIME_SLICING 1 +#define configUSE_PREEMPTION 1 +#define configUSE_TIME_SLICING 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 ) -#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) -#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 2000 ) -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 279000 ) ) -#define configMAX_TASK_NAME_LEN ( 10 ) -#define configUSE_TRACE_FACILITY 0 -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 0 -#define configUSE_CO_ROUTINES 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 1 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 2000 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 900 ) ) +#define configMAX_TASK_NAME_LEN ( 10 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 + +#define configMAX_PRIORITIES ( 10 ) +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configUSE_COUNTING_SEMAPHORES 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configNUM_TX_DESCRIPTORS 15 +#define configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN 2 -#define configMAX_PRIORITIES ( 10 ) -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) -#define configTIMER_QUEUE_LENGTH 20 -#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 3 ) -#define configUSE_COUNTING_SEMAPHORES 1 -#define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configNUM_TX_DESCRIPTORS 15 - /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ - -#define configUSE_MALLOC_FAILED_HOOK 1 -#define configUSE_MUTEXES 1 -#define configUSE_RECURSIVE_MUTEXES 1 -#define INCLUDE_vTaskPrioritySet 0 -#define INCLUDE_uxTaskPriorityGet 0 -#define INCLUDE_vTaskDelete 0 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskSuspend 0 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_TIMERS 1 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) +/* +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +*/ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskGetStackHighWaterMark2 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 + +unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ + +#define projCOVERAGE_TEST 0 #define configKERNEL_INTERRUPT_PRIORITY 255 /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile index 5d5660bba5..1acba387ee 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile @@ -24,10 +24,48 @@ INCLUDE_DIRS += -I$(FREERTOS_DIR)/Demo/CORTEX_M3_MPS2_QEMU_GCC/CMSIS INCLUDE_DIRS += -I$(KERNEL_DIR)/include INCLUDE_DIRS += -I$(KERNEL_DIR)/portable/GCC/ARM_CM3 -SOURCE_FILES += main_blinky.c -CFLAGS := -DmainCREATE_SIMPLE_BLINKY_DEMO_ONLY=1 +ifeq ($(FULL_DEMO), 1) + SOURCE_FILES += main_full.c + SOURCE_FILES += $(KERNEL_DIR)/stream_buffer.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/AbortDelay.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/BlockQ.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/blocktim.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/countsem.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/death.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/dynamic.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/EventGroupsDemo.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/flop.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/GenQTest.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/integer.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/IntSemTest.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/MessageBufferAMP.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/MessageBufferDemo.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/PollQ.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/QPeek.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/QueueOverwrite.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/QueueSet.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/QueueSetPolling.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/recmutex.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/semtest.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StaticAllocation.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StreamBufferDemo.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StreamBufferInterrupt.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/TaskNotify.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/TimerDemo.c + SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Full/print.c -DEFINES := -DprojCOVERAGE_TEST -DQEMU_SOC_MPS2 -DHEAP3 + INCLUDE_DIRS += -I$(FREERTOS_DIR)/Demo/Common/include + INCLUDE_DIRS += -I${FREERTOS_PLUS_DIR}/Source/FreeRTOS-Plus-Trace/Include/ + + CFLAGS := -DmainCREATE_FULL_DEMO_ONLY=1 +else + SOURCE_FILES += main_blinky.c + + CFLAGS := -DmainCREATE_SIMPLE_BLINKY_DEMO_ONLY=1 +endif + +#DEFINES := -DprojCOVERAGE_TEST -DQEMU_SOC_MPS2 -DHEAP3 +DEFINES := -DQEMU_SOC_MPS2 -DHEAP3 LDFLAGS = -T ./scripts/mps2_m3.ld -specs=nano.specs --specs=rdimon.specs -lc -lrdimon LDFLAGS += -Xlinker -Map=${BUILD_DIR}/output.map diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Readme.md b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Readme.md index ee1bc01a8e..4986f69e9a 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Readme.md +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Readme.md @@ -1,8 +1,8 @@ # Emulating MPS2 Cortex M3 AN385 on QEMU ## Requirements -1. GNU Arm Embedded Toolchain download [here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) -3. qemu-arm-system download [here](https://www.qemu.org/download) +1. GNU Arm Embedded Toolchain download [here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) (tested on versiom 9.3.1 20200408) +3. qemu-arm-system download [here](https://www.qemu.org/download) (tested on version 5.0.1 (v5.0.1-dirty)) 2. Make (tested on version 3.82) 4. Linux OS (tested on Ubuntu 18.04) @@ -36,9 +36,40 @@ $ sudo qemu-system-arm -machine mps2-an385 -monitor null -semihosting \ -serial stdio -nographic ``` ### Blinky Demo Expectations -after running the blinky demo you shoud see on the screen the word blinking +After running the blinky demo you shoud see on the screen the word blinking printed continuously +## Full Demo +### How to build blinky demo +Navigate with the command line to FreeRTOS/Demo/CORTEX\_M3\_MPS2\_QEMU\_GCC +For a release build run: + +``` +$ export PATH=/path/to/arm/toolchain:$PATH +$ make FULL_DEMO=1 +``` +For a versions with debugging symbols and no optimizations **-O0**, run: +``` +$ make FULL_DEMO=1 DEBUG=1 +``` + +### How to run the Full Demo +run: +``` +$ sudo qemu-system-arm -machine mps2-an385 -monitor null -semihosting \ + --semihosting-config enable=on,target=native \ + -kernel ./build/RTOSDemo.axf \ + -serial stdio -nographic +``` +### Full Demo Expectations +The full demo includes a ‘check’ that executes every (simulated) ten seconds, +but has the highest priority to ensure it gets processing time. Its main +function is to check all the standard demo tasks are still operational. The +check task maintains a status string that is output to the console each time +it executes. If all the standard demo tasks are running without error, then +the string contains “OK” and the current tick count. If an error has been +detected, then the string contains a message that indicates which task +reported the error. ## How to start debugging 1. gdb diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.c new file mode 100644 index 0000000000..dc7a8d3ef1 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.c @@ -0,0 +1,58 @@ +/* + * FreeRTOS V202012.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/*----------------------------------------------------------- + * Example console I/O wrappers. + *----------------------------------------------------------*/ + +#include +#include + +#include +#include + +SemaphoreHandle_t xStdioMutex; +StaticSemaphore_t xStdioMutexBuffer; + +void console_init(void) +{ + xStdioMutex = xSemaphoreCreateMutexStatic(&xStdioMutexBuffer); +} + +void console_print(const char *fmt, ...) +{ + va_list vargs; + + va_start(vargs, fmt); + + xSemaphoreTake(xStdioMutex, portMAX_DELAY); + + vprintf(fmt, vargs); + + xSemaphoreGive(xStdioMutex); + + va_end(vargs); +} diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.h b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.h new file mode 100644 index 0000000000..35223873b9 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/console.h @@ -0,0 +1,45 @@ +/* + * FreeRTOS V202012.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef CONSOLE_H +#define CONSOLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Example console I/O wrappers. + *----------------------------------------------------------*/ + +void console_init(void); +void console_print(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* CONSOLE_H */ diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c index 4be504c9ef..fe4c9cbdd6 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c @@ -37,16 +37,31 @@ void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); void vApplicationMallocFailedHook( void ); void vApplicationIdleHook( void ); void vApplicationTickHook( void ); +void vFullDemoIdleFunction( void ); +void vFullDemoTickHookFunction( void ); +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, + uint32_t *pulTimerTaskStackSize ); +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize ); void main_blinky( void ); +void main_full( void ); extern void initialise_monitor_handles(void); +StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + int main () { #if (mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1) { main_blinky(); } +#elif (mainCREATE_FULL_DEMO_ONLY == 1) + { + main_full(); + } #else { #error "Invalid Selection...\nPlease Select a Demo application from the main command" @@ -93,11 +108,23 @@ volatile size_t xFreeHeapSpace; management options. If there is a lot of heap memory free then the configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up RAM. */ +#if (mainCREATE_FULL_DEMO_ONLY == 1) + { + /* Call the idle task processing used by the full demo. The simple + blinky demo does not use the idle task hook. */ + vFullDemoIdleFunction(); + } +#endif } /*-----------------------------------------------------------*/ void vApplicationTickHook( void ) { +#if (mainSELECTED_APPLICATION == FULL_DEMO ) +{ + vFullDemoTickHookFunction(); +} +#endif /* mainSELECTED_APPLICATION */ } /*-----------------------------------------------------------*/ @@ -124,3 +151,52 @@ void vLoggingPrintf( const char *pcFormat, ... ) vprintf( pcFormat, arg ); va_end( arg ); } +/* 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, + uint32_t *pulIdleTaskStackSize ) +{ +/* 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. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/*-----------------------------------------------------------*/ +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, + uint32_t *pulTimerTaskStackSize ) +{ + /* 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; + + /* 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. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_full.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_full.c new file mode 100644 index 0000000000..d2110c2251 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main_full.c @@ -0,0 +1,905 @@ +/* + * FreeRTOS V202012.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* + ******************************************************************************* + * NOTE 1: The POSIX port is a simulation (or is that emulation?) only! Do not + * expect to get real time behaviour from the POSIX port or this demo + * application. It is provided as a convenient development and demonstration + * test bed only. + * + * Linux will not be running the FreeRTOS simulator threads continuously, so + * the timing information in the FreeRTOS+Trace logs have no meaningful units. + * See the documentation page for the Linux simulator for an explanation of + * the slow timing: + * https://freertos-wordpress.corp.amazon.com/FreeRTOS-simulator-for-Linux.html + * - READ THE WEB DOCUMENTATION FOR THIS PORT FOR MORE INFORMATION ON USING IT - + * + * NOTE 2: This project provides two demo applications. A simple blinky style + * project, and a more comprehensive test and demo application. The + * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main.c is used to select + * between the two. See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY + * in main.c. This file implements the comprehensive test and demo version. + * + * NOTE 3: This file only contains the source code that is specific to the + * full demo. Generic functions, such FreeRTOS hook functions, are defined in + * main.c. + ******************************************************************************* + * + * main() creates all the demo application tasks, then starts the scheduler. + * The web documentation provides more details of the standard demo application + * tasks, which provide no particular functionality but do provide a good + * example of how to use the FreeRTOS API. + * + * In addition to the standard demo tasks, the following tasks and tests are + * defined and/or created within this file: + * + * "Check" task - This only executes every five seconds but has a high priority + * to ensure it gets processor time. Its main function is to check that all the + * standard demo tasks are still operational. While no errors have been + * discovered the check task will print out "OK" and the current simulated tick + * time. If an error is discovered in the execution of a task then the check + * task will print out an appropriate error message. + * + */ + + +/* Standard includes. */ +#include +#include +#include +#include + +/* Kernel includes. */ +#include +#include +#include +#include +#include + +/* Standard demo includes. */ +#include "BlockQ.h" +#include "integer.h" +#include "semtest.h" +#include "PollQ.h" +#include "GenQTest.h" +#include "QPeek.h" +#include "recmutex.h" +#include "flop.h" +#include "TimerDemo.h" +#include "countsem.h" +#include "death.h" +#include "dynamic.h" +#include "QueueSet.h" +#include "QueueOverwrite.h" +#include "EventGroupsDemo.h" +#include "IntSemTest.h" +#include "TaskNotify.h" +#include "QueueSetPolling.h" +#include "StaticAllocation.h" +#include "blocktim.h" +#include "AbortDelay.h" +#include "MessageBufferDemo.h" +#include "StreamBufferDemo.h" +#include "StreamBufferInterrupt.h" +#include "MessageBufferAMP.h" +#include "console.h" + +/* Priorities at which the tasks are created. */ +#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) +#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) +#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainQUEUE_OVERWRITE_PRIORITY ( tskIDLE_PRIORITY ) + +#define mainTIMER_TEST_PERIOD ( 50 ) + +/* + * Exercises code that is not otherwise covered by the standard demo/test + * tasks. + */ +extern BaseType_t xRunCodeCoverageTestAdditions( void ); + +/* Task function prototypes. */ +static void prvCheckTask( void *pvParameters ); + +/* A task that is created from the idle task to test the functionality of +eTaskStateGet(). */ +static void prvTestTask( void *pvParameters ); + +/* + * Called from the idle task hook function to demonstrate a few utility + * functions that are not demonstrated by any of the standard demo tasks. + */ +static void prvDemonstrateTaskStateAndHandleGetFunctions( void ); + +/* + * Called from the idle task hook function to demonstrate the use of + * xTimerPendFunctionCall() as xTimerPendFunctionCall() is not demonstrated by + * any of the standard demo tasks. + */ +static void prvDemonstratePendingFunctionCall( void ); + +/* + * The function that is pended by prvDemonstratePendingFunctionCall(). + */ +static void prvPendedFunction( void *pvParameter1, uint32_t ulParameter2 ); + +/* + * prvDemonstrateTimerQueryFunctions() is called from the idle task hook + * function to demonstrate the use of functions that query information about a + * software timer. prvTestTimerCallback() is the callback function for the + * timer being queried. + */ +static void prvDemonstrateTimerQueryFunctions( void ); +static void prvTestTimerCallback( TimerHandle_t xTimer ); + +/* + * A task to demonstrate the use of the xQueueSpacesAvailable() function. + */ +static void prvDemoQueueSpaceFunctions( void *pvParameters ); + +/* + * Tasks that ensure indefinite delays are truly indefinite. + */ +static void prvPermanentlyBlockingSemaphoreTask( void *pvParameters ); +static void prvPermanentlyBlockingNotificationTask( void *pvParameters ); + +/* + * The test function and callback function used when exercising the timer AP + * function that changes the timer's auto-reload mode. + */ +static void prvDemonstrateChangingTimerReloadMode( void *pvParameters ); +static void prvReloadModeTestTimerCallback( TimerHandle_t xTimer ); + +/*-----------------------------------------------------------*/ + +/* The variable into which error messages are latched. */ +static char *pcStatusMessage = "OK: No errors"; + +/* This semaphore is created purely to test using the vSemaphoreDelete() and +semaphore tracing API functions. It has no other purpose. */ +static SemaphoreHandle_t xMutexToDelete = NULL; + +/*-----------------------------------------------------------*/ + +int main_full( void ) +{ + /* Start the check task as described at the top of this file. */ + xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL ); + + /* Create the standard demo tasks. */ + vStartTaskNotifyTask(); + // vStartTaskNotifyArrayTask(); + vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY ); + vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); + vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); + vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY ); + vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY ); + vStartQueuePeekTasks(); + vStartMathTasks( mainFLOP_TASK_PRIORITY ); + vStartRecursiveMutexTasks(); + vStartCountingSemaphoreTasks(); + vStartDynamicPriorityTasks(); + vStartQueueOverwriteTask( mainQUEUE_OVERWRITE_PRIORITY ); + vStartEventGroupTasks(); + vStartInterruptSemaphoreTasks(); + vCreateBlockTimeTasks(); + vCreateAbortDelayTasks(); + xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); + xTaskCreate( prvPermanentlyBlockingSemaphoreTask, "BlockSem", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); + xTaskCreate( prvPermanentlyBlockingNotificationTask, "BlockNoti", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); + + vStartMessageBufferTasks( configMINIMAL_STACK_SIZE ); + vStartStreamBufferTasks(); + vStartStreamBufferInterruptDemo(); + vStartMessageBufferAMPTasks( configMINIMAL_STACK_SIZE ); + + #if( configUSE_QUEUE_SETS == 1 ) + { + vStartQueueSetTasks(); + vStartQueueSetPollingTask(); + } + #endif + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + vStartStaticallyAllocatedTasks(); + } + #endif + + #if( configUSE_PREEMPTION != 0 ) + { + /* Don't expect these tasks to pass when preemption is not used. */ + vStartTimerDemoTask( mainTIMER_TEST_PERIOD ); + } + #endif + + /* The suicide tasks must be created last as they need to know how many + tasks were running prior to their creation. This then allows them to + ascertain whether or not the correct/expected number of tasks are running at + any given time. */ + vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY ); + + /* Create the semaphore that will be deleted in the idle task hook. This + is done purely to test the use of vSemaphoreDelete(). */ + xMutexToDelete = xSemaphoreCreateMutex(); + + /* Start the scheduler itself. */ + vTaskStartScheduler(); + + /* Should never get here unless there was not enough heap space to create + the idle and other system tasks. */ + return 0; +} +/*-----------------------------------------------------------*/ + +static void prvCheckTask( void *pvParameters ) +{ +TickType_t xNextWakeTime; +const TickType_t xCycleFrequency = pdMS_TO_TICKS( 10000UL ); +HeapStats_t xHeapStats; + + /* Just to remove compiler warning. */ + ( void ) pvParameters; + + /* Initialise xNextWakeTime - this only needs to be done once. */ + xNextWakeTime = xTaskGetTickCount(); + + for( ;; ) + { + /* Place this task in the blocked state until it is time to run again. */ + vTaskDelayUntil( &xNextWakeTime, xCycleFrequency ); + + /* Check the standard demo tasks are running without error. */ + #if( configUSE_PREEMPTION != 0 ) + { + /* These tasks are only created when preemption is used. */ + if( xAreTimerDemoTasksStillRunning( xCycleFrequency ) != pdTRUE ) + { + pcStatusMessage = "Error: TimerDemo"; + } + } + #endif + + if( xAreStreamBufferTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: StreamBuffer"; + } + else if( xAreMessageBufferTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: MessageBuffer"; + } + else if( xAreTaskNotificationTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: Notification"; + } + // else if( xAreTaskNotificationArrayTasksStillRunning() != pdTRUE ) + // { + // pcStatusMessage = "Error: NotificationArray"; + // } + else if( xAreInterruptSemaphoreTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: IntSem"; + } + else if( xAreEventGroupTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: EventGroup"; + } + else if( xAreIntegerMathsTaskStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: IntMath"; + } + else if( xAreGenericQueueTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: GenQueue"; + } + else if( xAreQueuePeekTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: QueuePeek"; + } + else if( xAreBlockingQueuesStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: BlockQueue"; + } + else if( xAreSemaphoreTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: SemTest"; + } + else if( xArePollingQueuesStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: PollQueue"; + } + else if( xAreMathsTaskStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Flop"; + } + else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: RecMutex"; + } + else if( xAreCountingSemaphoreTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: CountSem"; + } + else if( xIsCreateTaskStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: Death"; + } + else if( xAreDynamicPriorityTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Dynamic"; + } + else if( xIsQueueOverwriteTaskStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Queue overwrite"; + } + else if( xAreBlockTimeTestTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Block time"; + } + else if( xAreAbortDelayTestTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Abort delay"; + } + else if( xIsInterruptStreamBufferDemoStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Stream buffer interrupt"; + } + else if( xAreMessageBufferAMPTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Message buffer AMP"; + } + + #if( configUSE_QUEUE_SETS == 1 ) + else if( xAreQueueSetTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Queue set"; + } + else if( xAreQueueSetPollTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Queue set polling"; + } + #endif + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + else if( xAreStaticAllocationTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Static allocation"; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + printf( "%s - tick count %u \r\n", + pcStatusMessage, + xTaskGetTickCount() ); + + // Reset the error condition + pcStatusMessage = "OK: No errors"; + } +} +/*-----------------------------------------------------------*/ + +static void prvTestTask( void *pvParameters ) +{ +const unsigned long ulMSToSleep = 5; + + /* Just to remove compiler warnings. */ + ( void ) pvParameters; + + /* This task is just used to test the eTaskStateGet() function. It + does not have anything to do. */ + for( ;; ) + { + /* Sleep to reduce CPU load, but don't sleep indefinitely in case there are + tasks waiting to be terminated by the idle task. */ + vTaskDelay( pdMS_TO_TICKS( ulMSToSleep ) ); + } +} +/*-----------------------------------------------------------*/ + +/* Called from vApplicationIdleHook(), which is defined in main.c. */ +void vFullDemoIdleFunction( void ) +{ +const unsigned long ulMSToSleep = 15; +void *pvAllocated; + + /* Sleep to reduce CPU load, but don't sleep indefinitely in case there are + tasks waiting to be terminated by the idle task. */ + vTaskDelay( pdMS_TO_TICKS( ulMSToSleep ) ); + + /* Demonstrate a few utility functions that are not demonstrated by any of + the standard demo tasks. */ + prvDemonstrateTaskStateAndHandleGetFunctions(); + + /* Demonstrate the use of xTimerPendFunctionCall(), which is not + demonstrated by any of the standard demo tasks. */ + prvDemonstratePendingFunctionCall(); + + /* Demonstrate the use of functions that query information about a software + timer. */ + prvDemonstrateTimerQueryFunctions(); + + /* If xMutexToDelete has not already been deleted, then delete it now. + This is done purely to demonstrate the use of, and test, the + vSemaphoreDelete() macro. Care must be taken not to delete a semaphore + that has tasks blocked on it. */ + if( xMutexToDelete != NULL ) + { + /* For test purposes, add the mutex to the registry, then remove it + again, before it is deleted - checking its name is as expected before + and after the assertion into the registry and its removal from the + registry. */ + configASSERT( pcQueueGetName( xMutexToDelete ) == NULL ); + vQueueAddToRegistry( xMutexToDelete, "Test_Mutex" ); + configASSERT( strcmp( pcQueueGetName( xMutexToDelete ), "Test_Mutex" ) == 0 ); + vQueueUnregisterQueue( xMutexToDelete ); + configASSERT( pcQueueGetName( xMutexToDelete ) == NULL ); + + vSemaphoreDelete( xMutexToDelete ); + xMutexToDelete = NULL; + } + + /* Exercise heap_5 a bit. The malloc failed hook will trap failed + allocations so there is no need to test here. */ + pvAllocated = pvPortMalloc( ( rand() % 500 ) + 1 ); + vPortFree( pvAllocated ); + + /* Exit after a fixed time so code coverage results are written to the + disk. */ + #if( projCOVERAGE_TEST == 1 ) + { + const TickType_t xMaxRunTime = pdMS_TO_TICKS( 30000UL ); + + /* Exercise code not otherwise executed by standard demo/test tasks. */ + if( xRunCodeCoverageTestAdditions() != pdPASS ) + { + pcStatusMessage = "Code coverage additions failed.\r\n"; + } + + if( ( xTaskGetTickCount() - configINITIAL_TICK_COUNT ) >= xMaxRunTime ) + { + vTaskEndScheduler(); + } + } + #endif +} +/*-----------------------------------------------------------*/ + +/* Called by vApplicationTickHook(), which is defined in main.c. */ +void vFullDemoTickHookFunction( void ) +{ +TaskHandle_t xTimerTask; + + /* Call the periodic timer test, which tests the timer API functions that + can be called from an ISR. */ + #if( configUSE_PREEMPTION != 0 ) + { + /* Only created when preemption is used. */ + vTimerPeriodicISRTests(); + } + #endif + + /* Call the periodic queue overwrite from ISR demo. */ + vQueueOverwritePeriodicISRDemo(); + + #if( configUSE_QUEUE_SETS == 1 ) /* Remove the tests if queue sets are not defined. */ + { + /* Write to a queue that is in use as part of the queue set demo to + demonstrate using queue sets from an ISR. */ + vQueueSetAccessQueueSetFromISR(); + vQueueSetPollingInterruptAccess(); + } + #endif + + /* Exercise event groups from interrupts. */ + vPeriodicEventGroupsProcessing(); + + /* Exercise giving mutexes from an interrupt. */ + vInterruptSemaphorePeriodicTest(); + + /* Exercise using task notifications from an interrupt. */ + xNotifyTaskFromISR(); + // xNotifyArrayTaskFromISR(); + + /* Writes to stream buffer byte by byte to test the stream buffer trigger + level functionality. */ + vPeriodicStreamBufferProcessing(); + + /* Writes a string to a string buffer four bytes at a time to demonstrate + a stream being sent from an interrupt to a task. */ + vBasicStreamBufferSendFromISR(); + + /* For code coverage purposes. */ + xTimerTask = xTimerGetTimerDaemonTaskHandle(); + configASSERT( uxTaskPriorityGetFromISR( xTimerTask ) == configTIMER_TASK_PRIORITY ); +} +/*-----------------------------------------------------------*/ + +static void prvPendedFunction( void *pvParameter1, uint32_t ulParameter2 ) +{ +static intptr_t ulLastParameter1 = 1000UL, ulLastParameter2 = 0UL; +intptr_t ulParameter1; + + ulParameter1 = ( intptr_t ) pvParameter1; + + /* Ensure the parameters are as expected. */ + configASSERT( ulParameter1 == ( ulLastParameter1 + 1 ) ); + configASSERT( ulParameter2 == ( ulLastParameter2 + 1 ) ); + + /* Remember the parameters for the next time the function is called. */ + ulLastParameter1 = ulParameter1; + ulLastParameter2 = ulParameter2; + + /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulLastParameter1; + ( void ) ulLastParameter2; +} +/*-----------------------------------------------------------*/ + +static void prvTestTimerCallback( TimerHandle_t xTimer ) +{ + /* This is the callback function for the timer accessed by + prvDemonstrateTimerQueryFunctions(). The callback does not do anything. */ + ( void ) xTimer; +} +/*-----------------------------------------------------------*/ + +static void prvDemonstrateTimerQueryFunctions( void ) +{ +static TimerHandle_t xTimer = NULL; +const char *pcTimerName = "TestTimer"; +volatile TickType_t xExpiryTime; +const TickType_t xDontBlock = 0; + + if( xTimer == NULL ) + { + xTimer = xTimerCreate( pcTimerName, portMAX_DELAY, pdTRUE, NULL, prvTestTimerCallback ); + + if( xTimer != NULL ) + { + /* Called from the idle task so a block time must not be + specified. */ + xTimerStart( xTimer, xDontBlock ); + } + } + + if( xTimer != NULL ) + { + /* Demonstrate querying a timer's name. */ + configASSERT( strcmp( pcTimerGetName( xTimer ), pcTimerName ) == 0 ); + + /* Demonstrate querying a timer's period. */ + configASSERT( xTimerGetPeriod( xTimer ) == portMAX_DELAY ); + + /* Demonstrate querying a timer's next expiry time, although nothing is + done with the returned value. Note if the expiry time is less than the + maximum tick count then the expiry time has overflowed from the current + time. In this case the expiry time was set to portMAX_DELAY, so it is + expected to be less than the current time until the current time has + itself overflowed. */ + xExpiryTime = xTimerGetExpiryTime( xTimer ); + ( void ) xExpiryTime; + } +} +/*-----------------------------------------------------------*/ + +static void prvDemonstratePendingFunctionCall( void ) +{ +static intptr_t ulParameter1 = 1000UL, ulParameter2 = 0UL; +const TickType_t xDontBlock = 0; /* This is called from the idle task so must *not* attempt to block. */ + + /* prvPendedFunction() just expects the parameters to be incremented by one + each time it is called. */ + ulParameter1++; + ulParameter2++; + + /* Pend the function call, sending the parameters. */ + xTimerPendFunctionCall( prvPendedFunction, ( void * ) ulParameter1, ulParameter2, xDontBlock ); +} +/*-----------------------------------------------------------*/ + +static void prvDemonstrateTaskStateAndHandleGetFunctions( void ) +{ +TaskHandle_t xIdleTaskHandle, xTimerTaskHandle; +char *pcTaskName; +static portBASE_TYPE xPerformedOneShotTests = pdFALSE; +TaskHandle_t xTestTask; +TaskStatus_t xTaskInfo; +extern StackType_t uxTimerTaskStack[]; + + /* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and + xTaskGetIdleTaskHandle() functions. Also try using the function that sets + the task number. */ + xIdleTaskHandle = xTaskGetIdleTaskHandle(); + xTimerTaskHandle = xTimerGetTimerDaemonTaskHandle(); + + /* This is the idle hook, so the current task handle should equal the + returned idle task handle. */ + if( xTaskGetCurrentTaskHandle() != xIdleTaskHandle ) + { + pcStatusMessage = "Error: Returned idle task handle was incorrect"; + } + + /* Check the same handle is obtained using the idle task's name. First try + with the wrong name, then the right name. */ + if( xTaskGetHandle( "Idle" ) == xIdleTaskHandle ) + { + pcStatusMessage = "Error: Returned handle for name Idle was incorrect"; + } + + if( xTaskGetHandle( "IDLE" ) != xIdleTaskHandle ) + { + pcStatusMessage = "Error: Returned handle for name Idle was incorrect"; + } + + /* Check the timer task handle was returned correctly. */ + pcTaskName = pcTaskGetName( xTimerTaskHandle ); + if( strcmp( pcTaskName, "Tmr Svc" ) != 0 ) + { + pcStatusMessage = "Error: Returned timer task handle was incorrect"; + } + + if( xTaskGetHandle( "Tmr Svc" ) != xTimerTaskHandle ) + { + pcStatusMessage = "Error: Returned handle for name Tmr Svc was incorrect"; + } + + /* This task is running, make sure it's state is returned as running. */ + if( eTaskStateGet( xIdleTaskHandle ) != eRunning ) + { + pcStatusMessage = "Error: Returned idle task state was incorrect"; + } + + /* If this task is running, then the timer task must be blocked. */ + if( eTaskStateGet( xTimerTaskHandle ) != eBlocked ) + { + pcStatusMessage = "Error: Returned timer task state was incorrect"; + } + + /* Also with the vTaskGetInfo() function. */ + vTaskGetInfo( xTimerTaskHandle, /* The task being queried. */ + &xTaskInfo, /* The structure into which information on the task will be written. */ + pdTRUE, /* Include the task's high watermark in the structure. */ + eInvalid ); /* Include the task state in the structure. */ + + /* Check the information returned by vTaskGetInfo() is as expected. */ + if( ( xTaskInfo.eCurrentState != eBlocked ) || + ( strcmp( xTaskInfo.pcTaskName, "Tmr Svc" ) != 0 ) || + ( xTaskInfo.uxCurrentPriority != configTIMER_TASK_PRIORITY ) || + ( xTaskInfo.pxStackBase != uxTimerTaskStack ) || + ( xTaskInfo.xHandle != xTimerTaskHandle ) ) + { + pcStatusMessage = "Error: vTaskGetInfo() returned incorrect information about the timer task"; + } + + /* Other tests that should only be performed once follow. The test task + is not created on each iteration because to do so would cause the death + task to report an error (too many tasks running). */ + if( xPerformedOneShotTests == pdFALSE ) + { + /* Don't run this part of the test again. */ + xPerformedOneShotTests = pdTRUE; + + /* Create a test task to use to test other eTaskStateGet() return values. */ + if( xTaskCreate( prvTestTask, "Test", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTestTask ) == pdPASS ) + { + /* If this task is running, the test task must be in the ready state. */ + if( eTaskStateGet( xTestTask ) != eReady ) + { + pcStatusMessage = "Error: Returned test task state was incorrect 1"; + } + + /* Now suspend the test task and check its state is reported correctly. */ + vTaskSuspend( xTestTask ); + if( eTaskStateGet( xTestTask ) != eSuspended ) + { + pcStatusMessage = "Error: Returned test task state was incorrect 2"; + } + + /* Now delete the task and check its state is reported correctly. */ + vTaskDelete( xTestTask ); + if( eTaskStateGet( xTestTask ) != eDeleted ) + { + pcStatusMessage = "Error: Returned test task state was incorrect 3"; + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvDemoQueueSpaceFunctions( void *pvParameters ) +{ +QueueHandle_t xQueue = NULL; +const unsigned portBASE_TYPE uxQueueLength = 10; +unsigned portBASE_TYPE uxReturn, x; + + /* Remove compiler warnings. */ + ( void ) pvParameters; + + /* Create the queue that will be used. Nothing is actually going to be + sent or received so the queue item size is set to 0. */ + xQueue = xQueueCreate( uxQueueLength, 0 ); + configASSERT( xQueue ); + + for( ;; ) + { + for( x = 0; x < uxQueueLength; x++ ) + { + /* Ask how many messages are available... */ + uxReturn = uxQueueMessagesWaiting( xQueue ); + + /* Check the number of messages being reported as being available + is as expected, and force an assert if not. */ + if( uxReturn != x ) + { + /* xQueue cannot be NULL so this is deliberately causing an + assert to be triggered as there is an error. */ + configASSERT( xQueue == NULL ); + } + + /* Ask how many spaces remain in the queue... */ + uxReturn = uxQueueSpacesAvailable( xQueue ); + + /* Check the number of spaces being reported as being available + is as expected, and force an assert if not. */ + if( uxReturn != ( uxQueueLength - x ) ) + { + /* xQueue cannot be NULL so this is deliberately causing an + assert to be triggered as there is an error. */ + configASSERT( xQueue == NULL ); + } + + /* Fill one more space in the queue. */ + xQueueSendToBack( xQueue, NULL, 0 ); + } + + /* Perform the same check while the queue is full. */ + uxReturn = uxQueueMessagesWaiting( xQueue ); + if( uxReturn != uxQueueLength ) + { + configASSERT( xQueue == NULL ); + } + + uxReturn = uxQueueSpacesAvailable( xQueue ); + + if( uxReturn != 0 ) + { + configASSERT( xQueue == NULL ); + } + + /* The queue is full, start again. */ + xQueueReset( xQueue ); + + #if( configUSE_PREEMPTION == 0 ) + taskYIELD(); + #endif + } +} +/*-----------------------------------------------------------*/ + +static void prvPermanentlyBlockingSemaphoreTask( void *pvParameters ) +{ +SemaphoreHandle_t xSemaphore; + + /* Prevent compiler warning about unused parameter in the case that + configASSERT() is not defined. */ + ( void ) pvParameters; + + /* This task should block on a semaphore, and never return. */ + xSemaphore = xSemaphoreCreateBinary(); + configASSERT( xSemaphore ); + + xSemaphoreTake( xSemaphore, portMAX_DELAY ); + + /* The above xSemaphoreTake() call should never return, force an assert if + it does. */ + configASSERT( pvParameters != NULL ); + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvPermanentlyBlockingNotificationTask( void *pvParameters ) +{ + /* Prevent compiler warning about unused parameter in the case that + configASSERT() is not defined. */ + ( void ) pvParameters; + + /* This task should block on a task notification, and never return. */ + ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + /* The above ulTaskNotifyTake() call should never return, force an assert + if it does. */ + configASSERT( pvParameters != NULL ); + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvReloadModeTestTimerCallback( TimerHandle_t xTimer ) +{ +intptr_t ulTimerID; + + /* Increment the timer's ID to show the callback has executed. */ + ulTimerID = ( intptr_t ) pvTimerGetTimerID( xTimer ); + ulTimerID++; + vTimerSetTimerID( xTimer, ( void * ) ulTimerID ); +} +/*-----------------------------------------------------------*/ + +static void prvDemonstrateChangingTimerReloadMode( void *pvParameters ) +{ +TimerHandle_t xTimer; +const char * const pcTimerName = "TestTimer"; +const TickType_t x100ms = pdMS_TO_TICKS( 100UL ); + + /* Avoid compiler warnings about unused parameter. */ + ( void ) pvParameters; + + xTimer = xTimerCreate( pcTimerName, + x100ms, + pdFALSE, /* Created as a one-shot timer. */ + 0, + prvReloadModeTestTimerCallback ); + configASSERT( xTimer ); + configASSERT( xTimerIsTimerActive( xTimer ) == pdFALSE ); + configASSERT( xTimerGetTimerDaemonTaskHandle() != NULL ); + configASSERT( strcmp( pcTimerName, pcTimerGetName( xTimer ) ) == 0 ); + configASSERT( xTimerGetPeriod( xTimer ) == x100ms ); + + /* Timer was created as a one-shot timer. Its callback just increments the + timer's ID - so set the ID to 0, let the timer run for a number of timeout + periods, then check the timer has only executed once. */ + vTimerSetTimerID( xTimer, ( void * ) 0 ); + xTimerStart( xTimer, portMAX_DELAY ); + vTaskDelay( 3UL * x100ms ); + configASSERT( ( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) ) == 1UL ); + + /* Now change the timer to be an auto-reload timer and check it executes + the expected number of times. */ + vTimerSetReloadMode( xTimer, pdTRUE ); + vTimerSetTimerID( xTimer, ( void * ) 0 ); + xTimerStart( xTimer, 0 ); + vTaskDelay( ( 3UL * x100ms ) + ( x100ms / 2UL ) ); /* Three full periods. */ + configASSERT( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) == 3UL ); + configASSERT( xTimerStop( xTimer, 0 ) != pdFAIL ); + + /* Now change the timer back to be a one-shot timer and check it only + executes once. */ + vTimerSetReloadMode( xTimer, pdFALSE ); + vTimerSetTimerID( xTimer, ( void * ) 0 ); + xTimerStart( xTimer, 0 ); + vTaskDelay( 3UL * x100ms ); + configASSERT( xTimerStop( xTimer, 0 ) != pdFAIL ); + configASSERT( ( uintptr_t ) ( pvTimerGetTimerID( xTimer ) ) == 1UL ); + + /* Clean up at the end. */ + xTimerDelete( xTimer, portMAX_DELAY ); + vTaskDelete( NULL ); +} diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/scripts/mps2_m3.ld b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/scripts/mps2_m3.ld index 59d2ab19ad..2e7e5e68df 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/scripts/mps2_m3.ld +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/scripts/mps2_m3.ld @@ -31,7 +31,7 @@ MEMORY } ENTRY(Reset_Handler) -_Min_Heap_Size = 0x40000 ; /* Required amount of heap. */ +_Min_Heap_Size = 0x300000 ; /* Required amount of heap. */ _Min_Stack_Size = 0x4000 ; /* Required amount of stack. */ M_VECTOR_RAM_SIZE = (16 + 48) * 4; _estack = ORIGIN(RAM) + LENGTH(RAM); diff --git a/FreeRTOS/Demo/Common/Full/death.c b/FreeRTOS/Demo/Common/Full/death.c index d12891a2c5..691ab19cd7 100644 --- a/FreeRTOS/Demo/Common/Full/death.c +++ b/FreeRTOS/Demo/Common/Full/death.c @@ -19,10 +19,9 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS * - * 1 tab == 4 spaces! */ /** @@ -47,8 +46,8 @@ /* Changes from V2.0.0 - + Delay periods are now specified using variables and constants of - TickType_t rather than unsigned long. + + Delay periods are now specified using variables and constants of + TickType_t rather than unsigned long. */ #include @@ -61,7 +60,7 @@ Changes from V2.0.0 #include "death.h" #include "print.h" -#define deathSTACK_SIZE ( ( unsigned short ) 512 ) +#define deathSTACK_SIZE ( ( unsigned short ) 512 ) /* The task originally created which is responsible for periodically dynamically creating another four tasks. */ @@ -89,16 +88,16 @@ void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority ) { unsigned portBASE_TYPE *puxPriority; - /* Create the Creator tasks - passing in as a parameter the priority at which - the suicidal tasks should be created. */ - puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) ); - *puxPriority = uxPriority; + /* Create the Creator tasks - passing in as a parameter the priority at which + the suicidal tasks should be created. */ + puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) ); + *puxPriority = uxPriority; - xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL ); + xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL ); - /* Record the number of tasks that are running now so we know if any of the - suicidal tasks have failed to be killed. */ - uxTasksRunningAtStart = uxTaskGetNumberOfTasks(); + /* Record the number of tasks that are running now so we know if any of the + suicidal tasks have failed to be killed. */ + uxTasksRunningAtStart = uxTaskGetNumberOfTasks(); } /*-----------------------------------------------------------*/ @@ -108,36 +107,36 @@ portDOUBLE d1, d2; TaskHandle_t xTaskToKill; const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS; - if( pvParameters != NULL ) - { - /* This task is periodically created four times. Tow created tasks are - passed a handle to the other task so it can kill it before killing itself. - The other task is passed in null. */ - xTaskToKill = *( TaskHandle_t* )pvParameters; - } - else - { - xTaskToKill = NULL; - } + if( pvParameters != NULL ) + { + /* This task is periodically created four times. Tow created tasks are + passed a handle to the other task so it can kill it before killing itself. + The other task is passed in null. */ + xTaskToKill = *( TaskHandle_t* )pvParameters; + } + else + { + xTaskToKill = NULL; + } - for( ;; ) - { - /* Do something random just to use some stack and registers. */ - d1 = 2.4; - d2 = 89.2; - d2 *= d1; - vTaskDelay( xDelay ); + for( ;; ) + { + /* Do something random just to use some stack and registers. */ + d1 = 2.4; + d2 = 89.2; + d2 *= d1; + vTaskDelay( xDelay ); - if( xTaskToKill != NULL ) - { - /* Make sure the other task has a go before we delete it. */ - vTaskDelay( ( TickType_t ) 0 ); - /* Kill the other task that was created by vCreateTasks(). */ - vTaskDelete( xTaskToKill ); - /* Kill ourselves. */ - vTaskDelete( NULL ); - } - } + if( xTaskToKill != NULL ) + { + /* Make sure the other task has a go before we delete it. */ + vTaskDelay( ( TickType_t ) 0 ); + /* Kill the other task that was created by vCreateTasks(). */ + vTaskDelete( xTaskToKill ); + /* Kill ourselves. */ + vTaskDelete( NULL ); + } + } }/*lint !e818 !e550 Function prototype must be as per standard for task functions. */ /*-----------------------------------------------------------*/ @@ -147,25 +146,25 @@ const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS; unsigned portBASE_TYPE uxPriority; const char * const pcTaskStartMsg = "Create task started.\r\n"; - /* Queue a message for printing to say the task has started. */ - vPrintDisplayMessage( &pcTaskStartMsg ); + /* Queue a message for printing to say the task has started. */ + vPrintDisplayMessage( &pcTaskStartMsg ); - uxPriority = *( unsigned portBASE_TYPE * ) pvParameters; - vPortFree( pvParameters ); + uxPriority = *( unsigned portBASE_TYPE * ) pvParameters; + vPortFree( pvParameters ); - for( ;; ) - { - /* Just loop round, delaying then creating the four suicidal tasks. */ - vTaskDelay( xDelay ); + for( ;; ) + { + /* Just loop round, delaying then creating the four suicidal tasks. */ + vTaskDelay( xDelay ); - xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 ); - xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL ); + xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 ); + xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL ); - xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 ); - xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL ); + xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 ); + xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL ); - ++sCreationCount; - } + ++sCreationCount; + } } /*-----------------------------------------------------------*/ @@ -177,27 +176,28 @@ static short sLastCreationCount = 0; short sReturn = pdTRUE; unsigned portBASE_TYPE uxTasksRunningNow; - if( sLastCreationCount == sCreationCount ) - { - sReturn = pdFALSE; - } - - uxTasksRunningNow = uxTaskGetNumberOfTasks(); + if( sLastCreationCount == sCreationCount ) + { + sReturn = pdFALSE; + } + sLastCreationCount = sCreationCount; - if( uxTasksRunningNow < uxTasksRunningAtStart ) - { - sReturn = pdFALSE; - } - else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning ) - { - sReturn = pdFALSE; - } - else - { - /* Everything is okay. */ - } + uxTasksRunningNow = uxTaskGetNumberOfTasks(); - return sReturn; + if( uxTasksRunningNow < uxTasksRunningAtStart ) + { + sReturn = pdFALSE; + } + else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning ) + { + sReturn = pdFALSE; + } + else + { + /* Everything is okay. */ + } + + return sReturn; }