initial
This commit is contained in:
commit
b7ab42dd94
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
SOFTWARE/build
|
||||
SOFTWARE-FreeRTOS/build
|
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
[submodule "SOFTWARE/Lib/pico-onewire"]
|
||||
path = SOFTWARE/Lib/pico-onewire
|
||||
url = https://github.com/adamboardman/pico-onewire.git
|
||||
[submodule "SOFTWARE/Server/libconf"]
|
||||
path = SOFTWARE/Server/libconf
|
||||
url = https://git.aixiao.me/aixiao/libconf.git
|
||||
[submodule "SOFTWARE-FreeRTOS/FreeRTOS-Kernel"]
|
||||
path = SOFTWARE-FreeRTOS/FreeRTOS-Kernel
|
||||
url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git
|
Binary file not shown.
BIN
HARDWARE/DOC/DS18B20.pdf
Normal file
BIN
HARDWARE/DOC/DS18B20.pdf
Normal file
Binary file not shown.
BIN
HARDWARE/DOC/HC-12 english datasheets.pdf
Normal file
BIN
HARDWARE/DOC/HC-12 english datasheets.pdf
Normal file
Binary file not shown.
BIN
HARDWARE/DOC/ZC05.pdf
Normal file
BIN
HARDWARE/DOC/ZC05.pdf
Normal file
Binary file not shown.
BIN
HARDWARE/DOC/ZC13.pdf
Normal file
BIN
HARDWARE/DOC/ZC13.pdf
Normal file
Binary file not shown.
BIN
HARDWARE/DOC/ZE07-CO.pdf
Normal file
BIN
HARDWARE/DOC/ZE07-CO.pdf
Normal file
Binary file not shown.
BIN
HARDWARE/IMG/db.jpg
Normal file
BIN
HARDWARE/IMG/db.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
HARDWARE/IMG/display.png
Normal file
BIN
HARDWARE/IMG/display.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
BIN
HARDWARE/ProProject_Danger-alarm_2024-03-21.epro
Normal file
BIN
HARDWARE/ProProject_Danger-alarm_2024-03-21.epro
Normal file
Binary file not shown.
45
README.md
Normal file
45
README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# 基于 Raspberry Pico / Pico W 的厨房危险(火灾)报警 (Pico W WiFi传输暂时不玩)
|
||||
* 使用 DS18B20温度传感器
|
||||
* 使用 CH4 N55A甲烷气体传感器(进口) (弃用)
|
||||
* 使用 PASCO2V01 CO2二氧化碳传感器模块(进口模块暂时买不到!)
|
||||
* 使用 MH-Z14B CO2二氧化碳传感器模块(国产)(0 - 5000ppm)
|
||||
* 使用 ZE07-CO CO一氧化碳传感器模块(国产)
|
||||
* 使用 HC-12 433MHZ传感器模块(国产)
|
||||
* 使用 ZC05/ZC13 可燃气体(天然气 CH4)传感器模块(国产)
|
||||
|
||||
## Build
|
||||
```
|
||||
# 使用WSL Debian GNU/Linux 12 (bookworm) 构建
|
||||
# 确保Pico-SDK环境变量
|
||||
export PICO_SDK_PATH=/mnt/c/Users/niuyuling/Desktop/raspberry-pico/SDK/pico-sdk
|
||||
export PICO_EXTRAS_PATH=/mnt/c/Users/niuyuling/Desktop/raspberry-pico/SDK/pico-extras
|
||||
|
||||
apt install cmake gcc-arm-none-eabi gcc g++
|
||||
apt install gdb-multiarch automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev
|
||||
|
||||
git clone https://git.aixiao.me/aixiao/Danger-alarm.git
|
||||
cd Danger-alarm
|
||||
git submodule init
|
||||
git submodule update
|
||||
mkdir -p SOFTWARE/build
|
||||
cd SOFTWARE/build
|
||||
#cmake ..
|
||||
cmake -DPICO_BOARD=pico_w ..
|
||||
make
|
||||
|
||||
|
||||
# 树莓派Zero W 433MHZ HC-12接收服务端构建
|
||||
apt install libmysqlclient-dev
|
||||
cd ~
|
||||
git clone https://github.com/WiringPi/WiringPi.git
|
||||
cd WiringPi
|
||||
./build
|
||||
cd ~/Danger-alarm/SOFTWARE/Server/hc-12
|
||||
make clean; make
|
||||
./hc-12
|
||||
|
||||
```
|
||||
## display
|
||||
![brief](HARDWARE/IMG/db.jpg)
|
||||
![brief](HARDWARE/IMG/display.png)
|
||||
|
79
SOFTWARE-FreeRTOS/CMakeLists.txt
Normal file
79
SOFTWARE-FreeRTOS/CMakeLists.txt
Normal file
@ -0,0 +1,79 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
# Check if the environment variable PICO_SDK_PATH is set
|
||||
if(DEFINED ENV{PICO_SDK_PATH})
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
else()
|
||||
message(FATAL_ERROR "Environment variable PICO_SDK_PATH is not set. Please set it to the path of the pico-sdk.")
|
||||
endif()
|
||||
|
||||
# Include the Pico SDK
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
# Pull in FreeRTOS
|
||||
set( FREERTOS_KERNEL_PATH "../FreeRTOS-Kernel" )
|
||||
include(FreeRTOS_Kernel_import.cmake)
|
||||
|
||||
project(main CXX C ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
|
||||
add_subdirectory(
|
||||
../SOFTWARE/Lib/pico-onewire
|
||||
${CMAKE_BINARY_DIR}/pico-onewire
|
||||
)
|
||||
|
||||
|
||||
add_executable(
|
||||
main
|
||||
)
|
||||
|
||||
pico_generate_pio_header(main ${CMAKE_CURRENT_LIST_DIR}/Source/uart_tx.pio)
|
||||
pico_generate_pio_header(main ${CMAKE_CURRENT_LIST_DIR}/Source/uart_rx.pio)
|
||||
|
||||
target_Sources(main PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/Source/common.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/Source/main.c
|
||||
|
||||
)
|
||||
|
||||
target_include_directories(main PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/Source
|
||||
${CMAKE_CURRENT_LIST_DIR}/Common/include
|
||||
)
|
||||
|
||||
target_compile_options(main PUBLIC
|
||||
### Gnu/Clang C Options
|
||||
$<$<COMPILE_LANG_AND_ID:C,GNU>:-fdiagnostics-color=always>
|
||||
$<$<COMPILE_LANG_AND_ID:C,Clang>:-fcolor-diagnostics>
|
||||
|
||||
$<$<COMPILE_LANG_AND_ID:C,Clang,GNU>:-Wall>
|
||||
$<$<COMPILE_LANG_AND_ID:C,Clang,GNU>:-Wextra>
|
||||
#$<$<COMPILE_LANG_AND_ID:C,Clang,GNU>:-Werror>
|
||||
$<$<COMPILE_LANG_AND_ID:C,Clang>:-Weverything>
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
main
|
||||
pico_one_wire
|
||||
FreeRTOS-Kernel
|
||||
FreeRTOS-Kernel-Heap4
|
||||
pico_stdlib
|
||||
pico_util
|
||||
pico_runtime
|
||||
pico_multicore
|
||||
hardware_rtc
|
||||
hardware_i2c
|
||||
hardware_uart
|
||||
hardware_pwm
|
||||
hardware_adc
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
pico_enable_stdio_uart(main 1)
|
||||
pico_enable_stdio_usb(main 1)
|
||||
pico_add_extra_outputs(main)
|
347
SOFTWARE-FreeRTOS/Common/ARMv8M/mpu_demo/mpu_demo.c
Normal file
347
SOFTWARE-FreeRTOS/Common/ARMv8M/mpu_demo/mpu_demo.c
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/**
|
||||
* @brief Size of the shared memory region.
|
||||
*/
|
||||
#define SHARED_MEMORY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief Memory region shared between two tasks.
|
||||
*/
|
||||
static uint8_t ucSharedMemory[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
#if ( configTOTAL_MPU_REGIONS == 16 )
|
||||
static uint8_t ucSharedMemory1[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory2[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory3[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory4[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory5[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory6[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory7[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static uint8_t ucSharedMemory8[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
||||
|
||||
/**
|
||||
* @brief Memory region used to track Memory Fault intentionally caused by the
|
||||
* RO Access task.
|
||||
*
|
||||
* RO Access task sets ucROTaskFaultTracker[ 0 ] to 1 before accessing illegal
|
||||
* memory. Illegal memory access causes Memory Fault and the fault handler
|
||||
* checks ucROTaskFaultTracker[ 0 ] to see if this is an expected fault. We
|
||||
* recover gracefully from an expected fault by jumping to the next instruction.
|
||||
*
|
||||
* @note We are declaring a region of 32 bytes even though we need only one. The
|
||||
* reason is that the size of an MPU region must be a multiple of 32 bytes.
|
||||
*/
|
||||
static volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) ) = { 0 };
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Implements the task which has Read Only access to the memory region
|
||||
* ucSharedMemory.
|
||||
*
|
||||
* @param pvParameters[in] Parameters as passed during task creation.
|
||||
*/
|
||||
static void prvROAccessTask( void * pvParameters );
|
||||
|
||||
/**
|
||||
* @brief Implements the task which has Read Write access to the memory region
|
||||
* ucSharedMemory.
|
||||
*
|
||||
* @param pvParameters[in] Parameters as passed during task creation.
|
||||
*/
|
||||
static void prvRWAccessTask( void * pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvROAccessTask( void * pvParameters )
|
||||
{
|
||||
uint8_t ucVal;
|
||||
|
||||
/* Unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This task performs the following sequence for all the shared memory
|
||||
* regions:
|
||||
*
|
||||
* 1. Perfrom a read access to the shared memory. Since this task has
|
||||
* RO access to the shared memory, the read operation is successful.
|
||||
*
|
||||
* 2. Set ucROTaskFaultTracker[ 0 ] to 1 before performing a write to
|
||||
* the shared memory. Since this task has Read Only access to the
|
||||
* shared memory, the write operation would result in a Memory Fault.
|
||||
* Setting ucROTaskFaultTracker[ 0 ] to 1 tells the Memory Fault
|
||||
* Handler that this is an expected fault. The handler recovers from
|
||||
* the expected fault gracefully by jumping to the next instruction.
|
||||
*
|
||||
* 3. Perfrom a write to the shared memory resulting in a memory fault.
|
||||
*
|
||||
* 4. Ensure that the write access did generate MemFault and the fault
|
||||
* handler did clear the ucROTaskFaultTracker[ 0 ].
|
||||
*/
|
||||
/* Perform the above mentioned sequence on ucSharedMemory. */
|
||||
ucVal = ucSharedMemory[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
#if ( configTOTAL_MPU_REGIONS == 16 )
|
||||
{
|
||||
/* Perform the above mentioned sequence on ucSharedMemory1. */
|
||||
ucVal = ucSharedMemory1[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory1[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory2. */
|
||||
ucVal = ucSharedMemory2[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory2[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory3. */
|
||||
ucVal = ucSharedMemory3[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory3[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory4. */
|
||||
ucVal = ucSharedMemory4[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory4[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory5. */
|
||||
ucVal = ucSharedMemory5[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory5[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory6. */
|
||||
ucVal = ucSharedMemory6[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory6[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory7. */
|
||||
ucVal = ucSharedMemory7[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory7[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
|
||||
/* Perform the above mentioned sequence on ucSharedMemory8. */
|
||||
ucVal = ucSharedMemory8[ 0 ];
|
||||
/* Silent compiler warnings about unused variables. */
|
||||
( void ) ucVal;
|
||||
ucROTaskFaultTracker[ 0 ] = 1;
|
||||
ucSharedMemory8[ 0 ] = 0;
|
||||
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
||||
}
|
||||
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
||||
|
||||
/* Wait for a second. */
|
||||
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRWAccessTask( void * pvParameters )
|
||||
{
|
||||
/* Unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This task has RW access to ucSharedMemory and therefore can write to
|
||||
* it. */
|
||||
ucSharedMemory[ 0 ] = 0;
|
||||
|
||||
#if ( configTOTAL_MPU_REGIONS == 16 )
|
||||
{
|
||||
ucSharedMemory1[ 0 ] = 0;
|
||||
ucSharedMemory2[ 0 ] = 0;
|
||||
ucSharedMemory3[ 0 ] = 0;
|
||||
ucSharedMemory4[ 0 ] = 0;
|
||||
ucSharedMemory5[ 0 ] = 0;
|
||||
ucSharedMemory6[ 0 ] = 0;
|
||||
ucSharedMemory7[ 0 ] = 0;
|
||||
ucSharedMemory8[ 0 ] = 0;
|
||||
}
|
||||
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
||||
|
||||
/* Wait for a second. */
|
||||
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMPUDemo( void )
|
||||
{
|
||||
static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
TaskParameters_t xROAccessTaskParameters =
|
||||
{
|
||||
.pvTaskCode = prvROAccessTask,
|
||||
.pcName = "ROAccess",
|
||||
.usStackDepth = configMINIMAL_STACK_SIZE,
|
||||
.pvParameters = NULL,
|
||||
.uxPriority = tskIDLE_PRIORITY,
|
||||
.puxStackBuffer = xROAccessTaskStack,
|
||||
.xRegions =
|
||||
{
|
||||
{ ( void * ) ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
#if ( configTOTAL_MPU_REGIONS == 16 )
|
||||
{ ( void * ) ucSharedMemory1, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory2, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory3, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory4, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory5, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory6, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory7, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory8, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
||||
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
||||
{ ( void * ) ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ 0, 0, 0 },
|
||||
}
|
||||
};
|
||||
TaskParameters_t xRWAccessTaskParameters =
|
||||
{
|
||||
.pvTaskCode = prvRWAccessTask,
|
||||
.pcName = "RWAccess",
|
||||
.usStackDepth = configMINIMAL_STACK_SIZE,
|
||||
.pvParameters = NULL,
|
||||
.uxPriority = tskIDLE_PRIORITY,
|
||||
.puxStackBuffer = xRWAccessTaskStack,
|
||||
.xRegions =
|
||||
{
|
||||
{ ( void * ) ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
#if ( configTOTAL_MPU_REGIONS == 16 )
|
||||
{ ( void * ) ucSharedMemory1, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory2, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory3, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory4, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory5, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory6, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory7, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ ( void * ) ucSharedMemory8, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
/* Create an unprivileged task with RO access to ucSharedMemory. */
|
||||
xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );
|
||||
|
||||
/* Create an unprivileged task with RW access to ucSharedMemory. */
|
||||
xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )
|
||||
{
|
||||
uint32_t ulPC;
|
||||
uint16_t usOffendingInstruction;
|
||||
|
||||
/* Is this an expected fault? */
|
||||
if( ucROTaskFaultTracker[ 0 ] == 1 )
|
||||
{
|
||||
/* Read program counter. */
|
||||
ulPC = pulFaultStackAddress[ 6 ];
|
||||
|
||||
/* Read the offending instruction. */
|
||||
usOffendingInstruction = *( uint16_t * ) ulPC;
|
||||
|
||||
/* From ARM docs:
|
||||
* If the value of bits[15:11] of the halfword being decoded is one of
|
||||
* the following, the halfword is the first halfword of a 32-bit
|
||||
* instruction:
|
||||
* - 0b11101.
|
||||
* - 0b11110.
|
||||
* - 0b11111.
|
||||
* Otherwise, the halfword is a 16-bit instruction.
|
||||
*/
|
||||
|
||||
/* Extract bits[15:11] of the offending instruction. */
|
||||
usOffendingInstruction = usOffendingInstruction & 0xF800;
|
||||
usOffendingInstruction = ( usOffendingInstruction >> 11 );
|
||||
|
||||
/* Determine if the offending instruction is a 32-bit instruction or
|
||||
* a 16-bit instruction. */
|
||||
if( ( usOffendingInstruction == 0x001F ) ||
|
||||
( usOffendingInstruction == 0x001E ) ||
|
||||
( usOffendingInstruction == 0x001D ) )
|
||||
{
|
||||
/* Since the offending instruction is a 32-bit instruction,
|
||||
* increment the program counter by 4 to move to the next
|
||||
* instruction. */
|
||||
ulPC += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since the offending instruction is a 16-bit instruction,
|
||||
* increment the program counter by 2 to move to the next
|
||||
* instruction. */
|
||||
ulPC += 2;
|
||||
}
|
||||
|
||||
/* Save the new program counter on the stack. */
|
||||
pulFaultStackAddress[ 6 ] = ulPC;
|
||||
|
||||
/* Mark the fault as handled. */
|
||||
ucROTaskFaultTracker[ 0 ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an unexpected fault - loop forever. */
|
||||
for( ; ; )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
44
SOFTWARE-FreeRTOS/Common/ARMv8M/mpu_demo/mpu_demo.h
Normal file
44
SOFTWARE-FreeRTOS/Common/ARMv8M/mpu_demo/mpu_demo.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 __MPU_DEMO_H__
|
||||
#define __MPU_DEMO_H__
|
||||
|
||||
/**
|
||||
* @brief Creates all the tasks for MPU demo.
|
||||
*
|
||||
* The MPU demo creates 2 unprivileged tasks - One of which has Read Only access
|
||||
* to a shared memory region while the other has Read Write access. The task
|
||||
* with Read Only access then tries to write to the shared memory which results
|
||||
* in a Memory fault. The fault handler examines that it is the fault generated
|
||||
* by the task with Read Only access and if so, it recovers from the fault
|
||||
* gracefully by moving the Program Counter to the next instruction to the one
|
||||
* which generated the fault. If any other memory access violation occurs, the
|
||||
* fault handler will get stuck in an infinite loop.
|
||||
*/
|
||||
void vStartMPUDemo( void );
|
||||
|
||||
#endif /* __MPU_DEMO_H__ */
|
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* "Reg tests" - These tests fill the registers with known values, then check
|
||||
* that each register maintains its expected value for the lifetime of the
|
||||
* task. Each task uses a different set of values. The reg test tasks execute
|
||||
* with a very low priority, so get preempted very frequently. A register
|
||||
* containing an unexpected value is indicative of an error in the context
|
||||
* switching mechanism.
|
||||
*/
|
||||
|
||||
#include "reg_test_asm.h"
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vRegTest1Asm_NonSecure( void ) /* __attribute__(( naked )) */
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
".extern ulRegTest1LoopCounter \n"
|
||||
".syntax unified \n"
|
||||
" \n"
|
||||
" /* Fill the core registers with known values. */ \n"
|
||||
" movs r1, #101 \n"
|
||||
" movs r2, #102 \n"
|
||||
" movs r3, #103 \n"
|
||||
" movs r4, #104 \n"
|
||||
" movs r5, #105 \n"
|
||||
" movs r6, #106 \n"
|
||||
" movs r7, #107 \n"
|
||||
" movs r0, #108 \n"
|
||||
" mov r8, r0 \n"
|
||||
" movs r0, #109 \n"
|
||||
" mov r9, r0 \n"
|
||||
" movs r0, #110 \n"
|
||||
" mov r10, r0 \n"
|
||||
" movs r0, #111 \n"
|
||||
" mov r11, r0 \n"
|
||||
" movs r0, #112 \n"
|
||||
" mov r12, r0 \n"
|
||||
" movs r0, #100 \n"
|
||||
" \n"
|
||||
"reg1_loop: \n"
|
||||
" \n"
|
||||
" /* Verify that core registers contain correct values. */ \n"
|
||||
" cmp r0, #100 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r1, #101 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r2, #102 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r3, #103 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r4, #104 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r5, #105 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r6, #106 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" cmp r7, #107 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" movs r0, #108 \n"
|
||||
" cmp r8, r0 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" movs r0, #109 \n"
|
||||
" cmp r9, r0 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" movs r0, #110 \n"
|
||||
" cmp r10, r0 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" movs r0, #111 \n"
|
||||
" cmp r11, r0 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" movs r0, #112 \n"
|
||||
" cmp r12, r0 \n"
|
||||
" bne reg1_error_loop \n"
|
||||
" \n"
|
||||
" /* Everything passed, inc the loop counter. */ \n"
|
||||
" push { r1 } \n"
|
||||
" ldr r0, =ulRegTest1LoopCounter \n"
|
||||
" ldr r1, [r0] \n"
|
||||
" adds r1, r1, #1 \n"
|
||||
" str r1, [r0] \n"
|
||||
" \n"
|
||||
" /* Yield to increase test coverage. */ \n"
|
||||
" movs r0, #0x01 \n"
|
||||
" ldr r1, =0xe000ed04 \n" /* NVIC_ICSR. */
|
||||
" lsls r0, #28 \n" /* Shift to PendSV bit. */
|
||||
" str r0, [r1] \n"
|
||||
" dsb \n"
|
||||
" pop { r1 } \n"
|
||||
" \n"
|
||||
" /* Start again. */ \n"
|
||||
" movs r0, #100 \n"
|
||||
" b reg1_loop \n"
|
||||
" \n"
|
||||
"reg1_error_loop: \n"
|
||||
" /* If this line is hit then there was an error in \n"
|
||||
" * a core register value. The loop ensures the \n"
|
||||
" * loop counter stops incrementing. */ \n"
|
||||
" b reg1_error_loop \n"
|
||||
" nop \n"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vRegTest2Asm_NonSecure( void ) /* __attribute__(( naked )) */
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
".extern ulRegTest2LoopCounter \n"
|
||||
".syntax unified \n"
|
||||
" \n"
|
||||
" /* Fill the core registers with known values. */ \n"
|
||||
" movs r1, #1 \n"
|
||||
" movs r2, #2 \n"
|
||||
" movs r3, #3 \n"
|
||||
" movs r4, #4 \n"
|
||||
" movs r5, #5 \n"
|
||||
" movs r6, #6 \n"
|
||||
" movs r7, #7 \n"
|
||||
" movs r0, #8 \n"
|
||||
" mov r8, r0 \n"
|
||||
" movs r0, #9 \n"
|
||||
" mov r9, r0 \n"
|
||||
" movs r0, #10 \n"
|
||||
" mov r10, r0 \n"
|
||||
" movs r0, #11 \n"
|
||||
" mov r11, r0 \n"
|
||||
" movs r0, #12 \n"
|
||||
" mov r12, r0 \n"
|
||||
" movs r0, #10 \n"
|
||||
" \n"
|
||||
"reg2_loop: \n"
|
||||
" \n"
|
||||
" /* Verify that core registers contain correct values. */ \n"
|
||||
" cmp r0, #10 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r1, #1 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r2, #2 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r3, #3 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r4, #4 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r5, #5 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r6, #6 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" cmp r7, #7 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" movs r0, #8 \n"
|
||||
" cmp r8, r0 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" movs r0, #9 \n"
|
||||
" cmp r9, r0 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" movs r0, #10 \n"
|
||||
" cmp r10, r0 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" movs r0, #11 \n"
|
||||
" cmp r11, r0 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" movs r0, #12 \n"
|
||||
" cmp r12, r0 \n"
|
||||
" bne reg2_error_loop \n"
|
||||
" \n"
|
||||
" /* Everything passed, inc the loop counter. */ \n"
|
||||
" push { r1 } \n"
|
||||
" ldr r0, =ulRegTest2LoopCounter \n"
|
||||
" ldr r1, [r0] \n"
|
||||
" adds r1, r1, #1 \n"
|
||||
" str r1, [r0] \n"
|
||||
" pop { r1 } \n"
|
||||
" \n"
|
||||
" /* Start again. */ \n"
|
||||
" movs r0, #10 \n"
|
||||
" b reg2_loop \n"
|
||||
" \n"
|
||||
"reg2_error_loop: \n"
|
||||
" /* If this line is hit then there was an error in \n"
|
||||
" * a core register value. The loop ensures the \n"
|
||||
" * loop counter stops incrementing. */ \n"
|
||||
" b reg2_error_loop \n"
|
||||
" nop \n"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vRegTestAsm_NonSecureCallback( void )
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
".syntax unified \n"
|
||||
" \n"
|
||||
" /* Store callee saved registers. */ \n"
|
||||
" push { r4-r7 } \n"
|
||||
" mov r0, r8 \n"
|
||||
" mov r1, r9 \n"
|
||||
" mov r2, r10 \n"
|
||||
" mov r3, r11 \n"
|
||||
" mov r4, r12 \n"
|
||||
" push { r0-r4 } \n"
|
||||
" \n"
|
||||
" /* Fill the core registers with known values. */ \n"
|
||||
" movs r1, #151 \n"
|
||||
" movs r2, #152 \n"
|
||||
" movs r3, #153 \n"
|
||||
" movs r4, #154 \n"
|
||||
" movs r5, #155 \n"
|
||||
" movs r6, #156 \n"
|
||||
" movs r7, #157 \n"
|
||||
" movs r0, #158 \n"
|
||||
" mov r8, r0 \n"
|
||||
" movs r0, #159 \n"
|
||||
" mov r9, r0 \n"
|
||||
" movs r0, #160 \n"
|
||||
" mov r10, r0 \n"
|
||||
" movs r0, #161 \n"
|
||||
" mov r11, r0 \n"
|
||||
" movs r0, #162 \n"
|
||||
" mov r12, r0 \n"
|
||||
" movs r0, #150 \n"
|
||||
" \n"
|
||||
" /* Force a context switch by pending non-secure sv. */ \n"
|
||||
" push { r0, r1 } \n"
|
||||
" movs r0, #0x01 \n"
|
||||
" ldr r1, =0xe000ed04 \n" /* NVIC_ICSR. */
|
||||
" lsls r0, #28 \n" /* Shift to PendSV bit. */
|
||||
" str r0, [r1] \n"
|
||||
" dsb \n"
|
||||
" pop { r0, r1 } \n"
|
||||
" \n"
|
||||
" /* Verify that core registers contain correct values. */ \n"
|
||||
" cmp r0, #150 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r1, #151 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r2, #152 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r3, #153 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r4, #154 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r5, #155 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r6, #156 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" cmp r7, #157 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" movs r0, #158 \n"
|
||||
" cmp r8, r0 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" movs r0, #159 \n"
|
||||
" cmp r9, r0 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" movs r0, #160 \n"
|
||||
" cmp r10, r0 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" movs r0, #161 \n"
|
||||
" cmp r11, r0 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" movs r0, #162 \n"
|
||||
" cmp r12, r0 \n"
|
||||
" bne reg_nscb_error_loop \n"
|
||||
" \n"
|
||||
" /* Everything passed, finish. */ \n"
|
||||
" b reg_nscb_success \n"
|
||||
" \n"
|
||||
"reg_nscb_error_loop : \n"
|
||||
" /* If this line is hit then there was an error in \n"
|
||||
" * a core register value. The loop ensures the \n"
|
||||
" * loop counter stops incrementing. */ \n"
|
||||
" b reg_nscb_error_loop \n"
|
||||
" nop \n"
|
||||
" \n"
|
||||
"reg_nscb_success: \n"
|
||||
" /* Restore callee saved registers. */ \n"
|
||||
" pop { r0-r4 } \n"
|
||||
" mov r8, r0 \n"
|
||||
" mov r9, r1 \n"
|
||||
" mov r10, r2 \n"
|
||||
" mov r11, r3 \n"
|
||||
" mov r12, r4 \n"
|
||||
" pop { r4-r7 } \n"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 REG_TEST_ASM_H
|
||||
#define REG_TEST_ASM_H
|
||||
|
||||
/**
|
||||
* @brief Functions that implement reg tests in assembly.
|
||||
*
|
||||
* These are called from the FreeRTOS tasks on the non-secure side.
|
||||
*/
|
||||
void vRegTest1Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest2Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests in assembly.
|
||||
*
|
||||
* This is passed as function pointer to the secure side and called
|
||||
* from the secure side.
|
||||
*/
|
||||
void vRegTestAsm_NonSecureCallback( void );
|
||||
|
||||
#endif /* REG_TEST_ASM_H */
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <arm_cmse.h>
|
||||
|
||||
/* Interface includes. */
|
||||
#include "secure_reg_test_asm.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "secure_port_macros.h"
|
||||
|
||||
/* typedef for non-secure callback function. */
|
||||
typedef RegTestCallback_t NonSecureRegTestCallback_t __attribute__( ( cmse_nonsecure_call ) );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTestAsm_Secure( void )
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
".syntax unified \n"
|
||||
" \n"
|
||||
" /* Store callee saved registers. */ \n"
|
||||
" push { r4-r7 } \n"
|
||||
" mov r0, r8 \n"
|
||||
" mov r1, r9 \n"
|
||||
" mov r2, r10 \n"
|
||||
" mov r3, r11 \n"
|
||||
" mov r4, r12 \n"
|
||||
" push { r0-r4 } \n"
|
||||
" \n"
|
||||
" /* Fill the core registers with known values. */ \n"
|
||||
" movs r1, #201 \n"
|
||||
" movs r2, #202 \n"
|
||||
" movs r3, #203 \n"
|
||||
" movs r4, #204 \n"
|
||||
" movs r5, #205 \n"
|
||||
" movs r6, #206 \n"
|
||||
" movs r7, #207 \n"
|
||||
" movs r0, #208 \n"
|
||||
" mov r8, r0 \n"
|
||||
" movs r0, #209 \n"
|
||||
" mov r9, r0 \n"
|
||||
" movs r0, #210 \n"
|
||||
" mov r10, r0 \n"
|
||||
" movs r0, #211 \n"
|
||||
" mov r11, r0 \n"
|
||||
" movs r0, #212 \n"
|
||||
" mov r12, r0 \n"
|
||||
" movs r0, #200 \n"
|
||||
" \n"
|
||||
" /* Force a context switch by pending non-secure sv. */ \n"
|
||||
" push { r0, r1 } \n"
|
||||
" movs r0, #0x01 \n"
|
||||
" ldr r1, =0xe002ed04 \n" /* NVIC_ICSR_NS. */
|
||||
" lsls r0, #28 \n" /* Shift to PendSV bit. */
|
||||
" str r0, [r1] \n"
|
||||
" dsb \n"
|
||||
" pop { r0, r1 } \n"
|
||||
" \n"
|
||||
" /* Verify that core registers contain correct values. */ \n"
|
||||
" cmp r0, #200 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r1, #201 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r2, #202 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r3, #203 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r4, #204 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r5, #205 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r6, #206 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r7, #207 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" movs r0, #208 \n"
|
||||
" cmp r8, r0 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" movs r0, #209 \n"
|
||||
" cmp r9, r0 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" movs r0, #210 \n"
|
||||
" cmp r10, r0 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" movs r0, #211 \n"
|
||||
" cmp r11, r0 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" movs r0, #212 \n"
|
||||
" cmp r12, r0 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" \n"
|
||||
" /* Everything passed, finish. */ \n"
|
||||
" b secure_reg_test_success \n"
|
||||
" \n"
|
||||
"secure_reg_test_error_loop: \n"
|
||||
" /* If this line is hit then there was an error in \n"
|
||||
" * a core register value. The loop ensures the \n"
|
||||
" * loop counter stops incrementing. */ \n"
|
||||
" b secure_reg_test_error_loop \n"
|
||||
" nop \n"
|
||||
" \n"
|
||||
"secure_reg_test_success: \n"
|
||||
" /* Restore callee saved registers. */ \n"
|
||||
" pop { r0-r4 } \n"
|
||||
" mov r8, r0 \n"
|
||||
" mov r9, r1 \n"
|
||||
" mov r10, r2 \n"
|
||||
" mov r11, r3 \n"
|
||||
" mov r12, r4 \n"
|
||||
" pop { r4-r7 } \n"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback )
|
||||
{
|
||||
NonSecureRegTestCallback_t pxNonSecureRegTestCallback;
|
||||
|
||||
/* Return function pointer with cleared LSB. */
|
||||
pxNonSecureRegTestCallback = ( NonSecureRegTestCallback_t ) cmse_nsfptr_create( pxRegTestCallback );
|
||||
|
||||
/* Invoke the callback which runs reg tests. */
|
||||
pxNonSecureRegTestCallback();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 SECURE_REG_TEST_ASM_H
|
||||
#define SECURE_REG_TEST_ASM_H
|
||||
|
||||
/* Callback function pointer definition. */
|
||||
typedef void ( * RegTestCallback_t )( void );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests for the secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side.
|
||||
*/
|
||||
void vRegTestAsm_Secure( void );
|
||||
|
||||
/**
|
||||
* @brief Invokes the supplied reg test callback on the non-secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side..
|
||||
*/
|
||||
void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback );
|
||||
|
||||
#endif /* SECURE_REG_TEST_ASM_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 REG_TEST_ASM_H
|
||||
#define REG_TEST_ASM_H
|
||||
|
||||
/**
|
||||
* @brief Functions that implement reg tests in assembly.
|
||||
*
|
||||
* These are called from the FreeRTOS tasks on the non-secure side.
|
||||
*/
|
||||
void vRegTest1Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest2Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest3Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest4Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests in assembly.
|
||||
*
|
||||
* This is passed as function pointer to the secure side and called
|
||||
* from the secure side.
|
||||
*/
|
||||
void vRegTestAsm_NonSecureCallback( void );
|
||||
|
||||
#endif /* REG_TEST_ASM_H */
|
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <arm_cmse.h>
|
||||
|
||||
/* Interface includes. */
|
||||
#include "secure_reg_test_asm.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "secure_port_macros.h"
|
||||
|
||||
/* typedef for non-secure callback function. */
|
||||
typedef RegTestCallback_t NonSecureRegTestCallback_t __attribute__( ( cmse_nonsecure_call ) );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTestAsm_Secure( void )
|
||||
{
|
||||
__asm volatile
|
||||
(
|
||||
".syntax unified \n"
|
||||
" \n"
|
||||
" /* Store callee saved registers. */ \n"
|
||||
" push { r4-r12 } \n"
|
||||
" \n"
|
||||
" /* Fill the core registers with known values. */ \n"
|
||||
" movs r0, #200 \n"
|
||||
" movs r1, #201 \n"
|
||||
" movs r1, #201 \n"
|
||||
" movs r2, #202 \n"
|
||||
" movs r3, #203 \n"
|
||||
" movs r4, #204 \n"
|
||||
" movs r5, #205 \n"
|
||||
" movs r6, #206 \n"
|
||||
" movs r7, #207 \n"
|
||||
" movs r8, #208 \n"
|
||||
" movs r9, #209 \n"
|
||||
" movs r10, #210 \n"
|
||||
" movs r11, #211 \n"
|
||||
" movs r12, #212 \n"
|
||||
" \n"
|
||||
" /* Fill the FPU registers with known values. */ \n"
|
||||
" vmov.f32 s0, #1.0 \n"
|
||||
" vmov.f32 s2, #2.0 \n"
|
||||
" vmov.f32 s3, #3.5 \n"
|
||||
" vmov.f32 s4, #4.5 \n"
|
||||
" vmov.f32 s5, #5.0 \n"
|
||||
" vmov.f32 s6, #6.0 \n"
|
||||
" vmov.f32 s7, #7.5 \n"
|
||||
" vmov.f32 s8, #8.5 \n"
|
||||
" vmov.f32 s9, #9.0 \n"
|
||||
" vmov.f32 s10, #10.0 \n"
|
||||
" vmov.f32 s11, #11.5 \n"
|
||||
" vmov.f32 s12, #12.5 \n"
|
||||
" vmov.f32 s13, #13.0 \n"
|
||||
" vmov.f32 s14, #14.0 \n"
|
||||
" vmov.f32 s15, #1.5 \n"
|
||||
" vmov.f32 s16, #2.5 \n"
|
||||
" vmov.f32 s17, #3.0 \n"
|
||||
" vmov.f32 s18, #4.0 \n"
|
||||
" vmov.f32 s19, #5.5 \n"
|
||||
" vmov.f32 s20, #6.5 \n"
|
||||
" vmov.f32 s21, #7.0 \n"
|
||||
" vmov.f32 s22, #8.0 \n"
|
||||
" vmov.f32 s23, #9.5 \n"
|
||||
" vmov.f32 s24, #10.5 \n"
|
||||
" vmov.f32 s25, #11.0 \n"
|
||||
" vmov.f32 s26, #12.0 \n"
|
||||
" vmov.f32 s27, #13.5 \n"
|
||||
" vmov.f32 s28, #14.5 \n"
|
||||
" vmov.f32 s29, #1.0 \n"
|
||||
" vmov.f32 s30, #2.0 \n"
|
||||
" vmov.f32 s31, #3.5 \n"
|
||||
" \n"
|
||||
" /* Force a context switch by pending non-secure sv. */ \n"
|
||||
" push { r0, r1 } \n"
|
||||
" movs r0, #0x01 \n"
|
||||
" ldr r1, =0xe002ed04 \n" /* NVIC_ICSR_NS. */
|
||||
" lsls r0, #28 \n" /* Shift to PendSV bit. */
|
||||
" str r0, [r1] \n"
|
||||
" dsb \n"
|
||||
" pop { r0, r1 } \n"
|
||||
" \n"
|
||||
" /* Verify that core registers contain correct values. */ \n"
|
||||
" cmp r0, #200 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r1, #201 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r2, #202 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r3, #203 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r4, #204 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r5, #205 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r6, #206 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r7, #207 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r8, #208 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r9, #209 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r10, #210 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r11, #211 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" cmp r12, #212 \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" \n"
|
||||
" /* Verify that FPU registers contain correct values. */ \n"
|
||||
" vmov.f32 s1, #1.0 \n"
|
||||
" vcmp.f32 s0, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #2.0 \n"
|
||||
" vcmp.f32 s2, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #3.5 \n"
|
||||
" vcmp.f32 s3, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #4.5 \n"
|
||||
" vcmp.f32 s4, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #5.0 \n"
|
||||
" vcmp.f32 s5, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #6.0 \n"
|
||||
" vcmp.f32 s6, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #7.5 \n"
|
||||
" vcmp.f32 s7, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #8.5 \n"
|
||||
" vcmp.f32 s8, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #9.0 \n"
|
||||
" vcmp.f32 s9, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #10.0 \n"
|
||||
" vcmp.f32 s10, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #11.5 \n"
|
||||
" vcmp.f32 s11, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #12.5 \n"
|
||||
" vcmp.f32 s12, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #13.0 \n"
|
||||
" vcmp.f32 s13, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #14.0 \n"
|
||||
" vcmp.f32 s14, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #1.5 \n"
|
||||
" vcmp.f32 s15, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #2.5 \n"
|
||||
" vcmp.f32 s16, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #3.0 \n"
|
||||
" vcmp.f32 s17, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #4.0 \n"
|
||||
" vcmp.f32 s18, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #5.5 \n"
|
||||
" vcmp.f32 s19, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #6.5 \n"
|
||||
" vcmp.f32 s20, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #7.0 \n"
|
||||
" vcmp.f32 s21, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #8.0 \n"
|
||||
" vcmp.f32 s22, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #9.5 \n"
|
||||
" vcmp.f32 s23, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #10.5 \n"
|
||||
" vcmp.f32 s24, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #11.0 \n"
|
||||
" vcmp.f32 s25, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #12.0 \n"
|
||||
" vcmp.f32 s26, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #13.5 \n"
|
||||
" vcmp.f32 s27, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #14.5 \n"
|
||||
" vcmp.f32 s28, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #1.0 \n"
|
||||
" vcmp.f32 s29, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #2.0 \n"
|
||||
" vcmp.f32 s30, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" vmov.f32 s1, #3.5 \n"
|
||||
" vcmp.f32 s31, s1 \n"
|
||||
" vmrs APSR_nzcv, FPSCR \n"
|
||||
" bne secure_reg_test_error_loop \n"
|
||||
" \n"
|
||||
" /* Everything passed, finish. */ \n"
|
||||
" b secure_reg_test_success \n"
|
||||
" \n"
|
||||
"secure_reg_test_error_loop: \n"
|
||||
" /* If this line is hit then there was an error in \n"
|
||||
" * a core register value. The loop ensures the \n"
|
||||
" * loop counter stops incrementing. */ \n"
|
||||
" b secure_reg_test_error_loop \n"
|
||||
" nop \n"
|
||||
" \n"
|
||||
"secure_reg_test_success: \n"
|
||||
" /* Restore callee saved registers. */ \n"
|
||||
" pop { r4-r12 } \n"
|
||||
);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback )
|
||||
{
|
||||
NonSecureRegTestCallback_t pxNonSecureRegTestCallback;
|
||||
|
||||
/* Return function pointer with cleared LSB. */
|
||||
pxNonSecureRegTestCallback = ( NonSecureRegTestCallback_t ) cmse_nsfptr_create( pxRegTestCallback );
|
||||
|
||||
/* Invoke the callback which runs reg tests. */
|
||||
pxNonSecureRegTestCallback();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 SECURE_REG_TEST_ASM_H
|
||||
#define SECURE_REG_TEST_ASM_H
|
||||
|
||||
/* Callback function pointer definition. */
|
||||
typedef void ( * RegTestCallback_t )( void );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests for the secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side.
|
||||
*/
|
||||
void vRegTestAsm_Secure( void );
|
||||
|
||||
/**
|
||||
* @brief Invokes the supplied reg test callback on the non-secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side..
|
||||
*/
|
||||
void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback );
|
||||
|
||||
#endif /* SECURE_REG_TEST_ASM_H */
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 REG_TEST_ASM_H
|
||||
#define REG_TEST_ASM_H
|
||||
|
||||
/**
|
||||
* @brief Functions that implement reg tests in assembly.
|
||||
*
|
||||
* These are called from the FreeRTOS tasks on the non-secure side.
|
||||
*/
|
||||
void vRegTest1Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest2Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests in assembly.
|
||||
*
|
||||
* This is passed as function pointer to the secure side and called
|
||||
* from the secure side.
|
||||
*/
|
||||
void vRegTestAsm_NonSecureCallback( void );
|
||||
|
||||
#endif /* REG_TEST_ASM_H */
|
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* "Reg tests" - These tests fill the registers with known values, then check
|
||||
* that each register maintains its expected value for the lifetime of the
|
||||
* task. Each task uses a different set of values. The reg test tasks execute
|
||||
* with a very low priority, so get preempted very frequently. A register
|
||||
* containing an unexpected value is indicative of an error in the context
|
||||
* switching mechanism.
|
||||
*/
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
THUMB
|
||||
|
||||
EXTERN ulRegTest1LoopCounter
|
||||
EXTERN ulRegTest2LoopCounter
|
||||
|
||||
PUBLIC vRegTest1Asm_NonSecure
|
||||
PUBLIC vRegTest2Asm_NonSecure
|
||||
PUBLIC vRegTestAsm_NonSecureCallback
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
vRegTest1Asm_NonSecure:
|
||||
/* Fill the core registers with known values. */
|
||||
movs r1, #101
|
||||
movs r2, #102
|
||||
movs r3, #103
|
||||
movs r4, #104
|
||||
movs r5, #105
|
||||
movs r6, #106
|
||||
movs r7, #107
|
||||
movs r0, #108
|
||||
mov r8, r0
|
||||
movs r0, #109
|
||||
mov r9, r0
|
||||
movs r0, #110
|
||||
mov r10, r0
|
||||
movs r0, #111
|
||||
mov r11, r0
|
||||
movs r0, #112
|
||||
mov r12, r0
|
||||
movs r0, #100
|
||||
|
||||
reg1_loop:
|
||||
/* Verify that core registers contain correct values. */
|
||||
cmp r0, #100
|
||||
bne reg1_error_loop
|
||||
cmp r1, #101
|
||||
bne reg1_error_loop
|
||||
cmp r2, #102
|
||||
bne reg1_error_loop
|
||||
cmp r3, #103
|
||||
bne reg1_error_loop
|
||||
cmp r4, #104
|
||||
bne reg1_error_loop
|
||||
cmp r5, #105
|
||||
bne reg1_error_loop
|
||||
cmp r6, #106
|
||||
bne reg1_error_loop
|
||||
cmp r7, #107
|
||||
bne reg1_error_loop
|
||||
movs r0, #108
|
||||
cmp r8, r0
|
||||
bne reg1_error_loop
|
||||
movs r0, #109
|
||||
cmp r9, r0
|
||||
bne reg1_error_loop
|
||||
movs r0, #110
|
||||
cmp r10, r0
|
||||
bne reg1_error_loop
|
||||
movs r0, #111
|
||||
cmp r11, r0
|
||||
bne reg1_error_loop
|
||||
movs r0, #112
|
||||
cmp r12, r0
|
||||
bne reg1_error_loop
|
||||
|
||||
/* Everything passed, inc the loop counter. */
|
||||
push { r1 }
|
||||
ldr r0, =ulRegTest1LoopCounter
|
||||
ldr r1, [r0]
|
||||
adds r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/* Yield to increase test coverage. */
|
||||
movs r0, #0x01
|
||||
ldr r1, =0xe000ed04 /* NVIC_ICSR. */
|
||||
lsls r0, r0, #28 /* Shift to PendSV bit. */
|
||||
str r0, [r1]
|
||||
dsb
|
||||
pop { r1 }
|
||||
|
||||
/* Start again. */
|
||||
movs r0, #100
|
||||
b reg1_loop
|
||||
|
||||
reg1_error_loop:
|
||||
/* If this line is hit then there was an error in
|
||||
* a core register value. The loop ensures the
|
||||
* loop counter stops incrementing. */
|
||||
b reg1_error_loop
|
||||
nop
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
vRegTest2Asm_NonSecure:
|
||||
/* Fill the core registers with known values. */
|
||||
movs r1, #1
|
||||
movs r2, #2
|
||||
movs r3, #3
|
||||
movs r4, #4
|
||||
movs r5, #5
|
||||
movs r6, #6
|
||||
movs r7, #7
|
||||
movs r0, #8
|
||||
mov r8, r0
|
||||
movs r0, #9
|
||||
mov r9, r0
|
||||
movs r0, #10
|
||||
mov r10, r0
|
||||
movs r0, #11
|
||||
mov r11, r0
|
||||
movs r0, #12
|
||||
mov r12, r0
|
||||
movs r0, #10
|
||||
|
||||
reg2_loop:
|
||||
/* Verify that core registers contain correct values. */
|
||||
cmp r0, #10
|
||||
bne reg2_error_loop
|
||||
cmp r1, #1
|
||||
bne reg2_error_loop
|
||||
cmp r2, #2
|
||||
bne reg2_error_loop
|
||||
cmp r3, #3
|
||||
bne reg2_error_loop
|
||||
cmp r4, #4
|
||||
bne reg2_error_loop
|
||||
cmp r5, #5
|
||||
bne reg2_error_loop
|
||||
cmp r6, #6
|
||||
bne reg2_error_loop
|
||||
cmp r7, #7
|
||||
bne reg2_error_loop
|
||||
movs r0, #8
|
||||
cmp r8, r0
|
||||
bne reg2_error_loop
|
||||
movs r0, #9
|
||||
cmp r9, r0
|
||||
bne reg2_error_loop
|
||||
movs r0, #10
|
||||
cmp r10, r0
|
||||
bne reg2_error_loop
|
||||
movs r0, #11
|
||||
cmp r11, r0
|
||||
bne reg2_error_loop
|
||||
movs r0, #12
|
||||
cmp r12, r0
|
||||
bne reg2_error_loop
|
||||
|
||||
/* Everything passed, inc the loop counter. */
|
||||
push { r1 }
|
||||
ldr r0, =ulRegTest2LoopCounter
|
||||
ldr r1, [r0]
|
||||
adds r1, r1, #1
|
||||
str r1, [r0]
|
||||
pop { r1 }
|
||||
|
||||
/* Start again. */
|
||||
movs r0, #10
|
||||
b reg2_loop
|
||||
|
||||
reg2_error_loop:
|
||||
/* If this line is hit then there was an error in
|
||||
* a core register value. The loop ensures the
|
||||
* loop counter stops incrementing. */
|
||||
b reg2_error_loop
|
||||
nop
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
vRegTestAsm_NonSecureCallback:
|
||||
/* Store callee saved registers. */
|
||||
push { r4-r7 }
|
||||
mov r0, r8
|
||||
mov r1, r9
|
||||
mov r2, r10
|
||||
mov r3, r11
|
||||
mov r4, r12
|
||||
push { r0-r4 }
|
||||
|
||||
/* Fill the core registers with known values. */
|
||||
movs r1, #151
|
||||
movs r2, #152
|
||||
movs r3, #153
|
||||
movs r4, #154
|
||||
movs r5, #155
|
||||
movs r6, #156
|
||||
movs r7, #157
|
||||
movs r0, #158
|
||||
mov r8, r0
|
||||
movs r0, #159
|
||||
mov r9, r0
|
||||
movs r0, #160
|
||||
mov r10, r0
|
||||
movs r0, #161
|
||||
mov r11, r0
|
||||
movs r0, #162
|
||||
mov r12, r0
|
||||
movs r0, #150
|
||||
|
||||
/* Force a context switch by pending non-secure sv. */
|
||||
push { r0, r1 }
|
||||
movs r0, #0x01
|
||||
ldr r1, =0xe000ed04 /* NVIC_ICSR. */
|
||||
lsls r0, r0, #28 /* Shift to PendSV bit. */
|
||||
str r0, [r1]
|
||||
dsb
|
||||
pop { r0, r1 }
|
||||
|
||||
/* Verify that core registers contain correct values. */
|
||||
cmp r0, #150
|
||||
bne reg_nscb_error_loop
|
||||
cmp r1, #151
|
||||
bne reg_nscb_error_loop
|
||||
cmp r2, #152
|
||||
bne reg_nscb_error_loop
|
||||
cmp r3, #153
|
||||
bne reg_nscb_error_loop
|
||||
cmp r4, #154
|
||||
bne reg_nscb_error_loop
|
||||
cmp r5, #155
|
||||
bne reg_nscb_error_loop
|
||||
cmp r6, #156
|
||||
bne reg_nscb_error_loop
|
||||
cmp r7, #157
|
||||
bne reg_nscb_error_loop
|
||||
movs r0, #158
|
||||
cmp r8, r0
|
||||
bne reg_nscb_error_loop
|
||||
movs r0, #159
|
||||
cmp r9, r0
|
||||
bne reg_nscb_error_loop
|
||||
movs r0, #160
|
||||
cmp r10, r0
|
||||
bne reg_nscb_error_loop
|
||||
movs r0, #161
|
||||
cmp r11, r0
|
||||
bne reg_nscb_error_loop
|
||||
movs r0, #162
|
||||
cmp r12, r0
|
||||
bne reg_nscb_error_loop
|
||||
|
||||
/* Everything passed, finish. */
|
||||
b reg_nscb_success
|
||||
|
||||
reg_nscb_error_loop:
|
||||
/* If this line is hit then there was an error in
|
||||
* a core register value. The loop ensures the
|
||||
* loop counter stops incrementing. */
|
||||
b reg_nscb_error_loop
|
||||
nop
|
||||
|
||||
reg_nscb_success:
|
||||
/* Restore callee saved registers. */
|
||||
pop { r0-r4 }
|
||||
mov r8, r0
|
||||
mov r9, r1
|
||||
mov r10, r2
|
||||
mov r11, r3
|
||||
mov r12, r4
|
||||
pop { r4-r7 }
|
||||
bx lr
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
END
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <arm_cmse.h>
|
||||
|
||||
/* Interface includes. */
|
||||
#include "secure_reg_test_asm.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "secure_port_macros.h"
|
||||
|
||||
/* Implemented in assembly. */
|
||||
extern void vRegTestAsm_SecureImpl( void );
|
||||
|
||||
/* typedef for non-secure callback function. */
|
||||
typedef __cmse_nonsecure_call void ( * NonSecureRegTestCallback_t ) ( void );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTestAsm_Secure( void )
|
||||
{
|
||||
/* Call the function implemented in assembly. */
|
||||
vRegTestAsm_SecureImpl();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback )
|
||||
{
|
||||
NonSecureRegTestCallback_t pxNonSecureRegTestCallback;
|
||||
|
||||
/* Return function pointer with cleared LSB. */
|
||||
pxNonSecureRegTestCallback = ( NonSecureRegTestCallback_t ) cmse_nsfptr_create( pxRegTestCallback );
|
||||
|
||||
/* Invoke the callback which runs reg tests. */
|
||||
pxNonSecureRegTestCallback();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 SECURE_REG_TEST_ASM_H
|
||||
#define SECURE_REG_TEST_ASM_H
|
||||
|
||||
/* Callback function pointer definition. */
|
||||
typedef void ( * RegTestCallback_t )( void );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests for the secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side.
|
||||
*/
|
||||
void vRegTestAsm_Secure( void );
|
||||
|
||||
/**
|
||||
* @brief Invokes the supplied reg test callback on the non-secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side..
|
||||
*/
|
||||
void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback );
|
||||
|
||||
#endif /* SECURE_REG_TEST_ASM_H */
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
THUMB
|
||||
|
||||
PUBLIC vRegTestAsm_SecureImpl
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
vRegTestAsm_SecureImpl:
|
||||
/* Store callee saved registers. */
|
||||
push { r4-r7 }
|
||||
mov r0, r8
|
||||
mov r1, r9
|
||||
mov r2, r10
|
||||
mov r3, r11
|
||||
mov r4, r12
|
||||
push { r0-r4 }
|
||||
|
||||
/* Fill the core registers with known values. */
|
||||
movs r1, #201
|
||||
movs r2, #202
|
||||
movs r3, #203
|
||||
movs r4, #204
|
||||
movs r5, #205
|
||||
movs r6, #206
|
||||
movs r7, #207
|
||||
movs r0, #208
|
||||
mov r8, r0
|
||||
movs r0, #209
|
||||
mov r9, r0
|
||||
movs r0, #210
|
||||
mov r10, r0
|
||||
movs r0, #211
|
||||
mov r11, r0
|
||||
movs r0, #212
|
||||
mov r12, r0
|
||||
movs r0, #200
|
||||
|
||||
/* Force a context switch by pending non-secure sv. */
|
||||
push { r0, r1 }
|
||||
movs r0, #0x01
|
||||
ldr r1, =0xe002ed04 /* NVIC_ICSR_NS. */
|
||||
lsls r0, r0, #28 /* Shift to PendSV bit. */
|
||||
str r0, [r1]
|
||||
dsb
|
||||
pop { r0, r1 }
|
||||
|
||||
/* Verify that core registers contain correct values. */
|
||||
cmp r0, #200
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r1, #201
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r2, #202
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r3, #203
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r4, #204
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r5, #205
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r6, #206
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r7, #207
|
||||
bne secure_reg_test_error_loop
|
||||
movs r0, #208
|
||||
cmp r8, r0
|
||||
bne secure_reg_test_error_loop
|
||||
movs r0, #209
|
||||
cmp r9, r0
|
||||
bne secure_reg_test_error_loop
|
||||
movs r0, #210
|
||||
cmp r10, r0
|
||||
bne secure_reg_test_error_loop
|
||||
movs r0, #211
|
||||
cmp r11, r0
|
||||
bne secure_reg_test_error_loop
|
||||
movs r0, #212
|
||||
cmp r12, r0
|
||||
bne secure_reg_test_error_loop
|
||||
|
||||
/* Everything passed, finish. */
|
||||
b secure_reg_test_success
|
||||
|
||||
secure_reg_test_error_loop:
|
||||
/* If this line is hit then there was an error in
|
||||
* a core register value. The loop ensures the
|
||||
* loop counter stops incrementing. */
|
||||
b secure_reg_test_error_loop
|
||||
nop
|
||||
|
||||
secure_reg_test_success:
|
||||
/* Restore callee saved registers. */
|
||||
pop { r0-r4 }
|
||||
mov r8, r0
|
||||
mov r9, r1
|
||||
mov r10, r2
|
||||
mov r11, r3
|
||||
mov r12, r4
|
||||
pop { r4-r7 }
|
||||
bx lr
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
END
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 REG_TEST_ASM_H
|
||||
#define REG_TEST_ASM_H
|
||||
|
||||
/**
|
||||
* @brief Functions that implement reg tests in assembly.
|
||||
*
|
||||
* These are called from the FreeRTOS tasks on the non-secure side.
|
||||
*/
|
||||
void vRegTest1Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest2Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest3Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
void vRegTest4Asm_NonSecure( void ) __attribute__( ( naked ) );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests in assembly.
|
||||
*
|
||||
* This is passed as function pointer to the secure side and called
|
||||
* from the secure side.
|
||||
*/
|
||||
void vRegTestAsm_NonSecureCallback( void );
|
||||
|
||||
#endif /* REG_TEST_ASM_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <arm_cmse.h>
|
||||
|
||||
/* Interface includes. */
|
||||
#include "secure_reg_test_asm.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "secure_port_macros.h"
|
||||
|
||||
/* Implemented in assembly. */
|
||||
extern void vRegTestAsm_SecureImpl( void );
|
||||
|
||||
/* typedef for non-secure callback function. */
|
||||
typedef __cmse_nonsecure_call void ( * NonSecureRegTestCallback_t ) ( void );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTestAsm_Secure( void )
|
||||
{
|
||||
/* Call the function implemented in assembly. */
|
||||
vRegTestAsm_SecureImpl();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback )
|
||||
{
|
||||
NonSecureRegTestCallback_t pxNonSecureRegTestCallback;
|
||||
|
||||
/* Return function pointer with cleared LSB. */
|
||||
pxNonSecureRegTestCallback = ( NonSecureRegTestCallback_t ) cmse_nsfptr_create( pxRegTestCallback );
|
||||
|
||||
/* Invoke the callback which runs reg tests. */
|
||||
pxNonSecureRegTestCallback();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 SECURE_REG_TEST_ASM_H
|
||||
#define SECURE_REG_TEST_ASM_H
|
||||
|
||||
/* Callback function pointer definition. */
|
||||
typedef void ( * RegTestCallback_t )( void );
|
||||
|
||||
/**
|
||||
* @brief Function that implements reg tests for the secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side.
|
||||
*/
|
||||
void vRegTestAsm_Secure( void );
|
||||
|
||||
/**
|
||||
* @brief Invokes the supplied reg test callback on the non-secure side.
|
||||
*
|
||||
* This function is exported as "non-secure callable" and is called
|
||||
* from a FreeRTOS task on the non-secure side..
|
||||
*/
|
||||
void vRegTest_NonSecureCallback( RegTestCallback_t pxRegTestCallback );
|
||||
|
||||
#endif /* SECURE_REG_TEST_ASM_H */
|
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
THUMB
|
||||
|
||||
PUBLIC vRegTestAsm_SecureImpl
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
vRegTestAsm_SecureImpl:
|
||||
/* Store callee saved registers. */
|
||||
push { r4-r12 }
|
||||
|
||||
/* Fill the core registers with known values. */
|
||||
movs r0, #200
|
||||
movs r1, #201
|
||||
movs r1, #201
|
||||
movs r2, #202
|
||||
movs r3, #203
|
||||
movs r4, #204
|
||||
movs r5, #205
|
||||
movs r6, #206
|
||||
movs r7, #207
|
||||
movs r8, #208
|
||||
movs r9, #209
|
||||
movs r10, #210
|
||||
movs r11, #211
|
||||
movs r12, #212
|
||||
|
||||
/* Fill the FPU registers with known values. */
|
||||
vmov.f32 s0, #1.0
|
||||
vmov.f32 s2, #2.0
|
||||
vmov.f32 s3, #3.5
|
||||
vmov.f32 s4, #4.5
|
||||
vmov.f32 s5, #5.0
|
||||
vmov.f32 s6, #6.0
|
||||
vmov.f32 s7, #7.5
|
||||
vmov.f32 s8, #8.5
|
||||
vmov.f32 s9, #9.0
|
||||
vmov.f32 s10, #10.0
|
||||
vmov.f32 s11, #11.5
|
||||
vmov.f32 s12, #12.5
|
||||
vmov.f32 s13, #13.0
|
||||
vmov.f32 s14, #14.0
|
||||
vmov.f32 s15, #1.5
|
||||
vmov.f32 s16, #2.5
|
||||
vmov.f32 s17, #3.0
|
||||
vmov.f32 s18, #4.0
|
||||
vmov.f32 s19, #5.5
|
||||
vmov.f32 s20, #6.5
|
||||
vmov.f32 s21, #7.0
|
||||
vmov.f32 s22, #8.0
|
||||
vmov.f32 s23, #9.5
|
||||
vmov.f32 s24, #10.5
|
||||
vmov.f32 s25, #11.0
|
||||
vmov.f32 s26, #12.0
|
||||
vmov.f32 s27, #13.5
|
||||
vmov.f32 s28, #14.5
|
||||
vmov.f32 s29, #1.0
|
||||
vmov.f32 s30, #2.0
|
||||
vmov.f32 s31, #3.5
|
||||
|
||||
/* Force a context switch by pending non-secure sv. */
|
||||
push { r0, r1 }
|
||||
movs r0, #0x01
|
||||
ldr r1, =0xe002ed04 /* NVIC_ICSR_NS. */
|
||||
lsls r0, #28 /* Shift to PendSV bit. */
|
||||
str r0, [r1]
|
||||
dsb
|
||||
pop { r0, r1 }
|
||||
|
||||
/* Verify that core registers contain correct values. */
|
||||
cmp r0, #200
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r1, #201
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r2, #202
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r3, #203
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r4, #204
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r5, #205
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r6, #206
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r7, #207
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r8, #208
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r9, #209
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r10, #210
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r11, #211
|
||||
bne secure_reg_test_error_loop
|
||||
cmp r12, #212
|
||||
bne secure_reg_test_error_loop
|
||||
|
||||
/* Verify that FPU registers contain correct values. */
|
||||
vmov.f32 s1, #1.0
|
||||
vcmp.f32 s0, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #2.0
|
||||
vcmp.f32 s2, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #3.5
|
||||
vcmp.f32 s3, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #4.5
|
||||
vcmp.f32 s4, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #5.0
|
||||
vcmp.f32 s5, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #6.0
|
||||
vcmp.f32 s6, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #7.5
|
||||
vcmp.f32 s7, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #8.5
|
||||
vcmp.f32 s8, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #9.0
|
||||
vcmp.f32 s9, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #10.0
|
||||
vcmp.f32 s10, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #11.5
|
||||
vcmp.f32 s11, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #12.5
|
||||
vcmp.f32 s12, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #13.0
|
||||
vcmp.f32 s13, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #14.0
|
||||
vcmp.f32 s14, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #1.5
|
||||
vcmp.f32 s15, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #2.5
|
||||
vcmp.f32 s16, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #3.0
|
||||
vcmp.f32 s17, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #4.0
|
||||
vcmp.f32 s18, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #5.5
|
||||
vcmp.f32 s19, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #6.5
|
||||
vcmp.f32 s20, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #7.0
|
||||
vcmp.f32 s21, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #8.0
|
||||
vcmp.f32 s22, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #9.5
|
||||
vcmp.f32 s23, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #10.5
|
||||
vcmp.f32 s24, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #11.0
|
||||
vcmp.f32 s25, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #12.0
|
||||
vcmp.f32 s26, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #13.5
|
||||
vcmp.f32 s27, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #14.5
|
||||
vcmp.f32 s28, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #1.0
|
||||
vcmp.f32 s29, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #2.0
|
||||
vcmp.f32 s30, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
vmov.f32 s1, #3.5
|
||||
vcmp.f32 s31, s1
|
||||
vmrs APSR_nzcv, FPSCR
|
||||
bne secure_reg_test_error_loop
|
||||
|
||||
/* Everything passed, finish. */
|
||||
b secure_reg_test_success
|
||||
|
||||
secure_reg_test_error_loop:
|
||||
/* If this line is hit then there was an error in
|
||||
* a core register value. The loop ensures the
|
||||
* loop counter stops incrementing. */
|
||||
b secure_reg_test_error_loop
|
||||
nop
|
||||
|
||||
secure_reg_test_success:
|
||||
/* Restore callee saved registers. */
|
||||
pop { r4-r12 }
|
||||
bx lr
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
END
|
58
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/nsc_functions.c
Normal file
58
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/nsc_functions.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <arm_cmse.h>
|
||||
#include "nsc_functions.h"
|
||||
#include "secure_port_macros.h"
|
||||
|
||||
/**
|
||||
* @brief Counter returned from NSCFunction.
|
||||
*/
|
||||
static uint32_t ulSecureCounter = 0;
|
||||
|
||||
/**
|
||||
* @brief typedef for non-secure callback.
|
||||
*/
|
||||
typedef void ( *NonSecureCallback_t )( void ) __attribute__( ( cmse_nonsecure_call ) );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
secureportNON_SECURE_CALLABLE uint32_t NSCFunction( Callback_t pxCallback )
|
||||
{
|
||||
NonSecureCallback_t pxNonSecureCallback;
|
||||
|
||||
/* Return function pointer with cleared LSB. */
|
||||
pxNonSecureCallback = ( NonSecureCallback_t ) cmse_nsfptr_create( pxCallback );
|
||||
|
||||
/* Invoke the supplied callback. */
|
||||
pxNonSecureCallback();
|
||||
|
||||
/* Increment the secure side counter. */
|
||||
ulSecureCounter += 1;
|
||||
|
||||
/* Return the secure side counter. */
|
||||
return ulSecureCounter;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
50
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/nsc_functions.h
Normal file
50
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/nsc_functions.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 __NSC_FUNCTIONS_H__
|
||||
#define __NSC_FUNCTIONS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Callback function pointer definition.
|
||||
*/
|
||||
typedef void ( * Callback_t ) ( void );
|
||||
|
||||
/**
|
||||
* @brief Invokes the supplied callback which is on the non-secure side.
|
||||
*
|
||||
* Returns a number which is one more than the value returned in previous
|
||||
* invocation of this function. Initial invocation returns 1.
|
||||
*
|
||||
* @param pxCallback[in] The callback to invoke.
|
||||
*
|
||||
* @return A number which is one more than the value returned in previous
|
||||
* invocation of this function.
|
||||
*/
|
||||
uint32_t NSCFunction( Callback_t pxCallback );
|
||||
|
||||
#endif /* __NSC_FUNCTIONS_H__ */
|
133
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/tz_demo.c
Normal file
133
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/tz_demo.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Non-Secure callable functions. */
|
||||
#include "nsc_functions.h"
|
||||
|
||||
/**
|
||||
* @brief Counter incremented in the callback which is called from the secure
|
||||
* side.
|
||||
*
|
||||
* The size of an MPU region must be a multiple of 32 bytes. Therefore we need
|
||||
* to declare an array of size 8 to ensure that the total size is 32 bytes -
|
||||
* even though we only need 4 bytes. If we do not do that, anything placed after
|
||||
* 4 bytes and upto 32 bytes will also fall in the same MPU region and the task
|
||||
* having access to ulNonSecureCounter will also have access to all those items.
|
||||
*/
|
||||
static uint32_t ulNonSecureCounter[ 8 ] __attribute__( ( aligned( 32 ) ) ) = { 0 };
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Creates all the tasks for TZ demo.
|
||||
*/
|
||||
void vStartTZDemo( void );
|
||||
|
||||
/**
|
||||
* @brief Increments the ulNonSecureCounter.
|
||||
*
|
||||
* This function is called from the secure side.
|
||||
*/
|
||||
static void prvCallback( void );
|
||||
|
||||
/**
|
||||
* @brief Implements the task which calls the functions exported from the secure
|
||||
* side.
|
||||
*
|
||||
* @param pvParameters[in] Parameters as passed during task creation.
|
||||
*/
|
||||
static void prvSecureCallingTask( void * pvParameters );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartTZDemo( void )
|
||||
{
|
||||
static StackType_t xSecureCallingTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
||||
TaskParameters_t xSecureCallingTaskParameters =
|
||||
{
|
||||
.pvTaskCode = prvSecureCallingTask,
|
||||
.pcName = "SecCalling",
|
||||
.usStackDepth = configMINIMAL_STACK_SIZE,
|
||||
.pvParameters = NULL,
|
||||
.uxPriority = tskIDLE_PRIORITY,
|
||||
.puxStackBuffer = xSecureCallingTaskStack,
|
||||
.xRegions =
|
||||
{
|
||||
{ ulNonSecureCounter, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
/* Create an unprivileged task which calls secure functions. */
|
||||
xTaskCreateRestricted( &( xSecureCallingTaskParameters ), NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCallback( void )
|
||||
{
|
||||
/* This function is called from the secure side. Just increment the counter
|
||||
* here. The check that this counter keeps incrementing is performed in the
|
||||
* prvSecureCallingTask. */
|
||||
ulNonSecureCounter[ 0 ] += 1;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSecureCallingTask( void * pvParameters )
|
||||
{
|
||||
uint32_t ulLastSecureCounter = 0, ulLastNonSecureCounter = 0;
|
||||
uint32_t ulCurrentSecureCounter = 0;
|
||||
|
||||
/* This task calls secure side functions. So allocate a secure context for
|
||||
* it. */
|
||||
portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Call the secure side function. It does two things:
|
||||
* - It calls the supplied function (prvCallback) which in turn
|
||||
* increments the non-secure counter.
|
||||
* - It increments the secure counter and returns the incremented value.
|
||||
* Therefore at the end of this function call both the secure and
|
||||
* non-secure counters must have been incremented.
|
||||
*/
|
||||
ulCurrentSecureCounter = NSCFunction( prvCallback );
|
||||
|
||||
/* Make sure that both the counters are incremented. */
|
||||
configASSERT( ulCurrentSecureCounter == ulLastSecureCounter + 1 );
|
||||
configASSERT( ulNonSecureCounter[ 0 ] == ulLastNonSecureCounter + 1 );
|
||||
|
||||
/* Update the last values for both the counters. */
|
||||
ulLastSecureCounter = ulCurrentSecureCounter;
|
||||
ulLastNonSecureCounter = ulNonSecureCounter[ 0 ];
|
||||
|
||||
/* Wait for a second. */
|
||||
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
44
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/tz_demo.h
Normal file
44
SOFTWARE-FreeRTOS/Common/ARMv8M/tz_demo/tz_demo.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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 __TZ_DEMO_H__
|
||||
#define __TZ_DEMO_H__
|
||||
|
||||
/**
|
||||
* @brief Creates all the tasks for TZ demo.
|
||||
*
|
||||
* The Trust Zone (TZ) demo creates an unprivileged task which calls a secure
|
||||
* side function and passes a pointer to a callback function. The secure side
|
||||
* function does two things:
|
||||
* 1. It calls the provided callback function. The callback function increments
|
||||
* a counter.
|
||||
* 2. It increments a counter and returns the incremented value.
|
||||
* After the secure function call finishes, it verifies that both the counters
|
||||
* are incremented.
|
||||
*/
|
||||
void vStartTZDemo( void );
|
||||
|
||||
#endif /* __TZ_DEMO_H__ */
|
307
SOFTWARE-FreeRTOS/Common/Full/BlockQ.c
Normal file
307
SOFTWARE-FreeRTOS/Common/Full/BlockQ.c
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
* \page BlockQC blockQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.00:
|
||||
*
|
||||
+ Reversed the priority and block times of the second two demo tasks so
|
||||
+ they operate as per the description above.
|
||||
+
|
||||
+ Changes from V2.0.0
|
||||
+
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
+
|
||||
+ Changes from V4.0.2
|
||||
+
|
||||
+ The second set of tasks were created the wrong way around. This has been
|
||||
+ corrected.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
#include "print.h"
|
||||
|
||||
#define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
QueueHandle_t xQueue; /*< The queue to be used by the task. */
|
||||
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static void vBlockingQueueProducer( void * pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
* it is the expected number. */
|
||||
static void vBlockingQueueConsumer( void * pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
* found to be the expected value.
|
||||
* These are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
* are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
|
||||
xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
|
||||
xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
|
||||
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
|
||||
const TickType_t xDontBlock = ( TickType_t ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
* Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
* is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
* wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
* it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
* spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
* the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
* the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueProducer( void * pvParameters )
|
||||
{
|
||||
unsigned short usValue = 0;
|
||||
xBlockingQueueParameters * pxQueueParameters;
|
||||
const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
* used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
* consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueConsumer( void * pvParameters )
|
||||
{
|
||||
unsigned short usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters * pxQueueParameters;
|
||||
const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
* variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
* round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
* bits and we are only reading them. We also only care to see if they have
|
||||
* changed or not.
|
||||
*
|
||||
* Loop through each check variable and return pdFALSE if any are found not
|
||||
* to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
221
SOFTWARE-FreeRTOS/Common/Full/PollQ.c
Normal file
221
SOFTWARE-FreeRTOS/Common/Full/PollQ.c
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This is a very simple queue test. See the BlockQ. c documentation for a more
|
||||
* comprehensive version.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*
|
||||
* \page PollQC pollQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static void vPolledQueueProducer( void * pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static void vPolledQueueConsumer( void * pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no errors. */
|
||||
static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
static QueueHandle_t xPolledQueue;
|
||||
const unsigned portBASE_TYPE uxQueueSize = 10;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueProducer( void * pvParameters )
|
||||
{
|
||||
unsigned short usValue = 0, usLoop;
|
||||
QueueHandle_t * pxQueue;
|
||||
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
|
||||
const unsigned short usNumToProduce = 3;
|
||||
const char * const pcTaskStartMsg = "Polled queue producer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( QueueHandle_t * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full - this is an error. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
* check variable. */
|
||||
++sPollingProducerCount;
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
* empties the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueConsumer( void * pvParameters )
|
||||
{
|
||||
unsigned short usData, usExpectedValue = 0;
|
||||
QueueHandle_t * pxQueue;
|
||||
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
|
||||
const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( QueueHandle_t * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *pxQueue ) )
|
||||
{
|
||||
if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
* occurred. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
|
||||
/* Catch-up to the value we received so our next expected value
|
||||
* should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
* occurred. */
|
||||
++sPollingConsumerCount;
|
||||
}
|
||||
}
|
||||
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
* items in the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
portBASE_TYPE xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
|
||||
( sLastPollingProducerCount == sPollingProducerCount )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastPollingConsumerCount = sPollingConsumerCount;
|
||||
sLastPollingProducerCount = sPollingProducerCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
350
SOFTWARE-FreeRTOS/Common/Full/comtest.c
Normal file
350
SOFTWARE-FreeRTOS/Common/Full/comtest.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A loopback
|
||||
* connector should be used so that everything that is transmitted is also received.
|
||||
* The serial port does not use any flow control. On a standard 9way 'D' connector
|
||||
* pins two and three should be connected together.
|
||||
*
|
||||
* The first task repeatedly sends a string to a queue, character at a time. The
|
||||
* serial port interrupt will empty the queue and transmit the characters. The
|
||||
* task blocks for a pseudo random period before resending the string.
|
||||
*
|
||||
* The second task blocks on a queue waiting for a character to be received.
|
||||
* Characters received by the serial port interrupt routine are posted onto the
|
||||
* queue - unblocking the task making it ready to execute. If this is then the
|
||||
* highest priority task ready to run it will run immediately - with a context
|
||||
* switch occurring at the end of the interrupt service routine. The task
|
||||
* receiving characters is spawned with a higher priority than the task
|
||||
* transmitting the characters.
|
||||
*
|
||||
* With the loop back connector in place, one task will transmit a string and the
|
||||
* other will immediately receive it. The receiving task knows the string it
|
||||
* expects to receive so can detect an error.
|
||||
*
|
||||
* This also creates a third task. This is used to test semaphore usage from an
|
||||
* ISR and does nothing interesting.
|
||||
*
|
||||
* \page ComTestC comtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.00:
|
||||
*
|
||||
+ The priority of the Rx task has been lowered. Received characters are
|
||||
+ now processed (read from the queue) at the idle priority, allowing low
|
||||
+ priority tasks to run evenly at times of a high communications overhead.
|
||||
+
|
||||
+ Changes from V1.01:
|
||||
+
|
||||
+ The Tx task now waits a pseudo random time between transmissions.
|
||||
+ Previously a fixed period was used but this was not such a good test as
|
||||
+ interrupts fired at regular intervals.
|
||||
+
|
||||
+ Changes From V1.2.0:
|
||||
+
|
||||
+ Use vSerialPutString() instead of single character puts.
|
||||
+ Only stop the check variable incrementing after two consecutive errors.
|
||||
+
|
||||
+ Changed from V1.2.5
|
||||
+
|
||||
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was
|
||||
+ only 1. This is done to tie in better with the other demo application
|
||||
+ tasks.
|
||||
+
|
||||
+ Changes from V2.0.0
|
||||
+
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
+ Slight modification to task priorities.
|
||||
+
|
||||
*/
|
||||
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
* interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
|
||||
|
||||
#define comMAX_CONSECUTIVE_ERRORS ( 2 )
|
||||
|
||||
#define comSTACK_SIZE ( ( unsigned short ) 256 )
|
||||
|
||||
#define comRX_RELATIVE_PRIORITY ( 1 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort;
|
||||
|
||||
/* The transmit function as described at the top of the file. */
|
||||
static void vComTxTask( void * pvParameters );
|
||||
|
||||
/* The receive function as described at the top of the file. */
|
||||
static void vComRxTask( void * pvParameters );
|
||||
|
||||
/* The semaphore test function as described at the top of the file. */
|
||||
static void vSemTestTask( void * pvParameters );
|
||||
|
||||
/* The string that is repeatedly transmitted. */
|
||||
const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
|
||||
|
||||
/* Variables that are incremented on each cycle of each task. These are used to
|
||||
* check that both tasks are still executing. */
|
||||
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
|
||||
|
||||
/* The handle to the semaphore test task. */
|
||||
static TaskHandle_t xSemTestTaskHandle = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority,
|
||||
eCOMPort ePort,
|
||||
eBaud eBaudRate )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxBufferLength = 255;
|
||||
|
||||
/* Initialise the com port then spawn both tasks. */
|
||||
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
|
||||
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
|
||||
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComTxTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "COM Tx task started.\r\n";
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Send the string to the serial port. */
|
||||
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
|
||||
|
||||
/* We have posted all the characters in the string - increment the variable
|
||||
* used to check that this task is still running, then wait before re-sending
|
||||
* the string. */
|
||||
sTxCount++;
|
||||
|
||||
xTimeToWait = xTaskGetTickCount();
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComRxTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "COM Rx task started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "COM read error\r\n";
|
||||
const char * const pcTaskRestartMsg = "COM resynced\r\n";
|
||||
const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
|
||||
const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS;
|
||||
const char * pcExpectedChar;
|
||||
portBASE_TYPE xGotChar;
|
||||
char cRxedChar;
|
||||
short sResyncRequired, sConsecutiveErrors, sLatchedError;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The first expected character is the first character in the string. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
sConsecutiveErrors = 0;
|
||||
sLatchedError = pdFALSE;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Receive a message from the com port interrupt routine. If a message is
|
||||
* not yet available the call will block the task. */
|
||||
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
|
||||
|
||||
if( xGotChar == pdTRUE )
|
||||
{
|
||||
if( sResyncRequired == pdTRUE )
|
||||
{
|
||||
/* We got out of sequence and are waiting for the start of the next
|
||||
* transmission of the string. */
|
||||
if( cRxedChar == '\n' )
|
||||
{
|
||||
/* This is the end of the message so we can start again - with
|
||||
* the first character in the string being the next thing we expect
|
||||
* to receive. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say that we are going to try
|
||||
* again. */
|
||||
vPrintDisplayMessage( &pcTaskRestartMsg );
|
||||
|
||||
/* Stop incrementing the check variable, if consecutive errors occur. */
|
||||
sConsecutiveErrors++;
|
||||
|
||||
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
|
||||
{
|
||||
sLatchedError = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have received a character, but is it the expected character? */
|
||||
if( cRxedChar != *pcExpectedChar )
|
||||
{
|
||||
/* This was not the expected character so post a message for
|
||||
* printing to say that an error has occurred. We will then wait
|
||||
* to resynchronize. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sResyncRequired = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This was the expected character so next time we will expect
|
||||
* the next character in the string. Wrap back to the beginning
|
||||
* of the string when the null terminator has been reached. */
|
||||
pcExpectedChar++;
|
||||
|
||||
if( *pcExpectedChar == '\0' )
|
||||
{
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
|
||||
/* We have got through the entire string without error. */
|
||||
sConsecutiveErrors = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the count that is used to check that this task is still
|
||||
* running. This is only done if an error has never occurred. */
|
||||
if( sLatchedError == pdFALSE )
|
||||
{
|
||||
sRxCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskTimeoutMsg );
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSemTestTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
|
||||
portBASE_TYPE xError = pdFALSE;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xSerialWaitForSemaphore( xPort ) )
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
sSemCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xError = pdTRUE;
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
* bits and we are only reading them. We also only care to see if they have
|
||||
* changed or not. */
|
||||
|
||||
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastTxCount = sTxCount;
|
||||
sLastRxCount = sRxCount;
|
||||
sLastSemCount = sSemCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vComTestUnsuspendTask( void )
|
||||
{
|
||||
/* The task that is suspended on the semaphore will be referenced from the
|
||||
* Suspended list as it is blocking indefinitely. This call just checks that
|
||||
* the kernel correctly detects this and does not attempt to unsuspend the
|
||||
* task. */
|
||||
xTaskResumeFromISR( xSemTestTaskHandle );
|
||||
}
|
202
SOFTWARE-FreeRTOS/Common/Full/death.c
Normal file
202
SOFTWARE-FreeRTOS/Common/Full/death.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* four tasks. The original task is called the creator task, the four tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* Two of the created suicidal tasks kill one other suicidal task before killing
|
||||
* themselves - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
#include "print.h"
|
||||
|
||||
#define deathSTACK_SIZE ( ( unsigned short ) 512 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
* creating another four tasks. */
|
||||
static void vCreateTasks( void * pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static void vSuicidalTask( void * pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
* is used to check that the task is still running. */
|
||||
static volatile short sCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
* task can tell if any of the suicidal tasks have failed to die. */
|
||||
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
|
||||
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
|
||||
|
||||
/* Used to store a handle to the tasks that should be killed by a suicidal task,
|
||||
* before it kills itself. */
|
||||
TaskHandle_t xCreatedTask1, xCreatedTask2;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSuicidalTask( void * pvParameters )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
} /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCreateTasks( void * pvParameters )
|
||||
{
|
||||
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 );
|
||||
|
||||
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
|
||||
vPortFree( pvParameters );
|
||||
|
||||
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, &xCreatedTask2 );
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL );
|
||||
|
||||
++sCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
* are not any more than four extra tasks. */
|
||||
portBASE_TYPE xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static short sLastCreationCount = 0;
|
||||
short sReturn = pdTRUE;
|
||||
unsigned portBASE_TYPE uxTasksRunningNow;
|
||||
|
||||
if( sLastCreationCount == sCreationCount )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCreationCount = sCreationCount;
|
||||
|
||||
uxTasksRunningNow = uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return sReturn;
|
||||
}
|
574
SOFTWARE-FreeRTOS/Common/Full/dynamic.c
Normal file
574
SOFTWARE-FreeRTOS/Common/Full/dynamic.c
Normal file
@ -0,0 +1,574 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises it's priority above that of the controller task before each
|
||||
* increment, lowering it again to it's original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of it's loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume ().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from it's suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*
|
||||
* The final set of two tasks implements a third test. This simply raises the
|
||||
* priority of a task while the scheduler is suspended. Again this test was
|
||||
* added to exercise parts of the code not covered by the first test.
|
||||
*
|
||||
* \page Priorities dynamic.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
+ Added a second, simple test that uses the functions
|
||||
+ vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
|
||||
+
|
||||
+ Changes from V3.1.1
|
||||
+
|
||||
+ Added a third simple test that uses the vTaskPrioritySet() function
|
||||
+ while the scheduler is suspended.
|
||||
+ Modified the controller task slightly to test the calling of
|
||||
+ vTaskResumeAll() while the scheduler is suspended.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static void vLimitedIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static void vContinuousIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static void vCounterControlTask( void * pvParameters );
|
||||
|
||||
/* The simple test functions that check sending and receiving while the
|
||||
* scheduler is suspended. */
|
||||
static void vQueueReceiveWhenSuspendedTask( void * pvParameters );
|
||||
static void vQueueSendWhenSuspendedTask( void * pvParameters );
|
||||
|
||||
/* The simple test functions that check raising and lowering of task priorities
|
||||
* while the scheduler is suspended. */
|
||||
static void prvChangePriorityWhenSuspendedTask( void * pvParameters );
|
||||
static void prvChangePriorityHelperTask( void * pvParameters );
|
||||
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#define priSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME ( ( TickType_t ) 50 )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( unsigned long ) 0xff )
|
||||
#define priNO_BLOCK ( ( TickType_t ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
* to the controller task to prevent them having to be file scope. */
|
||||
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
* counter variables for demonstration purposes. */
|
||||
static unsigned long ulCounter;
|
||||
|
||||
/* Variable used in a similar way by the test that checks the raising and
|
||||
* lowering of task priorities while the scheduler is suspended. */
|
||||
static unsigned long ulPrioritySetCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
* Each complete iteration of the controller task increments this variable
|
||||
* provided no errors have been found. The variable maintaining the same value
|
||||
* is therefore indication of an error. */
|
||||
static unsigned short usCheckVariable = ( unsigned short ) 0;
|
||||
static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
|
||||
static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
|
||||
static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
QueueHandle_t xSuspendedTestQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Start the seven tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
|
||||
xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static void vLimitedIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned long * pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
* the task. */
|
||||
pulCounter = ( unsigned long * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
* suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static void vContinuousIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned long * pulCounter;
|
||||
unsigned portBASE_TYPE uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
* the task. */
|
||||
pulCounter = ( unsigned long * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
* shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Raise our priority above the controller task to ensure a context
|
||||
* switch does not occur while we are accessing this variable. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
( *pulCounter )++;
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static void vCounterControlTask( void * pvParameters )
|
||||
{
|
||||
unsigned long ulLastCounter;
|
||||
short sLoops;
|
||||
short sError = pdFALSE;
|
||||
const char * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( unsigned long ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
* shared variable without risk of corruption. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
ulLastCounter = ulCounter;
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
* exclusion the whole scheduler will be locked. This is just for
|
||||
* demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
* with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared variable. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( unsigned long ) 0;
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
* We should therefore not return from this call until the limited count
|
||||
* task has suspended itself with a known value in the counter variable.
|
||||
* The scheduler suspension is not necessary but is included for test
|
||||
* purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueSendWhenSuspendedTask( void * pvParameters )
|
||||
{
|
||||
static unsigned long ulValueToSend = ( unsigned long ) 0;
|
||||
const char * const pcTaskStartMsg = "Queue send while suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Queue send while suspended failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
if( xSuspendedQueueSendError == pdFALSE )
|
||||
{
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueReceiveWhenSuspendedTask( void * pvParameters )
|
||||
{
|
||||
static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue;
|
||||
const char * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n";
|
||||
portBASE_TYPE xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
* undesirable for a normal application. It is done here purely
|
||||
* to test the scheduler. The inner xTaskResumeAll() should
|
||||
* never return pdTRUE as the scheduler is still locked by the
|
||||
* outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
|
||||
if( xTaskResumeAll() )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
if( xSuspendedQueueReceiveError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityWhenSuspendedTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "Priority change when suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Start with the counter at 0 so we know what the counter should be
|
||||
* when we check it next. */
|
||||
ulPrioritySetCounter = ( unsigned long ) 0;
|
||||
|
||||
/* Resume the helper task. At this time it has a priority lower than
|
||||
* ours so no context switch should occur. */
|
||||
vTaskResume( xChangePriorityWhenSuspendedHandle );
|
||||
|
||||
/* Check to ensure the task just resumed has not executed. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Now try raising the priority while the scheduler is suspended. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
|
||||
|
||||
/* Again, even though the helper task has a priority greater than
|
||||
* ours, it should not have executed yet because the scheduler is
|
||||
* suspended. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Now the scheduler has been resumed the helper task should
|
||||
* immediately preempt us and execute. When it executes it will increment
|
||||
* the ulPrioritySetCounter exactly once before suspending itself.
|
||||
*
|
||||
* We should now always find the counter set to 1. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 1 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Delay until we try this again. */
|
||||
vTaskDelay( priSLEEP_TIME * 2 );
|
||||
|
||||
/* Set the priority of the helper task back ready for the next
|
||||
* execution of this task. */
|
||||
vTaskSuspendAll();
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityHelperTask( void * pvParameters )
|
||||
{
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This is the helper task for prvChangePriorityWhenSuspendedTask().
|
||||
* It has it's priority raised and lowered. When it runs it simply
|
||||
* increments the counter then suspends itself again. This allows
|
||||
* prvChangePriorityWhenSuspendedTask() to know how many times it has
|
||||
* executed. */
|
||||
ulPrioritySetCounter++;
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
* since the last call. */
|
||||
static unsigned short usLastTaskCheck = ( unsigned short ) 0;
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
* is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xPriorityRaiseWhenSuspendedError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
return xReturn;
|
||||
}
|
368
SOFTWARE-FreeRTOS/Common/Full/events.c
Normal file
368
SOFTWARE-FreeRTOS/Common/Full/events.c
Normal file
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file exercises the event mechanism whereby more than one task is
|
||||
* blocked waiting for the same event.
|
||||
*
|
||||
* The demo creates five tasks - four 'event' tasks, and a controlling task.
|
||||
* The event tasks have various different priorities and all block on reading
|
||||
* the same queue. The controlling task writes data to the queue, then checks
|
||||
* to see which of the event tasks read the data from the queue. The
|
||||
* controlling task has the lowest priority of all the tasks so is guaranteed
|
||||
* to always get preempted immediately upon writing to the queue.
|
||||
*
|
||||
* By selectively suspending and resuming the event tasks the controlling task
|
||||
* can check that the highest priority task that is blocked on the queue is the
|
||||
* task that reads the posted data from the queue.
|
||||
*
|
||||
* Two of the event tasks share the same priority. When neither of these tasks
|
||||
* are suspended they should alternate - one reading one message from the queue,
|
||||
* the other the next message, etc.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "mevents.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo specific constants. */
|
||||
#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
|
||||
#define evtNUM_TASKS ( 4 )
|
||||
#define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
|
||||
#define evtNO_DELAY 0
|
||||
|
||||
/* Just indexes used to uniquely identify the tasks. Note that two tasks are
|
||||
* 'highest' priority. */
|
||||
#define evtHIGHEST_PRIORITY_INDEX_2 3
|
||||
#define evtHIGHEST_PRIORITY_INDEX_1 2
|
||||
#define evtMEDIUM_PRIORITY_INDEX 1
|
||||
#define evtLOWEST_PRIORITY_INDEX 0
|
||||
|
||||
/* Each event task increments one of these counters each time it reads data
|
||||
* from the queue. */
|
||||
static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Each time the controlling task posts onto the queue it increments the
|
||||
* expected count of the task that it expected to read the data from the queue
|
||||
* (i.e. the task with the highest priority that should be blocked on the queue).
|
||||
*
|
||||
* xExpectedTaskCounters are incremented from the controlling task, and
|
||||
* xTaskCounters are incremented from the individual event tasks - therefore
|
||||
* comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
|
||||
* correct task was unblocked by the post. */
|
||||
static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Handles to the four event tasks. These are required to suspend and resume
|
||||
* the tasks. */
|
||||
static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
|
||||
|
||||
/* The single queue onto which the controlling task posts, and the four event
|
||||
* tasks block. */
|
||||
static QueueHandle_t xQueue;
|
||||
|
||||
/* Flag used to indicate whether or not an error has occurred at any time.
|
||||
* An error is either the queue being full when not expected, or an unexpected
|
||||
* task reading data from the queue. */
|
||||
static portBASE_TYPE xHealthStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Function that implements the event task. This is created four times. */
|
||||
static void prvMultiEventTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the controlling task. */
|
||||
static void prvEventControllerTask( void * pvParameters );
|
||||
|
||||
/* This is a utility function that posts data to the queue, then compares
|
||||
* xExpectedTaskCounters with xTaskCounters to ensure everything worked as
|
||||
* expected.
|
||||
*
|
||||
* The event tasks all have higher priorities the controlling task. Therefore
|
||||
* the controlling task will always get preempted between writhing to the queue
|
||||
* and checking the task counters.
|
||||
*
|
||||
* @param xExpectedTask The index to the task that the controlling task thinks
|
||||
* should be the highest priority task waiting for data, and
|
||||
* therefore the task that will unblock.
|
||||
*
|
||||
* @param xIncrement The number of items that should be written to the queue.
|
||||
*/
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
|
||||
portBASE_TYPE xIncrement );
|
||||
|
||||
/* This is just incremented each cycle of the controlling tasks function so
|
||||
* the main application can ensure the test is still running. */
|
||||
static portBASE_TYPE xCheckVariable = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMultiEventTasks( void )
|
||||
{
|
||||
/* Create the queue to be used for all the communications. */
|
||||
xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
/* Start the controlling task. This has the idle priority to ensure it is
|
||||
* always preempted by the event tasks. */
|
||||
xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
/* Start the four event tasks. Note that two have priority 3, one
|
||||
* priority 2 and the other priority 1. */
|
||||
xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMultiEventTask( void * pvParameters )
|
||||
{
|
||||
portBASE_TYPE * pxCounter;
|
||||
unsigned portBASE_TYPE uxDummy;
|
||||
const char * const pcTaskStartMsg = "Multi event task started.\r\n";
|
||||
|
||||
/* The variable this task will increment is passed in as a parameter. */
|
||||
pxCounter = ( portBASE_TYPE * ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Block on the queue. */
|
||||
if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
|
||||
{
|
||||
/* We unblocked by reading the queue - so simply increment
|
||||
* the counter specific to this task instance. */
|
||||
( *pxCounter )++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEventControllerTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Just to stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* All tasks are blocked on the queue. When a message is posted one of
|
||||
* the two tasks that share the highest priority should unblock to read
|
||||
* the queue. The next message written should unblock the other task with
|
||||
* the same high priority, and so on in order. No other task should
|
||||
* unblock to read data as they have lower priorities. */
|
||||
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* For the rest of these tests we don't need the second 'highest'
|
||||
* priority task - so it is suspended. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
|
||||
|
||||
/* Now suspend the other highest priority task. The medium priority
|
||||
* task will then be the task with the highest priority that remains
|
||||
* blocked on the queue. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
/* This time, when we post onto the queue we will expect the medium
|
||||
* priority task to unblock and preempt us. */
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Now try resuming the highest priority task while the scheduler is
|
||||
* suspended. The task should start executing as soon as the scheduler
|
||||
* is resumed - therefore when we post to the queue again, the highest
|
||||
* priority task should again preempt us. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now we are going to suspend the high and medium priority tasks. The
|
||||
* low priority task should then preempt us. Again the task suspension is
|
||||
* done with the whole scheduler suspended just for test purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Do the same basic test another few times - selectively suspending
|
||||
* and resuming tasks and each time calling prvCheckTaskCounters() passing
|
||||
* to the function the number of the task we expected to be unblocked by
|
||||
* the post. */
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for even more test. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now a slight change, first suspend all tasks. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* Now when we resume the low priority task and write to the queue 3
|
||||
* times. We expect the low priority task to service the queue three
|
||||
* times. */
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
|
||||
|
||||
/* Again suspend all tasks (only the low priority task is not suspended
|
||||
* already). */
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* This time we are going to suspend the scheduler, resume the low
|
||||
* priority task, then resume the high priority task. In this state we
|
||||
* will write to the queue three times. When the scheduler is resumed
|
||||
* we expect the high priority task to service all three messages. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should not have been serviced yet!. The scheduler
|
||||
* is still suspended. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* We should have been preempted by resuming the scheduler - so by the
|
||||
* time we are running again we expect the high priority task to have
|
||||
* removed three items from the queue. */
|
||||
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
|
||||
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The medium priority and second high priority tasks are still
|
||||
* suspended. Make sure to resume them before starting again. */
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
/* Just keep incrementing to show the task is still executing. */
|
||||
xCheckVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
|
||||
portBASE_TYPE xIncrement )
|
||||
{
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Write to the queue the requested number of times. The data written is
|
||||
* not important. */
|
||||
for( xDummy = 0; xDummy < xIncrement; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
/* Did not expect to ever find the queue full. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* All the tasks blocked on the queue have a priority higher than the
|
||||
* controlling task. Writing to the queue will therefore have caused this
|
||||
* task to be preempted. By the time this line executes the event task will
|
||||
* have executed and incremented its counter. Increment the expected counter
|
||||
* to the same value. */
|
||||
( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
|
||||
|
||||
/* Check the actual counts and expected counts really are the same. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
/* The counters were not the same. This means a task we did not expect
|
||||
* to unblock actually did unblock. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreMultiEventTasksStillRunning( void )
|
||||
{
|
||||
static portBASE_TYPE xPreviousCheckVariable = 0;
|
||||
|
||||
/* Called externally to periodically check that this test is still
|
||||
* operational. */
|
||||
|
||||
if( xPreviousCheckVariable == xCheckVariable )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
xPreviousCheckVariable = xCheckVariable;
|
||||
|
||||
return xHealthStatus;
|
||||
}
|
126
SOFTWARE-FreeRTOS/Common/Full/flash.c
Normal file
126
SOFTWARE-FreeRTOS/Common/Full/flash.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port
|
||||
* uses IO port F.
|
||||
*
|
||||
* \page flashC flash.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
+
|
||||
+ Changes from V2.1.1
|
||||
+
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
#include "print.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* Structure used to pass parameters to the LED tasks. */
|
||||
typedef struct LED_PARAMETERS
|
||||
{
|
||||
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
|
||||
TickType_t xFlashRate; /*< The rate at which the LED should flash. */
|
||||
} xLEDParameters;
|
||||
|
||||
/* The task that is created eight times - each time with a different xLEDParameters
|
||||
* structure passed in as the parameter. */
|
||||
static void vLEDFlashTask( void * pvParameters );
|
||||
|
||||
/* String to print if USE_STDIO is defined. */
|
||||
const char * const pcTaskStartMsg = "LED flash task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE uxLEDTask;
|
||||
xLEDParameters * pxLEDParameters;
|
||||
const unsigned portBASE_TYPE uxNumOfLEDs = 8;
|
||||
const TickType_t xFlashRate = 125;
|
||||
|
||||
/* Create the eight tasks. */
|
||||
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
|
||||
{
|
||||
/* Create and complete the structure used to pass parameters to the next
|
||||
* created task. */
|
||||
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
|
||||
pxLEDParameters->uxLED = uxLEDTask;
|
||||
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
|
||||
pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS;
|
||||
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vLEDFlashTask( void * pvParameters )
|
||||
{
|
||||
xLEDParameters * pxParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxParameters = ( xLEDParameters * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
}
|
||||
}
|
329
SOFTWARE-FreeRTOS/Common/Full/flop.c
Normal file
329
SOFTWARE-FreeRTOS/Common/Full/flop.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.2.3
|
||||
*
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
+ with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which loops continuously performing an (emulated)
|
||||
* floating point calculation.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle priority
|
||||
* means that these tasks will get pre-empted any time another task is ready to run
|
||||
* or a time slice occurs. More often than not the pre-emption will occur mid
|
||||
* calculation, creating a good test of the schedulers context switch mechanism - a
|
||||
* calculation producing an unexpected result could be a symptom of a corruption in
|
||||
* the context of a task.
|
||||
*
|
||||
* \page FlopC flop.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#define mathSTACK_SIZE ( ( unsigned short ) 512 )
|
||||
#define mathNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
* Each of the four is created twice. */
|
||||
static void vCompetingMathTask1( void * pvParameters );
|
||||
static void vCompetingMathTask2( void * pvParameters );
|
||||
static void vCompetingMathTask3( void * pvParameters );
|
||||
static void vCompetingMathTask4( void * pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
* task gets a calculation wrong it will
|
||||
* stop incrementing its check variable. */
|
||||
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask1( void * pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
|
||||
const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
d4 = ( d1 + d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask2( void * pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
|
||||
const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
d4 = ( d1 / d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know
|
||||
* this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask3( void * pvParameters )
|
||||
{
|
||||
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
|
||||
dTotal1 += ( portDOUBLE ) usPosition + 5.5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask4( void * pvParameters )
|
||||
{
|
||||
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
|
||||
dTotal1 += ( portDOUBLE ) usPosition * 12.123;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
* since the last call. */
|
||||
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
* are still incrementing. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
325
SOFTWARE-FreeRTOS/Common/Full/integer.c
Normal file
325
SOFTWARE-FreeRTOS/Common/Full/integer.c
Normal file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.2.3
|
||||
*
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
+ with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This does the same as flop. c, but uses variables of type long instead of
|
||||
* type double.
|
||||
*
|
||||
* As with flop. c, the tasks created in this file are a good test of the
|
||||
* scheduler context switch mechanism. The processor has to access 32bit
|
||||
* variables in two or four chunks (depending on the processor). The low
|
||||
* priority of these tasks means there is a high probability that a context
|
||||
* switch will occur mid calculation. See the flop. c documentation for
|
||||
* more information.
|
||||
*
|
||||
* \page IntegerC integer.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.2.1
|
||||
*
|
||||
+ The constants used in the calculations are larger to ensure the
|
||||
+ optimiser does not truncate them to 16 bits.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "integer.h"
|
||||
|
||||
#define intgSTACK_SIZE ( ( unsigned short ) 256 )
|
||||
#define intgNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different calculation on four byte
|
||||
* variables. Each of the four is created twice. */
|
||||
static void vCompeteingIntMathTask1( void * pvParameters );
|
||||
static void vCompeteingIntMathTask2( void * pvParameters );
|
||||
static void vCompeteingIntMathTask3( void * pvParameters );
|
||||
static void vCompeteingIntMathTask4( void * pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
* task gets a calculation wrong it will stop incrementing its check variable. */
|
||||
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask1( void * pvParameters )
|
||||
{
|
||||
long l1, l2, l3, l4;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L;
|
||||
const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
l1 = ( long ) 74565L;
|
||||
l2 = ( long ) 1234567L;
|
||||
l3 = ( long ) -918L;
|
||||
|
||||
l4 = ( l1 + l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask2( void * pvParameters )
|
||||
{
|
||||
long l1, l2, l3, l4;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L;
|
||||
const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
l1 = -389000L;
|
||||
l2 = 329999L;
|
||||
l3 = -89L;
|
||||
|
||||
l4 = ( l1 / l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask3( void * pvParameters )
|
||||
{
|
||||
long * plArray, lTotal1, lTotal2;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = ( unsigned short ) 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
lTotal1 = ( long ) 0;
|
||||
lTotal2 = ( long ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( long ) usPosition + ( long ) 5;
|
||||
lTotal1 += ( long ) usPosition + ( long ) 5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask4( void * pvParameters )
|
||||
{
|
||||
long * plArray, lTotal1, lTotal2;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short * pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
lTotal1 = ( long ) 0;
|
||||
lTotal2 = ( long ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( long ) usPosition * ( long ) 12;
|
||||
lTotal1 += ( long ) usPosition * ( long ) 12;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
* since the last call. */
|
||||
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
* are still incrementing. */
|
||||
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
103
SOFTWARE-FreeRTOS/Common/Full/print.c
Normal file
103
SOFTWARE-FreeRTOS/Common/Full/print.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages a queue of strings that are waiting to be displayed. This is used to
|
||||
* ensure mutual exclusion of console output.
|
||||
*
|
||||
* A task wishing to display a message will call vPrintDisplayMessage (), with a
|
||||
* pointer to the string as the parameter. The pointer is posted onto the
|
||||
* xPrintQueue queue.
|
||||
*
|
||||
* The task spawned in main. c blocks on xPrintQueue. When a message becomes
|
||||
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next
|
||||
* string, then uses the functions defined in the portable layer FileIO. c to
|
||||
* display the message.
|
||||
*
|
||||
* <b>NOTE:</b>
|
||||
* Using console IO can disrupt real time performance - depending on the port.
|
||||
* Standard C IO routines are not designed for real time applications. While
|
||||
* standard IO is useful for demonstration and debugging an alternative method
|
||||
* should be used if you actually require console IO as part of your application.
|
||||
*
|
||||
* \page PrintC print.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "print.h"
|
||||
|
||||
static QueueHandle_t xPrintQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintInitialise( void )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxQueueSize = 20;
|
||||
|
||||
/* Create the queue on which errors will be reported. */
|
||||
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend )
|
||||
{
|
||||
#ifdef USE_STDIO
|
||||
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 );
|
||||
#else
|
||||
/* Stop warnings. */
|
||||
( void ) ppcMessageToSend;
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
const char * pcPrintGetNextMessage( TickType_t xPrintRate )
|
||||
{
|
||||
char * pcMessage;
|
||||
|
||||
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
|
||||
{
|
||||
return pcMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
285
SOFTWARE-FreeRTOS/Common/Full/semtest.c
Normal file
285
SOFTWARE-FreeRTOS/Common/Full/semtest.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two sets of two tasks. The tasks within a set share a variable, access
|
||||
* to which is guarded by a semaphore.
|
||||
*
|
||||
* Each task starts by attempting to obtain the semaphore. On obtaining a
|
||||
* semaphore a task checks to ensure that the guarded variable has an expected
|
||||
* value. It then clears the variable to zero before counting it back up to the
|
||||
* expected value in increments of 1. After each increment the variable is checked
|
||||
* to ensure it contains the value to which it was just set. When the starting
|
||||
* value is again reached the task releases the semaphore giving the other task in
|
||||
* the set a chance to do exactly the same thing. The starting value is high
|
||||
* enough to ensure that a tick is likely to occur during the incrementing loop.
|
||||
*
|
||||
* An error is flagged if at any time during the process a shared variable is
|
||||
* found to have a value other than that expected. Such an occurrence would
|
||||
* suggest an error in the mutual exclusion mechanism by which access to the
|
||||
* variable is restricted.
|
||||
*
|
||||
* The first set of two tasks poll their semaphore. The second set use blocking
|
||||
* calls.
|
||||
*
|
||||
* \page SemTestC semtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V1.2.0:
|
||||
*
|
||||
+ The tasks that operate at the idle priority now use a lower expected
|
||||
+ count than those running at a higher priority. This prevents the low
|
||||
+ priority tasks from signaling an error because they have not been
|
||||
+ scheduled enough time for each of them to count the shared variable to
|
||||
+ the high value.
|
||||
+
|
||||
+ Changes from V2.0.0
|
||||
+
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than unsigned long.
|
||||
+
|
||||
+ Changes from V2.1.1
|
||||
+
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "semtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The value to which the shared variables are counted. */
|
||||
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )
|
||||
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )
|
||||
|
||||
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
#define semtstNUM_TASKS ( 4 )
|
||||
|
||||
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
|
||||
|
||||
/* The task function as described at the top of the file. */
|
||||
static void prvSemaphoreTest( void * pvParameters );
|
||||
|
||||
/* Structure used to pass parameters to each task. */
|
||||
typedef struct SEMAPHORE_PARAMETERS
|
||||
{
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
volatile unsigned long * pulSharedVariable;
|
||||
TickType_t xBlockTime;
|
||||
} xSemaphoreParameters;
|
||||
|
||||
/* Variables used to check that all the tasks are still running without errors. */
|
||||
static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
static volatile short sNextCheckVariable = 0;
|
||||
|
||||
/* Strings to print if USE_STDIO is defined. */
|
||||
const char * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
|
||||
const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
|
||||
const TickType_t xBlockTime = ( TickType_t ) 100;
|
||||
|
||||
/* Create the structure used to pass parameters to the first two tasks. */
|
||||
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxFirstSemaphoreParameters != NULL )
|
||||
{
|
||||
/* Create the semaphore used by the first two tasks. */
|
||||
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
/* Create the variable which is to be shared by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
|
||||
|
||||
/* Initialise the share variable to the value the tasks expect. */
|
||||
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
|
||||
/* The first two tasks do not block on semaphore calls. */
|
||||
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
|
||||
|
||||
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do exactly the same to create the second set of tasks, only this time
|
||||
* provide a block time for the semaphore calls. */
|
||||
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxSecondSemaphoreParameters != NULL )
|
||||
{
|
||||
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
|
||||
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
|
||||
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
|
||||
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSemaphoreTest( void * pvParameters )
|
||||
{
|
||||
xSemaphoreParameters * pxParameters;
|
||||
volatile unsigned long * pulSharedVariable, ulExpectedValue;
|
||||
unsigned long ulCounter;
|
||||
short sError = pdFALSE, sCheckVariableToUse;
|
||||
|
||||
/* See which check variable to use. sNextCheckVariable is not semaphore
|
||||
* protected! */
|
||||
portENTER_CRITICAL();
|
||||
sCheckVariableToUse = sNextCheckVariable;
|
||||
sNextCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcSemaphoreTaskStart );
|
||||
|
||||
/* A structure is passed in as the parameter. This contains the shared
|
||||
* variable being guarded. */
|
||||
pxParameters = ( xSemaphoreParameters * ) pvParameters;
|
||||
pulSharedVariable = pxParameters->pulSharedVariable;
|
||||
|
||||
/* If we are blocking we use a much higher count to ensure loads of context
|
||||
* switches occur during the count. */
|
||||
if( pxParameters->xBlockTime > ( TickType_t ) 0 )
|
||||
{
|
||||
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Try to obtain the semaphore. */
|
||||
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
/* We have the semaphore and so expect any other tasks using the
|
||||
* shared variable to have left it in the state we expect to find
|
||||
* it. */
|
||||
if( *pulSharedVariable != ulExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
/* Clear the variable, then count it back up to the expected value
|
||||
* before releasing the semaphore. Would expect a context switch or
|
||||
* two during this time. */
|
||||
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
|
||||
{
|
||||
*pulSharedVariable = ulCounter;
|
||||
|
||||
if( *pulSharedVariable != ulCounter )
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
}
|
||||
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the semaphore, and if no errors have occurred increment the check
|
||||
* variable. */
|
||||
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
if( sCheckVariableToUse < semtstNUM_TASKS )
|
||||
{
|
||||
( sCheckVariables[ sCheckVariableToUse ] )++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a block time then we are running at a priority higher
|
||||
* than the idle priority. This task takes a long time to complete
|
||||
* a cycle (deliberately so to test the guarding) so will be starving
|
||||
* out lower priority tasks. Block for some time to allow give lower
|
||||
* priority tasks some processor time. */
|
||||
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
|
||||
{
|
||||
/* We have not got the semaphore yet, so no point using the
|
||||
* processor. We are not blocking when attempting to obtain the
|
||||
* semaphore. */
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
portBASE_TYPE xTask, xReturn = pdTRUE;
|
||||
|
||||
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
|
||||
{
|
||||
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
799
SOFTWARE-FreeRTOS/Common/Minimal/AbortDelay.c
Normal file
799
SOFTWARE-FreeRTOS/Common/Minimal/AbortDelay.c
Normal file
@ -0,0 +1,799 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some test scenarios that ensure tasks respond correctly
|
||||
* to xTaskAbortDelay() calls. It also ensures tasks return the correct state
|
||||
* of eBlocked when blocked indefinitely in both the case where a task is
|
||||
* blocked on an object and when a task is blocked on a notification.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include "limits.h"
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
#include "event_groups.h"
|
||||
#include "stream_buffer.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "AbortDelay.h"
|
||||
|
||||
/* This file can only be used if the functionality it tests is included in the
|
||||
* build. Remove the whole file if this is not the case. */
|
||||
#if ( INCLUDE_xTaskAbortDelay == 1 )
|
||||
|
||||
#if ( INCLUDE_xTaskGetHandle != 1 )
|
||||
#error This test file uses the xTaskGetHandle() API function so INCLUDE_xTaskGetHandle must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
/* Task priorities. Allow these to be overridden. */
|
||||
#ifndef abtCONTROLLING_PRIORITY
|
||||
#define abtCONTROLLING_PRIORITY ( configMAX_PRIORITIES - 3 )
|
||||
#endif
|
||||
|
||||
#ifndef abtBLOCKING_PRIORITY
|
||||
#define abtBLOCKING_PRIORITY ( configMAX_PRIORITIES - 2 )
|
||||
#endif
|
||||
|
||||
/* The tests that are performed. */
|
||||
#define abtNOTIFY_WAIT_ABORTS 0
|
||||
#define abtNOTIFY_TAKE_ABORTS 1
|
||||
#define abtDELAY_ABORTS 2
|
||||
#define abtDELAY_UNTIL_ABORTS 3
|
||||
#define abtSEMAPHORE_TAKE_ABORTS 4
|
||||
#define abtEVENT_GROUP_ABORTS 5
|
||||
#define abtQUEUE_SEND_ABORTS 6
|
||||
#define abtSTREAM_BUFFER_RECEIVE 7
|
||||
#define abtMAX_TESTS 8
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The two test tasks. The controlling task specifies which test to executed.
|
||||
* More information is provided in the comments within the tasks.
|
||||
*/
|
||||
static void prvControllingTask( void * pvParameters );
|
||||
static void prvBlockingTask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Test functions called by the blocking task. Each function follows the same
|
||||
* pattern, but the way the task blocks is different in each case.
|
||||
*
|
||||
* In each function three blocking calls are made. The first and third
|
||||
* blocking call is expected to time out, while the middle blocking call is
|
||||
* expected to be aborted by the controlling task half way through the block
|
||||
* time.
|
||||
*/
|
||||
static void prvTestAbortingTaskNotifyWait( void );
|
||||
static void prvTestAbortingTaskNotifyTake( void );
|
||||
static void prvTestAbortingTaskDelay( void );
|
||||
static void prvTestAbortingTaskDelayUntil( void );
|
||||
static void prvTestAbortingSemaphoreTake( void );
|
||||
static void prvTestAbortingEventGroupWait( void );
|
||||
static void prvTestAbortingQueueSend( void );
|
||||
static void prvTestAbortingStreamBufferReceive( void );
|
||||
|
||||
/*
|
||||
* Performs a few tests to cover code paths not otherwise covered by the continuous
|
||||
* tests.
|
||||
*/
|
||||
static void prvPerformSingleTaskTests( void );
|
||||
|
||||
/*
|
||||
* Checks the amount of time a task spent in the Blocked state is within the
|
||||
* expected bounds.
|
||||
*/
|
||||
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime,
|
||||
TickType_t xExpectedBlockTime );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static volatile BaseType_t xControllingCycles = 0, xBlockingCycles = 0;
|
||||
static volatile BaseType_t xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Each task needs to know the other tasks handle so they can send signals to
|
||||
* each other. The handle is obtained from the task's name. */
|
||||
static const char * pcControllingTaskName = "AbtCtrl", * pcBlockingTaskName = "AbtBlk";
|
||||
|
||||
/* The maximum amount of time a task will block for. */
|
||||
const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 100 );
|
||||
const TickType_t xHalfMaxBlockTime = pdMS_TO_TICKS( 50 );
|
||||
|
||||
/* The actual block time is dependent on the priority of other tasks in the
|
||||
* system so the actual block time might be greater than that expected, but it
|
||||
* should be within an acceptable upper bound. */
|
||||
const TickType_t xAllowableMargin = pdMS_TO_TICKS( 7 );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateAbortDelayTasks( void )
|
||||
{
|
||||
/* Create the two test tasks described above. */
|
||||
xTaskCreate( prvControllingTask, pcControllingTaskName, configMINIMAL_STACK_SIZE, NULL, abtCONTROLLING_PRIORITY, NULL );
|
||||
xTaskCreate( prvBlockingTask, pcBlockingTaskName, configMINIMAL_STACK_SIZE, NULL, abtBLOCKING_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvControllingTask( void * pvParameters )
|
||||
{
|
||||
TaskHandle_t xBlockingTask;
|
||||
uint32_t ulTestToPerform = abtNOTIFY_WAIT_ABORTS;
|
||||
TickType_t xTimeAtStart;
|
||||
const TickType_t xStartMargin = 2UL;
|
||||
|
||||
/* Just to remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
xBlockingTask = xTaskGetHandle( pcBlockingTaskName );
|
||||
configASSERT( xBlockingTask );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Tell the secondary task to perform the next test. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xTaskNotify( xBlockingTask, ulTestToPerform, eSetValueWithOverwrite );
|
||||
|
||||
/* The secondary task has a higher priority, so will now be in the
|
||||
* Blocked state to wait for a maximum of xMaxBlockTime. It expects that
|
||||
* period to complete with a timeout. It will then block for
|
||||
* xMaxBlockTimeAgain, but this time it expects to the block time to abort
|
||||
* half way through. Block until it is time to send the abort to the
|
||||
* secondary task. xStartMargin is used because this task takes timing
|
||||
* from the beginning of the test, whereas the blocking task takes timing
|
||||
* from the entry into the Blocked state - and as the tasks run at
|
||||
* different priorities, there may be some discrepancy. Also, temporarily
|
||||
* raise the priority of the controlling task to that of the blocking
|
||||
* task to minimise discrepancies. */
|
||||
vTaskPrioritySet( NULL, abtBLOCKING_PRIORITY );
|
||||
vTaskDelay( xMaxBlockTime + xHalfMaxBlockTime + xStartMargin );
|
||||
|
||||
if( xTaskAbortDelay( xBlockingTask ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Reset the priority to the normal controlling priority. */
|
||||
vTaskPrioritySet( NULL, abtCONTROLLING_PRIORITY );
|
||||
|
||||
/* Now wait to be notified that the secondary task has completed its
|
||||
* test. */
|
||||
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
|
||||
/* Did the entire test run for the expected time, which is two full
|
||||
* block times plus the half block time caused by calling
|
||||
* xTaskAbortDelay()? */
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, ( xMaxBlockTime + xMaxBlockTime + xHalfMaxBlockTime ) );
|
||||
|
||||
/* Move onto the next test. */
|
||||
ulTestToPerform++;
|
||||
|
||||
if( ulTestToPerform >= abtMAX_TESTS )
|
||||
{
|
||||
ulTestToPerform = 0;
|
||||
}
|
||||
|
||||
/* To indicate this task is still executing. */
|
||||
xControllingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvBlockingTask( void * pvParameters )
|
||||
{
|
||||
TaskHandle_t xControllingTask;
|
||||
uint32_t ulNotificationValue;
|
||||
const uint32_t ulMax = 0xffffffffUL;
|
||||
|
||||
/* Just to remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Start by performing a few tests to cover code not exercised in the loops
|
||||
* below. */
|
||||
prvPerformSingleTaskTests();
|
||||
|
||||
xControllingTask = xTaskGetHandle( pcControllingTaskName );
|
||||
configASSERT( xControllingTask );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Wait to be notified of the test that is to be performed next. */
|
||||
xTaskNotifyWait( 0, ulMax, &ulNotificationValue, portMAX_DELAY );
|
||||
|
||||
switch( ulNotificationValue )
|
||||
{
|
||||
case abtNOTIFY_WAIT_ABORTS:
|
||||
prvTestAbortingTaskNotifyWait();
|
||||
break;
|
||||
|
||||
case abtNOTIFY_TAKE_ABORTS:
|
||||
prvTestAbortingTaskNotifyTake();
|
||||
break;
|
||||
|
||||
case abtDELAY_ABORTS:
|
||||
prvTestAbortingTaskDelay();
|
||||
break;
|
||||
|
||||
case abtDELAY_UNTIL_ABORTS:
|
||||
prvTestAbortingTaskDelayUntil();
|
||||
break;
|
||||
|
||||
case abtSEMAPHORE_TAKE_ABORTS:
|
||||
prvTestAbortingSemaphoreTake();
|
||||
break;
|
||||
|
||||
case abtEVENT_GROUP_ABORTS:
|
||||
prvTestAbortingEventGroupWait();
|
||||
break;
|
||||
|
||||
case abtQUEUE_SEND_ABORTS:
|
||||
prvTestAbortingQueueSend();
|
||||
break;
|
||||
|
||||
case abtSTREAM_BUFFER_RECEIVE:
|
||||
prvTestAbortingStreamBufferReceive();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not get here. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Let the primary task know the test is complete. */
|
||||
xTaskNotifyGive( xControllingTask );
|
||||
|
||||
/* To indicate this task is still executing. */
|
||||
xBlockingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvPerformSingleTaskTests( void )
|
||||
{
|
||||
TaskHandle_t xThisTask;
|
||||
BaseType_t xReturned;
|
||||
|
||||
/* Try unblocking this task using both the task and ISR versions of the API -
|
||||
* both should return false as this task is not blocked. */
|
||||
xThisTask = xTaskGetCurrentTaskHandle();
|
||||
|
||||
xReturned = xTaskAbortDelay( xThisTask );
|
||||
|
||||
if( xReturned != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskDelayUntil( void )
|
||||
{
|
||||
TickType_t xTimeAtStart, xLastBlockTime;
|
||||
BaseType_t xReturned;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* Take a copy of the time as it is updated in the call to
|
||||
* xTaskDelayUntil() but its original value is needed to determine the actual
|
||||
* time spend in the Blocked state. */
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
configASSERT( xReturned == pdTRUE );
|
||||
|
||||
/* Remove compiler warning about value being set but not used in the case
|
||||
* configASSERT() is not defined. */
|
||||
( void ) xReturned;
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through. Again take a copy of the time as it is updated in the call to
|
||||
* vTaskDelayUntil() buts its original value is needed to determine the amount
|
||||
* of time actually spent in the Blocked state. This uses vTaskDelayUntil()
|
||||
* in place of xTaskDelayUntil() for test coverage. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* As with the other tests, the third block period should not time out. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
configASSERT( xReturned == pdTRUE );
|
||||
|
||||
/* Remove compiler warning about value being set but not used in the case
|
||||
* configASSERT() is not defined. */
|
||||
( void ) xReturned;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskDelay( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskNotifyTake( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
uint32_t ulReturn;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingEventGroupWait( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
EventGroupHandle_t xEventGroup;
|
||||
EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticEventGroup_t xEventGroupBuffer;
|
||||
|
||||
/* Create the event group. Statically allocated memory is used so the
|
||||
* creation cannot fail. */
|
||||
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xEventGroup = xEventGroupCreate();
|
||||
configASSERT( xEventGroup );
|
||||
}
|
||||
#endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vEventGroupDelete( xEventGroup );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingStreamBufferReceive( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
StreamBufferHandle_t xStreamBuffer;
|
||||
size_t xReturn;
|
||||
const size_t xTriggerLevelBytes = ( size_t ) 1;
|
||||
uint8_t uxRxData;
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Defines the memory that will actually hold the streams within the
|
||||
* stream buffer. */
|
||||
static uint8_t ucStorageBuffer[ sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) + 1 ];
|
||||
|
||||
/* The variable used to hold the stream buffer structure. */
|
||||
StaticStreamBuffer_t xStreamBufferStruct;
|
||||
|
||||
|
||||
xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucStorageBuffer ),
|
||||
xTriggerLevelBytes,
|
||||
ucStorageBuffer,
|
||||
&xStreamBufferStruct );
|
||||
}
|
||||
#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||
{
|
||||
xStreamBuffer = xStreamBufferCreate( sizeof( uint8_t ), xTriggerLevelBytes );
|
||||
configASSERT( xStreamBuffer );
|
||||
}
|
||||
#endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through xMaxBlockTime. */
|
||||
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
|
||||
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vStreamBufferDelete( xStreamBuffer );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingQueueSend( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
const UBaseType_t xQueueLength = ( UBaseType_t ) 1;
|
||||
QueueHandle_t xQueue;
|
||||
uint8_t ucItemToQueue;
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticQueue_t xQueueBuffer;
|
||||
static uint8_t ucQueueStorage[ sizeof( uint8_t ) ];
|
||||
|
||||
/* Create the queue. Statically allocated memory is used so the
|
||||
* creation cannot fail. */
|
||||
xQueue = xQueueCreateStatic( xQueueLength, sizeof( uint8_t ), ucQueueStorage, &xQueueBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xQueue = xQueueCreate( xQueueLength, sizeof( uint8_t ) );
|
||||
configASSERT( xQueue );
|
||||
}
|
||||
#endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||
|
||||
/* This function tests aborting when in the blocked state waiting to send,
|
||||
* so the queue must be full. There is only one space in the queue. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vQueueDelete( xQueue );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingSemaphoreTake( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticSemaphore_t xSemaphoreBuffer;
|
||||
|
||||
/* Create the semaphore. Statically allocated memory is used so the
|
||||
* creation cannot fail. */
|
||||
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xSemaphore = xSemaphoreCreateBinary();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through xMaxBlockTime. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, portMAX_DELAY );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vSemaphoreDelete( xSemaphore );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskNotifyWait( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
* through xMaxBlockTime. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, portMAX_DELAY );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
|
||||
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime,
|
||||
TickType_t xExpectedBlockTime )
|
||||
{
|
||||
TickType_t xTimeNow, xActualBlockTime;
|
||||
|
||||
xTimeNow = xTaskGetTickCount();
|
||||
xActualBlockTime = xTimeNow - xStartTime;
|
||||
|
||||
/* The actual block time should not be less than the expected block time. */
|
||||
if( xActualBlockTime < xExpectedBlockTime )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* The actual block time can be greater than the expected block time, as it
|
||||
* depends on the priority of the other tasks, but it should be within an
|
||||
* acceptable margin. */
|
||||
if( xActualBlockTime > ( xExpectedBlockTime + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreAbortDelayTestTasksStillRunning( void )
|
||||
{
|
||||
static BaseType_t xLastControllingCycleCount = 0, xLastBlockingCycleCount = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
* last called? */
|
||||
if( xControllingCycles == xLastControllingCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xBlockingCycles == xLastBlockingCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastBlockingCycleCount = xBlockingCycles;
|
||||
xLastControllingCycleCount = xControllingCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* INCLUDE_xTaskAbortDelay == 1 */
|
306
SOFTWARE-FreeRTOS/Common/Minimal/BlockQ.c
Normal file
306
SOFTWARE-FreeRTOS/Common/Minimal/BlockQ.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
|
||||
#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
#define blckqSHORT_DELAY ( 5 )
|
||||
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||
#error This example cannot be used if dynamic allocation is not allowed.
|
||||
#endif
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
QueueHandle_t xQueue; /*< The queue to be used by the task. */
|
||||
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
* it is the expected number. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
* found to be the expected value.
|
||||
* These are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
* are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
|
||||
xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
|
||||
xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
|
||||
const UBaseType_t uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( ( TickType_t ) 1000 );
|
||||
const TickType_t xDontBlock = ( TickType_t ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
* Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
* is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
* wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
* it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
* spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
* the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
* the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
|
||||
{
|
||||
uint16_t usValue = 0;
|
||||
xBlockingQueueParameters * pxQueueParameters;
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
* used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
* consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
|
||||
#if ( configNUMBER_OF_CORES > 1 )
|
||||
{
|
||||
if( pxQueueParameters->xBlockTime == 0 )
|
||||
{
|
||||
vTaskDelay( blckqSHORT_DELAY );
|
||||
}
|
||||
}
|
||||
#elif configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
|
||||
{
|
||||
uint16_t usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters * pxQueueParameters;
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
* variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
* round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
|
||||
#if ( configNUMBER_OF_CORES > 1 )
|
||||
{
|
||||
if( pxQueueParameters->xBlockTime == 0 )
|
||||
{
|
||||
vTaskDelay( blckqSHORT_DELAY );
|
||||
}
|
||||
}
|
||||
#elif configUSE_PREEMPTION == 0
|
||||
{
|
||||
if( pxQueueParameters->xBlockTime == 0 )
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
BaseType_t xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
* bits and we are only reading them. We also only care to see if they have
|
||||
* changed or not.
|
||||
*
|
||||
* Loop through each check variable to and return pdFALSE if any are found not
|
||||
* to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
1058
SOFTWARE-FreeRTOS/Common/Minimal/EventGroupsDemo.c
Normal file
1058
SOFTWARE-FreeRTOS/Common/Minimal/EventGroupsDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
1039
SOFTWARE-FreeRTOS/Common/Minimal/GenQTest.c
Normal file
1039
SOFTWARE-FreeRTOS/Common/Minimal/GenQTest.c
Normal file
File diff suppressed because it is too large
Load Diff
741
SOFTWARE-FreeRTOS/Common/Minimal/IntQueue.c
Normal file
741
SOFTWARE-FreeRTOS/Common/Minimal/IntQueue.c
Normal file
@ -0,0 +1,741 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines one of the more complex set of demo/test tasks. They are
|
||||
* designed to stress test the queue implementation though pseudo simultaneous
|
||||
* multiple reads and multiple writes from both tasks of varying priority and
|
||||
* interrupts. The interrupts are prioritised such to ensure that nesting
|
||||
* occurs (for those ports that support it).
|
||||
*
|
||||
* The test ensures that, while being accessed from three tasks and two
|
||||
* interrupts, all the data sent to the queues is also received from
|
||||
* the same queue, and that no duplicate items are either sent or received.
|
||||
* The tests also ensure that a low priority task is never able to successfully
|
||||
* read from or write to a queue when a task of higher priority is attempting
|
||||
* the same operation.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* SafeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "IntQueue.h"
|
||||
#include "IntQueueTimer.h"
|
||||
|
||||
#if ( INCLUDE_eTaskGetState != 1 )
|
||||
#error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.
|
||||
#endif
|
||||
|
||||
/* Priorities used by test tasks. */
|
||||
#ifndef intqHIGHER_PRIORITY
|
||||
#define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
|
||||
#endif
|
||||
#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
|
||||
/* The number of values to send/receive before checking that all values were
|
||||
* processed as expected. */
|
||||
#define intqNUM_VALUES_TO_LOG ( 200 )
|
||||
#define intqSHORT_DELAY ( 140 )
|
||||
|
||||
/* The value by which the value being sent to or received from a queue should
|
||||
* increment past intqNUM_VALUES_TO_LOG before we check that all values have been
|
||||
* sent/received correctly. This is done to ensure that all tasks and interrupts
|
||||
* accessing the queue have completed their accesses with the
|
||||
* intqNUM_VALUES_TO_LOG range. */
|
||||
#define intqVALUE_OVERRUN ( 50 )
|
||||
|
||||
/* The delay used by the polling task. A short delay is used for code
|
||||
* coverage. */
|
||||
#define intqONE_TICK_DELAY ( 1 )
|
||||
|
||||
/* Each task and interrupt is given a unique identifier. This value is used to
|
||||
* identify which task sent or received each value. The identifier is also used
|
||||
* to distinguish between two tasks that are running the same task function. */
|
||||
#define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )
|
||||
#define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )
|
||||
#define intqLOW_PRIORITY_TASK ( ( UBaseType_t ) 3 )
|
||||
#define intqFIRST_INTERRUPT ( ( UBaseType_t ) 4 )
|
||||
#define intqSECOND_INTERRUPT ( ( UBaseType_t ) 5 )
|
||||
#define intqQUEUE_LENGTH ( ( UBaseType_t ) 10 )
|
||||
|
||||
/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
|
||||
* from each queue by each task, otherwise an error is detected. */
|
||||
#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
|
||||
|
||||
/* Send the next value to the queue that is normally empty. This is called
|
||||
* from within the interrupts. */
|
||||
#define timerNORMALLY_EMPTY_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
UBaseType_t uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyEmptyQueue++; \
|
||||
if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
uxValueForNormallyEmptyQueue--; \
|
||||
} \
|
||||
} \
|
||||
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
|
||||
/* Send the next value to the queue that is normally full. This is called
|
||||
* from within the interrupts. */
|
||||
#define timerNORMALLY_FULL_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
UBaseType_t uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyFullQueue++; \
|
||||
if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
uxValueForNormallyFullQueue--; \
|
||||
} \
|
||||
} \
|
||||
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
|
||||
/* Receive a value from the normally empty queue. This is called from within
|
||||
* an interrupt. */
|
||||
#define timerNORMALLY_EMPTY_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
prvQueueAccessLogError( __LINE__ ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
}
|
||||
|
||||
/* Receive a value from the normally full queue. This is called from within
|
||||
* an interrupt. */
|
||||
#define timerNORMALLY_FULL_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
|
||||
{ \
|
||||
prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
} \
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The two queues used by the test. */
|
||||
static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
|
||||
|
||||
/* Variables used to detect a stall in one of the tasks. */
|
||||
static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
|
||||
|
||||
/* Any unexpected behaviour sets xErrorStatus to fail and log the line that
|
||||
* caused the error in xErrorLine. */
|
||||
static BaseType_t xErrorStatus = pdPASS;
|
||||
static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
|
||||
|
||||
/* Used for sequencing between tasks. */
|
||||
static BaseType_t xWasSuspended = pdFALSE;
|
||||
|
||||
/* The values that are sent to the queues. An incremented value is sent each
|
||||
* time to each queue. */
|
||||
static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
|
||||
|
||||
/* A handle to some of the tasks is required so they can be suspended/resumed. */
|
||||
TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
|
||||
|
||||
/* When a value is received in a queue the value is ticked off in the array
|
||||
* the array position of the value is set to a the identifier of the task or
|
||||
* interrupt that accessed the queue. This way missing or duplicate values can be
|
||||
* detected. */
|
||||
static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
|
||||
/* The test tasks themselves. */
|
||||
static void prvLowerPriorityNormallyEmptyTask( void * pvParameters );
|
||||
static void prvLowerPriorityNormallyFullTask( void * pvParameters );
|
||||
static void prvHigherPriorityNormallyEmptyTask( void * pvParameters );
|
||||
static void prv1stHigherPriorityNormallyFullTask( void * pvParameters );
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void * pvParameters );
|
||||
|
||||
/* Used to mark the positions within the ucNormallyEmptyReceivedValues and
|
||||
* ucNormallyFullReceivedValues arrays, while checking for duplicates. */
|
||||
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue,
|
||||
UBaseType_t uxSource );
|
||||
static void prvRecordValue_NormallyFull( UBaseType_t uxValue,
|
||||
UBaseType_t uxSource );
|
||||
|
||||
/* Logs the line on which an error occurred. */
|
||||
static void prvQueueAccessLogError( UBaseType_t uxLine );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartInterruptQueueTasks( void )
|
||||
{
|
||||
/* Start the test tasks. */
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
|
||||
xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
|
||||
/* Create the queues that are accessed by multiple tasks and multiple
|
||||
* interrupts. */
|
||||
xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
|
||||
xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
* in use. The queue registry is provided as a means for kernel aware
|
||||
* debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
* is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
* by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
* defined to be less than 1. */
|
||||
vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
|
||||
vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyFull( UBaseType_t uxValue,
|
||||
UBaseType_t uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
* has already been marked as received an error has occurred. */
|
||||
if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue,
|
||||
UBaseType_t uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
* has already been marked as received an error has occurred. */
|
||||
if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueAccessLogError( UBaseType_t uxLine )
|
||||
{
|
||||
/* Latch the line number that caused the error. */
|
||||
xErrorLine = uxLine;
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHigherPriorityNormallyEmptyTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
|
||||
|
||||
/* The timer should not be started until after the scheduler has started.
|
||||
* More than one task is running this code so we check the parameter value
|
||||
* to determine which task should start the timer. */
|
||||
if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
vInitialiseTimerForIntQueueTest();
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Block waiting to receive a value from the normally empty queue.
|
||||
* Interrupts will write to the queue so we should receive a value. */
|
||||
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note which value was received so we can check all expected
|
||||
* values are received and no values are duplicated. */
|
||||
prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );
|
||||
}
|
||||
|
||||
/* Ensure the other task running this code gets a chance to execute. */
|
||||
taskYIELD();
|
||||
|
||||
if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Have we received all the expected values? */
|
||||
if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
|
||||
|
||||
uxTask1 = 0;
|
||||
uxTask2 = 0;
|
||||
uxInterrupts = 0;
|
||||
|
||||
/* Loop through the array, checking that both tasks have
|
||||
* placed values into the array, and that no values are missing.
|
||||
* Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value is missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Value was placed into the array by task 1. */
|
||||
uxTask1++;
|
||||
}
|
||||
else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
|
||||
{
|
||||
/* Value was placed into the array by task 2. */
|
||||
uxTask2++;
|
||||
}
|
||||
else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
|
||||
{
|
||||
uxInterrupts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 2 seemed to log any values. */
|
||||
uxErrorCount1++;
|
||||
|
||||
if( uxErrorCount1 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount1 = 0;
|
||||
}
|
||||
|
||||
if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 1 seemed to log any values. */
|
||||
uxErrorCount2++;
|
||||
|
||||
if( uxErrorCount2 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount2 = 0;
|
||||
}
|
||||
|
||||
if( uxInterrupts == 0 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Clear the array again, ready to start a new cycle. */
|
||||
memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops1++;
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyEmptyQueue = 0;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
* actually receive something from the queue. Until now it
|
||||
* will have been prevented from doing so by the higher
|
||||
* priority tasks. The lower priority task will resume us
|
||||
* if it receives something. We will then resume the other
|
||||
* higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyEmptyTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t uxValue, uxRxed;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* A value should only be obtained when the high priority task is
|
||||
* suspended. */
|
||||
if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
|
||||
|
||||
/* Wake the higher priority task again. */
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask1 );
|
||||
uxLowPriorityLoops1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we send so we can preempt the higher
|
||||
* priority task, and ensure we get the Tx value into the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyEmptyQueue++;
|
||||
uxValue = uxValueForNormallyEmptyQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv1stHigherPriorityNormallyFullTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t uxValueToTx, ux, uxInterrupts;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
* high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
/* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
|
||||
* expect it to ever time out. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Allow the other task running this code to run. */
|
||||
taskYIELD();
|
||||
|
||||
/* Have all the expected values been sent to the queue? */
|
||||
if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
/* Make sure the other high priority task completes its send of
|
||||
* any values below intqNUM_VALUE_TO_LOG. */
|
||||
vTaskDelay( intqSHORT_DELAY );
|
||||
|
||||
vTaskSuspend( xHighPriorityNormallyFullTask2 );
|
||||
|
||||
if( xWasSuspended == pdTRUE )
|
||||
{
|
||||
/* We would have expected the other high priority task to have
|
||||
* set this back to false by now. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Set the suspended flag so an error is not logged if the other
|
||||
* task recognises a time out when it is unsuspended. */
|
||||
xWasSuspended = pdTRUE;
|
||||
|
||||
/* Check interrupts are also sending. */
|
||||
uxInterrupts = 0U;
|
||||
|
||||
/* Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyFullReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value was missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
|
||||
{
|
||||
uxInterrupts++;
|
||||
}
|
||||
}
|
||||
|
||||
if( uxInterrupts == 0 )
|
||||
{
|
||||
/* No writes from interrupts were found. Are interrupts
|
||||
* actually running? */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Reset the array ready for the next cycle. */
|
||||
memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops2++;
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue = 0;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
* actually receive something from the queue. Until now it
|
||||
* will have been prevented from doing so by the higher
|
||||
* priority tasks. The lower priority task will resume us
|
||||
* if it receives something. We will then resume the other
|
||||
* higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyFullTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t uxValueToTx, ux;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
* high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
if( xWasSuspended != pdTRUE )
|
||||
{
|
||||
/* It is ok to time out if the task has been suspended. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
|
||||
xWasSuspended = pdFALSE;
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyFullTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t uxValue, uxTxed = 9999;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
|
||||
{
|
||||
/* Should only succeed when the higher priority task is suspended */
|
||||
if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskResume( xHighPriorityNormallyFullTask1 );
|
||||
uxLowPriorityLoops2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we receive so we can preempt the higher
|
||||
* priority task, and ensure we get the value from the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xFirstTimerHandler( void )
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
UBaseType_t uxRxedValue;
|
||||
static UBaseType_t uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
* accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( UBaseType_t ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xSecondTimerHandler( void )
|
||||
{
|
||||
UBaseType_t uxRxedValue;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
static UBaseType_t uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
* accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( UBaseType_t ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
BaseType_t xAreIntQueueTasksStillRunning( void )
|
||||
{
|
||||
static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
|
||||
|
||||
/* xErrorStatus can be set outside of this function. This function just
|
||||
* checks that all the tasks are still cycling. */
|
||||
|
||||
if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
|
||||
{
|
||||
/* The high priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
|
||||
|
||||
if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
|
||||
{
|
||||
/* The high priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
|
||||
|
||||
if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
|
||||
{
|
||||
/* The low priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
|
||||
|
||||
if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
|
||||
{
|
||||
/* The low priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
|
||||
|
||||
return xErrorStatus;
|
||||
}
|
537
SOFTWARE-FreeRTOS/Common/Minimal/IntSemTest.c
Normal file
537
SOFTWARE-FreeRTOS/Common/Minimal/IntSemTest.c
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Demonstrates and tests mutexes being used from an interrupt.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "IntSemTest.h"
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The priorities of the test tasks. */
|
||||
#define intsemMASTER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define intsemSLAVE_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
|
||||
/* The rate at which the tick hook will give the mutex. */
|
||||
#define intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 )
|
||||
|
||||
/* A block time of 0 means 'don't block'. */
|
||||
#define intsemNO_BLOCK 0
|
||||
|
||||
/* The maximum count value for the counting semaphore given from an
|
||||
* interrupt. */
|
||||
#define intsemMAX_COUNT 3
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The master is a task that receives a mutex that is given from an interrupt -
|
||||
* although generally mutexes should not be used given in interrupts (and
|
||||
* definitely never taken in an interrupt) there are some circumstances when it
|
||||
* may be desirable.
|
||||
*
|
||||
* The slave task is just used by the master task to force priority inheritance
|
||||
* on a mutex that is shared between the master and the slave - which is a
|
||||
* separate mutex to that given by the interrupt.
|
||||
*/
|
||||
static void vInterruptMutexSlaveTask( void * pvParameters );
|
||||
static void vInterruptMutexMasterTask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* A test whereby the master takes the shared and interrupt mutexes in that
|
||||
* order, then gives them back in the same order, ensuring the priority
|
||||
* inheritance is behaving as expected at each step.
|
||||
*/
|
||||
static void prvTakeAndGiveInTheSameOrder( void );
|
||||
|
||||
/*
|
||||
* A test whereby the master takes the shared and interrupt mutexes in that
|
||||
* order, then gives them back in the opposite order to which they were taken,
|
||||
* ensuring the priority inheritance is behaving as expected at each step.
|
||||
*/
|
||||
static void prvTakeAndGiveInTheOppositeOrder( void );
|
||||
|
||||
/*
|
||||
* A simple task that interacts with an interrupt using a counting semaphore,
|
||||
* primarily for code coverage purposes.
|
||||
*/
|
||||
static void vInterruptCountingSemaphoreTask( void * pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
* detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counters that are incremented on each cycle of a test. This is used to
|
||||
* detect a stalled task - a test that is no longer running. */
|
||||
static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0;
|
||||
|
||||
/* Handles of the test tasks that must be accessed from other test tasks. */
|
||||
static TaskHandle_t xSlaveHandle;
|
||||
|
||||
/* A mutex which is given from an interrupt - although generally mutexes should
|
||||
* not be used given in interrupts (and definitely never taken in an interrupt)
|
||||
* there are some circumstances when it may be desirable. */
|
||||
static SemaphoreHandle_t xISRMutex = NULL;
|
||||
|
||||
/* A counting semaphore which is given from an interrupt. */
|
||||
static SemaphoreHandle_t xISRCountingSemaphore = NULL;
|
||||
|
||||
/* A mutex which is shared between the master and slave tasks - the master
|
||||
* does both sharing of this mutex with the slave and receiving a mutex from the
|
||||
* interrupt. */
|
||||
static SemaphoreHandle_t xMasterSlaveMutex = NULL;
|
||||
|
||||
/* Flag that allows the master task to control when the interrupt gives or does
|
||||
* not give the mutex. There is no mutual exclusion on this variable, but this is
|
||||
* only test code and it should be fine in the 32=bit test environment. */
|
||||
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Used to coordinate timing between tasks and the interrupt. */
|
||||
const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartInterruptSemaphoreTasks( void )
|
||||
{
|
||||
/* Create the semaphores that are given from an interrupt. */
|
||||
xISRMutex = xSemaphoreCreateMutex();
|
||||
configASSERT( xISRMutex );
|
||||
xISRCountingSemaphore = xSemaphoreCreateCounting( intsemMAX_COUNT, 0 );
|
||||
configASSERT( xISRCountingSemaphore );
|
||||
|
||||
/* Create the mutex that is shared between the master and slave tasks (the
|
||||
* master receives a mutex from an interrupt and shares a mutex with the
|
||||
* slave. */
|
||||
xMasterSlaveMutex = xSemaphoreCreateMutex();
|
||||
configASSERT( xMasterSlaveMutex );
|
||||
|
||||
/* Create the tasks that share mutexes between then and with interrupts. */
|
||||
xTaskCreate( vInterruptMutexSlaveTask, "IntMuS", configMINIMAL_STACK_SIZE, NULL, intsemSLAVE_PRIORITY, &xSlaveHandle );
|
||||
xTaskCreate( vInterruptMutexMasterTask, "IntMuM", configMINIMAL_STACK_SIZE, NULL, intsemMASTER_PRIORITY, NULL );
|
||||
|
||||
/* Create the task that blocks on the counting semaphore. */
|
||||
xTaskCreate( vInterruptCountingSemaphoreTask, "IntCnt", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptMutexMasterTask( void * pvParameters )
|
||||
{
|
||||
/* Just to avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
prvTakeAndGiveInTheSameOrder();
|
||||
|
||||
/* Ensure not to starve out other tests. */
|
||||
ulMasterLoops++;
|
||||
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
|
||||
prvTakeAndGiveInTheOppositeOrder();
|
||||
|
||||
/* Ensure not to starve out other tests. */
|
||||
ulMasterLoops++;
|
||||
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeAndGiveInTheSameOrder( void )
|
||||
{
|
||||
/* Ensure the slave is suspended, and that this task is running at the
|
||||
* lower priority as expected as the start conditions. */
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Take the semaphore that is shared with the slave. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* This task now has the mutex. Unsuspend the slave so it too
|
||||
* attempts to take the mutex. */
|
||||
vTaskResume( xSlaveHandle );
|
||||
|
||||
/* The slave has the higher priority so should now have executed and
|
||||
* blocked on the semaphore. */
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* This task should now have inherited the priority of the slave
|
||||
* task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Now wait a little longer than the time between ISR gives to also
|
||||
* obtain the ISR mutex. */
|
||||
xOkToGiveMutex = pdTRUE;
|
||||
|
||||
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
xOkToGiveMutex = pdFALSE;
|
||||
|
||||
/* Attempting to take again immediately should fail as the mutex is
|
||||
* already held. */
|
||||
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Give back the ISR semaphore to ensure the priority is not
|
||||
* disinherited as the shared mutex (which the higher priority task is
|
||||
* attempting to obtain) is still held. */
|
||||
if( xSemaphoreGive( xISRMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Finally give back the shared mutex. This time the higher priority
|
||||
* task should run before this task runs again - so this task should have
|
||||
* disinherited the priority and the higher priority task should be in the
|
||||
* suspended state again. */
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Reset the mutex ready for the next round. */
|
||||
xQueueReset( xISRMutex );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeAndGiveInTheOppositeOrder( void )
|
||||
{
|
||||
/* Ensure the slave is suspended, and that this task is running at the
|
||||
* lower priority as expected as the start conditions. */
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Take the semaphore that is shared with the slave. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* This task now has the mutex. Unsuspend the slave so it too
|
||||
* attempts to take the mutex. */
|
||||
vTaskResume( xSlaveHandle );
|
||||
|
||||
/* The slave has the higher priority so should now have executed and
|
||||
* blocked on the semaphore. */
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* This task should now have inherited the priority of the slave
|
||||
* task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Now wait a little longer than the time between ISR gives to also
|
||||
* obtain the ISR mutex. */
|
||||
xOkToGiveMutex = pdTRUE;
|
||||
|
||||
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
xOkToGiveMutex = pdFALSE;
|
||||
|
||||
/* Attempting to take again immediately should fail as the mutex is
|
||||
* already held. */
|
||||
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Give back the shared semaphore to ensure the priority is not disinherited
|
||||
* as the ISR mutex is still held. The higher priority slave task should run
|
||||
* before this task runs again. */
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task as this task still
|
||||
* holds one semaphore (this is a simplification in the priority inheritance
|
||||
* mechanism. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Give back the ISR semaphore, which should result in the priority being
|
||||
* disinherited as it was the last mutex held. */
|
||||
if( xSemaphoreGive( xISRMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Reset the mutex ready for the next round. */
|
||||
xQueueReset( xISRMutex );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptMutexSlaveTask( void * pvParameters )
|
||||
{
|
||||
/* Just to avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This task starts by suspending itself so when it executes can be
|
||||
* controlled by the master task. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* This task will execute when the master task already holds the mutex.
|
||||
* Attempting to take the mutex will place this task in the Blocked
|
||||
* state. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptCountingSemaphoreTask( void * pvParameters )
|
||||
{
|
||||
BaseType_t xCount;
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) * ( intsemMAX_COUNT + 1 );
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Expect to start with the counting semaphore empty. */
|
||||
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Wait until it is expected that the interrupt will have filled the
|
||||
* counting semaphore. */
|
||||
xOkToGiveCountingSemaphore = pdTRUE;
|
||||
vTaskDelay( xDelay );
|
||||
xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Now it is expected that the counting semaphore is full. */
|
||||
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != intsemMAX_COUNT )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
if( uxQueueSpacesAvailable( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
ulCountingSemaphoreLoops++;
|
||||
|
||||
/* Expect to be able to take the counting semaphore intsemMAX_COUNT
|
||||
* times. A block time of 0 is used as the semaphore should already be
|
||||
* there. */
|
||||
xCount = 0;
|
||||
|
||||
while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS )
|
||||
{
|
||||
xCount++;
|
||||
}
|
||||
|
||||
if( xCount != intsemMAX_COUNT )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
/* Now raise the priority of this task so it runs immediately that the
|
||||
* semaphore is given from the interrupt. */
|
||||
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||||
|
||||
/* Block to wait for the semaphore to be given from the interrupt. */
|
||||
xOkToGiveCountingSemaphore = pdTRUE;
|
||||
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
|
||||
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
|
||||
xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Reset the priority so as not to disturb other tests too much. */
|
||||
vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
|
||||
|
||||
ulCountingSemaphoreLoops++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vInterruptSemaphorePeriodicTest( void )
|
||||
{
|
||||
static TickType_t xLastGiveTime = 0;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
TickType_t xTimeNow;
|
||||
|
||||
/* No mutual exclusion on xOkToGiveMutex, but this is only test code (and
|
||||
* only executed on a 32-bit architecture) so ignore that in this case. */
|
||||
xTimeNow = xTaskGetTickCountFromISR();
|
||||
|
||||
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
|
||||
{
|
||||
configASSERT( xISRMutex );
|
||||
|
||||
if( xOkToGiveMutex != pdFALSE )
|
||||
{
|
||||
/* Null is used as the second parameter in this give, and non-NULL
|
||||
* in the other gives for code coverage reasons. */
|
||||
xSemaphoreGiveFromISR( xISRMutex, NULL );
|
||||
|
||||
/* Second give attempt should fail. */
|
||||
configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL );
|
||||
}
|
||||
|
||||
if( xOkToGiveCountingSemaphore != pdFALSE )
|
||||
{
|
||||
xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
xLastGiveTime = xTimeNow;
|
||||
}
|
||||
|
||||
/* Remove compiler warnings about the value being set but not used. */
|
||||
( void ) xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreInterruptSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0;
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* If the demo tasks are running then it is expected that the loop counters
|
||||
* will have changed since this function was last called. */
|
||||
if( ulLastMasterLoopCounter == ulMasterLoops )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
ulLastMasterLoopCounter = ulMasterLoops;
|
||||
|
||||
if( ulLastCountingSemaphoreLoops == ulCountingSemaphoreLoops )
|
||||
{
|
||||
xErrorDetected = __LINE__;
|
||||
}
|
||||
|
||||
ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++;
|
||||
|
||||
if( xErrorDetected != pdFALSE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
328
SOFTWARE-FreeRTOS/Common/Minimal/MessageBufferAMP.c
Normal file
328
SOFTWARE-FreeRTOS/Common/Minimal/MessageBufferAMP.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* An example that mimics a message buffer being used to pass data from one core
|
||||
* to another. The core that sends the data is referred to as core A. The core
|
||||
* that receives the data is referred to as core B. The task implemented by
|
||||
* prvCoreATask() runs on core A. Two instances of the task implemented by
|
||||
* prvCoreBTasks() run on core B. prvCoreATask() sends messages via message
|
||||
* buffers to both instances of prvCoreBTasks(), one message buffer per channel.
|
||||
* A third message buffer is used to pass the handle of the message buffer
|
||||
* written to by core A to an interrupt service routine that is triggered by
|
||||
* core A but executes on core B.
|
||||
*
|
||||
* The example relies on the FreeRTOS provided default implementation of
|
||||
* sbSEND_COMPLETED() being overridden by an implementation in FreeRTOSConfig.h
|
||||
* that writes the handle of the message buffer that contains data into the
|
||||
* control message buffer, then generates an interrupt in core B. The necessary
|
||||
* implementation is provided in this file and can be enabled by adding the
|
||||
* following to FreeRTOSConfig.h:
|
||||
*
|
||||
* #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
|
||||
*
|
||||
* Core to core communication via message buffer requires the message buffers
|
||||
* to be at an address known to both cores within shared memory.
|
||||
*
|
||||
* Note that, while this example uses three message buffers, the same
|
||||
* functionality can be implemented using a single message buffer by using the
|
||||
* same design pattern described on the link below for queues, but using message
|
||||
* buffers instead. It is actually simpler with a message buffer as variable
|
||||
* length data can be written into the message buffer directly:
|
||||
* https://www.FreeRTOS.org/Pend-on-multiple-rtos-objects.html#alternative_design_pattern
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "message_buffer.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "MessageBufferAMP.h"
|
||||
|
||||
/* Enough for 3 4 byte pointers, including the additional 4 bytes per message
|
||||
* overhead of message buffers. */
|
||||
#define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )
|
||||
|
||||
/* Enough four 4 8 byte strings, plus the additional 4 bytes per message
|
||||
* overhead of message buffers. */
|
||||
#define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )
|
||||
|
||||
/* The number of instances of prvCoreBTasks that are created. */
|
||||
#define mbaNUMBER_OF_CORE_B_TASKS 2
|
||||
|
||||
/* A block time of 0 simply means, don't block. */
|
||||
#define mbaDONT_BLOCK 0
|
||||
|
||||
/* Macro that mimics an interrupt service routine executing by simply calling
|
||||
* the routine inline. */
|
||||
#define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Implementation of the task that, on a real dual core device, would run on
|
||||
* core A and send message to tasks running on core B.
|
||||
*/
|
||||
static void prvCoreATask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Implementation of the task that, on a real dual core device, would run on
|
||||
* core B and receive message from core A. The demo creates two instances of
|
||||
* this task.
|
||||
*/
|
||||
static void prvCoreBTasks( void * pvParameters );
|
||||
|
||||
/*
|
||||
* The function that, on a real dual core device, would handle inter-core
|
||||
* interrupts, but in this case is just called inline.
|
||||
*/
|
||||
static void prvCoreBInterruptHandler( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The message buffers used to pass data from core A to core B. */
|
||||
static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];
|
||||
|
||||
/* The control message buffer. This is used to pass the handle of the message
|
||||
* message buffer that holds application data into the core to core interrupt
|
||||
* service routine. */
|
||||
static MessageBufferHandle_t xControlMessageBuffer;
|
||||
|
||||
/* Counters used to indicate to the check that the tasks are still executing. */
|
||||
static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];
|
||||
|
||||
/* Set to pdFALSE if any errors are detected. Used to inform the check task
|
||||
* that something might be wrong. */
|
||||
BaseType_t xDemoStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMessageBufferAMPTasks( configSTACK_DEPTH_TYPE xStackSize )
|
||||
{
|
||||
BaseType_t x;
|
||||
|
||||
xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE );
|
||||
|
||||
xTaskCreate( prvCoreATask, /* The function that implements the task. */
|
||||
"AMPCoreA", /* Human readable name for the task. */
|
||||
xStackSize, /* Stack size (in words!). */
|
||||
NULL, /* Task parameter is not used. */
|
||||
tskIDLE_PRIORITY, /* The priority at which the task is created. */
|
||||
NULL ); /* No use for the task handle. */
|
||||
|
||||
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
|
||||
{
|
||||
xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE );
|
||||
configASSERT( xCoreBMessageBuffers[ x ] );
|
||||
|
||||
/* Pass the loop counter into the created task using the task's
|
||||
* parameter. The task then uses the value as an index into the
|
||||
* ulCycleCounters and xCoreBMessageBuffers arrays. */
|
||||
xTaskCreate( prvCoreBTasks,
|
||||
"AMPCoreB1",
|
||||
xStackSize,
|
||||
( void * ) x,
|
||||
tskIDLE_PRIORITY + 1,
|
||||
NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCoreATask( void * pvParameters )
|
||||
{
|
||||
BaseType_t x;
|
||||
uint32_t ulNextValue = 0;
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( 250 );
|
||||
char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
|
||||
|
||||
/* Remove warning about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Create the next string to send. The value is incremented on each
|
||||
* loop iteration, and the length of the string changes as the number of
|
||||
* digits in the value increases. */
|
||||
sprintf( cString, "%lu", ( unsigned long ) ulNextValue );
|
||||
|
||||
/* Send the value from this (pseudo) Core A to the tasks on the (pseudo)
|
||||
* Core B via the message buffers. This will result in sbSEND_COMPLETED()
|
||||
* being executed, which in turn will write the handle of the message
|
||||
* buffer written to into xControlMessageBuffer then generate an interrupt
|
||||
* in core B. */
|
||||
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
|
||||
{
|
||||
xMessageBufferSend( /* The message buffer to write to. */
|
||||
xCoreBMessageBuffers[ x ],
|
||||
/* The source of the data to send. */
|
||||
( void * ) cString,
|
||||
/* The length of the data to send. */
|
||||
strlen( cString ),
|
||||
/* The block time, should the buffer be full. */
|
||||
mbaDONT_BLOCK );
|
||||
}
|
||||
|
||||
/* Delay before repeating with a different and potentially different
|
||||
* length string. */
|
||||
vTaskDelay( xDelay );
|
||||
ulNextValue++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCoreBTasks( void * pvParameters )
|
||||
{
|
||||
BaseType_t x;
|
||||
size_t xReceivedBytes;
|
||||
uint32_t ulNextValue = 0;
|
||||
char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
|
||||
char cReceivedString[ 15 ];
|
||||
|
||||
/* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is
|
||||
* passed into this task using the task's parameter. */
|
||||
x = ( BaseType_t ) pvParameters;
|
||||
configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Create the string that is expected to be received this time round. */
|
||||
sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );
|
||||
|
||||
/* Wait to receive the next message from core A. */
|
||||
memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
|
||||
xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */
|
||||
xCoreBMessageBuffers[ x ],
|
||||
/* Location to store received data. */
|
||||
cReceivedString,
|
||||
/* Maximum number of bytes to receive. */
|
||||
sizeof( cReceivedString ),
|
||||
/* Ticks to wait if buffer is empty. */
|
||||
portMAX_DELAY );
|
||||
|
||||
/* Check the number of bytes received was as expected. */
|
||||
configASSERT( xReceivedBytes == strlen( cExpectedString ) );
|
||||
( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */
|
||||
|
||||
/* If the received string matches that expected then increment the loop
|
||||
* counter so the check task knows this task is still running. */
|
||||
if( strcmp( cReceivedString, cExpectedString ) == 0 )
|
||||
{
|
||||
( ulCycleCounters[ x ] )++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xDemoStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Expect the next string in sequence the next time around. */
|
||||
ulNextValue++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called by the re-implementation of sbSEND_COMPLETED(), which can be defined
|
||||
* as follows in FreeRTOSConfig.h:
|
||||
#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
|
||||
*/
|
||||
void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )
|
||||
{
|
||||
MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;
|
||||
|
||||
/* If sbSEND_COMPLETED() has been implemented as above, then this function
|
||||
* is called from within xMessageBufferSend(). As this function also calls
|
||||
* xMessageBufferSend() itself it is necessary to guard against a recursive
|
||||
* call. If the message buffer just updated is the message buffer written to
|
||||
* by this function, then this is a recursive call, and the function can just
|
||||
* exit without taking further action. */
|
||||
if( xUpdatedBuffer != xControlMessageBuffer )
|
||||
{
|
||||
/* Use xControlMessageBuffer to pass the handle of the message buffer
|
||||
* written to by core A to the interrupt handler about to be generated in
|
||||
* core B. */
|
||||
xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );
|
||||
|
||||
/* This is where the interrupt would be generated. In this case it is
|
||||
* not a genuine interrupt handler that executes, just a standard function
|
||||
* call. */
|
||||
mbaGENERATE_CORE_B_INTERRUPT();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handler for the interrupts that are triggered on core A but execute on core
|
||||
* B. */
|
||||
static void prvCoreBInterruptHandler( void )
|
||||
{
|
||||
MessageBufferHandle_t xUpdatedMessageBuffer;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* xControlMessageBuffer contains the handle of the message buffer that
|
||||
* contains data. */
|
||||
if( xMessageBufferReceive( xControlMessageBuffer,
|
||||
&xUpdatedMessageBuffer,
|
||||
sizeof( xUpdatedMessageBuffer ),
|
||||
mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )
|
||||
{
|
||||
/* Call the API function that sends a notification to any task that is
|
||||
* blocked on the xUpdatedMessageBuffer message buffer waiting for data to
|
||||
* arrive. */
|
||||
xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
/* Normal FreeRTOS yield from interrupt semantics, where
|
||||
* xHigherPriorityTaskWoken is initialized to pdFALSE and will then get set to
|
||||
* pdTRUE if the interrupt safe API unblocks a task that has a priority above
|
||||
* that of the currently executing task. */
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreMessageBufferAMPTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };
|
||||
BaseType_t x;
|
||||
|
||||
/* Called by the check task to determine the health status of the tasks
|
||||
* implemented in this demo. */
|
||||
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
|
||||
{
|
||||
if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )
|
||||
{
|
||||
xDemoStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastCycleCounters[ x ] = ulCycleCounters[ x ];
|
||||
}
|
||||
}
|
||||
|
||||
return xDemoStatus;
|
||||
}
|
971
SOFTWARE-FreeRTOS/Common/Minimal/MessageBufferDemo.c
Normal file
971
SOFTWARE-FreeRTOS/Common/Minimal/MessageBufferDemo.c
Normal file
@ -0,0 +1,971 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "message_buffer.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "MessageBufferDemo.h"
|
||||
|
||||
/* The number of bytes of storage in the message buffers used in this test. */
|
||||
#define mbMESSAGE_BUFFER_LENGTH_BYTES ( ( size_t ) 50 )
|
||||
|
||||
/* The number of additional bytes used to store the length of each message. */
|
||||
#define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
|
||||
|
||||
/* Start and end ASCII characters used in messages sent to the buffers. */
|
||||
#define mbASCII_SPACE 32
|
||||
#define mbASCII_TILDA 126
|
||||
|
||||
/* Defines the number of tasks to create in this test and demo. */
|
||||
#define mbNUMBER_OF_ECHO_CLIENTS ( 2 )
|
||||
#define mbNUMBER_OF_SENDER_TASKS ( 2 )
|
||||
|
||||
/* Priority of the test tasks. The send and receive go from low to high
|
||||
* priority tasks, and from high to low priority tasks. */
|
||||
#define mbLOWER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define mbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
|
||||
/* Block times used when sending and receiving from the message buffers. */
|
||||
#define mbRX_TX_BLOCK_TIME pdMS_TO_TICKS( 175UL )
|
||||
|
||||
/* A block time of 0 means "don't block". */
|
||||
#define mbDONT_BLOCK ( 0 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Performs various tests that do not require multiple tasks to interact.
|
||||
*/
|
||||
static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer );
|
||||
|
||||
/*
|
||||
* Tests sending and receiving various lengths of messages via a message buffer.
|
||||
* The echo client sends the messages to the echo server, which then sends the
|
||||
* message back to the echo client which, checks it receives exactly what it
|
||||
* sent.
|
||||
*/
|
||||
static void prvEchoClient( void * pvParameters );
|
||||
static void prvEchoServer( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Tasks that send and receive to a message buffer at a low priority and without
|
||||
* blocking, so the send and receive functions interleave in time as the tasks
|
||||
* are switched in and out.
|
||||
*/
|
||||
static void prvNonBlockingReceiverTask( void * pvParameters );
|
||||
static void prvNonBlockingSenderTask( void * pvParameters );
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
/* This file tests both statically and dynamically allocated message buffers.
|
||||
* Allocate the structures and buffers to be used by the statically allocated
|
||||
* objects, which get used in the echo tests. */
|
||||
static void prvReceiverTask( void * pvParameters );
|
||||
static void prvSenderTask( void * pvParameters );
|
||||
|
||||
static StaticMessageBuffer_t xStaticMessageBuffers[ mbNUMBER_OF_ECHO_CLIENTS ];
|
||||
static uint8_t ucBufferStorage[ mbNUMBER_OF_SENDER_TASKS ][ mbMESSAGE_BUFFER_LENGTH_BYTES + 1 ];
|
||||
static uint32_t ulSenderLoopCounters[ mbNUMBER_OF_SENDER_TASKS ] = { 0 };
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
|
||||
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||||
#define mbCOHERENCE_TEST_BUFFER_SIZE 20
|
||||
#define mbCOHERENCE_TEST_BYTES_WRITTEN 5
|
||||
#define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
|
||||
#define mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ( mbCOHERENCE_TEST_BUFFER_SIZE - ( mbCOHERENCE_TEST_BYTES_WRITTEN + mbBYTES_TO_STORE_MESSAGE_LENGTH ) )
|
||||
|
||||
static void prvSpaceAvailableCoherenceActor( void * pvParameters );
|
||||
static void prvSpaceAvailableCoherenceTester( void * pvParameters );
|
||||
static MessageBufferHandle_t xCoherenceTestMessageBuffer = NULL;
|
||||
|
||||
static uint32_t ulSizeCoherencyTestCycles = 0UL;
|
||||
#endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The buffers used by the echo client and server tasks. */
|
||||
typedef struct ECHO_MESSAGE_BUFFERS
|
||||
{
|
||||
/* Handles to the data structures that describe the message buffers. */
|
||||
MessageBufferHandle_t xEchoClientBuffer;
|
||||
MessageBufferHandle_t xEchoServerBuffer;
|
||||
} EchoMessageBuffers_t;
|
||||
static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||||
|
||||
/* The non-blocking tasks monitor their operation, and if no errors have been
|
||||
* found, increment ulNonBlockingRxCounter. xAreMessageBufferTasksStillRunning()
|
||||
* then checks ulNonBlockingRxCounter and only returns pdPASS if
|
||||
* ulNonBlockingRxCounter is still incrementing. */
|
||||
static uint32_t ulNonBlockingRxCounter = 0;
|
||||
|
||||
/* A message that is longer than the buffer, parts of which are written to the
|
||||
* message buffer to test writing different lengths at different offsets. */
|
||||
static const char * pc55ByteString = "One two three four five six seven eight nine ten eleven";
|
||||
|
||||
/* Remember the required stack size so tasks can be created at run time (after
|
||||
* initialisation time. */
|
||||
static configSTACK_DEPTH_TYPE xBlockingStackSize = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
|
||||
#ifndef configMESSAGE_BUFFER_BLOCK_TASK_STACK_SIZE
|
||||
xBlockingStackSize = ( xStackSize + ( xStackSize >> 1U ) );
|
||||
#else
|
||||
xBlockingStackSize = configMESSAGE_BUFFER_BLOCK_TASK_STACK_SIZE;
|
||||
#endif
|
||||
|
||||
/* The echo servers sets up the message buffers before creating the echo
|
||||
* client tasks. One set of tasks has the server as the higher priority, and
|
||||
* the other has the client as the higher priority. */
|
||||
xTaskCreate( prvEchoServer, "1EchoServer", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
|
||||
xTaskCreate( prvEchoServer, "2EchoServer", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
|
||||
|
||||
/* The non blocking tasks run continuously and will interleave with each
|
||||
* other, so must be created at the lowest priority. The message buffer they
|
||||
* use is created and passed in using the task's parameter. */
|
||||
xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* The sender tasks set up the message buffers before creating the
|
||||
* receiver tasks. Priorities must be 0 and 1 as the priority is used to
|
||||
* index into the xStaticMessageBuffers and ucBufferStorage arrays. */
|
||||
xTaskCreate( prvSenderTask, "1Sender", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
|
||||
xTaskCreate( prvSenderTask, "2Sender", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||||
{
|
||||
xCoherenceTestMessageBuffer = xMessageBufferCreate( mbCOHERENCE_TEST_BUFFER_SIZE );
|
||||
configASSERT( xCoherenceTestMessageBuffer );
|
||||
|
||||
xTaskCreate( prvSpaceAvailableCoherenceActor, "mbsanity1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvSpaceAvailableCoherenceTester, "mbsanity2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer )
|
||||
{
|
||||
size_t xReturned, xItem, xExpectedSpace, xNextLength;
|
||||
const size_t xMax6ByteMessages = mbMESSAGE_BUFFER_LENGTH_BYTES / ( 6 + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||||
const size_t x6ByteLength = 6, x17ByteLength = 17;
|
||||
uint8_t * pucFullBuffer, * pucData, * pucReadData;
|
||||
TickType_t xTimeBeforeCall, xTimeAfterCall;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( 25 ), xAllowableMargin = pdMS_TO_TICKS( 3 );
|
||||
UBaseType_t uxOriginalPriority;
|
||||
|
||||
/* Remove warning in case configASSERT() is not defined. */
|
||||
( void ) xAllowableMargin;
|
||||
|
||||
/* To minimise stack and heap usage a full size buffer is allocated from
|
||||
* the heap, then buffers which hold smaller amounts of data are overlayed
|
||||
* with the larger buffer - just make sure not to use both at once!. */
|
||||
pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
configASSERT( pucFullBuffer );
|
||||
|
||||
pucData = pucFullBuffer;
|
||||
pucReadData = pucData + x17ByteLength;
|
||||
|
||||
/* Nothing has been added or removed yet, so expect the free space to be
|
||||
* exactly as created and the length of the next message to be 0. */
|
||||
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == 0 );
|
||||
/* In case configASSERT() is not define. */
|
||||
( void ) xExpectedSpace;
|
||||
( void ) xNextLength;
|
||||
|
||||
/* Try sending more bytes than possible, first using the FromISR version, then
|
||||
* with an infinite block time to ensure this task does not lock up. */
|
||||
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), NULL );
|
||||
configASSERT( xReturned == ( size_t ) 0 );
|
||||
/* In case configASSERT() is not defined. */
|
||||
( void ) xReturned;
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), portMAX_DELAY );
|
||||
configASSERT( xReturned == ( size_t ) 0 );
|
||||
/* In case configASSERT() is not defined. */
|
||||
( void ) xReturned;
|
||||
|
||||
/* The buffer is 50 bytes long. When an item is added to the buffer an
|
||||
* additional 4 bytes are added to hold the item's size. That means adding
|
||||
* 6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore,
|
||||
* with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the
|
||||
* buffer is completely full. NOTE: The numbers in this paragraph assume
|
||||
* sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) == 4. */
|
||||
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
|
||||
{
|
||||
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );
|
||||
|
||||
/* Generate recognizable data to write to the buffer. This is just
|
||||
* ascii characters that shows which loop iteration the data was written
|
||||
* in. The 'FromISR' version is used to give it some exercise as a block
|
||||
* time is not used. That requires the call to be in a critical section
|
||||
* so this code can also run on FreeRTOS ports that do not support
|
||||
* interrupt nesting (and so don't have interrupt safe critical
|
||||
* sections).*/
|
||||
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, x6ByteLength, NULL );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
configASSERT( xReturned == x6ByteLength );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* The space in the buffer will have reduced by the amount of user data
|
||||
* written into the buffer and the amount of space used to store the length
|
||||
* of the data written into the buffer. */
|
||||
xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||||
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xReturned == xExpectedSpace );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Only 6 byte messages are written. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == x6ByteLength );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
}
|
||||
|
||||
/* Now the buffer should be full, and attempting to add anything will should
|
||||
* fail. */
|
||||
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE );
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Adding with a timeout should also fail after the appropriate time. The
|
||||
* priority is temporarily boosted in this part of the test to keep the
|
||||
* allowable margin to a minimum. */
|
||||
uxOriginalPriority = uxTaskPriorityGet( NULL );
|
||||
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||||
xTimeBeforeCall = xTaskGetTickCount();
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );
|
||||
xTimeAfterCall = xTaskGetTickCount();
|
||||
vTaskPrioritySet( NULL, uxOriginalPriority );
|
||||
configASSERT( ( ( TickType_t ) ( xTimeAfterCall - xTimeBeforeCall ) ) >= xBlockTime );
|
||||
configASSERT( ( ( TickType_t ) ( xTimeAfterCall - xTimeBeforeCall ) ) < ( xBlockTime + xAllowableMargin ) );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) xTimeBeforeCall;
|
||||
( void ) xTimeAfterCall;
|
||||
|
||||
/* The buffer is now full of data in the form "000000", "111111", etc. Make
|
||||
* sure the data is read out as expected. */
|
||||
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
|
||||
{
|
||||
/* Generate the data that is expected to be read out for this loop
|
||||
* iteration. */
|
||||
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
|
||||
|
||||
/* Try reading the message into a buffer that is too small. The message
|
||||
* should remain in the buffer. */
|
||||
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Should still be at least one 6 byte message still available. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == x6ByteLength );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Read the next 6 bytes out. The 'FromISR' version is used to give it
|
||||
* some exercise as a block time is not used. THa requires the code to be
|
||||
* in a critical section so this test can be run with FreeRTOS ports that
|
||||
* do not support interrupt nesting (and therefore don't have interrupt
|
||||
* safe critical sections). */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
configASSERT( xReturned == x6ByteLength );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Does the data read out match that expected? */
|
||||
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
|
||||
|
||||
/* The space in the buffer will have increased by the amount of user
|
||||
* data read from into the buffer and the amount of space used to store the
|
||||
* length of the data read into the buffer. */
|
||||
xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||||
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xReturned == xExpectedSpace );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
}
|
||||
|
||||
/* The buffer should be empty again. */
|
||||
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||||
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
( void ) xExpectedSpace; /* In case configASSERT() is not defined. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == 0 );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
|
||||
|
||||
/* Reading with a timeout should also fail after the appropriate time. The
|
||||
* priority is temporarily boosted in this part of the test to keep the
|
||||
* allowable margin to a minimum. */
|
||||
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||||
xTimeBeforeCall = xTaskGetTickCount();
|
||||
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );
|
||||
xTimeAfterCall = xTaskGetTickCount();
|
||||
vTaskPrioritySet( NULL, uxOriginalPriority );
|
||||
configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );
|
||||
configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) xTimeBeforeCall;
|
||||
( void ) xTimeAfterCall;
|
||||
|
||||
|
||||
/* In the next loop 17 bytes are written to then read out on each iteration.
|
||||
* The expected length variable is always used after 17 bytes have been written
|
||||
* into the buffer - the length of the message is also written, making a total
|
||||
* of 21 bytes consumed for each 17 byte message. */
|
||||
xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||||
|
||||
/* Reading and writing 17 bytes at a time will result in 21 bytes being
|
||||
* written into the buffer, and as 50 is not divisible by 21, writing multiple
|
||||
* times will cause the data to wrap in the buffer.*/
|
||||
for( xItem = 0; xItem < 100; xItem++ )
|
||||
{
|
||||
/* Generate recognizable data to write to the queue. This is just
|
||||
* ascii characters that shows which loop iteration the data was written
|
||||
* in. */
|
||||
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == x17ByteLength );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Only 17 byte messages are written. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == x17ByteLength );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* The space in the buffer will have reduced by the amount of user data
|
||||
* written into the buffer and the amount of space used to store the length
|
||||
* of the data written into the buffer. */
|
||||
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xReturned == xExpectedSpace );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Read the 17 bytes out again. */
|
||||
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x17ByteLength, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == x17ByteLength );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Does the data read out match that expected? */
|
||||
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );
|
||||
|
||||
/* Don't expect any messages to be available as the data was read out
|
||||
* again. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == 0 );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
}
|
||||
|
||||
/* The buffer should be empty again. */
|
||||
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||||
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||||
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
|
||||
/* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test)
|
||||
* bytes of the full 50 bytes, as that would not leave space for the four bytes
|
||||
* taken by the data length. */
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
#ifndef configMESSAGE_BUFFER_LENGTH_TYPE
|
||||
{
|
||||
/* The following will fail if configMESSAGE_BUFFER_LENGTH_TYPE is set
|
||||
* to a non 32-bit type. */
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 2, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 3, mbDONT_BLOCK );
|
||||
configASSERT( xReturned == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
}
|
||||
#endif /* ifndef configMESSAGE_BUFFER_LENGTH_TYPE */
|
||||
|
||||
/* Don't expect any messages to be available as the above were too large to
|
||||
* get written. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == 0 );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Can write mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) bytes though. */
|
||||
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
|
||||
configASSERT( xReturned == mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||||
configASSERT( xNextLength == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );
|
||||
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||||
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucFullBuffer, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
|
||||
configASSERT( xReturned == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
configASSERT( memcmp( ( const void * ) pucFullBuffer, pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) == 0 );
|
||||
|
||||
/* Clean up. */
|
||||
vPortFree( pucFullBuffer );
|
||||
xMessageBufferReset( xMessageBuffer );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNonBlockingSenderTask( void * pvParameters )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
int32_t iDataToSend = 0;
|
||||
size_t xStringLength;
|
||||
const int32_t iMaxValue = 1500;
|
||||
char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||||
|
||||
/* In this case the message buffer has already been created and is passed
|
||||
* into the task using the task's parameter. */
|
||||
|
||||
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||||
|
||||
/* Create a string from an incrementing number. The length of the
|
||||
* string will increase and decrease as the value of the number increases
|
||||
* then overflows. */
|
||||
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||||
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||||
xStringLength = strlen( cTxString );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Doesn't block so calls can interleave with the non-blocking
|
||||
* receives performed by prvNonBlockingReceiverTask(). */
|
||||
if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength )
|
||||
{
|
||||
iDataToSend++;
|
||||
|
||||
if( iDataToSend > iMaxValue )
|
||||
{
|
||||
/* The value sent is reset back to 0 to ensure the string being sent
|
||||
* does not remain at the same length for too long. */
|
||||
iDataToSend = 0;
|
||||
}
|
||||
|
||||
/* Create the next string. */
|
||||
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||||
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||||
xStringLength = strlen( cTxString );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNonBlockingReceiverTask( void * pvParameters )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
BaseType_t xNonBlockingReceiveError = pdFALSE;
|
||||
int32_t iDataToSend = 0;
|
||||
size_t xStringLength, xReceiveLength;
|
||||
const int32_t iMaxValue = 1500;
|
||||
char cExpectedString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||||
char cRxString[ 12 ];
|
||||
|
||||
/* In this case the message buffer has already been created and is passed
|
||||
* into the task using the task's parameter. */
|
||||
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||||
|
||||
/* Create a string from an incrementing number. The length of the
|
||||
* string will increase and decrease as the value of the number increases
|
||||
* then overflows. This should always match the string sent to the buffer by
|
||||
* the non blocking sender task. */
|
||||
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||||
memset( cRxString, 0x00, sizeof( cRxString ) );
|
||||
sprintf( cExpectedString, "%d", ( int ) iDataToSend );
|
||||
xStringLength = strlen( cExpectedString );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Doesn't block so calls can interleave with the non-blocking
|
||||
* receives performed by prvNonBlockingReceiverTask(). */
|
||||
xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK );
|
||||
|
||||
/* Should only ever receive no data is available, or the expected
|
||||
* length of data is available. */
|
||||
if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) )
|
||||
{
|
||||
xNonBlockingReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
if( xReceiveLength == xStringLength )
|
||||
{
|
||||
/* Ensure the received data was that expected, then generate the
|
||||
* next expected string. */
|
||||
if( strcmp( cRxString, cExpectedString ) != 0 )
|
||||
{
|
||||
xNonBlockingReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
iDataToSend++;
|
||||
|
||||
if( iDataToSend > iMaxValue )
|
||||
{
|
||||
/* The value sent is reset back to 0 to ensure the string being sent
|
||||
* does not remain at the same length for too long. */
|
||||
iDataToSend = 0;
|
||||
}
|
||||
|
||||
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||||
memset( cRxString, 0x00, sizeof( cRxString ) );
|
||||
sprintf( cExpectedString, "%d", ( int ) iDataToSend );
|
||||
xStringLength = strlen( cExpectedString );
|
||||
|
||||
if( xNonBlockingReceiveError == pdFALSE )
|
||||
{
|
||||
/* No errors detected so increment the counter that lets the
|
||||
* check task know this test is still functioning correctly. */
|
||||
ulNonBlockingRxCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
static void prvSenderTask( void * pvParameters )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer, xTempMessageBuffer;
|
||||
int32_t iDataToSend = 0;
|
||||
const int32_t iSendsBetweenIncrements = 100;
|
||||
char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||||
const TickType_t xTicksToWait = mbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );
|
||||
StaticMessageBuffer_t xStaticMessageBuffer;
|
||||
size_t xBytesSent;
|
||||
|
||||
|
||||
/* The task's priority is used as an index into the loop counters used to
|
||||
* indicate this task is still running. */
|
||||
UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
|
||||
|
||||
/* Make sure a change in priority does not inadvertently result in an
|
||||
* invalid array index. */
|
||||
configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS );
|
||||
|
||||
/* Avoid compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ) / mbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */
|
||||
&( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */
|
||||
&( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */
|
||||
|
||||
/* Now the message buffer has been created the receiver task can be created.
|
||||
* If this sender task has the higher priority then the receiver task is
|
||||
* created at the lower priority - if this sender task has the lower priority
|
||||
* then the receiver task is created at the higher priority. */
|
||||
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
|
||||
{
|
||||
/* Here prvSingleTaskTests() performs various tests on a message buffer
|
||||
* that was created statically. */
|
||||
prvSingleTaskTests( xMessageBuffer );
|
||||
xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbLOWER_PRIORITY, NULL );
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Create a string from an incrementing number. The length of the
|
||||
* string will increase and decrease as the value of the number increases
|
||||
* then overflows. */
|
||||
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||||
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||||
|
||||
do
|
||||
{
|
||||
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), xTicksToWait );
|
||||
} while( xBytesSent == 0 ); /* Buffer may become full when receiver is running at the idle priority. */
|
||||
|
||||
iDataToSend++;
|
||||
|
||||
if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )
|
||||
{
|
||||
/* Increment a loop counter so a check task can tell this task is
|
||||
* still running as expected. */
|
||||
ulSenderLoopCounters[ uxIndex ]++;
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )
|
||||
{
|
||||
/* Allow other tasks to run. */
|
||||
vTaskDelay( xShortDelay );
|
||||
}
|
||||
|
||||
/* This message buffer is just created and deleted to ensure no
|
||||
* issues when attempting to delete a message buffer that was
|
||||
* created using statically allocated memory. To save stack space
|
||||
* the buffer is set to point to the cTxString array - this is
|
||||
* ok because nothing is actually written to the memory. */
|
||||
xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer );
|
||||
vMessageBufferDelete( xTempMessageBuffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
static void prvReceiverTask( void * pvParameters )
|
||||
{
|
||||
MessageBufferHandle_t const pxMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||||
char cExpectedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
|
||||
char cReceivedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
|
||||
int32_t iExpectedData = 0;
|
||||
const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );
|
||||
size_t xReceivedBytes;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Generate the next expected string in the cExpectedString buffer. */
|
||||
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||||
sprintf( cExpectedString, "%d", ( int ) iExpectedData );
|
||||
|
||||
/* Receive the next string from the message buffer. */
|
||||
memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
|
||||
|
||||
do
|
||||
{
|
||||
xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );
|
||||
} while( xReceivedBytes == 0 );
|
||||
|
||||
/* Ensure the received string matches the expected string. */
|
||||
configASSERT( strcmp( cExpectedString, cReceivedString ) == 0 );
|
||||
|
||||
iExpectedData++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEchoClient( void * pvParameters )
|
||||
{
|
||||
size_t xSendLength = 0, ux;
|
||||
char * pcStringToSend, * pcStringReceived, cNextChar = mbASCII_SPACE;
|
||||
const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );
|
||||
|
||||
/* The task's priority is used as an index into the loop counters used to
|
||||
* indicate this task is still running. */
|
||||
UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
|
||||
|
||||
/* Pointers to the client and server message buffers are passed into this task
|
||||
* using the task's parameter. */
|
||||
EchoMessageBuffers_t * pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters;
|
||||
|
||||
/* Prevent compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Create the buffer into which strings to send to the server will be
|
||||
* created, and the buffer into which strings echoed back from the server will
|
||||
* be copied. */
|
||||
pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
|
||||
configASSERT( pcStringToSend );
|
||||
configASSERT( pcStringReceived );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Generate the length of the next string to send. */
|
||||
xSendLength++;
|
||||
|
||||
/* The message buffer is being used to hold variable length data, so
|
||||
* each data item requires sizeof( size_t ) bytes to hold the data's
|
||||
* length, hence the sizeof() in the if() condition below. */
|
||||
if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )
|
||||
{
|
||||
/* Back to a string length of 1. */
|
||||
xSendLength = sizeof( char );
|
||||
|
||||
/* Maintain a count of the number of times this code executes so a
|
||||
* check task can determine if this task is still functioning as
|
||||
* expected or not. As there are two client tasks, and the priorities
|
||||
* used are 0 and 1, the task's priority is used as an index into the
|
||||
* loop count array. */
|
||||
ulEchoLoopCounters[ uxIndex ]++;
|
||||
}
|
||||
|
||||
memset( pcStringToSend, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
|
||||
for( ux = 0; ux < xSendLength; ux++ )
|
||||
{
|
||||
pcStringToSend[ ux ] = cNextChar;
|
||||
|
||||
cNextChar++;
|
||||
|
||||
if( cNextChar > mbASCII_TILDA )
|
||||
{
|
||||
cNextChar = mbASCII_SPACE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the generated string to the buffer. */
|
||||
do
|
||||
{
|
||||
ux = xMessageBufferSend( pxMessageBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );
|
||||
|
||||
if( ux == 0 )
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
} while( ux == 0 );
|
||||
|
||||
/* Wait for the string to be echoed back. */
|
||||
memset( pcStringReceived, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
xMessageBufferReceive( pxMessageBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );
|
||||
|
||||
configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEchoServer( void * pvParameters )
|
||||
{
|
||||
MessageBufferHandle_t xTempMessageBuffer;
|
||||
size_t xReceivedLength;
|
||||
char * pcReceivedString;
|
||||
EchoMessageBuffers_t xMessageBuffers;
|
||||
TickType_t xTimeOnEntering;
|
||||
const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
|
||||
|
||||
/* Prevent compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Create the message buffer used to send data from the client to the server,
|
||||
* and the message buffer used to echo the data from the server back to the
|
||||
* client. */
|
||||
xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
configASSERT( xMessageBuffers.xEchoClientBuffer );
|
||||
configASSERT( xMessageBuffers.xEchoServerBuffer );
|
||||
|
||||
/* Create the buffer into which received strings will be copied. */
|
||||
pcReceivedString = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
configASSERT( pcReceivedString );
|
||||
|
||||
/* Don't expect to receive anything yet! */
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );
|
||||
configASSERT( ( ( TickType_t ) ( xTaskGetTickCount() - xTimeOnEntering ) ) >= xTicksToBlock );
|
||||
configASSERT( xReceivedLength == 0 );
|
||||
( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Now the message buffers have been created the echo client task can be
|
||||
* created. If this server task has the higher priority then the client task
|
||||
* is created at the lower priority - if this server task has the lower
|
||||
* priority then the client task is created at the higher priority. */
|
||||
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
|
||||
{
|
||||
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here prvSingleTaskTests() performs various tests on a message buffer
|
||||
* that was created dynamically. */
|
||||
prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer );
|
||||
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL );
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
memset( pcReceivedString, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
|
||||
/* Has any data been sent by the client? */
|
||||
xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, portMAX_DELAY );
|
||||
|
||||
/* Should always receive data as max delay was used. */
|
||||
configASSERT( xReceivedLength > 0 );
|
||||
|
||||
/* Echo the received data back to the client. */
|
||||
xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );
|
||||
|
||||
/* This message buffer is just created and deleted to ensure no memory
|
||||
* leaks. */
|
||||
xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||||
vMessageBufferDelete( xTempMessageBuffer );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Tests within configRUN_ADDITIONAL_TESTS blocks only execute on larger
|
||||
* platforms or have been added to pre-existing files that are already in use
|
||||
* by other test projects without ensuring they don't cause those pre-existing
|
||||
* projects to run out of program or data memory. */
|
||||
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||||
|
||||
static void prvSpaceAvailableCoherenceActor( void * pvParameters )
|
||||
{
|
||||
static char * cTxString = "12345";
|
||||
char cRxString[ mbCOHERENCE_TEST_BYTES_WRITTEN + 1 ]; /* +1 for NULL terminator. */
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Add bytes to the buffer so the other task should see
|
||||
* mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING bytes free. */
|
||||
xMessageBufferSend( xCoherenceTestMessageBuffer, ( void * ) cTxString, strlen( cTxString ), 0 );
|
||||
configASSERT( xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer ) == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING );
|
||||
|
||||
/* Read out message again so the other task should read the full
|
||||
* mbCOHERENCE_TEST_BUFFER_SIZE bytes free again. */
|
||||
memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) );
|
||||
xMessageBufferReceive( xCoherenceTestMessageBuffer, ( void * ) cRxString, mbCOHERENCE_TEST_BYTES_WRITTEN, 0 );
|
||||
configASSERT( strcmp( cTxString, cRxString ) == 0 );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSpaceAvailableCoherenceTester( void * pvParameters )
|
||||
{
|
||||
size_t xSpaceAvailable;
|
||||
BaseType_t xErrorFound = pdFALSE;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This message buffer is only ever empty or contains 5 bytes. So all
|
||||
* queries of its free space should result in one of the two values tested
|
||||
* below. */
|
||||
xSpaceAvailable = xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer );
|
||||
|
||||
if( ( xSpaceAvailable == mbCOHERENCE_TEST_BUFFER_SIZE ) ||
|
||||
( xSpaceAvailable == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ) )
|
||||
{
|
||||
/* Only continue to increment the variable that shows this task
|
||||
* is still executing if no errors have been found. */
|
||||
if( xErrorFound == pdFALSE )
|
||||
{
|
||||
ulSizeCoherencyTestCycles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xErrorFound = pdTRUE;
|
||||
}
|
||||
|
||||
configASSERT( xErrorFound == pdFALSE );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* configRUN_ADDITIONAL_TESTS == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreMessageBufferTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||||
static uint32_t ulLastNonBlockingRxCounter = 0;
|
||||
BaseType_t xReturn = pdPASS, x;
|
||||
|
||||
for( x = 0; x < mbNUMBER_OF_ECHO_CLIENTS; x++ )
|
||||
{
|
||||
if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];
|
||||
}
|
||||
}
|
||||
|
||||
if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;
|
||||
}
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static uint32_t ulLastSenderLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||||
|
||||
for( x = 0; x < mbNUMBER_OF_SENDER_TASKS; x++ )
|
||||
{
|
||||
if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||||
{
|
||||
static uint32_t ullastSizeCoherencyTestCycles = 0UL;
|
||||
|
||||
if( ullastSizeCoherencyTestCycles == ulSizeCoherencyTestCycles )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ullastSizeCoherencyTestCycles = ulSizeCoherencyTestCycles;
|
||||
}
|
||||
}
|
||||
#endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
222
SOFTWARE-FreeRTOS/Common/Minimal/PollQ.c
Normal file
222
SOFTWARE-FreeRTOS/Common/Minimal/PollQ.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version of PollQ. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes from V2.0.0
|
||||
*
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
+ TickType_t rather than uint32_t.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define pollqQUEUE_SIZE ( 10 )
|
||||
#define pollqPRODUCER_DELAY ( pdMS_TO_TICKS( ( TickType_t ) 200 ) )
|
||||
#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( TickType_t ) ( 20 / portTICK_PERIOD_MS ) )
|
||||
#define pollqNO_DELAY ( ( TickType_t ) 0 )
|
||||
#define pollqVALUES_TO_PRODUCE ( ( BaseType_t ) 3 )
|
||||
#define pollqINITIAL_VALUE ( ( BaseType_t ) 0 )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no
|
||||
* errors. */
|
||||
static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
static QueueHandle_t xPolledQueue;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
|
||||
if( xPolledQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
* in use. The queue registry is provided as a means for kernel aware
|
||||
* debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
* is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
* by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
* defined to be less than 1. */
|
||||
vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
|
||||
{
|
||||
uint16_t usValue = ( uint16_t ) 0;
|
||||
BaseType_t xError = pdFALSE, xLoop;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full so if we get here there
|
||||
* has been an error. */
|
||||
xError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
* check variable. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingProducerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
usValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
* empties the queue. */
|
||||
vTaskDelay( pollqPRODUCER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
|
||||
{
|
||||
uint16_t usData, usExpectedValue = ( uint16_t ) 0;
|
||||
BaseType_t xError = pdFALSE;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *( ( QueueHandle_t * ) pvParameters ) ) )
|
||||
{
|
||||
if( xQueueReceive( *( ( QueueHandle_t * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
* occurred. */
|
||||
xError = pdTRUE;
|
||||
|
||||
/* Catch-up to the value we received so our next expected
|
||||
* value should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
* occurred. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingConsumerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
/* Next time round we would expect the number to be one higher. */
|
||||
usExpectedValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
* items in the queue. */
|
||||
vTaskDelay( pollqCONSUMER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
BaseType_t xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* Check both the consumer and producer poll count to check they have both
|
||||
* been changed since out last trip round. We do not need a critical section
|
||||
* around the check variables as this is called from a higher priority than
|
||||
* the other tasks that access the same variables. */
|
||||
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
|
||||
( xPollingProducerCount == pollqINITIAL_VALUE )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the check variables back down so we know if they have been
|
||||
* incremented the next time around. */
|
||||
xPollingConsumerCount = pollqINITIAL_VALUE;
|
||||
xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
440
SOFTWARE-FreeRTOS/Common/Minimal/QPeek.c
Normal file
440
SOFTWARE-FreeRTOS/Common/Minimal/QPeek.c
Normal file
@ -0,0 +1,440 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the behaviour when data is peeked from a queue when there are
|
||||
* multiple tasks blocked on the queue.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "QPeek.h"
|
||||
|
||||
#define qpeekQUEUE_LENGTH ( 5 )
|
||||
#define qpeekNO_BLOCK ( 0 )
|
||||
#define qpeekSHORT_DELAY ( 10 )
|
||||
|
||||
#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
|
||||
#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the peeking behaviour.
|
||||
* Each task is given a different priority to demonstrate the order in which
|
||||
* tasks are woken as data is peeked from a queue.
|
||||
*/
|
||||
static void prvLowPriorityPeekTask( void * pvParameters );
|
||||
static void prvMediumPriorityPeekTask( void * pvParameters );
|
||||
static void prvHighPriorityPeekTask( void * pvParameters );
|
||||
static void prvHighestPriorityPeekTask( void * pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
* detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counter that is incremented on each cycle of a test. This is used to
|
||||
* detect a stalled task - a test that is no longer running. */
|
||||
static volatile uint32_t ulLoopCounter = 0;
|
||||
|
||||
/* Handles to the test tasks. */
|
||||
TaskHandle_t xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueuePeekTasks( void )
|
||||
{
|
||||
QueueHandle_t xQueue;
|
||||
|
||||
/* Create the queue that we are going to use for the test/demo. */
|
||||
xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
|
||||
if( xQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
* in use. The queue registry is provided as a means for kernel aware
|
||||
* debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
* is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
* by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
* defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" );
|
||||
|
||||
/* Create the demo tasks and pass it the queue just created. We are
|
||||
* passing the queue handle by value so it does not matter that it is declared
|
||||
* on the stack here. */
|
||||
xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
|
||||
xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
|
||||
xTaskCreate( prvHighestPriorityPeekTask, "PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighestPriorityPeekTask( void * pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
{
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Queue peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
* block, allowing the high priority task to execute. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we reach here the high and medium priority tasks should still
|
||||
* be blocked on the queue. We unblocked because the low priority task
|
||||
* wrote a value to the queue, which we should have peeked. Peeking the
|
||||
* data (rather than receiving it) will leave the data on the queue, so
|
||||
* the high priority task should then have also been unblocked, but not
|
||||
* yet executed. */
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we are going to actually receive the data, so when the high
|
||||
* priority task runs it will find the queue empty and return to the
|
||||
* blocked state. */
|
||||
ulValue = 0;
|
||||
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value - which should have been
|
||||
* the same value as was peeked. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we will block again as the queue is once more empty. The low
|
||||
* priority task can then execute again. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the low priority task should have again written to the
|
||||
* queue. */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
* the high priority task to also peek the data. The high priority task
|
||||
* will have been unblocked when we peeked the data as we left the data
|
||||
* in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* This time we are going to do the same as the above test, but the
|
||||
* high priority task is going to receive the data, rather than peek it.
|
||||
* This means that the medium priority task should never peek the value. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityPeekTask( void * pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
* block, allowing the medium priority task to execute. Both the high
|
||||
* and highest priority tasks will then be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the highest priority task should have peeked the data
|
||||
* (unblocking this task) then suspended (allowing this task to also peek
|
||||
* the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
* the medium priority task to also peek the data. The medium priority task
|
||||
* will have been unblocked when we peeked the data as we left the data
|
||||
* in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* This time we are going actually receive the value, so the medium
|
||||
* priority task will never peek the data - we removed it from the queue. */
|
||||
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityPeekTask( void * pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
* block, allowing the low priority task to execute. The highest, high
|
||||
* and medium priority tasks will then all be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the high priority task should have peeked the data
|
||||
* (unblocking this task) then suspended (allowing this task to also peek
|
||||
* the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Just so we know the test is still running. */
|
||||
ulLoopCounter++;
|
||||
|
||||
/* Now we can suspend ourselves so the low priority task can execute
|
||||
* again. */
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityPeekTask( void * pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Write some data to the queue. This should unblock the highest
|
||||
* priority task that is waiting to peek data from the queue. */
|
||||
ulValue = 0x11223344;
|
||||
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
* had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* By the time we get here the data should have been removed from
|
||||
* the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Write another value to the queue, again waking the highest priority
|
||||
* task that is blocked on the queue. */
|
||||
ulValue = 0x01234567;
|
||||
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
* had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* All the other tasks should now have successfully peeked the data.
|
||||
* The data is still in the queue so we should be able to receive it. */
|
||||
ulValue = 0;
|
||||
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
* want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
|
||||
/* Unsuspend the other tasks so we can repeat the test - this time
|
||||
* however not all the other tasks will peek the data as the high
|
||||
* priority task is actually going to remove it from the queue. Send
|
||||
* to front is used just to be different. As the queue is empty it
|
||||
* makes no difference to the result. */
|
||||
vTaskResume( xMediumPriorityTask );
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
ulValue = 0xaabbaabb;
|
||||
|
||||
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
* had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* This time we should find that the queue is empty. The high priority
|
||||
* task actually removed the data rather than just peeking it. */
|
||||
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Unsuspend the highest and high priority tasks so we can go back
|
||||
* and repeat the whole thing. The medium priority task should not be
|
||||
* suspended as it was not able to peek the data in this last case. */
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
* want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreQueuePeekTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastLoopCounter = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loopcounter to
|
||||
* have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
* to true. */
|
||||
|
||||
return ( BaseType_t ) !xErrorDetected;
|
||||
}
|
235
SOFTWARE-FreeRTOS/Common/Minimal/QueueOverwrite.c
Normal file
235
SOFTWARE-FreeRTOS/Common/Minimal/QueueOverwrite.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic task to demonstrate the xQueueOverwrite() function. See the comments
|
||||
* in the function itself.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "QueueOverwrite.h"
|
||||
|
||||
/* A block time of 0 just means "don't block". */
|
||||
#define qoDONT_BLOCK 0
|
||||
|
||||
/* Number of times to overwrite the value in the queue. */
|
||||
#define qoLOOPS 5
|
||||
|
||||
/* The task that uses the queue. */
|
||||
static void prvQueueOverwriteTask( void * pvParameters );
|
||||
|
||||
/* Variable that is incremented on each loop of prvQueueOverwriteTask() provided
|
||||
* prvQueueOverwriteTask() has not found any errors. */
|
||||
static uint32_t ulLoopCounter = 0;
|
||||
|
||||
/* Set to pdFALSE if an error is discovered by the
|
||||
* vQueueOverwritePeriodicISRDemo() function. */
|
||||
static BaseType_t xISRTestStatus = pdPASS;
|
||||
|
||||
/* The queue that is accessed from the ISR. The queue accessed by the task is
|
||||
* created inside the task itself. */
|
||||
static QueueHandle_t xISRQueue = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueOverwriteTask( UBaseType_t uxPriority )
|
||||
{
|
||||
const UBaseType_t uxQueueLength = 1;
|
||||
|
||||
/* Create the queue used by the ISR. xQueueOverwriteFromISR() should only
|
||||
* be used on queues that have a length of 1. */
|
||||
xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
|
||||
|
||||
/* Create the test task. The queue used by the test task is created inside
|
||||
* the task itself. */
|
||||
xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueOverwriteTask( void * pvParameters )
|
||||
{
|
||||
QueueHandle_t xTaskQueue;
|
||||
const UBaseType_t uxQueueLength = 1;
|
||||
uint32_t ulValue, ulStatus = pdPASS, x;
|
||||
|
||||
/* The parameter is not used. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Create the queue. xQueueOverwrite() should only be used on queues that
|
||||
* have a length of 1. */
|
||||
xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
|
||||
configASSERT( xTaskQueue );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* The queue is empty. Writing to the queue then reading from the queue
|
||||
* should return the item written. */
|
||||
ulValue = 10;
|
||||
xQueueOverwrite( xTaskQueue, &ulValue );
|
||||
|
||||
ulValue = 0;
|
||||
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
|
||||
if( ulValue != 10 )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Now try writing to the queue several times. Each time the value
|
||||
* in the queue should get overwritten. */
|
||||
for( x = 0; x < qoLOOPS; x++ )
|
||||
{
|
||||
/* Write to the queue. */
|
||||
xQueueOverwrite( xTaskQueue, &x );
|
||||
|
||||
/* Check the value in the queue is that written, even though the
|
||||
* queue was not necessarily empty. */
|
||||
xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
|
||||
if( ulValue != x )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* There should always be one item in the queue. */
|
||||
if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty the queue again. */
|
||||
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xTaskQueue ) != 0 )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( ulStatus != pdFAIL )
|
||||
{
|
||||
/* Increment a counter to show this task is still running without
|
||||
* error. */
|
||||
ulLoopCounter++;
|
||||
}
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xIsQueueOverwriteTaskStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( xISRTestStatus != pdPASS )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else if( ulLoopCounter > 0 )
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task has either stalled of discovered an error. */
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLoopCounter = 0;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueOverwritePeriodicISRDemo( void )
|
||||
{
|
||||
static uint32_t ulCallCount = 0;
|
||||
const uint32_t ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL;
|
||||
uint32_t ulRx;
|
||||
|
||||
/* This function should be called from an interrupt, such as the tick hook
|
||||
* function vApplicationTickHook(). */
|
||||
|
||||
configASSERT( xISRQueue );
|
||||
|
||||
switch( ulCallCount )
|
||||
{
|
||||
case 0:
|
||||
|
||||
/* The queue is empty. Write ulTx1 to the queue. In this demo the
|
||||
* last parameter is not used because there are no tasks blocked on
|
||||
* this queue. */
|
||||
xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
|
||||
|
||||
/* Peek the queue to check it holds the expected value. */
|
||||
xQueuePeekFromISR( xISRQueue, &ulRx );
|
||||
|
||||
if( ulRx != ulTx1 )
|
||||
{
|
||||
xISRTestStatus = pdFAIL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
/* The queue already holds ulTx1. Overwrite the value in the queue
|
||||
* with ulTx2. */
|
||||
xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
/* Read from the queue to empty the queue again. The value read
|
||||
* should be ulTx2. */
|
||||
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL );
|
||||
|
||||
if( ulRx != ulTx2 )
|
||||
{
|
||||
xISRTestStatus = pdFAIL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Run the next case in the switch statement above next time this function
|
||||
* is called. */
|
||||
ulCallCount++;
|
||||
|
||||
if( ulCallCount >= ulNumberOfSwitchCases )
|
||||
{
|
||||
/* Go back to the start. */
|
||||
ulCallCount = 0;
|
||||
}
|
||||
}
|
1160
SOFTWARE-FreeRTOS/Common/Minimal/QueueSet.c
Normal file
1160
SOFTWARE-FreeRTOS/Common/Minimal/QueueSet.c
Normal file
File diff suppressed because it is too large
Load Diff
182
SOFTWARE-FreeRTOS/Common/Minimal/QueueSetPolling.c
Normal file
182
SOFTWARE-FreeRTOS/Common/Minimal/QueueSetPolling.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tests the use of queue sets.
|
||||
*
|
||||
* A receive task creates a number of queues and adds them to a queue set before
|
||||
* blocking on the queue set receive. A transmit task and (optionally) an
|
||||
* interrupt repeatedly unblocks the receive task by sending messages to the
|
||||
* queues in a pseudo random order. The receive task removes the messages from
|
||||
* the queues and flags an error if the received message does not match that
|
||||
* expected. The task sends values in the range 0 to
|
||||
* queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range
|
||||
* queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX.
|
||||
*/
|
||||
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "QueueSetPolling.h"
|
||||
|
||||
#if ( configUSE_QUEUE_SETS == 1 ) /* Remove tests if queue sets are not defined. */
|
||||
|
||||
/* The length of each created queue. */
|
||||
#define setpollQUEUE_LENGTH 10
|
||||
|
||||
/* Block times used in this demo. A block time or 0 means "don't block". */
|
||||
#define setpollDONT_BLOCK 0
|
||||
|
||||
/* The ISR sends to the queue every setpollISR_TX_PERIOD ticks. */
|
||||
#define queuesetISR_TX_PERIOD ( 50UL )
|
||||
|
||||
/*
|
||||
* The task that reads from the queue set.
|
||||
*/
|
||||
static void prvQueueSetReceivingTask( void * pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue that is added to the set. */
|
||||
static QueueHandle_t xQueue = NULL;
|
||||
|
||||
/* The handle of the queue set to which the queue is added. */
|
||||
static QueueSetHandle_t xQueueSet = NULL;
|
||||
|
||||
/* Set to pdFAIL if an error is detected by any queue set task.
|
||||
* ulCycleCounter will only be incremented if xQueueSetTasksStatus equals pdPASS. */
|
||||
static volatile BaseType_t xQueueSetPollStatus = pdPASS;
|
||||
|
||||
/* Counter used to ensure the task is still running. */
|
||||
static uint32_t ulCycleCounter = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueSetPollingTask( void )
|
||||
{
|
||||
/* Create the queue that is added to the set, the set, and add the queue to
|
||||
* the set. */
|
||||
xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH );
|
||||
|
||||
if( ( xQueue != NULL ) && ( xQueueSet != NULL ) )
|
||||
{
|
||||
xQueueAddToSet( xQueue, xQueueSet );
|
||||
|
||||
/* Create the task. */
|
||||
xTaskCreate( prvQueueSetReceivingTask, "SetPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetReceivingTask( void * pvParameters )
|
||||
{
|
||||
uint32_t ulReceived, ulExpected = 0;
|
||||
QueueHandle_t xActivatedQueue;
|
||||
|
||||
/* Remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Is a message waiting? A block time is not used to ensure the queue
|
||||
* set is polled while it is being written to from an interrupt. */
|
||||
xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK );
|
||||
|
||||
if( xActivatedQueue != NULL )
|
||||
{
|
||||
/* Reading from the queue should pass with a zero block time as
|
||||
* this task will only run when something has been posted to a task
|
||||
* in the queue set. */
|
||||
if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( ulReceived == ulExpected )
|
||||
{
|
||||
ulExpected++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( xQueueSetPollStatus == pdPASS )
|
||||
{
|
||||
ulCycleCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueSetPollingInterruptAccess( void )
|
||||
{
|
||||
static uint32_t ulCallCount = 0, ulValueToSend = 0;
|
||||
|
||||
/* It is intended that this function is called from the tick hook
|
||||
* function, so each call is one tick period apart. */
|
||||
ulCallCount++;
|
||||
|
||||
if( ulCallCount > queuesetISR_TX_PERIOD )
|
||||
{
|
||||
ulCallCount = 0;
|
||||
|
||||
if( xQueueSendFromISR( xQueue, ( void * ) &ulValueToSend, NULL ) == pdPASS )
|
||||
{
|
||||
/* Send the next value next time. */
|
||||
ulValueToSend++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreQueueSetPollTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastCycleCounter = 0;
|
||||
|
||||
if( ulLastCycleCounter == ulCycleCounter )
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastCycleCounter = ulCycleCounter;
|
||||
|
||||
return xQueueSetPollStatus;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
#endif /* ( configUSE_QUEUE_SETS == 1 ) */
|
1113
SOFTWARE-FreeRTOS/Common/Minimal/StaticAllocation.c
Normal file
1113
SOFTWARE-FreeRTOS/Common/Minimal/StaticAllocation.c
Normal file
File diff suppressed because it is too large
Load Diff
1247
SOFTWARE-FreeRTOS/Common/Minimal/StreamBufferDemo.c
Normal file
1247
SOFTWARE-FreeRTOS/Common/Minimal/StreamBufferDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
228
SOFTWARE-FreeRTOS/Common/Minimal/StreamBufferInterrupt.c
Normal file
228
SOFTWARE-FreeRTOS/Common/Minimal/StreamBufferInterrupt.c
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* A simple example that shows a stream buffer being used to pass data from an
|
||||
* interrupt to a task.
|
||||
*
|
||||
* There are two strings, pcStringToSend and pcStringToReceive, where
|
||||
* pcStringToReceive is a substring of pcStringToSend. The interrupt sends
|
||||
* a few bytes of pcStringToSend to a stream buffer ever few times that it
|
||||
* executes. A task reads the bytes from the stream buffer, looking for the
|
||||
* substring, and flagging an error if the received data is invalid.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "stream_buffer.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "StreamBufferInterrupt.h"
|
||||
|
||||
#define sbiSTREAM_BUFFER_LENGTH_BYTES ( ( size_t ) 100 )
|
||||
#define sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 ( ( BaseType_t ) 10 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Implements the task that receives a stream of bytes from the interrupt. */
|
||||
static void prvReceivingTask( void * pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The stream buffer that is used to send data from an interrupt to the task. */
|
||||
static StreamBufferHandle_t xStreamBuffer = NULL;
|
||||
|
||||
/* The string that is sent from the interrupt to the task four bytes at a
|
||||
* time. Must be multiple of 4 bytes long as the ISR sends 4 bytes at a time*/
|
||||
static const char * pcStringToSend = "_____Hello FreeRTOS_____";
|
||||
|
||||
/* The string to task is looking for, which must be a substring of
|
||||
* pcStringToSend. */
|
||||
static const char * pcStringToReceive = "Hello FreeRTOS";
|
||||
|
||||
/* Set to pdFAIL if anything unexpected happens. */
|
||||
static BaseType_t xDemoStatus = pdPASS;
|
||||
|
||||
/* Incremented each time pcStringToReceive is correctly received, provided no
|
||||
* errors have occurred. Used so the check task can check this task is still
|
||||
* running as expected. */
|
||||
static uint32_t ulCycleCount = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartStreamBufferInterruptDemo( void )
|
||||
{
|
||||
/* Create the stream buffer that sends data from the interrupt to the
|
||||
* task, and create the task. */
|
||||
xStreamBuffer = xStreamBufferCreate( /* The buffer length in bytes. */
|
||||
sbiSTREAM_BUFFER_LENGTH_BYTES,
|
||||
/* The stream buffer's trigger level. */
|
||||
sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 );
|
||||
|
||||
xTaskCreate( prvReceivingTask, /* The function that implements the task. */
|
||||
"StrIntRx", /* Human readable name for the task. */
|
||||
configMINIMAL_STACK_SIZE, /* Stack size (in words!). */
|
||||
NULL, /* Task parameter is not used. */
|
||||
tskIDLE_PRIORITY + 2, /* The priority at which the task is created. */
|
||||
NULL ); /* No use for the task handle. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvReceivingTask( void * pvParameters )
|
||||
{
|
||||
char cRxBuffer[ 20 ];
|
||||
BaseType_t xNextByte = 0;
|
||||
|
||||
/* Remove warning about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the string will fit in the Rx buffer, including the NULL
|
||||
* terminator. */
|
||||
configASSERT( sizeof( cRxBuffer ) > strlen( pcStringToReceive ) );
|
||||
|
||||
/* Make sure the stream buffer has been created. */
|
||||
configASSERT( xStreamBuffer != NULL );
|
||||
|
||||
/* Start with the Rx buffer in a known state. */
|
||||
memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Keep receiving characters until the end of the string is received.
|
||||
* Note: An infinite block time is used to simplify the example. Infinite
|
||||
* block times are not recommended in production code as they do not allow
|
||||
* for error recovery. */
|
||||
xStreamBufferReceive( /* The stream buffer data is being received from. */
|
||||
xStreamBuffer,
|
||||
/* Where to place received data. */
|
||||
( void * ) &( cRxBuffer[ xNextByte ] ),
|
||||
/* The number of bytes to receive. */
|
||||
sizeof( char ),
|
||||
|
||||
/* The time to wait for the next data if the buffer
|
||||
* is empty. */
|
||||
portMAX_DELAY );
|
||||
|
||||
/* If xNextByte is 0 then this task is looking for the start of the
|
||||
* string, which is 'H'. */
|
||||
if( xNextByte == 0 )
|
||||
{
|
||||
if( cRxBuffer[ xNextByte ] == 'H' )
|
||||
{
|
||||
/* The start of the string has been found. Now receive
|
||||
* characters until the end of the string is found. */
|
||||
xNextByte++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Receiving characters while looking for the end of the string,
|
||||
* which is an 'S'. */
|
||||
if( cRxBuffer[ xNextByte ] == 'S' )
|
||||
{
|
||||
/* The string has now been received. Check its validity. */
|
||||
if( strcmp( cRxBuffer, pcStringToReceive ) != 0 )
|
||||
{
|
||||
xDemoStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Return to start looking for the beginning of the string
|
||||
* again. */
|
||||
memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) );
|
||||
xNextByte = 0;
|
||||
|
||||
/* Increment the cycle count as an indication to the check task
|
||||
* that this demo is still running. */
|
||||
if( xDemoStatus == pdPASS )
|
||||
{
|
||||
ulCycleCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Receive the next character the next time around, while
|
||||
* continuing to look for the end of the string. */
|
||||
xNextByte++;
|
||||
|
||||
configASSERT( ( size_t ) xNextByte < sizeof( cRxBuffer ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vBasicStreamBufferSendFromISR( void )
|
||||
{
|
||||
static size_t xNextByteToSend = 0;
|
||||
const BaseType_t xCallsBetweenSends = 100, xBytesToSend = 4;
|
||||
static BaseType_t xCallCount = 0;
|
||||
|
||||
/* Is it time to write to the stream buffer again? */
|
||||
xCallCount++;
|
||||
|
||||
if( xCallCount > xCallsBetweenSends )
|
||||
{
|
||||
xCallCount = 0;
|
||||
|
||||
/* Send the next four bytes to the stream buffer. */
|
||||
xStreamBufferSendFromISR( xStreamBuffer,
|
||||
( const void * ) ( pcStringToSend + xNextByteToSend ),
|
||||
xBytesToSend,
|
||||
NULL );
|
||||
|
||||
/* Send the next four bytes the next time around, wrapping to the start
|
||||
* of the string if necessary. */
|
||||
xNextByteToSend += xBytesToSend;
|
||||
|
||||
if( xNextByteToSend >= strlen( pcStringToSend ) )
|
||||
{
|
||||
xNextByteToSend = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xIsInterruptStreamBufferDemoStillRunning( void )
|
||||
{
|
||||
uint32_t ulLastCycleCount = 0;
|
||||
|
||||
/* Check the demo is still running. */
|
||||
if( ulLastCycleCount == ulCycleCount )
|
||||
{
|
||||
xDemoStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastCycleCount = ulCycleCount;
|
||||
}
|
||||
|
||||
return xDemoStatus;
|
||||
}
|
720
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotify.c
Normal file
720
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotify.c
Normal file
@ -0,0 +1,720 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the behaviour of direct task notifications.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <limits.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "TaskNotify.h"
|
||||
|
||||
/* Allow parameters to be overridden on a demo by demo basis. */
|
||||
#ifndef notifyNOTIFIED_TASK_STACK_SIZE
|
||||
#define notifyNOTIFIED_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#endif
|
||||
|
||||
#define notifyTASK_PRIORITY ( tskIDLE_PRIORITY )
|
||||
|
||||
/* Constants used in tests when setting/clearing bits. */
|
||||
#define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff )
|
||||
#define notifyUINT32_HIGH_BYTE ( ( uint32_t ) 0xff000000 )
|
||||
#define notifyUINT32_LOW_BYTE ( ( uint32_t ) 0x000000ff )
|
||||
|
||||
#define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Implementation of the task that gets notified.
|
||||
*/
|
||||
static void prvNotifiedTask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Performs a few initial tests that can be done prior to creating the second
|
||||
* task.
|
||||
*/
|
||||
static void prvSingleTaskTests( void );
|
||||
|
||||
/*
|
||||
* Software timer callback function from which xTaskNotify() is called.
|
||||
*/
|
||||
static void prvNotifyingTimer( TimerHandle_t xTimer );
|
||||
|
||||
/*
|
||||
* Utility function to create pseudo random numbers.
|
||||
*/
|
||||
static UBaseType_t prvRand( void );
|
||||
|
||||
/*
|
||||
* Callback for a timer that is used during preliminary testing. The timer
|
||||
* tests the behaviour when 1: a task waiting for a notification is suspended
|
||||
* and then resumed without ever receiving a notification, and 2: when a task
|
||||
* waiting for a notification receives a notification while it is suspended.
|
||||
*/
|
||||
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Used to latch errors during the test's execution. */
|
||||
static BaseType_t xErrorStatus = pdPASS;
|
||||
|
||||
/* Used to ensure the task has not stalled. */
|
||||
static volatile uint32_t ulNotifyCycleCount = 0;
|
||||
|
||||
/* The handle of the task that receives the notifications. */
|
||||
static TaskHandle_t xTaskToNotify = NULL;
|
||||
|
||||
/* Used to count the notifications sent to the task from a software timer and
|
||||
* the number of notifications received by the task from the software timer. The
|
||||
* two should stay synchronised. */
|
||||
static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
|
||||
|
||||
/* The timer used to notify the task. */
|
||||
static TimerHandle_t xTimer = NULL;
|
||||
|
||||
/* Used by the pseudo random number generating function. */
|
||||
static size_t uxNextRand = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartTaskNotifyTask( void )
|
||||
{
|
||||
/* Create the task that performs some tests by itself, then loops around
|
||||
* being notified by both a software timer and an interrupt. */
|
||||
xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
|
||||
"Notified", /* Text name for the task - for debugging only - not used by the kernel. */
|
||||
notifyNOTIFIED_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
|
||||
NULL, /* Task parameter, not used in this case. */
|
||||
notifyTASK_PRIORITY, /* Task priority, 0 is the lowest. */
|
||||
&xTaskToNotify ); /* Used to pass a handle to the task out is needed, otherwise set to NULL. */
|
||||
|
||||
/* Pseudo seed the random number generator. */
|
||||
uxNextRand = ( size_t ) prvRand;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSingleTaskTests( void )
|
||||
{
|
||||
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
|
||||
BaseType_t xReturned;
|
||||
uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;
|
||||
TickType_t xTimeOnEntering;
|
||||
const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
|
||||
const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
|
||||
TimerHandle_t xSingleTaskTimer;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Check blocking when there are no notifications. */
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Should have blocked for the entire block time. */
|
||||
if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
configASSERT( ulNotifiedValue == 0UL );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Check no blocking when notifications are pending. First notify itself -
|
||||
* this would not be a normal thing to do and is done here for test purposes
|
||||
* only. */
|
||||
xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||||
|
||||
/* Even through the 'without overwrite' action was used the update should
|
||||
* have been successful. */
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* No bits should have been pending previously. */
|
||||
configASSERT( ulPreviousValue == 0 );
|
||||
( void ) ulPreviousValue;
|
||||
|
||||
/* The task should now have a notification pending, and so not time out. */
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||||
|
||||
if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The task should have been notified, and the notified value should
|
||||
* be equal to ulFirstNotifiedConst. */
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Check the non-overwriting functionality. The notification is done twice
|
||||
* using two different notification values. The action says don't overwrite so
|
||||
* only the first notification should pass and the value read back should also
|
||||
* be that used with the first notification. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Waiting for the notification should now return immediately so a block
|
||||
* time of zero is used. */
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Do the same again, only this time use the overwriting version. This time
|
||||
* both notifications should pass, and the value written the second time should
|
||||
* overwrite the value written the first time, and so be the value that is read
|
||||
* back. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Check notifications with no action pass without updating the value. Even
|
||||
* though ulFirstNotifiedConst is used as the value the value read back should
|
||||
* remain at ulSecondNotifiedConst. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||||
( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Check incrementing values. Send ulMaxLoop increment notifications, then
|
||||
* ensure the received value is as expected - which should be
|
||||
* ulSecondNotificationValueConst plus how ever many times to loop iterated. */
|
||||
for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
|
||||
{
|
||||
xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
}
|
||||
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
/* Should not be any notifications pending now. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
( void ) ulNotifiedValue;
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Check all bits can be set by notifying the task with one additional bit set
|
||||
* on each notification, and exiting the loop when all the bits are found to be
|
||||
* set. As there are 32-bits the loop should execute 32 times before all the
|
||||
* bits are found to be set. */
|
||||
ulNotifyingValue = 0x01;
|
||||
ulLoop = 0;
|
||||
|
||||
/* Start with all bits clear. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
do
|
||||
{
|
||||
/* Set the next bit in the task's notified value. */
|
||||
xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
|
||||
|
||||
/* Wait for the notified value - which of course will already be
|
||||
* available. Don't clear the bits on entry or exit as this loop is exited
|
||||
* when all the bits are set. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
ulLoop++;
|
||||
|
||||
/* Use the next bit on the next iteration around this loop. */
|
||||
ulNotifyingValue <<= 1UL;
|
||||
} while( ulNotifiedValue != notifyUINT32_MAX );
|
||||
|
||||
/* As a 32-bit value was used the loop should have executed 32 times before
|
||||
* all the bits were set. */
|
||||
configASSERT( ulLoop == 32 );
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Check bits are cleared on entry but not on exit when a notification fails
|
||||
* to arrive before timing out - both with and without a timeout value. Wait
|
||||
* for the notification again - but this time it is not given by anything and
|
||||
* should return pdFAIL. The parameters are set to clear bit zero on entry and
|
||||
* bit one on exit. As no notification was received only the bit cleared on
|
||||
* entry should actually get cleared. */
|
||||
xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Notify the task with no action so as not to update the bits even though
|
||||
* notifyUINT32_MAX is used as the notification value. */
|
||||
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
|
||||
|
||||
/* Reading back the value should should find bit 0 is clear, as this was
|
||||
* cleared on entry, but bit 1 is not clear as it will not have been cleared on
|
||||
* exit as no notification was received. */
|
||||
xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Now try clearing the bit on exit. For that to happen a notification must be
|
||||
* received, so the task is notified first. */
|
||||
xTaskNotify( xTaskToNotify, 0, eNoAction );
|
||||
xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
|
||||
|
||||
/* However as the bit is cleared on exit, after the returned notification
|
||||
* value is set, the returned notification value should not have the bit
|
||||
* cleared... */
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||||
|
||||
/* ...but reading the value back again should find that the bit was indeed
|
||||
* cleared internally. The returned value should be pdFAIL however as nothing
|
||||
* has notified the task in the mean time. */
|
||||
xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Now try querying the previous value while notifying a task. */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||||
|
||||
/* Clear all bits. */
|
||||
xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
|
||||
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulPreviousValue == 0 );
|
||||
|
||||
ulExpectedValue = 0;
|
||||
|
||||
for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
|
||||
{
|
||||
/* Set the next bit up, and expect to receive the last bits set (so
|
||||
* the previous value will not yet have the bit being set this time
|
||||
* around). */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulExpectedValue == ulPreviousValue );
|
||||
ulExpectedValue |= ulLoop;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Clear the previous notifications. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
/* The task should not have any notifications pending, so an attempt to clear
|
||||
* the notification state should fail. */
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
|
||||
|
||||
/* Get the task to notify itself. This is not a normal thing to do, and is
|
||||
* only done here for test purposes. */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||||
|
||||
/* Now the notification state should be eNotified, so it should now be
|
||||
* possible to clear the notification state. */
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Clear bits in the notification value. */
|
||||
|
||||
/* Get the task to set all bits its own notification value. This is not a
|
||||
* normal thing to do, and is only done here for test purposes. */
|
||||
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eSetBits );
|
||||
|
||||
/* Now clear the top bytes - the returned value from the first call should
|
||||
* indicate that previously all bits were set. */
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX );
|
||||
|
||||
/* Next clear the bottom bytes - the returned value this time should indicate
|
||||
* that the top byte was clear (before the bottom byte was cleared. */
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) );
|
||||
|
||||
/* Next clear all bytes - the returned value should indicate that previously the
|
||||
* high and low bytes were clear. */
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
|
||||
|
||||
/* Now all bits should be clear. */
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, 0UL ) == 0 );
|
||||
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
|
||||
|
||||
/* Now the notification state should be eNotified, so it should now be
|
||||
* possible to clear the notification state. */
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Create a timer that will try notifying this task while it is suspended. */
|
||||
xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
|
||||
configASSERT( xSingleTaskTimer );
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
/* Ensure no notifications are pending. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
|
||||
|
||||
/* Raise the task's priority so it can suspend itself before the timer
|
||||
* expires. */
|
||||
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||||
|
||||
/* Start the timer that will try notifying this task while it is
|
||||
* suspended, then wait for a notification. The first time the callback
|
||||
* executes the timer will suspend the task, then resume the task, without
|
||||
* ever sending a notification to the task. */
|
||||
ulNotifiedValue = 0;
|
||||
xTimerStart( xSingleTaskTimer, portMAX_DELAY );
|
||||
|
||||
/* Check a notification is not received. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
|
||||
configASSERT( xReturned == pdFALSE );
|
||||
configASSERT( ulNotifiedValue == 0 );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
/* Start the timer that will try notifying this task while it is
|
||||
* suspended, then wait for a notification. The second time the callback
|
||||
* executes the timer will suspend the task, notify the task, then resume the
|
||||
* task (previously it was suspended and resumed without being notified). */
|
||||
xTimerStart( xSingleTaskTimer, portMAX_DELAY );
|
||||
|
||||
/* Check a notification is received. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||||
configASSERT( ulNotifiedValue != 0 );
|
||||
|
||||
/* Return the task to its proper priority and delete the timer as it is
|
||||
* not used again. */
|
||||
vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
|
||||
xTimerDelete( xSingleTaskTimer, portMAX_DELAY );
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
/* Leave all bits cleared. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )
|
||||
{
|
||||
static uint32_t ulCallCount = 0;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) xExpiredTimer;
|
||||
|
||||
/* Callback for a timer that is used during preliminary testing. The timer
|
||||
* tests the behaviour when 1: a task waiting for a notification is suspended
|
||||
* and then resumed without ever receiving a notification, and 2: when a task
|
||||
* waiting for a notification receives a notification while it is suspended. */
|
||||
|
||||
if( ulCallCount == 0 )
|
||||
{
|
||||
vTaskSuspend( xTaskToNotify );
|
||||
configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
|
||||
vTaskResume( xTaskToNotify );
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskSuspend( xTaskToNotify );
|
||||
|
||||
/* Sending a notification while the task is suspended should pass, but
|
||||
* not cause the task to resume. ulCallCount is just used as a convenient
|
||||
* non-zero value. */
|
||||
xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );
|
||||
|
||||
/* Make sure giving the notification didn't resume the task. */
|
||||
configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
|
||||
|
||||
vTaskResume( xTaskToNotify );
|
||||
}
|
||||
|
||||
ulCallCount++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNotifyingTimer( TimerHandle_t xNotUsed )
|
||||
{
|
||||
( void ) xNotUsed;
|
||||
|
||||
xTaskNotifyGive( xTaskToNotify );
|
||||
|
||||
/* This value is also incremented from an interrupt. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
ulTimerNotificationsSent++;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNotifiedTask( void * pvParameters )
|
||||
{
|
||||
const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
|
||||
TickType_t xPeriod;
|
||||
const uint32_t ulCyclesToRaisePriority = 50UL;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Run a few tests that can be done from a single task before entering the
|
||||
* main loop. */
|
||||
prvSingleTaskTests();
|
||||
|
||||
/* Create the software timer that is used to send notifications to this
|
||||
* task. Notifications are also received from an interrupt. */
|
||||
xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Start the timer again with a different period. Sometimes the period
|
||||
* will be higher than the task's block time, sometimes it will be lower
|
||||
* than the task's block time. */
|
||||
xPeriod = prvRand() % xMaxPeriod;
|
||||
|
||||
if( xPeriod < xMinPeriod )
|
||||
{
|
||||
xPeriod = xMinPeriod;
|
||||
}
|
||||
|
||||
/* Change the timer period and start the timer. */
|
||||
xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
|
||||
|
||||
/* Block waiting for the notification again with a different period.
|
||||
* Sometimes the period will be higher than the task's block time,
|
||||
* sometimes it will be lower than the task's block time. */
|
||||
xPeriod = prvRand() % xMaxPeriod;
|
||||
|
||||
if( xPeriod < xMinPeriod )
|
||||
{
|
||||
xPeriod = xMinPeriod;
|
||||
}
|
||||
|
||||
/* Block to wait for a notification but without clearing the
|
||||
* notification count, so only add one to the count of received
|
||||
* notifications as any other notifications will remain pending. */
|
||||
if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
|
||||
{
|
||||
ulTimerNotificationsReceived++;
|
||||
}
|
||||
|
||||
/* Take a notification without clearing again, but this time without a
|
||||
* block time specified. */
|
||||
if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
|
||||
{
|
||||
ulTimerNotificationsReceived++;
|
||||
}
|
||||
|
||||
/* Wait for the next notification from the timer, clearing all
|
||||
* notifications if one is received, so this time adding the total number
|
||||
* of notifications that were pending as none will be left pending after
|
||||
* the function call. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
|
||||
|
||||
/* Occasionally raise the priority of the task being notified to test
|
||||
* the path where the task is notified from an ISR and becomes the highest
|
||||
* priority ready state task, but the pxHigherPriorityTaskWoken parameter
|
||||
* is NULL (which it is in the tick hook that sends notifications to this
|
||||
* task). */
|
||||
if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
|
||||
{
|
||||
vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
|
||||
|
||||
/* Wait for the next notification again, clearing all notifications
|
||||
* if one is received, but this time blocking indefinitely. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
|
||||
/* Reset the priority. */
|
||||
vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for the next notification again, clearing all notifications
|
||||
* if one is received, but this time blocking indefinitely. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
}
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void xNotifyTaskFromISR( void )
|
||||
{
|
||||
static BaseType_t xCallCount = 0, xAPIToUse = 0;
|
||||
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
|
||||
uint32_t ulPreviousValue;
|
||||
const uint32_t ulUnexpectedValue = 0xff;
|
||||
|
||||
/* Check the task notification demo tasks were actually created. */
|
||||
configASSERT( xTaskToNotify );
|
||||
|
||||
/* The task performs some tests before starting the timer that gives the
|
||||
* notification from this interrupt. If the timer has not been created yet
|
||||
* then the initial tests have not yet completed and the notification should
|
||||
* not be sent. */
|
||||
if( xTimer != NULL )
|
||||
{
|
||||
xCallCount++;
|
||||
|
||||
if( xCallCount >= xCallInterval )
|
||||
{
|
||||
/* It is time to 'give' the notification again. */
|
||||
xCallCount = 0;
|
||||
|
||||
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
|
||||
* and xTaskNotifyAndQueryFromISR(). */
|
||||
switch( xAPIToUse )
|
||||
{
|
||||
case 0:
|
||||
vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
|
||||
xAPIToUse++;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
|
||||
xAPIToUse++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ulPreviousValue = ulUnexpectedValue;
|
||||
xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
|
||||
configASSERT( ulPreviousValue != ulUnexpectedValue );
|
||||
xAPIToUse = 0;
|
||||
break;
|
||||
|
||||
default: /* Should never get here!. */
|
||||
break;
|
||||
}
|
||||
|
||||
ulTimerNotificationsSent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check the created tasks are still running and have not
|
||||
* detected any errors. */
|
||||
BaseType_t xAreTaskNotificationTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastNotifyCycleCount = 0;
|
||||
const uint32_t ulMaxSendReceiveDeviation = 5UL;
|
||||
|
||||
/* Check the cycle count is still incrementing to ensure the task is still
|
||||
* actually running. */
|
||||
if( ulLastNotifyCycleCount == ulNotifyCycleCount )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastNotifyCycleCount = ulNotifyCycleCount;
|
||||
}
|
||||
|
||||
/* Check the count of 'takes' from the software timer is keeping track with
|
||||
* the amount of 'gives'. */
|
||||
if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
|
||||
{
|
||||
if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return xErrorStatus;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static UBaseType_t prvRand( void )
|
||||
{
|
||||
const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;
|
||||
|
||||
/* Utility function to generate a pseudo random number. */
|
||||
uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;
|
||||
return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
1218
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotifyArray.c
Normal file
1218
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotifyArray.c
Normal file
File diff suppressed because it is too large
Load Diff
1224
SOFTWARE-FreeRTOS/Common/Minimal/TimerDemo.c
Normal file
1224
SOFTWARE-FreeRTOS/Common/Minimal/TimerDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
597
SOFTWARE-FreeRTOS/Common/Minimal/blocktim.c
Normal file
597
SOFTWARE-FreeRTOS/Common/Minimal/blocktim.c
Normal file
@ -0,0 +1,597 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some test scenarios that ensure tasks do not exit queue
|
||||
* send or receive functions prematurely. A description of the tests is
|
||||
* included within the code.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "blocktim.h"
|
||||
|
||||
/* Task priorities and stack sizes. Allow these to be overridden. */
|
||||
#ifndef bktPRIMARY_PRIORITY
|
||||
#define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
|
||||
#endif
|
||||
|
||||
#ifndef bktSECONDARY_PRIORITY
|
||||
#define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
|
||||
#endif
|
||||
|
||||
#ifndef bktBLOCK_TIME_TASK_STACK_SIZE
|
||||
#define bktBLOCK_TIME_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#endif
|
||||
|
||||
/* Task behaviour. */
|
||||
#define bktQUEUE_LENGTH ( 5 )
|
||||
#define bktSHORT_WAIT pdMS_TO_TICKS( ( TickType_t ) 20 )
|
||||
#define bktPRIMARY_BLOCK_TIME ( 10 )
|
||||
#define bktALLOWABLE_MARGIN ( 15 )
|
||||
#define bktTIME_TO_BLOCK ( 175 )
|
||||
#define bktDONT_BLOCK ( ( TickType_t ) 0 )
|
||||
#define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
|
||||
|
||||
/* In case the demo does not have software timers enabled, as this file uses
|
||||
* the configTIMER_TASK_PRIORITY setting. */
|
||||
#ifndef configTIMER_TASK_PRIORITY
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The two test tasks. Their behaviour is commented within the functions.
|
||||
*/
|
||||
static void vPrimaryBlockTimeTestTask( void * pvParameters );
|
||||
static void vSecondaryBlockTimeTestTask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Very basic tests to verify the block times are as expected.
|
||||
*/
|
||||
static void prvBasicDelayTests( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue on which the tasks block. */
|
||||
static QueueHandle_t xTestQueue;
|
||||
|
||||
/* Handle to the secondary task is required by the primary task for calls
|
||||
* to vTaskSuspend/Resume(). */
|
||||
static TaskHandle_t xSecondary;
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
|
||||
static volatile BaseType_t xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Provides a simple mechanism for the primary task to know when the
|
||||
* secondary task has executed. */
|
||||
static volatile UBaseType_t xRunIndicator;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateBlockTimeTasks( void )
|
||||
{
|
||||
/* Create the queue on which the two tasks block. */
|
||||
xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
|
||||
|
||||
if( xTestQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one
|
||||
* is in use. The queue registry is provided as a means for kernel aware
|
||||
* debuggers to locate queues and has no purpose if a kernel aware
|
||||
* debugger is not being used. The call to vQueueAddToRegistry() will be
|
||||
* removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
* defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
|
||||
|
||||
/* Create the two test tasks. */
|
||||
xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
|
||||
xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPrimaryBlockTimeTestTask( void * pvParameters )
|
||||
{
|
||||
BaseType_t xItem, xData;
|
||||
TickType_t xTimeWhenBlocking;
|
||||
TickType_t xTimeToBlock, xBlockedTime;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/*********************************************************************
|
||||
* Test 0
|
||||
*
|
||||
* Basic vTaskDelay() and vTaskDelayUntil() tests. */
|
||||
prvBasicDelayTests();
|
||||
|
||||
/*********************************************************************
|
||||
* Test 1
|
||||
*
|
||||
* Simple block time wakeup test on queue receives. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is empty. Attempt to read from the queue using a block
|
||||
* time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
* anything on the queue. */
|
||||
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
* although we would not necessarily run as soon as we were
|
||||
* unblocked so a margin is allowed. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Test 2
|
||||
*
|
||||
* Simple block time wakeup test on queue sends.
|
||||
*
|
||||
* First fill the queue. It should be empty so all sends should pass. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is full. Attempt to write to the queue using a block
|
||||
* time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
* anything on the queue. */
|
||||
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
* although we would not necessarily run as soon as we were
|
||||
* unblocked so a margin is allowed. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Test 3
|
||||
*
|
||||
* Wake the other task, it will block attempting to post to the queue.
|
||||
* When we read from the queue the other task will wake, but before it
|
||||
* can run we will post to the queue again. When the other task runs it
|
||||
* will find the queue still full, even though it was woken. It should
|
||||
* recognise that its block time has not expired and return to block for
|
||||
* the remains of its block time.
|
||||
*
|
||||
* Wake the other task so it blocks attempting to post to the already
|
||||
* full queue. */
|
||||
xRunIndicator = 0;
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task has not yet executed. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
|
||||
/* Make sure the other task is blocked on the queue. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we make space on the queue the other task should wake
|
||||
* but not execute as this task has higher priority. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Now fill the queue again before the other task gets a chance to
|
||||
* execute. If the other task had executed we would find the queue
|
||||
* full ourselves, and the other task have set xRunIndicator. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
* on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
* queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
* queue function. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Set the priority back down. */
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblocks it will check that it
|
||||
* unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
/*********************************************************************
|
||||
* Test 4
|
||||
*
|
||||
* As per test 3 - but with the send and receive the other way around.
|
||||
* The other task blocks attempting to read from the queue.
|
||||
*
|
||||
* Empty the queue. We should find that it is full. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake the other task so it blocks attempting to read from the
|
||||
* already empty queue. */
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we place an item on the queue the other task should
|
||||
* wake but not execute as this task has higher priority. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Now empty the queue again before the other task gets a chance to
|
||||
* execute. If the other task had executed we would find the queue
|
||||
* empty ourselves, and the other task would be suspended. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
* on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
* queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
* queue function. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblocks it will check that it
|
||||
* unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSecondaryBlockTimeTestTask( void * pvParameters )
|
||||
{
|
||||
TickType_t xTimeWhenBlocking, xBlockedTime;
|
||||
BaseType_t xData;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/*********************************************************************
|
||||
* Test 0, 1 and 2
|
||||
*
|
||||
* This task does not participate in these tests. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
* Test 3
|
||||
*
|
||||
* The first thing we do is attempt to read from the queue. It should be
|
||||
* full so we block. Note the time before we block so we can check the
|
||||
* wake time is as per that expected. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not sent anything to
|
||||
* the queue. */
|
||||
xData = 0;
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* How long were we inside the send function? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
* either. A margin is permitted as we would not necessarily run as
|
||||
* soon as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Suspend ready for test 3. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
* Test 4
|
||||
*
|
||||
* As per test three, but with the send and receive reversed. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not received
|
||||
* anything on the queue. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
* either. A margin is permitted as we would not necessarily run as soon
|
||||
* as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
xSecondaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvBasicDelayTests( void )
|
||||
{
|
||||
TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime;
|
||||
const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 ), xHalfPeriod = xPeriod / ( TickType_t ) 2;
|
||||
BaseType_t xDidBlock;
|
||||
|
||||
/* Temporarily increase priority so the timing is more accurate, but not so
|
||||
* high as to disrupt the timer tests. */
|
||||
vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
|
||||
|
||||
/* Crude check to too see that vTaskDelay() blocks for the expected
|
||||
* period. */
|
||||
xPreTime = xTaskGetTickCount();
|
||||
vTaskDelay( bktTIME_TO_BLOCK );
|
||||
xPostTime = xTaskGetTickCount();
|
||||
|
||||
/* The priority is higher, so the allowable margin is halved when compared
|
||||
* to the other tests in this file. */
|
||||
if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Now crude tests to check the vTaskDelayUntil() functionality. */
|
||||
xPostTime = xTaskGetTickCount();
|
||||
xLastUnblockTime = xPostTime;
|
||||
|
||||
for( x = 0; x < xCycles; x++ )
|
||||
{
|
||||
/* Calculate the next expected unblock time from the time taken before
|
||||
* this loop was entered. */
|
||||
xExpectedUnblockTime = xPostTime + ( x * xPeriod );
|
||||
|
||||
vTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
|
||||
/* Crude tests for return value of xTaskDelayUntil(). First a standard block
|
||||
* should return that the task does block. */
|
||||
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( xDidBlock != pdTRUE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Now delay a few ticks so repeating the above block period will not block for
|
||||
* the full amount of time, but will still block. */
|
||||
vTaskDelay( xHalfPeriod );
|
||||
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( xDidBlock != pdTRUE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* This time block for longer than xPeriod before calling xTaskDelayUntil() so
|
||||
* the call to xTaskDelayUntil() should not block. */
|
||||
vTaskDelay( xPeriod );
|
||||
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( xDidBlock != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Catch up. */
|
||||
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( xDidBlock != pdTRUE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Again block for slightly longer than a period so ensure the time is in the
|
||||
* past next time xTaskDelayUntil() gets called. */
|
||||
vTaskDelay( xPeriod + xAllowableMargin );
|
||||
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( xDidBlock != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Reset to the original task priority ready for the other tests. */
|
||||
vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreBlockTimeTestTasksStillRunning( void )
|
||||
{
|
||||
static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
* last called? */
|
||||
if( xPrimaryCycles == xLastPrimaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xSecondaryCycles == xLastSecondaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastSecondaryCycleCount = xSecondaryCycles;
|
||||
xLastPrimaryCycleCount = xPrimaryCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
265
SOFTWARE-FreeRTOS/Common/Minimal/comtest.c
Normal file
265
SOFTWARE-FreeRTOS/Common/Minimal/comtest.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This version of comtest. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A
|
||||
* loopback connector should be used so that everything that is transmitted is
|
||||
* also received. The serial port does not use any flow control. On a
|
||||
* standard 9way 'D' connector pins two and three should be connected together.
|
||||
*
|
||||
* The first task posts a sequence of characters to the Tx queue, toggling an
|
||||
* LED on each successful post. At the end of the sequence it sleeps for a
|
||||
* pseudo-random period before resending the same sequence.
|
||||
*
|
||||
* The UART Tx end interrupt is enabled whenever data is available in the Tx
|
||||
* queue. The Tx end ISR removes a single character from the Tx queue and
|
||||
* passes it to the UART for transmission.
|
||||
*
|
||||
* The second task blocks on the Rx queue waiting for a character to become
|
||||
* available. When the UART Rx end interrupt receives a character it places
|
||||
* it in the Rx queue, waking the second task. The second task checks that the
|
||||
* characters removed from the Rx queue form the same sequence as those posted
|
||||
* to the Tx queue, and toggles an LED for each correct character.
|
||||
*
|
||||
* The receiving task is spawned with a higher priority than the transmitting
|
||||
* task. The receiver will therefore wake every time a character is
|
||||
* transmitted so neither the Tx or Rx queue should ever hold more than a few
|
||||
* characters.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "partest.h"
|
||||
|
||||
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define comTX_LED_OFFSET ( 0 )
|
||||
#define comRX_LED_OFFSET ( 1 )
|
||||
#define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
* interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
|
||||
#define comOFFSET_TIME ( ( TickType_t ) 3 )
|
||||
|
||||
/* We should find that each character can be queued for Tx immediately and we
|
||||
* don't have to block to send. */
|
||||
#define comNO_BLOCK ( ( TickType_t ) 0 )
|
||||
|
||||
/* The Rx task will block on the Rx queue for a long period. */
|
||||
#define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff )
|
||||
|
||||
/* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */
|
||||
#define comFIRST_BYTE ( 'A' )
|
||||
#define comLAST_BYTE ( 'X' )
|
||||
|
||||
#define comBUFFER_LEN ( ( UBaseType_t ) ( comLAST_BYTE - comFIRST_BYTE ) + ( UBaseType_t ) 1 )
|
||||
#define comINITIAL_RX_COUNT_VALUE ( 0 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort = NULL;
|
||||
|
||||
/* The transmit task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
|
||||
|
||||
/* The receive task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
|
||||
|
||||
/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
|
||||
* toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
|
||||
* ( uxBaseLED + comTX_LED_OFFSET ). */
|
||||
static UBaseType_t uxBaseLED = 0;
|
||||
|
||||
/* Check variable used to ensure no error have occurred. The Rx task will
|
||||
* increment this variable after every successfully received sequence. If at any
|
||||
* time the sequence is incorrect the the variable will stop being incremented. */
|
||||
static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vAltStartComTestTasks( UBaseType_t uxPriority,
|
||||
uint32_t ulBaudRate,
|
||||
UBaseType_t uxLED )
|
||||
{
|
||||
/* Initialise the com port then spawn the Rx and Tx tasks. */
|
||||
uxBaseLED = uxLED;
|
||||
xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );
|
||||
|
||||
/* The Tx task is spawned with a lower priority than the Rx task. */
|
||||
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComTxTask, pvParameters )
|
||||
{
|
||||
char cByteToSend;
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Simply transmit a sequence of characters from comFIRST_BYTE to
|
||||
* comLAST_BYTE. */
|
||||
for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
|
||||
{
|
||||
if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* We have posted all the characters in the string - wait before
|
||||
* re-sending. Wait a pseudo-random time as this will provide a better
|
||||
* test. */
|
||||
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComRxTask, pvParameters )
|
||||
{
|
||||
signed char cExpectedByte, cByteRxed;
|
||||
BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* We expect to receive the characters from comFIRST_BYTE to
|
||||
* comLAST_BYTE in an incrementing order. Loop to receive each byte. */
|
||||
for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
|
||||
{
|
||||
/* Block on the queue that contains received bytes until a byte is
|
||||
* available. */
|
||||
if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
|
||||
{
|
||||
/* Was this the byte we were expecting? If so, toggle the LED,
|
||||
* otherwise we are out on sync and should break out of the loop
|
||||
* until the expected character sequence is about to restart. */
|
||||
if( cByteRxed == cExpectedByte )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
||||
}
|
||||
else
|
||||
{
|
||||
xResyncRequired = pdTRUE;
|
||||
break; /*lint !e960 Non-switch break allowed. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* Did we break out of the loop because the characters were received in
|
||||
* an unexpected order? If so wait here until the character sequence is
|
||||
* about to restart. */
|
||||
if( xResyncRequired == pdTRUE )
|
||||
{
|
||||
while( cByteRxed != comLAST_BYTE )
|
||||
{
|
||||
/* Block until the next char is available. */
|
||||
xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
|
||||
}
|
||||
|
||||
/* Note that an error occurred which caused us to have to resync.
|
||||
* We use this to stop incrementing the loop counter so
|
||||
* sAreComTestTasksStillRunning() will return false - indicating an
|
||||
* error. */
|
||||
xErrorOccurred++;
|
||||
|
||||
/* We have now resynced with the Tx task and can continue. */
|
||||
xResyncRequired = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
|
||||
{
|
||||
/* Increment the count of successful loops. As error
|
||||
* occurring (i.e. an unexpected character being received) will
|
||||
* prevent this counter being incremented for the rest of the
|
||||
* execution. Don't worry about mutual exclusion on this
|
||||
* variable - it doesn't really matter as we just want it
|
||||
* to change. */
|
||||
uxRxLoops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* If the count of successful reception loops has not changed than at
|
||||
* some time an error occurred (i.e. a character was received out of sequence)
|
||||
* and we will return false. */
|
||||
if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the count of successful Rx loops. When this function is called
|
||||
* again we expect this to have been incremented. */
|
||||
uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
316
SOFTWARE-FreeRTOS/Common/Minimal/comtest_strings.c
Normal file
316
SOFTWARE-FreeRTOS/Common/Minimal/comtest_strings.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Creates a task and a timer that operate on an interrupt driven serial port.
|
||||
* This demo assumes that the characters transmitted on a port will also be
|
||||
* received on the same port. Therefore, the UART must either be connected to
|
||||
* an echo server, or the uart connector must have a loopback connector fitted.
|
||||
* See http://www.serialporttool.com/CommEcho.htm for a suitable echo server
|
||||
* for Windows hosts.
|
||||
*
|
||||
* The timer sends a string to the UART, toggles an LED, then resets itself by
|
||||
* changing its own period. The period is calculated as a pseudo random number
|
||||
* between comTX_MAX_BLOCK_TIME and comTX_MIN_BLOCK_TIME.
|
||||
*
|
||||
* The task blocks on an Rx queue waiting for a character to become available.
|
||||
* Received characters are checked to ensure they match those transmitted by the
|
||||
* Tx timer. An error is latched if characters are missing, incorrect, or
|
||||
* arrive too slowly.
|
||||
*
|
||||
* How characters are actually transmitted and received is port specific. Demos
|
||||
* that include this test/demo file will provide example drivers. The Tx timer
|
||||
* executes in the context of the timer service (daemon) task, and must
|
||||
* therefore never attempt to block.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
|
||||
#ifndef configUSE_TIMERS
|
||||
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
#if configUSE_TIMERS != 1
|
||||
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest_strings.h"
|
||||
#include "partest.h"
|
||||
|
||||
/* The size of the stack given to the Rx task. */
|
||||
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* See the comment above the declaration of the uxBaseLED variable. */
|
||||
#define comTX_LED_OFFSET ( 0 )
|
||||
#define comRX_LED_OFFSET ( 1 )
|
||||
|
||||
/* The Tx timer transmits the sequence of characters at a pseudo random
|
||||
* interval that is capped between comTX_MAX_BLOCK_TIME and
|
||||
* comTX_MIN_BLOCK_TIME. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
|
||||
#define comOFFSET_TIME ( ( TickType_t ) 3 )
|
||||
|
||||
/* States for the simple state machine implemented in the Rx task. */
|
||||
#define comtstWAITING_START_OF_STRING 0
|
||||
#define comtstWAITING_END_OF_STRING 1
|
||||
|
||||
/* A short delay in ticks - this delay is used to allow the Rx queue to fill up
|
||||
* a bit so more than one character can be processed at a time. This is relative
|
||||
* to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap
|
||||
* between transmissions. It could be worked out more scientifically from the
|
||||
* baud rate being used. */
|
||||
#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 )
|
||||
|
||||
/* The string that is transmitted and received. */
|
||||
#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
|
||||
/* A block time of 0 simply means "don't block". */
|
||||
#define comtstDONT_BLOCK ( TickType_t ) 0
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort = NULL;
|
||||
|
||||
/* The callback function allocated to the transmit timer, as described in the
|
||||
* comments at the top of this file. */
|
||||
static void prvComTxTimerCallback( TimerHandle_t xTimer );
|
||||
|
||||
/* The receive task as described in the comments at the top of this file. */
|
||||
static void vComRxTask( void * pvParameters );
|
||||
|
||||
/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
|
||||
* will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
|
||||
static UBaseType_t uxBaseLED = 0;
|
||||
|
||||
/* The Rx task toggles uxRxLoops on each successful iteration of its defined
|
||||
* function - provided no errors have ever been latched. If this variable stops
|
||||
* incrementing, then an error has occurred. */
|
||||
static volatile UBaseType_t uxRxLoops = 0UL;
|
||||
|
||||
/* The timer used to periodically transmit the string. This is the timer that
|
||||
* has prvComTxTimerCallback allocated to it as its callback function. */
|
||||
static TimerHandle_t xTxTimer = NULL;
|
||||
|
||||
/* The string length is held at file scope so the Tx timer does not need to
|
||||
* calculate it each time it executes. */
|
||||
static size_t xStringLength = 0U;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartComTestStringsTasks( UBaseType_t uxPriority,
|
||||
uint32_t ulBaudRate,
|
||||
UBaseType_t uxLED )
|
||||
{
|
||||
/* Store values that are used at run time. */
|
||||
uxBaseLED = uxLED;
|
||||
|
||||
/* Calculate the string length here, rather than each time the Tx timer
|
||||
* executes. */
|
||||
xStringLength = strlen( comTRANSACTED_STRING );
|
||||
|
||||
/* Include the null terminator in the string length as this is used to
|
||||
* detect the end of the string in the Rx task. */
|
||||
xStringLength++;
|
||||
|
||||
/* Initialise the com port, then spawn the Rx task and create the Tx
|
||||
* timer. */
|
||||
xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
|
||||
|
||||
/* Create the Rx task and the Tx timer. The timer is started from the
|
||||
* Rx task. */
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
|
||||
configASSERT( xTxTimer );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvComTxTimerCallback( TimerHandle_t xTimer )
|
||||
{
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* The parameter is not used in this case. */
|
||||
( void ) xTimer;
|
||||
|
||||
/* Send the string. How this is actually performed depends on the
|
||||
* sample driver provided with this demo. However - as this is a timer,
|
||||
* it executes in the context of the timer task and therefore must not
|
||||
* block. */
|
||||
vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength );
|
||||
|
||||
/* Toggle an LED to give a visible indication that another transmission
|
||||
* has been performed. */
|
||||
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
||||
|
||||
/* Wait a pseudo random time before sending the string again. */
|
||||
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
||||
|
||||
/* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
/* Reset the timer to run again xTimeToWait ticks from now. This function
|
||||
* is called from the context of the timer task, so the block time must not
|
||||
* be anything other than zero. */
|
||||
xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComRxTask( void * pvParameters )
|
||||
{
|
||||
BaseType_t xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;
|
||||
char * pcExpectedByte, cRxedChar;
|
||||
const xComPortHandle xPort = NULL;
|
||||
|
||||
/* The parameter is not used in this example. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Start the Tx timer. This only needs to be started once, as it will
|
||||
* reset itself thereafter. */
|
||||
xTimerStart( xTxTimer, portMAX_DELAY );
|
||||
|
||||
/* The first expected Rx character is the first in the string that is
|
||||
* transmitted. */
|
||||
pcExpectedByte = comTRANSACTED_STRING;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Wait for the next character. */
|
||||
if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
|
||||
{
|
||||
/* A character definitely should have been received by now. As a
|
||||
* character was not received an error must have occurred (which might
|
||||
* just be that the loopback connector is not fitted). */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
switch( xState )
|
||||
{
|
||||
case comtstWAITING_START_OF_STRING:
|
||||
|
||||
if( cRxedChar == *pcExpectedByte )
|
||||
{
|
||||
/* The received character was the first character of the
|
||||
* string. Move to the next state to check each character
|
||||
* as it comes in until the entire string has been received. */
|
||||
xState = comtstWAITING_END_OF_STRING;
|
||||
pcExpectedByte++;
|
||||
|
||||
/* Block for a short period. This just allows the Rx queue
|
||||
* to contain more than one character, and therefore prevent
|
||||
* thrashing reads to the queue, and repetitive context
|
||||
* switches as each character is received. */
|
||||
vTaskDelay( comSHORT_DELAY );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case comtstWAITING_END_OF_STRING:
|
||||
|
||||
if( cRxedChar == *pcExpectedByte )
|
||||
{
|
||||
/* The received character was the expected character. Was
|
||||
* it the last character in the string - i.e. the null
|
||||
* terminator? */
|
||||
if( cRxedChar == 0x00 )
|
||||
{
|
||||
/* The entire string has been received. If no errors
|
||||
* have been latched, then increment the loop counter to
|
||||
* show this task is still healthy. */
|
||||
if( xErrorOccurred == pdFALSE )
|
||||
{
|
||||
uxRxLoops++;
|
||||
|
||||
/* Toggle an LED to give a visible sign that a
|
||||
* complete string has been received. */
|
||||
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
||||
}
|
||||
|
||||
/* Go back to wait for the start of the next string. */
|
||||
pcExpectedByte = comTRANSACTED_STRING;
|
||||
xState = comtstWAITING_START_OF_STRING;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for the next character in the string. */
|
||||
pcExpectedByte++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The character received was not that expected. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Should not get here. Stop the Rx loop counter from
|
||||
* incrementing to latch the error. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* If the count of successful reception loops has not changed than at
|
||||
* some time an error occurred (i.e. a character was received out of sequence)
|
||||
* and false is returned. */
|
||||
if( uxRxLoops == 0UL )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the count of successful Rx loops. When this function is called
|
||||
* again it should have been incremented again. */
|
||||
uxRxLoops = 0UL;
|
||||
|
||||
return xReturn;
|
||||
}
|
290
SOFTWARE-FreeRTOS/Common/Minimal/countsem.c
Normal file
290
SOFTWARE-FreeRTOS/Common/Minimal/countsem.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Simple demonstration of the usage of counting semaphore.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "countsem.h"
|
||||
|
||||
/* The maximum count value that the semaphore used for the demo can hold. */
|
||||
#define countMAX_COUNT_VALUE ( 200 )
|
||||
|
||||
/* Constants used to indicate whether or not the semaphore should have been
|
||||
* created with its maximum count value, or its minimum count value. These
|
||||
* numbers are used to ensure that the pointers passed in as the task parameters
|
||||
* are valid. */
|
||||
#define countSTART_AT_MAX_COUNT ( 0xaa )
|
||||
#define countSTART_AT_ZERO ( 0x55 )
|
||||
|
||||
/* Two tasks are created for the test. One uses a semaphore created with its
|
||||
* count value set to the maximum, and one with the count value set to zero. */
|
||||
#define countNUM_TEST_TASKS ( 2 )
|
||||
#define countDONT_BLOCK ( 0 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
* detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The demo task. This simply counts the semaphore up to its maximum value,
|
||||
* the counts it back down again. The result of each semaphore 'give' and
|
||||
* 'take' is inspected, with an error being flagged if it is found not to be
|
||||
* the expected result.
|
||||
*/
|
||||
static void prvCountingSemaphoreTask( void * pvParameters );
|
||||
|
||||
/*
|
||||
* Utility function to increment the semaphore count value up from zero to
|
||||
* countMAX_COUNT_VALUE.
|
||||
*/
|
||||
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
|
||||
volatile UBaseType_t * puxLoopCounter );
|
||||
|
||||
/*
|
||||
* Utility function to decrement the semaphore count value up from
|
||||
* countMAX_COUNT_VALUE to zero.
|
||||
*/
|
||||
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
|
||||
volatile UBaseType_t * puxLoopCounter );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The structure that is passed into the task as the task parameter. */
|
||||
typedef struct COUNT_SEM_STRUCT
|
||||
{
|
||||
/* The semaphore to be used for the demo. */
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
|
||||
/* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
|
||||
* its count value set to its max count value, or countSTART_AT_ZERO if it
|
||||
* should have been created with its count value set to 0. */
|
||||
UBaseType_t uxExpectedStartCount;
|
||||
|
||||
/* Incremented on each cycle of the demo task. Used to detect a stalled
|
||||
* task. */
|
||||
volatile UBaseType_t uxLoopCounter;
|
||||
} xCountSemStruct;
|
||||
|
||||
/* Two structures are defined, one is passed to each test task. */
|
||||
static xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartCountingSemaphoreTasks( void )
|
||||
{
|
||||
/* Create the semaphores that we are going to use for the test/demo. The
|
||||
* first should be created such that it starts at its maximum count value,
|
||||
* the second should be created such that it starts with a count value of zero. */
|
||||
xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
|
||||
xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
|
||||
xParameters[ 0 ].uxLoopCounter = 0;
|
||||
|
||||
xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 );
|
||||
xParameters[ 1 ].uxExpectedStartCount = 0;
|
||||
xParameters[ 1 ].uxLoopCounter = 0;
|
||||
|
||||
/* Were the semaphores created? */
|
||||
if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is
|
||||
* in use. The registry is provided as a means for kernel aware
|
||||
* debuggers to locate semaphores and has no purpose if a kernel aware
|
||||
* debugger is not being used. The call to vQueueAddToRegistry() will be
|
||||
* removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
* defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" );
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" );
|
||||
|
||||
/* Create the demo tasks, passing in the semaphore to use as the parameter. */
|
||||
xTaskCreate( prvCountingSemaphoreTask, "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvCountingSemaphoreTask, "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
|
||||
volatile UBaseType_t * puxLoopCounter )
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
* 'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) );
|
||||
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
* the semaphore. */
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
|
||||
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
|
||||
volatile UBaseType_t * puxLoopCounter )
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
* the semaphore. */
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ux );
|
||||
|
||||
if( xSemaphoreGive( xSemaphore ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
* 'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCountingSemaphoreTask( void * pvParameters )
|
||||
{
|
||||
xCountSemStruct * pxParameter;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Counting semaphore demo started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
/* The semaphore to be used was passed as the parameter. */
|
||||
pxParameter = ( xCountSemStruct * ) pvParameters;
|
||||
|
||||
/* Did we expect to find the semaphore already at its max count value, or
|
||||
* at zero? */
|
||||
if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
|
||||
{
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
|
||||
/* Now we expect the semaphore count to be 0, so this time there is an
|
||||
* error if we can take the semaphore. */
|
||||
if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreCountingSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static UBaseType_t uxLastCount0 = 0, uxLastCount1 = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Return fail if any 'give' or 'take' did not result in the expected
|
||||
* behaviour. */
|
||||
if( xErrorDetected != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
/* Return fail if either task is not still incrementing its loop counter. */
|
||||
if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount0 = xParameters[ 0 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount1 = xParameters[ 1 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
218
SOFTWARE-FreeRTOS/Common/Minimal/crflash.c
Normal file
218
SOFTWARE-FreeRTOS/Common/Minimal/crflash.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo application file demonstrates the use of queues to pass data
|
||||
* between co-routines.
|
||||
*
|
||||
* N represents the number of 'fixed delay' co-routines that are created and
|
||||
* is set during initialisation.
|
||||
*
|
||||
* N 'fixed delay' co-routines are created that just block for a fixed
|
||||
* period then post the number of an LED onto a queue. Each such co-routine
|
||||
* uses a different block period. A single 'flash' co-routine is also created
|
||||
* that blocks on the same queue, waiting for the number of the next LED it
|
||||
* should flash. Upon receiving a number it simply toggle the instructed LED
|
||||
* then blocks on the queue once more. In this manner each LED from LED 0 to
|
||||
* LED N-1 is caused to flash at a different rate.
|
||||
*
|
||||
* The 'fixed delay' co-routines are created with co-routine priority 0. The
|
||||
* flash co-routine is created with co-routine priority 1. This means that
|
||||
* the queue should never contain more than a single item. This is because
|
||||
* posting to the queue will unblock the 'flash' co-routine, and as this has
|
||||
* a priority greater than the tasks posting to the queue it is guaranteed to
|
||||
* have emptied the queue and blocked once again before the queue can contain
|
||||
* any more date. An error is indicated if an attempt to post data to the
|
||||
* queue fails - indicating that the queue is already full.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "partest.h"
|
||||
#include "crflash.h"
|
||||
|
||||
/* The queue should only need to be of length 1. See the description at the
|
||||
* top of the file. */
|
||||
#define crfQUEUE_LENGTH 1
|
||||
|
||||
#define crfFIXED_DELAY_PRIORITY 0
|
||||
#define crfFLASH_PRIORITY 1
|
||||
|
||||
/* Only one flash co-routine is created so the index is not significant. */
|
||||
#define crfFLASH_INDEX 0
|
||||
|
||||
/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
|
||||
* created. */
|
||||
#define crfMAX_FLASH_TASKS 8
|
||||
|
||||
/* We don't want to block when posting to the queue. */
|
||||
#define crfPOSTING_BLOCK_TIME 0
|
||||
|
||||
#if ( configUSE_CO_ROUTINES == 1 )
|
||||
|
||||
/*
|
||||
* The 'fixed delay' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex );
|
||||
|
||||
/*
|
||||
* The 'flash' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex );
|
||||
|
||||
/* The queue used to pass data between the 'fixed delay' co-routines and the
|
||||
* 'flash' co-routine. */
|
||||
static QueueHandle_t xFlashQueue;
|
||||
|
||||
/* This will be set to pdFALSE if we detect an error. */
|
||||
static BaseType_t xCoRoutineFlashStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See the header file for details.
|
||||
*/
|
||||
void vStartFlashCoRoutines( UBaseType_t uxNumberToCreate )
|
||||
{
|
||||
UBaseType_t uxIndex;
|
||||
|
||||
if( uxNumberToCreate > crfMAX_FLASH_TASKS )
|
||||
{
|
||||
uxNumberToCreate = crfMAX_FLASH_TASKS;
|
||||
}
|
||||
|
||||
/* Create the queue used to pass data between the co-routines. */
|
||||
xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
|
||||
if( xFlashQueue )
|
||||
{
|
||||
/* Create uxNumberToCreate 'fixed delay' co-routines. */
|
||||
for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ )
|
||||
{
|
||||
xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex );
|
||||
}
|
||||
|
||||
/* Create the 'flash' co-routine. */
|
||||
xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the xResult variable does not need to be
|
||||
* static as we do not need it to maintain its state between blocks. */
|
||||
BaseType_t xResult;
|
||||
|
||||
/* The uxIndex parameter of the co-routine function is used as an index into
|
||||
* the xFlashRates array to obtain the delay period to use. */
|
||||
static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] =
|
||||
{
|
||||
150 / portTICK_PERIOD_MS,
|
||||
200 / portTICK_PERIOD_MS,
|
||||
250 / portTICK_PERIOD_MS,
|
||||
300 / portTICK_PERIOD_MS,
|
||||
350 / portTICK_PERIOD_MS,
|
||||
400 / portTICK_PERIOD_MS,
|
||||
450 / portTICK_PERIOD_MS,
|
||||
500 / portTICK_PERIOD_MS
|
||||
};
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Post our uxIndex value onto the queue. This is used as the LED to
|
||||
* flash. */
|
||||
crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* For the reasons stated at the top of the file we should always
|
||||
* find that we can post to the queue. If we could not then an error
|
||||
* has occurred. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
|
||||
crDELAY( xHandle, xFlashRates[ uxIndex ] );
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the variable do not need to be
|
||||
* static as we do not need it to maintain their state between blocks. */
|
||||
BaseType_t xResult;
|
||||
UBaseType_t uxLEDToFlash;
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
( void ) uxIndex;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Block to wait for the number of the LED to flash. */
|
||||
crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* We would not expect to wake unless we received something. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We received the number of an LED to flash - flash it! */
|
||||
vParTestToggleLED( uxLEDToFlash );
|
||||
}
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreFlashCoRoutinesStillRunning( void )
|
||||
{
|
||||
/* Return pdPASS or pdFAIL depending on whether an error has been detected
|
||||
* or not. */
|
||||
return xCoRoutineFlashStatus;
|
||||
}
|
||||
|
||||
#endif /* if ( configUSE_CO_ROUTINES == 1 ) */
|
236
SOFTWARE-FreeRTOS/Common/Minimal/crhook.c
Normal file
236
SOFTWARE-FreeRTOS/Common/Minimal/crhook.c
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo file demonstrates how to send data between an ISR and a
|
||||
* co-routine. A tick hook function is used to periodically pass data between
|
||||
* the RTOS tick and a set of 'hook' co-routines.
|
||||
*
|
||||
* hookNUM_HOOK_CO_ROUTINES co-routines are created. Each co-routine blocks
|
||||
* to wait for a character to be received on a queue from the tick ISR, checks
|
||||
* to ensure the character received was that expected, then sends the number
|
||||
* back to the tick ISR on a different queue.
|
||||
*
|
||||
* The tick ISR checks the numbers received back from the 'hook' co-routines
|
||||
* matches the number previously sent.
|
||||
*
|
||||
* If at any time a queue function returns unexpectedly, or an incorrect value
|
||||
* is received either by the tick hook or a co-routine then an error is
|
||||
* latched.
|
||||
*
|
||||
* This demo relies on each 'hook' co-routine to execute between each
|
||||
* hookTICK_CALLS_BEFORE_POST tick interrupts. This and the heavy use of
|
||||
* queues from within an interrupt may result in an error being detected on
|
||||
* slower targets simply due to timing.
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "crhook.h"
|
||||
|
||||
/* The number of 'hook' co-routines that are to be created. */
|
||||
#define hookNUM_HOOK_CO_ROUTINES ( 4 )
|
||||
|
||||
/* The number of times the tick hook should be called before a character is
|
||||
* posted to the 'hook' co-routines. */
|
||||
#define hookTICK_CALLS_BEFORE_POST ( 500 )
|
||||
|
||||
/* There should never be more than one item in any queue at any time. */
|
||||
#define hookHOOK_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/* Don't block when initially posting to the queue. */
|
||||
#define hookNO_BLOCK_TIME ( 0 )
|
||||
|
||||
/* The priority relative to other co-routines (rather than tasks) that the
|
||||
* 'hook' co-routines should take. */
|
||||
#define mainHOOK_CR_PRIORITY ( 1 )
|
||||
/*-----------------------------------------------------------*/
|
||||
#if ( configUSE_CO_ROUTINES == 1 )
|
||||
|
||||
/*
|
||||
* The co-routine function itself.
|
||||
*/
|
||||
static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex );
|
||||
|
||||
|
||||
/*
|
||||
* The tick hook function. This receives a number from each 'hook' co-routine
|
||||
* then sends a number to each co-routine. An error is flagged if a send or
|
||||
* receive fails, or an unexpected number is received.
|
||||
*/
|
||||
void vApplicationTickHook( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Queues used to send data FROM a co-routine TO the tick hook function.
|
||||
* The hook functions received (Rx's) on these queues. One queue per
|
||||
* 'hook' co-routine. */
|
||||
static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Queues used to send data FROM the tick hook TO a co-routine function.
|
||||
* The hood function transmits (Tx's) on these queues. One queue per
|
||||
* 'hook' co-routine. */
|
||||
static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Set to true if an error is detected at any time. */
|
||||
static BaseType_t xCoRoutineErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartHookCoRoutines( void )
|
||||
{
|
||||
UBaseType_t uxIndex, uxValueToPost = 0;
|
||||
|
||||
for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
|
||||
{
|
||||
/* Create a queue to transmit to and receive from each 'hook'
|
||||
* co-routine. */
|
||||
xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
|
||||
/* To start things off the tick hook function expects the queue it
|
||||
* uses to receive data to contain a value. */
|
||||
xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
|
||||
|
||||
/* Create the 'hook' co-routine itself. */
|
||||
xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static UBaseType_t uxCallCounter = 0, uxNumberToPost = 0;
|
||||
void vApplicationTickHook( void )
|
||||
{
|
||||
UBaseType_t uxReceivedNumber;
|
||||
BaseType_t xIndex, xCoRoutineWoken;
|
||||
|
||||
/* Is it time to talk to the 'hook' co-routines again? */
|
||||
uxCallCounter++;
|
||||
|
||||
if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
|
||||
{
|
||||
uxCallCounter = 0;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
xCoRoutineWoken = pdFALSE;
|
||||
|
||||
if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
|
||||
{
|
||||
/* There is no reason why we would not expect the queue to
|
||||
* contain a value. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Each queue used to receive data from the 'hook' co-routines
|
||||
* should contain the number we last posted to the same co-routine. */
|
||||
if( uxReceivedNumber != uxNumberToPost )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Nothing should be blocked waiting to post to the queue. */
|
||||
if( xCoRoutineWoken != pdFALSE )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the next cycle by posting the next number onto each Tx queue. */
|
||||
uxNumberToPost++;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
|
||||
{
|
||||
/* Posting to the queue should have woken the co-routine that
|
||||
* was blocked on the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
|
||||
UBaseType_t uxIndex )
|
||||
{
|
||||
static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
BaseType_t xResult;
|
||||
|
||||
/* Each co-routine MUST start with a call to crSTART(); */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Wait to receive a value from the tick hook. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
|
||||
|
||||
/* There is no reason why we should not have received something on
|
||||
* the queue. */
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Send the same number back to the idle hook so it can verify it. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* There is no reason why we should not have been able to post to
|
||||
* the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each co-routine MUST end with a call to crEND(). */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreHookCoRoutinesStillRunning( void )
|
||||
{
|
||||
if( xCoRoutineErrorDetected )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if ( configUSE_CO_ROUTINES == 1 ) */
|
200
SOFTWARE-FreeRTOS/Common/Minimal/death.c
Normal file
200
SOFTWARE-FreeRTOS/Common/Minimal/death.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* two tasks. The original task is called the creator task, the two tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* One of the created suicidal tasks kill one other suicidal task before killing
|
||||
* itself - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
|
||||
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
* creating another four tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
* is used to check that the task is still running. */
|
||||
static volatile uint16_t usCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
* task can tell if any of the suicidal tasks have failed to die.
|
||||
*/
|
||||
static volatile UBaseType_t uxTasksRunningAtStart = 0;
|
||||
|
||||
/* When a task deletes itself, it stack and TCB are cleaned up by the Idle task.
|
||||
* Under heavy load the idle task might not get much processing time, so it would
|
||||
* be legitimate for several tasks to remain undeleted for a short period. There
|
||||
* may also be a few other unexpected tasks if, for example, the tasks that test
|
||||
* static allocation are also being used. */
|
||||
static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3;
|
||||
|
||||
/* Used to store a handle to the task that should be killed by a suicidal task,
|
||||
* before it kills itself. */
|
||||
TaskHandle_t xCreatedTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateSuicidalTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) NULL, uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vSuicidalTask, pvParameters )
|
||||
{
|
||||
volatile long l1, l2;
|
||||
TaskHandle_t xTaskToKill;
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 200 );
|
||||
|
||||
/* Test deletion of a task's secure context, if any. */
|
||||
portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
|
||||
|
||||
if( pvParameters != NULL )
|
||||
{
|
||||
/* This task is periodically created four times. Two 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. */
|
||||
l1 = 2;
|
||||
l2 = 89;
|
||||
l2 *= l1;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
} /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCreateTasks, pvParameters )
|
||||
{
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 1000 );
|
||||
UBaseType_t uxPriority;
|
||||
|
||||
/* Remove compiler warning about unused parameter. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Delay at the start to ensure tasks created by other demos have been
|
||||
* created before storing the current number of tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks();
|
||||
|
||||
uxPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Just loop round, delaying then creating the four suicidal tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
xCreatedTask = NULL;
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
|
||||
xTaskCreate( vSuicidalTask, "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
|
||||
|
||||
++usCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
* are not any more than four extra tasks. */
|
||||
BaseType_t xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static uint16_t usLastCreationCount = 0xfff;
|
||||
BaseType_t xReturn = pdTRUE;
|
||||
static UBaseType_t uxTasksRunningNow;
|
||||
|
||||
if( usLastCreationCount == usCreationCount )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
usLastCreationCount = usCreationCount;
|
||||
}
|
||||
|
||||
uxTasksRunningNow = ( UBaseType_t ) uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
488
SOFTWARE-FreeRTOS/Common/Minimal/dynamic.c
Normal file
488
SOFTWARE-FreeRTOS/Common/Minimal/dynamic.c
Normal file
@ -0,0 +1,488 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises its priority above that of the controller task before each
|
||||
* increment, lowering it again to its original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of its loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from its suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
|
||||
|
||||
static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#ifndef priSUSPENDED_RX_TASK_STACK_SIZE
|
||||
#define priSUSPENDED_RX_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE )
|
||||
#endif
|
||||
#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME pdMS_TO_TICKS( 128 )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( uint32_t ) 0xff )
|
||||
#define priNO_BLOCK ( ( TickType_t ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
* to the controller task to prevent them having to be file scope. */
|
||||
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
* counter variables for demonstration purposes. */
|
||||
static uint32_t ulCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
* Each complete iteration of the controller task increments this variable
|
||||
* provided no errors have been found. The variable maintaining the same value
|
||||
* is therefore indication of an error. */
|
||||
static volatile uint16_t usCheckVariable = ( uint16_t ) 0;
|
||||
static volatile BaseType_t xSuspendedQueueSendError = pdFALSE;
|
||||
static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
QueueHandle_t xSuspendedTestQueue;
|
||||
|
||||
/* The value the queue receive task expects to receive next. This is file
|
||||
* scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still
|
||||
* incrementing. */
|
||||
static uint32_t ulExpectedValue = ( uint32_t ) 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Start the three tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
|
||||
if( xSuspendedTestQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
* in use. The queue registry is provided as a means for kernel aware
|
||||
* debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
* is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
* by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
* defined to be less than 1. */
|
||||
vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" );
|
||||
|
||||
xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, "C_CTRL", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RX", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
|
||||
{
|
||||
volatile uint32_t * pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
* the task. */
|
||||
pulCounter = ( volatile uint32_t * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
* suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
|
||||
{
|
||||
volatile uint32_t * pulCounter;
|
||||
UBaseType_t uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
* the task. */
|
||||
pulCounter = ( volatile uint32_t * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
* shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Raise the priority above the controller task to ensure a context
|
||||
* switch does not occur while the variable is being accessed. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
{
|
||||
configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) );
|
||||
( *pulCounter )++;
|
||||
}
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
configASSERT( ( uxTaskPriorityGet( NULL ) == uxOurPriority ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static portTASK_FUNCTION( vCounterControlTask, pvParameters )
|
||||
{
|
||||
uint32_t ulLastCounter;
|
||||
short sLoops;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( uint32_t ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
* shared variable without risk of corruption. This is not really
|
||||
* needed as the other task raises its priority above this task's
|
||||
* priority. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
{
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
ulLastCounter = ulCounter;
|
||||
}
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
#if ( configNUMBER_OF_CORES > 1 )
|
||||
{
|
||||
eTaskState eState = eTaskGetState( xContinuousIncrementHandle );
|
||||
configASSERT( ( eState == eReady ) || ( eState == eRunning ) );
|
||||
}
|
||||
#else
|
||||
{
|
||||
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
* exclusion the whole scheduler will be locked. This is just for
|
||||
* demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
* with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared
|
||||
* variable. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( uint32_t ) 0;
|
||||
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
* We should therefore not return from this call until the limited count
|
||||
* task has suspended itself with a known value in the counter variable. */
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* This task should not run again until xLimitedIncrementHandle has
|
||||
* suspended itself. */
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
static uint32_t ulValueToSend = ( uint32_t ) 0;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
uint32_t ulReceivedValue;
|
||||
BaseType_t xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
* undesirable for a normal application. It is done here purely
|
||||
* to test the scheduler. The inner xTaskResumeAll() should
|
||||
* never return pdTRUE as the scheduler is still locked by the
|
||||
* outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
|
||||
if( xTaskResumeAll() != pdFALSE )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError != pdTRUE )
|
||||
{
|
||||
/* Only increment the variable if an error has not occurred. This
|
||||
* allows xAreDynamicPriorityTasksStillRunning() to check for stalled
|
||||
* tasks as well as explicit errors. */
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
BaseType_t xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
* since the last call. */
|
||||
static uint16_t usLastTaskCheck = ( uint16_t ) 0;
|
||||
static uint32_t ulLastExpectedValue = ( uint32_t ) 0U;
|
||||
BaseType_t xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
* is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( ulExpectedValue == ulLastExpectedValue )
|
||||
{
|
||||
/* The value being received by the queue receive task has not
|
||||
* incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
ulLastExpectedValue = ulExpectedValue;
|
||||
|
||||
return xReturn;
|
||||
}
|
117
SOFTWARE-FreeRTOS/Common/Minimal/flash.c
Normal file
117
SOFTWARE-FreeRTOS/Common/Minimal/flash.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This version of flash .c is for use on systems that have limited stack space
|
||||
* and no display facilities. The complete version can be found in the
|
||||
* Demo/Common/Full directory.
|
||||
*
|
||||
* Three tasks are created, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 200ms, the second every 400ms, the third every 600ms.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define ledNUMBER_OF_LEDS ( 3 )
|
||||
#define ledFLASH_RATE_BASE ( ( TickType_t ) 333 )
|
||||
|
||||
/* Variable used by the created tasks to calculate the LED number to use, and
|
||||
* the rate at which they should flash the LED. */
|
||||
static volatile UBaseType_t uxFlashTaskNumber = 0;
|
||||
|
||||
/* The task that is created three times. */
|
||||
static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
BaseType_t xLEDTask;
|
||||
|
||||
/* Create the three tasks. */
|
||||
for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )
|
||||
{
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
|
||||
{
|
||||
TickType_t xFlashRate, xLastFlashTime;
|
||||
UBaseType_t uxLED;
|
||||
|
||||
/* The parameters are not used. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Calculate the LED and flash rate. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* See which of the eight LED's we should use. */
|
||||
uxLED = uxFlashTaskNumber;
|
||||
|
||||
/* Update so the next task uses the next LED. */
|
||||
uxFlashTaskNumber++;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) uxLED );
|
||||
xFlashRate /= portTICK_PERIOD_MS;
|
||||
|
||||
/* We will turn the LED on and off again in the delay period, so each
|
||||
* delay is only half the total period. */
|
||||
xFlashRate /= ( TickType_t ) 2;
|
||||
|
||||
/* We need to initialise xLastFlashTime prior to the first call to
|
||||
* vTaskDelayUntil(). */
|
||||
xLastFlashTime = xTaskGetTickCount();
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
}
|
||||
} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */
|
95
SOFTWARE-FreeRTOS/Common/Minimal/flash_timer.c
Normal file
95
SOFTWARE-FreeRTOS/Common/Minimal/flash_timer.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Repeatedly toggles one or more LEDs using software timers - one timer per
|
||||
* LED.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash_timer.h"
|
||||
|
||||
/* The toggle rates are all a multple of ledFLASH_RATE_BASE. */
|
||||
#define ledFLASH_RATE_BASE ( ( ( TickType_t ) 333 ) / portTICK_PERIOD_MS )
|
||||
|
||||
/* A block time of zero simple means "don't block". */
|
||||
#define ledDONT_BLOCK ( ( TickType_t ) 0 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The callback function used by each LED flashing timer. All the timers use
|
||||
* this function, and the timer ID is used within the function to determine
|
||||
* which timer has actually expired.
|
||||
*/
|
||||
static void prvLEDTimerCallback( TimerHandle_t xTimer );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTimers( UBaseType_t uxNumberOfLEDs )
|
||||
{
|
||||
UBaseType_t uxLEDTimer;
|
||||
TimerHandle_t xTimer;
|
||||
|
||||
/* Create and start the requested number of timers. */
|
||||
for( uxLEDTimer = 0; uxLEDTimer < uxNumberOfLEDs; ++uxLEDTimer )
|
||||
{
|
||||
/* Create the timer. */
|
||||
xTimer = xTimerCreate( "Flasher", /* A text name, purely to help debugging. */
|
||||
ledFLASH_RATE_BASE * ( uxLEDTimer + 1 ), /* The timer period, which is a multiple of ledFLASH_RATE_BASE. */
|
||||
pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
|
||||
( void * ) uxLEDTimer, /* The ID is used to identify the timer within the timer callback function, as each timer uses the same callback. */
|
||||
prvLEDTimerCallback /* Each timer uses the same callback. */
|
||||
);
|
||||
|
||||
/* If the timer was created successfully, attempt to start it. If the
|
||||
* scheduler has not yet been started then the timer command queue must
|
||||
* be long enough to hold each command sent to it until such time that the
|
||||
* scheduler is started. The timer command queue length is set by
|
||||
* configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */
|
||||
if( xTimer != NULL )
|
||||
{
|
||||
xTimerStart( xTimer, ledDONT_BLOCK );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLEDTimerCallback( TimerHandle_t xTimer )
|
||||
{
|
||||
BaseType_t xTimerID;
|
||||
|
||||
/* The timer ID is used to identify the timer that has actually expired as
|
||||
* each timer uses the same callback. The ID is then also used as the number
|
||||
* of the LED that is to be toggled. */
|
||||
xTimerID = ( BaseType_t ) pvTimerGetTimerID( xTimer );
|
||||
vParTestToggleLED( xTimerID );
|
||||
}
|
346
SOFTWARE-FreeRTOS/Common/Minimal/flop.c
Normal file
346
SOFTWARE-FreeRTOS/Common/Minimal/flop.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates eight tasks, each of which loops continuously performing a floating
|
||||
* point calculation.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle
|
||||
* priority means that these tasks will get pre-empted any time another task is
|
||||
* ready to run or a time slice occurs. More often than not the pre-emption
|
||||
* will occur mid calculation, creating a good test of the schedulers context
|
||||
* switch mechanism - a calculation producing an unexpected result could be a
|
||||
* symptom of a corruption in the context of a task.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#ifndef mathSTACK_SIZE
|
||||
#define mathSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#endif
|
||||
|
||||
#define mathNUMBER_OF_TASKS ( 4 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
* Each of the four is created twice. */
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
* task gets a calculation wrong it will stop setting its check variable. */
|
||||
static uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE d1, d2, d3, d4;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
volatile portDOUBLE dAnswer;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Some ports require that tasks that use a hardware floating point unit
|
||||
* tell the kernel that they require a floating point context before any
|
||||
* floating point instructions are executed. */
|
||||
portTASK_USES_FLOATING_POINT();
|
||||
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
dAnswer = ( d1 + d2 ) * d3;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
d4 = ( d1 + d2 ) * d3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct then set set the check
|
||||
* variable. The check variable will get set to pdFALSE each time
|
||||
* xAreMathsTaskStillRunning() is executed. */
|
||||
( *pusTaskCheckVariable ) = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE d1, d2, d3, d4;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
volatile portDOUBLE dAnswer;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Some ports require that tasks that use a hardware floating point unit
|
||||
* tell the kernel that they require a floating point context before any
|
||||
* floating point instructions are executed. */
|
||||
portTASK_USES_FLOATING_POINT();
|
||||
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
dAnswer = ( d1 / d2 ) * d3;
|
||||
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
d4 = ( d1 / d2 ) * d3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct then set set the check
|
||||
* variable. The check variable will get set to pdFALSE each time
|
||||
* xAreMathsTaskStillRunning() is executed. */
|
||||
( *pusTaskCheckVariable ) = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Some ports require that tasks that use a hardware floating point unit
|
||||
* tell the kernel that they require a floating point context before any
|
||||
* floating point instructions are executed. */
|
||||
portTASK_USES_FLOATING_POINT();
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5;
|
||||
dTotal1 += ( portDOUBLE ) xPosition + 5.5;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ xPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct then set set the check
|
||||
* variable. The check variable will get set to pdFALSE each time
|
||||
* xAreMathsTaskStillRunning() is executed. */
|
||||
( *pusTaskCheckVariable ) = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Some ports require that tasks that use a hardware floating point unit
|
||||
* tell the kernel that they require a floating point context before any
|
||||
* floating point instructions are executed. */
|
||||
portTASK_USES_FLOATING_POINT();
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pdArray[ xPosition ] = ( portDOUBLE ) xPosition * 12.123;
|
||||
dTotal1 += ( portDOUBLE ) xPosition * 12.123;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ xPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct then set set the check
|
||||
* variable. The check variable will get set to pdFALSE each time
|
||||
* xAreMathsTaskStillRunning() is executed. */
|
||||
( *pusTaskCheckVariable ) = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn = pdPASS, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
* have been set to pdPASS. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] != pdTRUE )
|
||||
{
|
||||
/* The check has not been set so the associated task has either
|
||||
* stalled or detected an error. */
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the variable so it can be checked again the next time this
|
||||
* function is executed. */
|
||||
usTaskCheck[ xTask ] = pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
161
SOFTWARE-FreeRTOS/Common/Minimal/integer.c
Normal file
161
SOFTWARE-FreeRTOS/Common/Minimal/integer.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates one or more tasks that repeatedly perform a set of integer
|
||||
* calculations. The result of each run-time calculation is compared to the
|
||||
* known expected result - with a mismatch being indicative of an error in the
|
||||
* context switch mechanism.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "integer.h"
|
||||
|
||||
/* The constants used in the calculation. */
|
||||
#define intgCONST1 ( ( long ) 123 )
|
||||
#define intgCONST2 ( ( long ) 234567 )
|
||||
#define intgCONST3 ( ( long ) -3 )
|
||||
#define intgCONST4 ( ( long ) 7 )
|
||||
#define intgEXPECTED_ANSWER ( ( ( intgCONST1 + intgCONST2 ) * intgCONST3 ) / intgCONST4 )
|
||||
|
||||
#define intgSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* As this is the minimal version, we will only create one task. */
|
||||
#define intgNUMBER_OF_TASKS ( 1 )
|
||||
|
||||
/* The task function. Repeatedly performs a 32 bit calculation, checking the
|
||||
* result against the expected result. If the result is incorrect then the
|
||||
* context switch must have caused some corruption. */
|
||||
static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters );
|
||||
|
||||
/* Variables that are set to true within the calculation task to indicate
|
||||
* that the task is still executing. The check task sets the variable back to
|
||||
* false, flagging an error if the variable is still false the next time it
|
||||
* is called. */
|
||||
static BaseType_t xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( BaseType_t ) pdFALSE };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartIntegerMathTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
short sTask;
|
||||
|
||||
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
|
||||
{
|
||||
xTaskCreate( vCompeteingIntMathTask, "IntMath", intgSTACK_SIZE, ( void * ) &( xTaskCheck[ sTask ] ), uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters )
|
||||
{
|
||||
/* These variables are all effectively set to constants so they are volatile to
|
||||
* ensure the compiler does not just get rid of them. */
|
||||
volatile long lValue;
|
||||
short sError = pdFALSE;
|
||||
volatile BaseType_t * pxTaskHasExecuted;
|
||||
|
||||
/* Set a pointer to the variable we are going to set to true each
|
||||
* iteration. This is also a good test of the parameter passing mechanism
|
||||
* within each port. */
|
||||
pxTaskHasExecuted = ( volatile BaseType_t * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
/* Perform the calculation. This will store partial value in
|
||||
* registers, resulting in a good test of the context switch mechanism. */
|
||||
lValue = intgCONST1;
|
||||
lValue += intgCONST2;
|
||||
|
||||
/* Yield in case cooperative scheduling is being used. */
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Finish off the calculation. */
|
||||
lValue *= intgCONST3;
|
||||
lValue /= intgCONST4;
|
||||
|
||||
/* If the calculation is found to be incorrect we stop setting the
|
||||
* TaskHasExecuted variable so the check task can see an error has
|
||||
* occurred. */
|
||||
if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* We have not encountered any errors, so set the flag that show
|
||||
* we are still executing. This will be periodically cleared by
|
||||
* the check task. */
|
||||
portENTER_CRITICAL();
|
||||
*pxTaskHasExecuted = pdTRUE;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Yield in case cooperative scheduling is being used. */
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreIntegerMathsTaskStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn = pdTRUE;
|
||||
short sTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
* are still being set to true. */
|
||||
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
|
||||
{
|
||||
if( xTaskCheck[ sTask ] == pdFALSE )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
/* Reset the check variable so we can tell if it has been set by
|
||||
* the next time around. */
|
||||
xTaskCheck[ sTask ] = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
2
SOFTWARE-FreeRTOS/Common/Minimal/readme.txt
Normal file
2
SOFTWARE-FreeRTOS/Common/Minimal/readme.txt
Normal file
@ -0,0 +1,2 @@
|
||||
This directory contains the implementation of the "common demo tasks". These
|
||||
are test tasks and demo tasks that are used by nearly all the demo applications.
|
411
SOFTWARE-FreeRTOS/Common/Minimal/recmutex.c
Normal file
411
SOFTWARE-FreeRTOS/Common/Minimal/recmutex.c
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The tasks defined on this page demonstrate the use of recursive mutexes.
|
||||
*
|
||||
* For recursive mutex functionality the created mutex should be created using
|
||||
* xSemaphoreCreateRecursiveMutex(), then be manipulated
|
||||
* using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
|
||||
* functions.
|
||||
*
|
||||
* This demo creates three tasks all of which access the same recursive mutex:
|
||||
*
|
||||
* prvRecursiveMutexControllingTask() has the highest priority so executes
|
||||
* first and grabs the mutex. It then performs some recursive accesses -
|
||||
* between each of which it sleeps for a short period to let the lower
|
||||
* priority tasks execute. When it has completed its demo functionality
|
||||
* it gives the mutex back before suspending itself.
|
||||
*
|
||||
* prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
|
||||
* a blocking 'take'. The blocking task has a lower priority than the
|
||||
* controlling task so by the time it executes the mutex has already been
|
||||
* taken by the controlling task, causing the blocking task to block. It
|
||||
* does not unblock until the controlling task has given the mutex back,
|
||||
* and it does not actually run until the controlling task has suspended
|
||||
* itself (due to the relative priorities). When it eventually does obtain
|
||||
* the mutex all it does is give the mutex back prior to also suspending
|
||||
* itself. At this point both the controlling task and the blocking task are
|
||||
* suspended.
|
||||
*
|
||||
* prvRecursiveMutexPollingTask() runs at the idle priority. It spins round
|
||||
* a tight loop attempting to obtain the mutex with a non-blocking call. As
|
||||
* the lowest priority task it will not successfully obtain the mutex until
|
||||
* both the controlling and blocking tasks are suspended. Once it eventually
|
||||
* does obtain the mutex it first unsuspends both the controlling task and
|
||||
* blocking task prior to giving the mutex back - resulting in the polling
|
||||
* task temporarily inheriting the controlling tasks priority.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "recmutex.h"
|
||||
|
||||
/* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can
|
||||
* be overridden by a definition in FreeRTOSConfig.h. */
|
||||
#ifndef recmuCONTROLLING_TASK_PRIORITY
|
||||
#define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#endif
|
||||
#define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 )
|
||||
|
||||
/* The recursive call depth. */
|
||||
#define recmuMAX_COUNT ( 10 )
|
||||
|
||||
/* Misc. */
|
||||
#define recmuSHORT_DELAY ( pdMS_TO_TICKS( 20 ) )
|
||||
#define recmuNO_DELAY ( ( TickType_t ) 0 )
|
||||
#define recmu15ms_DELAY ( pdMS_TO_TICKS( 15 ) )
|
||||
|
||||
#ifndef recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE
|
||||
#define recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#endif
|
||||
|
||||
/* The three tasks as described at the top of this file. */
|
||||
static void prvRecursiveMutexControllingTask( void * pvParameters );
|
||||
static void prvRecursiveMutexBlockingTask( void * pvParameters );
|
||||
static void prvRecursiveMutexPollingTask( void * pvParameters );
|
||||
|
||||
/* The mutex used by the demo. */
|
||||
static SemaphoreHandle_t xMutex;
|
||||
|
||||
/* Variables used to detect and latch errors. */
|
||||
static volatile BaseType_t xErrorOccurred = pdFALSE, xControllingIsSuspended = pdFALSE, xBlockingIsSuspended = pdFALSE;
|
||||
static volatile UBaseType_t uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0;
|
||||
|
||||
/* Handles of the two higher priority tasks, required so they can be resumed
|
||||
* (unsuspended). */
|
||||
static TaskHandle_t xControllingTaskHandle, xBlockingTaskHandle;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartRecursiveMutexTasks( void )
|
||||
{
|
||||
/* Just creates the mutex and the three tasks. */
|
||||
|
||||
xMutex = xSemaphoreCreateRecursiveMutex();
|
||||
|
||||
if( xMutex != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
||||
* in use. The registry is provided as a means for kernel aware
|
||||
* debuggers to locate mutex and has no purpose if a kernel aware debugger
|
||||
* is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
* by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
* defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Recursive_Mutex" );
|
||||
|
||||
xTaskCreate( prvRecursiveMutexControllingTask, "Rec1", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
|
||||
xTaskCreate( prvRecursiveMutexBlockingTask, "Rec2", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );
|
||||
xTaskCreate( prvRecursiveMutexPollingTask, "Rec3", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexControllingTask( void * pvParameters )
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Should not be able to 'give' the mutex, as we have not yet 'taken'
|
||||
* it. The first time through, the mutex will not have been used yet,
|
||||
* subsequent times through, at this point the mutex will be held by the
|
||||
* polling task. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
for( ux = 0; ux < recmuMAX_COUNT; ux++ )
|
||||
{
|
||||
/* We should now be able to take the mutex as many times as
|
||||
* we like.
|
||||
*
|
||||
* The first time through the mutex will be immediately available, on
|
||||
* subsequent times through the mutex will be held by the polling task
|
||||
* at this point and this Take will cause the polling task to inherit
|
||||
* the priority of this task. In this case the block time must be
|
||||
* long enough to ensure the polling task will execute again before the
|
||||
* block time expires. If the block time does expire then the error
|
||||
* flag will be set here. */
|
||||
if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Ensure the other task attempting to access the mutex (and the
|
||||
* other demo tasks) are able to execute to ensure they either block
|
||||
* (where a block time is specified) or return an error (where no
|
||||
* block time is specified) as the mutex is held by this task. */
|
||||
vTaskDelay( recmuSHORT_DELAY );
|
||||
}
|
||||
|
||||
/* For each time we took the mutex, give it back. */
|
||||
for( ux = 0; ux < recmuMAX_COUNT; ux++ )
|
||||
{
|
||||
/* Ensure the other task attempting to access the mutex (and the
|
||||
* other demo tasks) are able to execute. */
|
||||
vTaskDelay( recmuSHORT_DELAY );
|
||||
|
||||
/* We should now be able to give the mutex as many times as we
|
||||
* took it. When the mutex is available again the Blocking task
|
||||
* should be unblocked but not run because it has a lower priority
|
||||
* than this task. The polling task should also not run at this point
|
||||
* as it too has a lower priority than this task. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Having given it back the same number of times as it was taken, we
|
||||
* should no longer be the mutex owner, so the next give should fail. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Keep count of the number of cycles this task has performed so a
|
||||
* stall can be detected. */
|
||||
uxControllingCycles++;
|
||||
|
||||
/* Suspend ourselves so the blocking task can execute. */
|
||||
xControllingIsSuspended = pdTRUE;
|
||||
vTaskSuspend( NULL );
|
||||
xControllingIsSuspended = pdFALSE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexBlockingTask( void * pvParameters )
|
||||
{
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* This task will run while the controlling task is blocked, and the
|
||||
* controlling task will block only once it has the mutex - therefore
|
||||
* this call should block until the controlling task has given up the
|
||||
* mutex, and not actually execute past this call until the controlling
|
||||
* task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY
|
||||
* to ensure the task's state is reported as Blocked and not Suspended in
|
||||
* a later call to configASSERT() (within the polling task). */
|
||||
if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS )
|
||||
{
|
||||
if( xControllingIsSuspended != pdTRUE )
|
||||
{
|
||||
/* Did not expect to execute until the controlling task was
|
||||
* suspended. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Give the mutex back before suspending ourselves to allow
|
||||
* the polling task to obtain the mutex. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
xBlockingIsSuspended = pdTRUE;
|
||||
vTaskSuspend( NULL );
|
||||
xBlockingIsSuspended = pdFALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should not leave the xSemaphoreTakeRecursive() function
|
||||
* until the mutex was obtained. */
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* The controlling and blocking tasks should be in lock step. */
|
||||
if( uxControllingCycles != ( UBaseType_t ) ( uxBlockingCycles + 1 ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
/* Keep count of the number of cycles this task has performed so a
|
||||
* stall can be detected. */
|
||||
uxBlockingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexPollingTask( void * pvParameters )
|
||||
{
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Keep attempting to obtain the mutex. It should only be obtained when
|
||||
* the blocking task has suspended itself, which in turn should only
|
||||
* happen when the controlling task is also suspended. */
|
||||
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
|
||||
{
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xControllingTaskHandle ) == eSuspended );
|
||||
configASSERT( eTaskGetState( xBlockingTaskHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Is the blocking task suspended? */
|
||||
if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep count of the number of cycles this task has performed
|
||||
* so a stall can be detected. */
|
||||
uxPollingCycles++;
|
||||
|
||||
/* We can resume the other tasks here even though they have a
|
||||
* higher priority than the polling task. When they execute they
|
||||
* will attempt to obtain the mutex but fail because the polling
|
||||
* task is still the mutex holder. The polling task (this task)
|
||||
* will then inherit the higher priority. The Blocking task will
|
||||
* block indefinitely when it attempts to obtain the mutex, the
|
||||
* Controlling task will only block for a fixed period and an
|
||||
* error will be latched if the polling task has not returned the
|
||||
* mutex by the time this fixed period has expired. */
|
||||
vTaskResume( xBlockingTaskHandle );
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
vTaskResume( xControllingTaskHandle );
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* The other two tasks should now have executed and no longer
|
||||
* be suspended. */
|
||||
if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
#if ( INCLUDE_uxTaskPriorityGet == 1 )
|
||||
{
|
||||
/* Check priority inherited. */
|
||||
configASSERT( uxTaskPriorityGet( NULL ) == recmuCONTROLLING_TASK_PRIORITY );
|
||||
}
|
||||
#endif /* INCLUDE_uxTaskPriorityGet */
|
||||
|
||||
#if ( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xControllingTaskHandle ) == eBlocked );
|
||||
configASSERT( eTaskGetState( xBlockingTaskHandle ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Release the mutex, disinheriting the higher priority again. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
|
||||
#if ( INCLUDE_uxTaskPriorityGet == 1 )
|
||||
{
|
||||
/* Check priority disinherited. */
|
||||
configASSERT( uxTaskPriorityGet( NULL ) == recmuPOLLING_TASK_PRIORITY );
|
||||
}
|
||||
#endif /* INCLUDE_uxTaskPriorityGet */
|
||||
}
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreRecursiveMutexTasksStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
static UBaseType_t uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;
|
||||
|
||||
/* Is the controlling task still cycling? */
|
||||
if( uxLastControllingCycles == uxControllingCycles )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastControllingCycles = uxControllingCycles;
|
||||
}
|
||||
|
||||
/* Is the blocking task still cycling? */
|
||||
if( uxLastBlockingCycles == uxBlockingCycles )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastBlockingCycles = uxBlockingCycles;
|
||||
}
|
||||
|
||||
/* Is the polling task still cycling? */
|
||||
if( uxLastPollingCycles == uxPollingCycles )
|
||||
{
|
||||
xErrorOccurred = __LINE__;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastPollingCycles = uxPollingCycles;
|
||||
}
|
||||
|
||||
if( xErrorOccurred != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
271
SOFTWARE-FreeRTOS/Common/Minimal/semtest.c
Normal file
271
SOFTWARE-FreeRTOS/Common/Minimal/semtest.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates two sets of two tasks. The tasks within a set share a variable, access
|
||||
* to which is guarded by a semaphore.
|
||||
*
|
||||
* Each task starts by attempting to obtain the semaphore. On obtaining a
|
||||
* semaphore a task checks to ensure that the guarded variable has an expected
|
||||
* value. It then clears the variable to zero before counting it back up to the
|
||||
* expected value in increments of 1. After each increment the variable is checked
|
||||
* to ensure it contains the value to which it was just set. When the starting
|
||||
* value is again reached the task releases the semaphore giving the other task in
|
||||
* the set a chance to do exactly the same thing. The starting value is high
|
||||
* enough to ensure that a tick is likely to occur during the incrementing loop.
|
||||
*
|
||||
* An error is flagged if at any time during the process a shared variable is
|
||||
* found to have a value other than that expected. Such an occurrence would
|
||||
* suggest an error in the mutual exclusion mechanism by which access to the
|
||||
* variable is restricted.
|
||||
*
|
||||
* The first set of two tasks poll their semaphore. The second set use blocking
|
||||
* calls.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "semtest.h"
|
||||
|
||||
/* The value to which the shared variables are counted. */
|
||||
#define semtstBLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xfff )
|
||||
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xff )
|
||||
|
||||
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
#define semtstNUM_TASKS ( 4 )
|
||||
|
||||
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
|
||||
|
||||
/* The task function as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );
|
||||
|
||||
/* Structure used to pass parameters to each task. */
|
||||
typedef struct SEMAPHORE_PARAMETERS
|
||||
{
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
volatile uint32_t * pulSharedVariable;
|
||||
TickType_t xBlockTime;
|
||||
} xSemaphoreParameters;
|
||||
|
||||
/* Variables used to check that all the tasks are still running without errors. */
|
||||
static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
static volatile short sNextCheckVariable = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartSemaphoreTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
|
||||
const TickType_t xBlockTime = ( TickType_t ) 100;
|
||||
|
||||
/* Create the structure used to pass parameters to the first two tasks. */
|
||||
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxFirstSemaphoreParameters != NULL )
|
||||
{
|
||||
/* Create the semaphore used by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
|
||||
|
||||
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
xSemaphoreGive( pxFirstSemaphoreParameters->xSemaphore );
|
||||
|
||||
/* Create the variable which is to be shared by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) );
|
||||
|
||||
/* Initialise the share variable to the value the tasks expect. */
|
||||
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
|
||||
/* The first two tasks do not block on semaphore calls. */
|
||||
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
|
||||
|
||||
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one
|
||||
* is in use. The registry is provided as a means for kernel aware
|
||||
* debuggers to locate semaphores and has no purpose if a kernel aware
|
||||
* debugger is not being used. The call to vQueueAddToRegistry() will
|
||||
* be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
* defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) pxFirstSemaphoreParameters->xSemaphore, "Counting_Sem_1" );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do exactly the same to create the second set of tasks, only this time
|
||||
* provide a block time for the semaphore calls. */
|
||||
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxSecondSemaphoreParameters != NULL )
|
||||
{
|
||||
pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
|
||||
|
||||
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
xSemaphoreGive( pxSecondSemaphoreParameters->xSemaphore );
|
||||
|
||||
pxSecondSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) );
|
||||
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
|
||||
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
|
||||
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one
|
||||
* is in use. The registry is provided as a means for kernel aware
|
||||
* debuggers to locate semaphores and has no purpose if a kernel aware
|
||||
* debugger is not being used. The call to vQueueAddToRegistry() will
|
||||
* be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
* defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) pxSecondSemaphoreParameters->xSemaphore, "Counting_Sem_2" );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )
|
||||
{
|
||||
xSemaphoreParameters * pxParameters;
|
||||
volatile uint32_t * pulSharedVariable, ulExpectedValue;
|
||||
uint32_t ulCounter;
|
||||
short sError = pdFALSE, sCheckVariableToUse;
|
||||
|
||||
/* See which check variable to use. sNextCheckVariable is not semaphore
|
||||
* protected! */
|
||||
portENTER_CRITICAL();
|
||||
sCheckVariableToUse = sNextCheckVariable;
|
||||
sNextCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* A structure is passed in as the parameter. This contains the shared
|
||||
* variable being guarded. */
|
||||
pxParameters = ( xSemaphoreParameters * ) pvParameters;
|
||||
pulSharedVariable = pxParameters->pulSharedVariable;
|
||||
|
||||
/* If we are blocking we use a much higher count to ensure loads of context
|
||||
* switches occur during the count. */
|
||||
if( pxParameters->xBlockTime > ( TickType_t ) 0 )
|
||||
{
|
||||
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
/* Try to obtain the semaphore. */
|
||||
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
/* We have the semaphore and so expect any other tasks using the
|
||||
* shared variable to have left it in the state we expect to find
|
||||
* it. */
|
||||
if( *pulSharedVariable != ulExpectedValue )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
/* Clear the variable, then count it back up to the expected value
|
||||
* before releasing the semaphore. Would expect a context switch or
|
||||
* two during this time. */
|
||||
for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
|
||||
{
|
||||
*pulSharedVariable = ulCounter;
|
||||
|
||||
if( *pulSharedVariable != ulCounter )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the semaphore, and if no errors have occurred increment the check
|
||||
* variable. */
|
||||
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
if( sCheckVariableToUse < semtstNUM_TASKS )
|
||||
{
|
||||
( sCheckVariables[ sCheckVariableToUse ] )++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a block time then we are running at a priority higher
|
||||
* than the idle priority. This task takes a long time to complete
|
||||
* a cycle (deliberately so to test the guarding) so will be starving
|
||||
* out lower priority tasks. Block for some time to allow give lower
|
||||
* priority tasks some processor time. */
|
||||
if( pxParameters->xBlockTime != ( TickType_t ) 0 )
|
||||
{
|
||||
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
|
||||
{
|
||||
/* We have not got the semaphore yet, so no point using the
|
||||
* processor. We are not blocking when attempting to obtain the
|
||||
* semaphore. */
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
BaseType_t xTask, xReturn = pdTRUE;
|
||||
|
||||
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
|
||||
{
|
||||
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
324
SOFTWARE-FreeRTOS/Common/Minimal/sp_flop.c
Normal file
324
SOFTWARE-FreeRTOS/Common/Minimal/sp_flop.c
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* FreeRTOS V202212.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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates eight tasks, each of which loops continuously performing a floating
|
||||
* point calculation - using single precision variables.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle priority
|
||||
* means that these tasks will get pre-empted any time another task is ready to run
|
||||
* or a time slice occurs. More often than not the pre-emption will occur mid
|
||||
* calculation, creating a good test of the schedulers context switch mechanism - a
|
||||
* calculation producing an unexpected result could be a symptom of a corruption in
|
||||
* the context of a task.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#define mathSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define mathNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
* Each of the four is created twice. */
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
* task gets a calculation wrong it will
|
||||
* stop incrementing its check variable. */
|
||||
static volatile uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
|
||||
{
|
||||
volatile float f1, f2, f3, f4;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
volatile float fAnswer;
|
||||
short sError = pdFALSE;
|
||||
|
||||
f1 = 123.4567F;
|
||||
f2 = 2345.6789F;
|
||||
f3 = -918.222F;
|
||||
|
||||
fAnswer = ( f1 + f2 ) * f3;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( uint16_t * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
f1 = 123.4567F;
|
||||
f2 = 2345.6789F;
|
||||
f3 = -918.222F;
|
||||
|
||||
f4 = ( f1 + f2 ) * f3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( f4 - fAnswer ) > 0.001F )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
|
||||
{
|
||||
volatile float f1, f2, f3, f4;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
volatile float fAnswer;
|
||||
short sError = pdFALSE;
|
||||
|
||||
f1 = -389.38F;
|
||||
f2 = 32498.2F;
|
||||
f3 = -2.0001F;
|
||||
|
||||
fAnswer = ( f1 / f2 ) * f3;
|
||||
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( uint16_t * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ; ; )
|
||||
{
|
||||
f1 = -389.38F;
|
||||
f2 = 32498.2F;
|
||||
f3 = -2.0001F;
|
||||
|
||||
f4 = ( f1 / f2 ) * f3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
* increment of the check variable. */
|
||||
if( fabs( f4 - fAnswer ) > 0.001F )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know
|
||||
* this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
|
||||
{
|
||||
volatile float * pfArray, fTotal1, fTotal2, fDifference, fPosition;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( uint16_t * ) pvParameters;
|
||||
|
||||
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
fTotal1 = 0.0F;
|
||||
fTotal2 = 0.0F;
|
||||
fPosition = 0.0F;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pfArray[ xPosition ] = fPosition + 5.5F;
|
||||
fTotal1 += fPosition + 5.5F;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
fTotal2 += pfArray[ xPosition ];
|
||||
}
|
||||
|
||||
fDifference = fTotal1 - fTotal2;
|
||||
|
||||
if( fabs( fDifference ) > 0.001F )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
|
||||
{
|
||||
volatile float * pfArray, fTotal1, fTotal2, fDifference, fPosition;
|
||||
volatile uint16_t * pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
* as the parameter. */
|
||||
pusTaskCheckVariable = ( uint16_t * ) pvParameters;
|
||||
|
||||
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
* array. Then run through the array adding up all the values. If the two totals
|
||||
* do not match, stop the check variable from incrementing. */
|
||||
for( ; ; )
|
||||
{
|
||||
fTotal1 = 0.0F;
|
||||
fTotal2 = 0.0F;
|
||||
fPosition = 0.0F;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pfArray[ xPosition ] = fPosition * 12.123F;
|
||||
fTotal1 += fPosition * 12.123F;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
fTotal2 += pfArray[ xPosition ];
|
||||
}
|
||||
|
||||
fDifference = fTotal1 - fTotal2;
|
||||
|
||||
if( fabs( fDifference ) > 0.001F )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
* variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
* since the last call. */
|
||||
static uint16_t usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
|
||||
BaseType_t xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
* are still incrementing. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
14
SOFTWARE-FreeRTOS/Common/ReadMe.txt
Normal file
14
SOFTWARE-FreeRTOS/Common/ReadMe.txt
Normal file
@ -0,0 +1,14 @@
|
||||
Contains the files that are not specific to any one demo, but are instead used
|
||||
by all the demo applications.
|
||||
|
||||
Most of the directories are now obsolete, and only maintained for backward
|
||||
compatibility. The directories in active use are:
|
||||
|
||||
+ Minimal - this contains the implementation of what are referred to as the
|
||||
"Standard Demo Tasks". These are used by all the demo applications. Their only
|
||||
purpose is to demonstrate the FreeRTOS API and test the FreeRTOS features. The
|
||||
directory is called 'Minimal' as it contains a minimal implementation of files
|
||||
contained in the 'Full' directory - but the 'Full' directory is no longer used.
|
||||
|
||||
+ include - contains header files for the C source files located in the Minimal
|
||||
directory.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x21FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x23FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x27FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
@ -0,0 +1,428 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition and functions for using AT91SAM9XE-related features, such
|
||||
/// has PIO pins, memories, etc.
|
||||
///
|
||||
/// !Usage
|
||||
/// -# The code for booting the board is provided by board_cstartup.S and
|
||||
/// board_lowlevel.c.
|
||||
/// -# For using board PIOs, board characteristics (clock, etc.) and external
|
||||
/// components, see board.h.
|
||||
/// -# For manipulating memories (remapping, SDRAM, etc.), see board_memories.h.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \unit
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition of AT91SAM9XE-EK characteristics, AT91SAM9XE-dependant PIOs and
|
||||
/// external components interfacing.
|
||||
///
|
||||
/// !Usage
|
||||
/// -# For operating frequency information, see "SAM9XE-EK - Operating frequencies".
|
||||
/// -# For using portable PIO definitions, see "SAM9XE-EK - PIO definitions".
|
||||
/// -# Several USB definitions are included here (see "SAM9XE-EK - USB device").
|
||||
/// -# For external components definitions, see "SAM79260-EK - External components".
|
||||
/// -# For memory-related definitions, see "SAM79260-EK - Memories".
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(at91sam9xe128)
|
||||
#include "at91sam9xe128/AT91SAM9XE128.h"
|
||||
#elif defined(at91sam9xe256)
|
||||
#include "at91sam9xe256/AT91SAM9XE256.h"
|
||||
#elif defined(at91sam9xe512)
|
||||
#include "at91sam9xe512/AT91SAM9XE512.h"
|
||||
#else
|
||||
#error Board does not support the specified chip.
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Board Description"
|
||||
/// This page lists several definition related to the board description.
|
||||
///
|
||||
/// !Definitions
|
||||
/// - BOARD_NAME
|
||||
|
||||
/// Name of the board.
|
||||
#define BOARD_NAME "AT91SAM9XE-EK"
|
||||
/// Board definition.
|
||||
#define at91sam9xeek
|
||||
/// Family definition.
|
||||
#define at91sam9xe
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Operating frequencies"
|
||||
/// This page lists several definition related to the board operating frequency
|
||||
/// (when using the initialization done by board_lowlevel.c).
|
||||
///
|
||||
/// !Definitions
|
||||
/// - BOARD_MAINOSC
|
||||
/// - BOARD_MCK
|
||||
|
||||
/// Frequency of the board main oscillator.
|
||||
#define BOARD_MAINOSC 18432000
|
||||
|
||||
/// Master clock frequency (when using board_lowlevel.c).
|
||||
#define BOARD_MCK ((18432000 * 97 / 9) / 2)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - USB device"
|
||||
/// This page lists constants describing several characteristics (controller
|
||||
/// type, D+ pull-up type, etc.) of the USB device controller of the chip/board.
|
||||
///
|
||||
/// !Constants
|
||||
/// - BOARD_USB_UDP
|
||||
/// - BOARD_USB_PULLUP_INTERNAL
|
||||
/// - BOARD_USB_NUMENDPOINTS
|
||||
/// - BOARD_USB_ENDPOINTS_MAXPACKETSIZE
|
||||
/// - BOARD_USB_ENDPOINTS_BANKS
|
||||
/// - BOARD_USB_BMATTRIBUTES
|
||||
|
||||
/// Chip has a UDP controller.
|
||||
#define BOARD_USB_UDP
|
||||
|
||||
/// Indicates the D+ pull-up is internal to the USB controller.
|
||||
#define BOARD_USB_PULLUP_INTERNAL
|
||||
|
||||
/// Number of endpoints in the USB controller.
|
||||
#define BOARD_USB_NUMENDPOINTS 6
|
||||
|
||||
/// Returns the maximum packet size of the given endpoint.
|
||||
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE(i) ((i >= 4) ? 512 : 64)
|
||||
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE_FS 64
|
||||
|
||||
/// Returns the number of FIFO banks for the given endpoint.
|
||||
#define BOARD_USB_ENDPOINTS_BANKS(i) (((i == 0) || (i == 3)) ? 1 : 2)
|
||||
|
||||
/// USB attributes configuration descriptor (bus or self powered, remote wakeup)
|
||||
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - PIO definitions"
|
||||
/// This pages lists all the pio definitions contained in board.h. The constants
|
||||
/// are named using the following convention: PIN_* for a constant which defines
|
||||
/// a single Pin instance (but may include several PIOs sharing the same
|
||||
/// controller), and PINS_* for a list of Pin instances.
|
||||
///
|
||||
/// !DBGU
|
||||
/// - PINS_DBGU
|
||||
///
|
||||
/// !LEDs
|
||||
/// - PIN_LED_0
|
||||
/// - PIN_LED_1
|
||||
/// - PINS_LEDS
|
||||
/// - LED_POWER
|
||||
/// - LED_DS1
|
||||
///
|
||||
/// !Push buttons
|
||||
/// - PIN_PUSHBUTTON_1
|
||||
/// - PIN_PUSHBUTTON_2
|
||||
/// - PINS_PUSHBUTTONS
|
||||
/// - PUSHBUTTON_BP1
|
||||
/// - PUSHBUTTON_BP2
|
||||
///
|
||||
/// !USART0
|
||||
/// - PIN_USART0_RXD
|
||||
/// - PIN_USART0_TXD
|
||||
/// - PIN_USART0_SCK
|
||||
///
|
||||
/// !SPI0
|
||||
/// - PIN_SPI0_MISO
|
||||
/// - PIN_SPI0_MOSI
|
||||
/// - PIN_SPI0_SPCK
|
||||
/// - PINS_SPI0
|
||||
/// - PIN_SPI0_NPCS0
|
||||
/// - PIN_SPI0_NPCS1
|
||||
///
|
||||
/// !SSC
|
||||
/// - PINS_SSC_TX
|
||||
///
|
||||
/// !USB
|
||||
/// - PIN_USB_VBUS
|
||||
///
|
||||
/// !MCI
|
||||
/// - PINS_MCI
|
||||
///
|
||||
/// !TWI0
|
||||
/// - PINS_TWI0
|
||||
|
||||
/// List of all DBGU pin definitions.
|
||||
#define PINS_DBGU {(1<<14) | (1<<15), AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// LED #0 pin definition.
|
||||
#define PIN_LED_0 {1 << 9, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/// LED #1 pin definition.
|
||||
#define PIN_LED_1 {1 << 6, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
/// List of all LED definitions.
|
||||
#define PINS_LEDS PIN_LED_0, PIN_LED_1
|
||||
/// Power LED index.
|
||||
#define LED_POWER 0
|
||||
/// DS1 LED index.
|
||||
#define LED_DS1 1
|
||||
|
||||
/// Push button #1 pin definition.
|
||||
#define PIN_PUSHBUTTON_1 {1 << 30, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_PULLUP}
|
||||
/// Pusb button #2 pin definition.
|
||||
#define PIN_PUSHBUTTON_2 {1UL << 31, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_PULLUP}
|
||||
/// List of all pushbutton pin definitions.
|
||||
#define PINS_PUSHBUTTONS PIN_PUSHBUTTON_1, PIN_PUSHBUTTON_2
|
||||
/// Push button #1 index.
|
||||
#define PUSHBUTTON_BP1 0
|
||||
/// Push button #2 index.
|
||||
#define PUSHBUTTON_BP2 1
|
||||
|
||||
/// USART0 TXD pin definition.
|
||||
#define PIN_USART0_TXD {1 << 4, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 RXD pin definition.
|
||||
#define PIN_USART0_RXD {1 << 5, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 RTS pin definition.
|
||||
#define PIN_USART0_RTS {1 << 26, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 CTS pin definition.
|
||||
#define PIN_USART0_CTS {1 << 27, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 SCK pin definition.
|
||||
#define PIN_USART0_SCK {1UL << 31, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// SPI0 MISO pin definition.
|
||||
#define PIN_SPI0_MISO {1 << 0, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_PULLUP}
|
||||
/// SPI0 MOSI pin definition.
|
||||
#define PIN_SPI0_MOSI {1 << 1, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// SPI0 SPCK pin definition.
|
||||
#define PIN_SPI0_SPCK {1 << 2, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// List of SPI0 pin definitions (MISO, MOSI & SPCK).
|
||||
#define PINS_SPI0 PIN_SPI0_MISO, PIN_SPI0_MOSI, PIN_SPI0_SPCK
|
||||
/// SPI0 chip select 0 pin definition.
|
||||
#define PIN_SPI0_NPCS0 {AT91C_PA3_SPI0_NPCS0, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// SPI0 chip select 1 pin definition.
|
||||
#define PIN_SPI0_NPCS1 {AT91C_PC11_SPI0_NPCS1, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
|
||||
/// SSC transmitter pins definition.
|
||||
#define PINS_SSC_TX {0x00038000, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// USB VBus monitoring pin definition.
|
||||
#define PIN_USB_VBUS {1 << 5, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_INPUT, PIO_DEFAULT}
|
||||
|
||||
/// List of MCI pins definitions.
|
||||
#define PINS_MCI {0x0000003B, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}, \
|
||||
{1 << 8, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// TWI0 pins definition.
|
||||
#define PINS_TWI0 {0x01800000, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - External components"
|
||||
/// This page lists the definitions related to external on-board components
|
||||
/// located in the board.h file for the AT91SAM9XE-EK.
|
||||
///
|
||||
/// !AT45 Dataflash Card (A)
|
||||
/// - BOARD_AT45_A_SPI_BASE
|
||||
/// - BOARD_AT45_A_SPI_ID
|
||||
/// - BOARD_AT45_A_SPI_PINS
|
||||
/// - BOARD_AT45_A_SPI
|
||||
/// - BOARD_AT45_A_NPCS
|
||||
/// - BOARD_AT45_A_NPCS_PIN
|
||||
///
|
||||
/// !AT45 Dataflash (B)
|
||||
/// - BOARD_AT45_B_SPI_BASE
|
||||
/// - BOARD_AT45_B_SPI_ID
|
||||
/// - BOARD_AT45_B_SPI_PINS
|
||||
/// - BOARD_AT45_B_SPI
|
||||
/// - BOARD_AT45_B_NPCS
|
||||
/// - BOARD_AT45_B_NPCS_PIN
|
||||
///
|
||||
/// !SD Card
|
||||
/// - BOARD_SD_MCI_BASE
|
||||
/// - BOARD_SD_MCI_ID
|
||||
/// - BOARD_SD_PINS
|
||||
/// - BOARD_SD_SLOT
|
||||
///
|
||||
///
|
||||
/// !EMAC
|
||||
/// - AT91C_BASE_EMAC
|
||||
/// - BOARD_EMAC_POWER_ALWAYS_ON
|
||||
/// - BOARD_EMAC_MODE_RMII
|
||||
/// - BOARD_EMAC_PINS
|
||||
/// - BOARD_EMAC_PIN_TEST
|
||||
/// - BOARD_EMAC_PIN_RPTR
|
||||
/// - BOARD_EMAC_RST_PINS
|
||||
/// - BOARD_EMAC_RUN_PINS
|
||||
|
||||
|
||||
/// Base address of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT45_A_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT45_A_NPCS 0
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT45_A_NPCS_PIN PIN_SPI0_NPCS0
|
||||
|
||||
/// Base address of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT45_B_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT45_B_NPCS 1
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT45_B_NPCS_PIN PIN_SPI0_NPCS1
|
||||
|
||||
/// Base address of SPI peripheral connected to the serialflash.
|
||||
#define BOARD_AT26_A_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT26_A_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT26_A_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT26_A_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT26_A_NPCS 0
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT26_A_NPCS_PIN PIN_SPI0_NPCS0
|
||||
|
||||
/// Base address of the MCI peripheral connected to the SD card.
|
||||
#define BOARD_SD_MCI_BASE AT91C_BASE_MCI
|
||||
/// Peripheral identifier of the MCI connected to the SD card.
|
||||
#define BOARD_SD_MCI_ID AT91C_ID_MCI
|
||||
/// MCI pins that shall be configured to access the SD card.
|
||||
#define BOARD_SD_PINS PINS_MCI
|
||||
/// MCI slot to which the SD card is connected to.
|
||||
#define BOARD_SD_SLOT MCI_SD_SLOTB
|
||||
|
||||
/// Board EMAC base address
|
||||
#if !defined(AT91C_BASE_EMAC) && defined(AT91C_BASE_EMACB)
|
||||
#define AT91C_BASE_EMAC AT91C_BASE_EMACB
|
||||
#endif
|
||||
/// Board EMAC power control - ALWAYS ON
|
||||
#define BOARD_EMAC_POWER_ALWAYS_ON
|
||||
/// Board EMAC work mode - RMII/MII ( 1 / 0 )
|
||||
#define BOARD_EMAC_MODE_RMII 1
|
||||
/// The PIN list of PIO for EMAC
|
||||
#define BOARD_EMAC_PINS { ((1<<19)|(1<<13)|(1<<12)|(1<<16)|(1<<15)|(1<<14)\
|
||||
|(1<<17)|(1<<18)|(1<<20)|(1<<21)|(1<<7)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT},\
|
||||
{ ((1<<11)|(1<<10)|(1<<26)|(1<<25)|(1<<27)|(1<<22)\
|
||||
|(1<<29)|(1<<28)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
/// The power up reset latch PIO for PHY
|
||||
#define BOARD_EMAC_PIN_TEST {(1<<17), AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
//#define BOARD_EMAC_PIN_RMII : connected to 3v3 (RMII)
|
||||
// We force the address
|
||||
// (1<<14) PHY address 0, (1<<15) PHY address 1 (PIO A, perih A)
|
||||
// (1<<25) PHY address 2, (1<<26) PHY address 3 (PIO A, perih B)
|
||||
#define BOARD_EMAC_PINS_PHYAD { ((1<<14)|(1<<15)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},\
|
||||
{ ((1<<25)|(1<<26)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
//#define BOARD_EMAC_PIN_10BT : not connected
|
||||
#define BOARD_EMAC_PIN_RPTR {(1<<27), AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/// The PIN Configure list for EMAC on power up reset
|
||||
#define BOARD_EMAC_RST_PINS BOARD_EMAC_PINS_PHYAD,\
|
||||
BOARD_EMAC_PIN_TEST,\
|
||||
BOARD_EMAC_PIN_RPTR
|
||||
/// The runtime pin configure list for EMAC
|
||||
#define BOARD_EMAC_RUN_PINS BOARD_EMAC_PINS
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Memories"
|
||||
/// This page lists definitions related to external on-board memories.
|
||||
///
|
||||
/// !Embedded Flash
|
||||
/// - BOARD_FLASH_EEFC
|
||||
///
|
||||
/// !SDRAM
|
||||
/// - BOARD_SDRAM_SIZE
|
||||
/// - PINS_SDRAM
|
||||
///
|
||||
/// !Nandflash
|
||||
/// - PINS_NANDFLASH
|
||||
/// - BOARD_NF_COMMAND_ADDR
|
||||
/// - BOARD_NF_ADDRESS_ADDR
|
||||
/// - BOARD_NF_DATA_ADDR
|
||||
/// - BOARD_NF_CE_PIN
|
||||
/// - BOARD_NF_RB_PIN
|
||||
|
||||
/// Indicates chip has an Enhanced EFC.
|
||||
#define BOARD_FLASH_EEFC
|
||||
/// Address of the IAP function in ROM.
|
||||
#define BOARD_FLASH_IAP_ADDRESS 0x100008
|
||||
|
||||
/// Board SDRAM size
|
||||
#define BOARD_SDRAM_SIZE 0x02000000
|
||||
/// List of all SDRAM pins definitions.
|
||||
#define PINS_SDRAM {0xFFFF0000, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
|
||||
/// Nandflash controller peripheral pins definition.
|
||||
#define PINS_NANDFLASH BOARD_NF_CE_PIN, BOARD_NF_RB_PIN
|
||||
/// Nandflash chip enable pin definition.
|
||||
#define BOARD_NF_CE_PIN {1 << 14, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
/// Nandflash ready/busy pin definition.
|
||||
#define BOARD_NF_RB_PIN {1 << 13, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_INPUT, PIO_PULLUP}
|
||||
/// Address for transferring command bytes to the nandflash.
|
||||
#define BOARD_NF_COMMAND_ADDR 0x40400000
|
||||
/// Address for transferring address bytes to the nandflash.
|
||||
#define BOARD_NF_ADDRESS_ADDR 0x40200000
|
||||
/// Address for transferring data bytes to the nandflash.
|
||||
#define BOARD_NF_DATA_ADDR 0x40000000
|
||||
|
||||
/// Address for transferring command bytes to the norflash.
|
||||
#define BOARD_NORFLASH_ADDR 0x10000000
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif //#ifndef BOARD_H
|
||||
|
@ -0,0 +1,169 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "ISR_Support.h"
|
||||
|
||||
/*
|
||||
IAR startup file for AT91SAM9XE microcontrollers.
|
||||
*/
|
||||
|
||||
MODULE ?cstartup
|
||||
|
||||
;; Forward declaration of sections.
|
||||
SECTION IRQ_STACK:DATA:NOROOT(2)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "board.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define ARM_MODE_ABT 0x17
|
||||
#define ARM_MODE_FIQ 0x11
|
||||
#define ARM_MODE_IRQ 0x12
|
||||
#define ARM_MODE_SVC 0x13
|
||||
#define ARM_MODE_SYS 0x1F
|
||||
|
||||
#define I_BIT 0x80
|
||||
#define F_BIT 0x40
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Startup routine
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Exception vectors
|
||||
*/
|
||||
SECTION .vectors:CODE:NOROOT(2)
|
||||
|
||||
PUBLIC resetVector
|
||||
PUBLIC irqHandler
|
||||
|
||||
EXTERN Undefined_Handler
|
||||
EXTERN vPortYieldProcessor
|
||||
EXTERN Prefetch_Handler
|
||||
EXTERN Abort_Handler
|
||||
EXTERN FIQ_Handler
|
||||
|
||||
ARM
|
||||
|
||||
__iar_init$$done: ; The interrupt vector is not needed
|
||||
; until after copy initialization is done
|
||||
|
||||
resetVector:
|
||||
; All default exception handlers (except reset) are
|
||||
; defined as weak symbol definitions.
|
||||
; If a handler is defined by the application it will take precedence.
|
||||
LDR pc, =resetHandler ; Reset
|
||||
LDR pc, Undefined_Addr ; Undefined instructions
|
||||
LDR pc, SWI_Addr ; Software interrupt (SWI/SVC)
|
||||
LDR pc, Prefetch_Addr ; Prefetch abort
|
||||
LDR pc, Abort_Addr ; Data abort
|
||||
B . ; RESERVED
|
||||
LDR pc, =irqHandler ; IRQ
|
||||
LDR pc, FIQ_Addr ; FIQ
|
||||
|
||||
Undefined_Addr: DCD Undefined_Handler
|
||||
SWI_Addr: DCD vPortYieldProcessor
|
||||
Prefetch_Addr: DCD Prefetch_Handler
|
||||
Abort_Addr: DCD Abort_Handler
|
||||
FIQ_Addr: DCD FIQ_Handler
|
||||
|
||||
/*
|
||||
Handles incoming interrupt requests by branching to the corresponding
|
||||
handler, as defined in the AIC. Supports interrupt nesting.
|
||||
*/
|
||||
irqHandler:
|
||||
portSAVE_CONTEXT
|
||||
|
||||
/* Write in the IVR to support Protect Mode */
|
||||
LDR lr, =AT91C_BASE_AIC
|
||||
LDR r0, [r14, #AIC_IVR]
|
||||
STR lr, [r14, #AIC_IVR]
|
||||
|
||||
/* Branch to C portion of the interrupt handler */
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Acknowledge interrupt */
|
||||
LDR lr, =AT91C_BASE_AIC
|
||||
STR lr, [r14, #AIC_EOICR]
|
||||
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/*
|
||||
After a reset, execution starts here, the mode is ARM, supervisor
|
||||
with interrupts disabled.
|
||||
Initializes the chip and branches to the main() function.
|
||||
*/
|
||||
SECTION .cstartup:CODE:NOROOT(2)
|
||||
|
||||
PUBLIC resetHandler
|
||||
EXTERN LowLevelInit
|
||||
EXTERN ?main
|
||||
REQUIRE resetVector
|
||||
ARM
|
||||
|
||||
resetHandler:
|
||||
|
||||
/* Set pc to actual code location (i.e. not in remap zone) */
|
||||
LDR pc, =label
|
||||
|
||||
/* Perform low-level initialization of the chip using LowLevelInit() */
|
||||
label:
|
||||
LDR r0, =LowLevelInit
|
||||
LDR r4, =SFE(CSTACK)
|
||||
MOV sp, r4
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Set up the interrupt stack pointer. */
|
||||
MSR cpsr_c, #ARM_MODE_IRQ | I_BIT | F_BIT ; Change the mode
|
||||
LDR sp, =SFE(IRQ_STACK)
|
||||
|
||||
/* Set up the SVC stack pointer. */
|
||||
MSR cpsr_c, #ARM_MODE_SVC | F_BIT ; Change the mode
|
||||
LDR sp, =SFE(CSTACK)
|
||||
|
||||
/* Branch to main() */
|
||||
LDR r0, =?main
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Loop indefinitely when program is finished */
|
||||
loop4:
|
||||
B loop4
|
||||
|
||||
END
|
@ -0,0 +1,194 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "board.h"
|
||||
#include "board_memories.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE - Oscillator & PLL Parameters"
|
||||
/// This page lists the parameters which are set for the PLL and main
|
||||
/// oscillator configuration.
|
||||
///
|
||||
/// !Parameters
|
||||
/// - BOARD_OSCOUNT
|
||||
/// - BOARD_CKGR_PLLA
|
||||
/// - BOARD_PLLACOUNT
|
||||
/// - BOARD_MULA
|
||||
/// - BOARD_DIVA
|
||||
/// - BOARD_CKGR_PLLB
|
||||
/// - BOARD_PLLBCOUNT
|
||||
/// - BOARD_MULB
|
||||
/// - BOARD_DIVB
|
||||
/// - BOARD_USBDIV
|
||||
/// - BOARD_PRESCALER
|
||||
|
||||
/// Main oscillator startup time (in number of slow clock ticks).
|
||||
#define BOARD_OSCOUNT (AT91C_CKGR_OSCOUNT & (64 << 8))
|
||||
|
||||
/// PLLA frequency range.
|
||||
#define BOARD_CKGR_PLLA (AT91C_CKGR_SRCA | AT91C_CKGR_OUTA_2)
|
||||
/// PLLA startup time (in number of slow clock ticks).
|
||||
#define BOARD_PLLACOUNT (63 << 8)
|
||||
/// PLLA MUL value.
|
||||
#define BOARD_MULA (AT91C_CKGR_MULA & (96 << 16))
|
||||
/// PLLA DIV value.
|
||||
#define BOARD_DIVA (AT91C_CKGR_DIVA & 9)
|
||||
|
||||
/// PLLB frequency range
|
||||
#define BOARD_CKGR_PLLB AT91C_CKGR_OUTB_1
|
||||
/// PLLB startup time (in number of slow clock ticks).
|
||||
#define BOARD_PLLBCOUNT BOARD_PLLACOUNT
|
||||
/// PLLB MUL value.
|
||||
#define BOARD_MULB (124 << 16)
|
||||
/// PLLB DIV value.
|
||||
#define BOARD_DIVB 12
|
||||
|
||||
/// USB PLL divisor value to obtain a 48MHz clock.
|
||||
#define BOARD_USBDIV AT91C_CKGR_USBDIV_2
|
||||
/// Master clock prescaler value.
|
||||
#define BOARD_PRESCALER AT91C_PMC_MDIV_2
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default spurious interrupt handler
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultSpuriousHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default handler for fast interrupt requests.
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultFiqHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default handler for standard interrupt requests.
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultIrqHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Performs the low-level initialization of the chip.
|
||||
//------------------------------------------------------------------------------
|
||||
void LowLevelInit(void)
|
||||
{
|
||||
unsigned char i;
|
||||
|
||||
// Set flash wait states
|
||||
//----------------------
|
||||
AT91C_BASE_EFC->EFC_FMR = 6 << 8;
|
||||
|
||||
//#if !defined(sdram)
|
||||
// Initialize main oscillator
|
||||
//---------------------------
|
||||
AT91C_BASE_PMC->PMC_MOR = BOARD_OSCOUNT | AT91C_CKGR_MOSCEN;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
// Initialize PLLA at 200MHz (198.656)
|
||||
AT91C_BASE_PMC->PMC_PLLAR = BOARD_CKGR_PLLA
|
||||
| BOARD_PLLACOUNT
|
||||
| BOARD_MULA
|
||||
| BOARD_DIVA;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
|
||||
|
||||
// Initialize PLLB for USB usage
|
||||
AT91C_BASE_PMC->PMC_PLLBR = BOARD_USBDIV
|
||||
| BOARD_CKGR_PLLB
|
||||
| BOARD_PLLBCOUNT
|
||||
| BOARD_MULB
|
||||
| BOARD_DIVB;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKB));
|
||||
|
||||
// Wait for the master clock if it was already initialized
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
// Switch to fast clock
|
||||
//---------------------
|
||||
// Switch to main oscillator + prescaler
|
||||
AT91C_BASE_PMC->PMC_MCKR = BOARD_PRESCALER;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
// Switch to PLL + prescaler
|
||||
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
//#endif //#if !defined(sdram)
|
||||
|
||||
// Initialize AIC
|
||||
//---------------
|
||||
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (unsigned int) DefaultFiqHandler;
|
||||
for (i = 1; i < 31; i++) {
|
||||
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (unsigned int) DefaultIrqHandler;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (unsigned int) DefaultSpuriousHandler;
|
||||
|
||||
// Unstack nested interrupts
|
||||
for (i = 0; i < 8 ; i++) {
|
||||
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
// Watchdog initialization
|
||||
//------------------------
|
||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
// Remap
|
||||
//------
|
||||
BOARD_RemapRam();
|
||||
|
||||
// Disable RTT and PIT interrupts (potential problem when program A
|
||||
// configures RTT, then program B wants to use PIT only, interrupts
|
||||
// from the RTT will still occur since they both use AT91C_ID_SYS)
|
||||
AT91C_BASE_RTTC->RTTC_RTMR &= ~(AT91C_RTTC_ALMIEN | AT91C_RTTC_RTTINCIEN);
|
||||
AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITIEN;
|
||||
}
|
||||
|
@ -0,0 +1,304 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
#include <pio/pio.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local macros
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Reads a register value. Useful to add trace information to read accesses.
|
||||
#define READ(peripheral, register) (peripheral->register)
|
||||
/// Writes data in a register. Useful to add trace information to write accesses.
|
||||
#define WRITE(peripheral, register, value) (peripheral->register = value)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Changes the mapping of the chip so that the remap area mirrors the
|
||||
/// internal ROM or the EBI CS0 (depending on the BMS input).
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_RemapRom(void)
|
||||
{
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_MRCR, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Changes the mapping of the chip so that the remap area mirrors the
|
||||
/// internal RAM.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_RemapRam(void)
|
||||
{
|
||||
WRITE(AT91C_BASE_MATRIX,
|
||||
MATRIX_MRCR,
|
||||
(AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initialize and configure the external SDRAM.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureSdram(void)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
static const Pin pinsSdram = PINS_SDRAM;
|
||||
volatile unsigned int *pSdram = (unsigned int *) AT91C_EBI_SDRAM;
|
||||
|
||||
// Enable corresponding PIOs
|
||||
PIO_Configure(&pinsSdram, 1);
|
||||
|
||||
// Enable EBI chip select for the SDRAM
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_EBI, AT91C_MATRIX_CS1A_SDRAMC);
|
||||
|
||||
|
||||
// CFG Control Register
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_CR, AT91C_SDRAMC_NC_9
|
||||
| AT91C_SDRAMC_NR_13
|
||||
| AT91C_SDRAMC_CAS_2
|
||||
| AT91C_SDRAMC_NB_4_BANKS
|
||||
| AT91C_SDRAMC_DBW_32_BITS
|
||||
| AT91C_SDRAMC_TWR_2
|
||||
| AT91C_SDRAMC_TRC_7
|
||||
| AT91C_SDRAMC_TRP_2
|
||||
| AT91C_SDRAMC_TRCD_2
|
||||
| AT91C_SDRAMC_TRAS_5
|
||||
| AT91C_SDRAMC_TXSR_8);
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NOP_CMD); // Perform NOP
|
||||
pSdram[0] = 0x00000000;
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_PRCGALL_CMD); // Set PRCHG AL
|
||||
pSdram[0] = 0x00000000; // Perform PRCHG
|
||||
|
||||
for (i = 0; i < 10000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 1st CBR
|
||||
pSdram[1] = 0x00000001; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 2 CBR
|
||||
pSdram[2] = 0x00000002; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 3 CBR
|
||||
pSdram[3] = 0x00000003; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 4 CBR
|
||||
pSdram[4] = 0x00000004; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 5 CBR
|
||||
pSdram[5] = 0x00000005; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 6 CBR
|
||||
pSdram[6] = 0x00000006; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 7 CBR
|
||||
pSdram[7] = 0x00000007; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 8 CBR
|
||||
pSdram[8] = 0x00000008; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_LMR_CMD); // Set LMR operation
|
||||
pSdram[9] = 0xcafedede; // Perform LMR burst=1, lat=2
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_TR, (BOARD_MCK * 7) / 1000000); // Set Refresh Timer
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NORMAL_CMD); // Set Normal mode
|
||||
pSdram[0] = 0x00000000; // Perform Normal mode
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initialize and configure the SDRAM for a 48 MHz MCK (ROM code clock settings).
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureSdram48MHz(void)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
static const Pin pinsSdram = PINS_SDRAM;
|
||||
volatile unsigned int *pSdram = (unsigned int *) AT91C_EBI_SDRAM;
|
||||
|
||||
// Enable corresponding PIOs
|
||||
PIO_Configure(&pinsSdram, 1);
|
||||
|
||||
// Enable EBI chip select for the SDRAM
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_EBI, AT91C_MATRIX_CS1A_SDRAMC);
|
||||
|
||||
|
||||
// CFG Control Register
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_CR, AT91C_SDRAMC_NC_9
|
||||
| AT91C_SDRAMC_NR_13
|
||||
| AT91C_SDRAMC_CAS_2
|
||||
| AT91C_SDRAMC_NB_4_BANKS
|
||||
| AT91C_SDRAMC_DBW_32_BITS
|
||||
| AT91C_SDRAMC_TWR_1
|
||||
| AT91C_SDRAMC_TRC_4
|
||||
| AT91C_SDRAMC_TRP_1
|
||||
| AT91C_SDRAMC_TRCD_1
|
||||
| AT91C_SDRAMC_TRAS_2
|
||||
| AT91C_SDRAMC_TXSR_3);
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NOP_CMD); // Perform NOP
|
||||
pSdram[0] = 0x00000000;
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_PRCGALL_CMD); // Set PRCHG AL
|
||||
pSdram[0] = 0x00000000; // Perform PRCHG
|
||||
|
||||
for (i = 0; i < 10000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 1st CBR
|
||||
pSdram[1] = 0x00000001; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 2 CBR
|
||||
pSdram[2] = 0x00000002; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 3 CBR
|
||||
pSdram[3] = 0x00000003; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 4 CBR
|
||||
pSdram[4] = 0x00000004; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 5 CBR
|
||||
pSdram[5] = 0x00000005; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 6 CBR
|
||||
pSdram[6] = 0x00000006; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 7 CBR
|
||||
pSdram[7] = 0x00000007; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 8 CBR
|
||||
pSdram[8] = 0x00000008; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_LMR_CMD); // Set LMR operation
|
||||
pSdram[9] = 0xcafedede; // Perform LMR burst=1, lat=2
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_TR, (48000000 * 7) / 1000000); // Set Refresh Timer
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NORMAL_CMD); // Set Normal mode
|
||||
pSdram[0] = 0x00000000; // Perform Normal mode
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NandFlash access. Pins must be configured after or
|
||||
/// before calling this function.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNandFlash(unsigned char busWidth)
|
||||
{
|
||||
// Configure EBI
|
||||
AT91C_BASE_MATRIX->MATRIX_EBI |= AT91C_MATRIX_CS3A_SM;
|
||||
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP3 = 0x00000000;
|
||||
AT91C_BASE_SMC->SMC_PULSE3 = 0x00030003;
|
||||
AT91C_BASE_SMC->SMC_CYCLE3 = 0x00050005;
|
||||
AT91C_BASE_SMC->SMC_CTRL3 = 0x00002003;
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NandFlash access at 48MHz. Pins must be configured
|
||||
/// after or before calling this function.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNandFlash48MHz(unsigned char busWidth)
|
||||
{
|
||||
// Configure EBI
|
||||
AT91C_BASE_CCFG->CCFG_EBICSA |= AT91C_EBI_CS3A_SM;
|
||||
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP3 = 0x00010001;
|
||||
AT91C_BASE_SMC->SMC_PULSE3 = 0x04030302;
|
||||
AT91C_BASE_SMC->SMC_CYCLE3 = 0x00070004;
|
||||
AT91C_BASE_SMC->SMC_CTRL3 = (AT91C_SMC_READMODE
|
||||
| AT91C_SMC_WRITEMODE
|
||||
| AT91C_SMC_NWAITM_NWAIT_DISABLE
|
||||
| ((0x1 << 16) & AT91C_SMC_TDF));
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NorFlash access at 48MHz.
|
||||
/// \Param busWidth Bus width
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNorFlash48MHz(unsigned char busWidth)
|
||||
{
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP0 = 0x00000001;
|
||||
AT91C_BASE_SMC->SMC_PULSE0 = 0x07070703;
|
||||
AT91C_BASE_SMC->SMC_CYCLE0 = 0x00070007;
|
||||
AT91C_BASE_SMC->SMC_CTRL0 = (AT91C_SMC_READMODE
|
||||
| AT91C_SMC_WRITEMODE
|
||||
| AT91C_SMC_NWAITM_NWAIT_DISABLE
|
||||
| ((0x1 << 16) & AT91C_SMC_TDF));
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
else if (busWidth == 32) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_THIRTY_TWO_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Set flash wait states in the EFC for 48MHz
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureFlash48MHz(void)
|
||||
{
|
||||
// Set flash wait states
|
||||
//----------------------
|
||||
AT91C_BASE_EFC->EFC_FMR = 6 << 8;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user