/*
* FreeRTOS Kernel V10 .0 .1
* Copyright ( C ) 2017 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 .
*
* http : //www.FreeRTOS.org
* http : //aws.amazon.com/freertos
*
* 1 tab = = 4 spaces !
*/
/******************************************************************************
* NOTE 1 : This project provides two demo applications . A simple blinky style
* project , and a more comprehensive test and demo application . The
* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting in main . c is used to select
* between the two . See the notes on using mainCREATE_SIMPLE_BLINKY_DEMO_ONLY
* in main . c . This file implements the comprehensive test and demo version .
*
* NOTE 2 : This file only contains the source code that is specific to the
* full demo . Generic functions , such FreeRTOS hook functions , and functions
* required to configure the hardware , are defined in main . c .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* main_full ( ) creates all the demo application tasks and software timers , then
* starts the scheduler . The WEB documentation provides more details of the
* standard demo application tasks . In addition to the standard demo tasks , the
* following tasks and tests are also defined :
*
* " Register test " tasks - These tasks are used in part to test the kernel port .
* They set each processor register to a known value , then check that the
* register still contains that value . Each of the tasks sets the registers
* to different values , and will get swapping in and out between setting and
* then subsequently checking the register values . Discovery of an incorrect
* value would be indicative of an error in the task switching mechanism .
*
* " ISR triggered task " - This is provided as an example of how to write a
* FreeRTOS compatible interrupt service routine . See the comments in
* ISRTriggeredTask . c .
*
* " High Frequency Timer Test " - The high frequency timer is created to test
* the interrupt nesting method . The standard demo interrupt nesting test tasks
* are created with priorities at or below configMAX_SYSCALL_INTERRUPT_PRIORITY
* because they use interrupt safe FreeRTOS API functions . The high frequency
* time is created with a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY ,
* so cannot us the same API functions .
* By way of demonstration , the demo application defines
* configMAX_SYSCALL_INTERRUPT_PRIORITY to be 3 , configKERNEL_INTERRUPT_PRIORITY
* to be 1 , and all other interrupts as follows :
*
* See the online documentation for this demo for more information on interrupt
* usage .
*
* " Check " timer - The check software timer period is initially set to three
* seconds . The callback function associated with the check software timer
* checks that all the standard demo tasks , and the register check tasks , are
* not only still executing , but are executing without reporting any errors . If
* the check software timer discovers that a task has either stalled , or
* reported an error , then it changes its own execution period from the initial
* three seconds , to just 200 ms . The check software timer also toggle LED
* mainCHECK_LED ; If mainCHECK_LED toggles every 3 seconds , no errors have
* been detected . If mainCHECK_LED toggles every 200 ms then an error has been
* detected in at least one task .
*
*/
/* Scheduler includes. */
# include "FreeRTOS.h"
# include "task.h"
# include "queue.h"
# include "semphr.h"
# include "timers.h"
/* Demo application includes. */
# include "partest.h"
# include "blocktim.h"
# include "flash_timer.h"
# include "semtest.h"
# include "GenQTest.h"
# include "QPeek.h"
# include "IntQueue.h"
# include "countsem.h"
# include "dynamic.h"
# include "QueueOverwrite.h"
# include "QueueSet.h"
# include "recmutex.h"
# include "EventGroupsDemo.h"
# include "flop_mz.h"
/*-----------------------------------------------------------*/
/* The period after which the check timer will expire, in ms, provided no errors
have been reported by any of the standard demo tasks . ms are converted to the
equivalent in ticks using the portTICK_PERIOD_MS constant . */
# define mainCHECK_TIMER_PERIOD_MS ( 3000UL / portTICK_PERIOD_MS )
/* The period at which the check timer will expire, in ms, if an error has been
reported in one of the standard demo tasks . ms are converted to the equivalent
in ticks using the portTICK_PERIOD_MS constant . */
# define mainERROR_CHECK_TIMER_PERIOD_MS ( 200UL / portTICK_PERIOD_MS )
/* The priorities of the various demo application tasks. */
# define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
# define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )
# define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )
# define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )
# define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )
# define mainQUEUE_OVERWRITE_TASK_PRIORITY ( tskIDLE_PRIORITY )
# define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY )
/* The LED controlled by the 'check' software timer. */
# define mainCHECK_LED ( 2 )
/* The number of LEDs that should be controlled by the flash software timer
standard demo . In this case it is only 1 as the starter kit has three LEDs , one
of which is controlled by the check timer and one of which is controlled by the
ISR triggered task . */
# define mainNUM_FLASH_TIMER_LEDS ( 1 )
/* Misc. */
# define mainDONT_BLOCK ( 0 )
/* The frequency at which the "high frequency interrupt" interrupt will
occur . */
# define mainTEST_INTERRUPT_FREQUENCY ( 20000 )
/*-----------------------------------------------------------*/
/*
* The check timer callback function , as described at the top of this file .
*/
static void prvCheckTimerCallback ( TimerHandle_t xTimer ) ;
/*
* It is important to ensure the high frequency timer test does not start before
* the kernel . It is therefore started from inside a software timer callback
* function , which will not execute until the timer service / daemon task is
* executing . A one - shot timer is used , so the callback function will only
* execute once ( unless it is manually reset / restarted ) .
*/
static void prvSetupHighFrequencyTimerTest ( TimerHandle_t xTimer ) ;
/*
* Tasks that test the context switch mechanism by filling the processor
* registers with known values , then checking that the values contained
* within the registers is as expected . The tasks are likely to get swapped
* in and out between setting the register values and checking the register
* values .
*/
static void prvRegTestTask1 ( void * pvParameters ) ;
static void prvRegTestTask2 ( void * pvParameters ) ;
/*
* The task that is periodically triggered by an interrupt , as described at the
* top of this file .
*/
extern void vStartISRTriggeredTask ( void ) ;
/*-----------------------------------------------------------*/
/* Variables incremented by prvRegTestTask1() and prvRegTestTask2() respectively
on each iteration of their function . These are used to detect errors in the
reg test tasks . */
volatile unsigned long ulRegTest1Cycles = 0 , ulRegTest2Cycles = 0 ;
/*-----------------------------------------------------------*/
/*
* Create the demo tasks then start the scheduler .
*/
int main_full ( void )
{
TimerHandle_t xTimer = NULL ;
/* Create all the other standard demo tasks. */
vStartLEDFlashTimers ( mainNUM_FLASH_TIMER_LEDS ) ;
vCreateBlockTimeTasks ( ) ;
vStartSemaphoreTasks ( mainSEM_TEST_PRIORITY ) ;
vStartGenericQueueTasks ( mainGEN_QUEUE_TASK_PRIORITY ) ;
vStartQueuePeekTasks ( ) ;
vStartInterruptQueueTasks ( ) ;
vStartISRTriggeredTask ( ) ;
vStartCountingSemaphoreTasks ( ) ;
vStartDynamicPriorityTasks ( ) ;
vStartQueueOverwriteTask ( mainQUEUE_OVERWRITE_TASK_PRIORITY ) ;
vStartQueueSetTasks ( ) ;
vStartRecursiveMutexTasks ( ) ;
vStartEventGroupTasks ( ) ;
vStartMathTasks ( mainFLOP_TASK_PRIORITY ) ;
/* Create the tasks defined within this file. */
xTaskCreate ( prvRegTestTask1 , /* The function that implements the task. */
" Reg1 " , /* Text name for the task to assist debugger - not used by FreeRTOS itself. */
configMINIMAL_STACK_SIZE , /* The stack size to allocate for the task - specified in words not bytes. */
NULL , /* The parameter to pass into the task - not used in this case so set to NULL. */
tskIDLE_PRIORITY , /* The priority to assign to the task. */
NULL ) ; /* Used to obtain a handle to the task being created - not used in this case so set to NULL. */
xTaskCreate ( prvRegTestTask2 , " Reg2 " , configMINIMAL_STACK_SIZE , NULL , tskIDLE_PRIORITY , NULL ) ;
/* Create the software timer that performs the 'check' functionality, as
described at the top of this file . */
xTimer = xTimerCreate ( " CheckTimer " , /* A text name, purely to help debugging. */
( mainCHECK_TIMER_PERIOD_MS ) , /* The timer period, in this case 3000ms (3s). */
pdTRUE , /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
( void * ) 0 , /* The ID is not used, so can be set to anything. */
prvCheckTimerCallback ) ; /* The callback function that inspects the status of all the other tasks. */
if ( xTimer ! = NULL )
{
xTimerStart ( xTimer , mainDONT_BLOCK ) ;
}
/* A software timer is also used to start the high frequency timer test.
This is to ensure the test does not start before the kernel . This time a
one shot software timer is used . */
xTimer = xTimerCreate ( " HighHzTimerSetup " , 1 , pdFALSE , ( void * ) 0 , prvSetupHighFrequencyTimerTest ) ;
if ( xTimer ! = NULL )
{
xTimerStart ( xTimer , mainDONT_BLOCK ) ;
}
/* Finally start the scheduler. */
vTaskStartScheduler ( ) ;
/* If all is well, the scheduler will now be running, and the following line
will never be reached . If the following line does execute , then there was
insufficient FreeRTOS heap memory available for the idle and / or timer tasks
to be created . See the memory management section on the FreeRTOS web site
for more details . http : //www.freertos.org/a00111.html */
for ( ; ; ) ;
}
/*-----------------------------------------------------------*/
static void prvRegTestTask1 ( void * pvParameters )
{
extern void vRegTest1 ( volatile unsigned long * ) ;
/* Avoid compiler warnings. */
( void ) pvParameters ;
/* Must be called before any hardware floating point operations are
performed to let the RTOS portable layer know that this task requires
a floating point context . */
portTASK_USES_FLOATING_POINT ( ) ;
/* Pass the address of the RegTest1 loop counter into the test function,
which is necessarily implemented in assembler . */
vRegTest1 ( & ulRegTest1Cycles ) ;
/* vRegTest1 should never exit! */
vTaskDelete ( NULL ) ;
}
/*-----------------------------------------------------------*/
static void prvRegTestTask2 ( void * pvParameters )
{
extern void vRegTest2 ( volatile unsigned long * ) ;
/* Avoid compiler warnings. */
( void ) pvParameters ;
/* Must be called before any hardware floating point operations are
performed to let the RTOS portable layer know that this task requires
a floating point context . */
portTASK_USES_FLOATING_POINT ( ) ;
/* Pass the address of the RegTest2 loop counter into the test function,
which is necessarily implemented in assembler . */
vRegTest2 ( & ulRegTest2Cycles ) ;
/* vRegTest1 should never exit! */
vTaskDelete ( NULL ) ;
}
/*-----------------------------------------------------------*/
static void prvCheckTimerCallback ( TimerHandle_t xTimer )
{
static long lChangedTimerPeriodAlready = pdFALSE ;
static unsigned long ulLastRegTest1Value = 0 , ulLastRegTest2Value = 0 , ulLastHighFrequencyTimerInterrupts = 0 ;
static const unsigned long ulExpectedHighFrequencyInterrupts = ( ( mainTEST_INTERRUPT_FREQUENCY / 1000UL ) * mainCHECK_TIMER_PERIOD_MS ) - 10 ; /* 10 allows for a margin of error. */
unsigned long ulErrorOccurred = pdFALSE ;
/* The count of the high frequency timer interrupts. */
extern unsigned long ulHighFrequencyTimerInterrupts ;
/* Avoid compiler warnings. */
( void ) xTimer ;
/* Check that the register test 1 task is still running. */
if ( ulLastRegTest1Value = = ulRegTest1Cycles )
{
ulErrorOccurred | = ( 0x01UL < < 1UL ) ;
}
ulLastRegTest1Value = ulRegTest1Cycles ;
/* Check that the register test 2 task is still running. */
if ( ulLastRegTest2Value = = ulRegTest2Cycles )
{
ulErrorOccurred | = ( 0x01UL < < 2UL ) ;
}
ulLastRegTest2Value = ulRegTest2Cycles ;
/* Have any of the standard demo tasks detected an error in their
operation ? */
if ( xAreGenericQueueTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 3UL ) ;
}
else if ( xAreQueuePeekTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 4UL ) ;
}
else if ( xAreBlockTimeTestTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 5UL ) ;
}
else if ( xAreSemaphoreTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 6UL ) ;
}
else if ( xAreIntQueueTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 7UL ) ;
}
else if ( xAreCountingSemaphoreTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 8UL ) ;
}
else if ( xAreDynamicPriorityTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 9UL ) ;
}
else if ( xIsQueueOverwriteTaskStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 10UL ) ;
}
else if ( xAreQueueSetTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 11UL ) ;
}
else if ( xAreRecursiveMutexTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 12UL ) ;
}
else if ( xAreEventGroupTasksStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 13UL ) ;
}
else if ( xAreMathsTaskStillRunning ( ) ! = pdTRUE )
{
ulErrorOccurred | = ( 0x01UL < < 15UL ) ;
}
/* Ensure the expected number of high frequency interrupts have occurred. */
if ( ulLastHighFrequencyTimerInterrupts ! = 0 )
{
if ( ( ulHighFrequencyTimerInterrupts - ulLastHighFrequencyTimerInterrupts ) < ulExpectedHighFrequencyInterrupts )
{
ulErrorOccurred | = ( 0x01UL < < 14UL ) ;
}
}
ulLastHighFrequencyTimerInterrupts = ulHighFrequencyTimerInterrupts ;
if ( ulErrorOccurred ! = pdFALSE )
{
/* An error occurred. Increase the frequency at which the check timer
toggles its LED to give visual feedback of the potential error
condition . */
if ( lChangedTimerPeriodAlready = = pdFALSE )
{
lChangedTimerPeriodAlready = pdTRUE ;
/* This call to xTimerChangePeriod() uses a zero block time.
Functions called from inside of a timer callback function must
* never * attempt to block as to do so could impact other software
timers . */
xTimerChangePeriod ( xTimer , ( mainERROR_CHECK_TIMER_PERIOD_MS ) , mainDONT_BLOCK ) ;
}
}
vParTestToggleLED ( mainCHECK_LED ) ;
}
/*-----------------------------------------------------------*/
static void prvSetupHighFrequencyTimerTest ( TimerHandle_t xTimer )
{
void vSetupTimerTest ( unsigned short usFrequencyHz ) ;
/* Avoid compiler warnings. */
( void ) xTimer ;
/* Setup the high frequency, high priority, timer test. It is setup in this
software timer callback to ensure it does not start before the kernel does .
This is a one shot timer - so the setup routine will only be executed once . */
vSetupTimerTest ( mainTEST_INTERRUPT_FREQUENCY ) ;
}
/*-----------------------------------------------------------*/