@ -33,9 +33,9 @@
FreeRTOS is distributed in the hope that it will be useful , but WITHOUT
ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
more details . You should have received a copy of the GNU General Public
License and the FreeRTOS license exception along with FreeRTOS ; if not it
can be viewed here : http : //www.freertos.org/a00114.html and also obtained
more details . You should have received a copy of the GNU General Public
License and the FreeRTOS license exception along with FreeRTOS ; if not it
can be viewed here : http : //www.freertos.org/a00114.html and also obtained
by writing to Richard Barry , contact details for whom are available on the
FreeRTOS WEB site .
@ -51,30 +51,39 @@
licensing and training services .
*/
/*
/* ****************************************************************************
* This project includes a lot of tasks and tests and is therefore complex .
* If you would prefer a much simpler project to get started with then select
* the ' Blinky ' build configuration within the HEW IDE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Creates all the demo application tasks , then starts the scheduler . The web
* documentation provides more details of the standard demo application tasks ,
* which provide no particular functionality but do provide a good example of
* how to use the FreeRTOS API . The tasks defined in flop . c are included in the
* set of standard demo tasks to ensure the floating point unit gets some
* exercise .
* exercise .
*
* In addition to the standard demo tasks , the following tasks and tests are
* In addition to the standard demo tasks , the following tasks and tests are
* defined and / or created within this file :
*
* Webserver ( " uIP " ) task - This serves a number of dynamically generated WEB
* pages to a standard WEB browser . The IP and MAC addresses are configured by
* constants defined at the bottom of FreeRTOSConfig . h . Use either a standard
* Ethernet cable to connect through a hug , or a cross over ( point to point )
* cable to connect directly . Ensure the IP address used is compatible with the
* IP address of the machine running the browser - the easiest way to achieve
* this is to ensure the first three octets of the IP addresses are the same .
*
* " Reg test " tasks - These fill the registers with known values , then check
* that each register still contains its expected value . Each task uses
* different values . The tasks run with very low priority so get preempted
* very frequently . A check variable is incremented on each iteration of the
* test loop . A register containing an unexpected value is indicative of an
* error in the context switching mechanism and will result in a branch to a
* different values . The tasks run with very low priority so get preempted
* very frequently . A check variable is incremented on each iteration of the
* test loop . A register containing an unexpected value is indicative of an
* error in the context switching mechanism and will result in a branch to a
* null loop - which in turn will prevent the check variable from incrementing
* any further and allow the check task ( described below ) to determine that an
* error has occurred . The nature of the reg test tasks necessitates that they
* error has occurred . The nature of the reg test tasks necessitates that they
* are written in assembly code .
*
* " Check " task - This only executes every five seconds but has a high priority
@ -84,24 +93,27 @@
* rate increasing to 200 ms being a visual indication that at least one task has
* reported unexpected behaviour .
*
* " High frequency timer test " - A high frequency periodic interrupt is
* generated using a timer - the interrupt is assigned a priority above
* " High frequency timer test " - A high frequency periodic interrupt is
* generated using a timer - the interrupt is assigned a priority above
* configMAX_SYSCALL_INTERRUPT_PRIORITY so should not be effected by anything
* the kernel is doing . The interrupt service routine measures the number of
* counts a separate timer performs between each interrupt to determine the
* jitter in the interrupt timing .
* the kernel is doing . The frequency and priority of the interrupt , in
* combination with other standard tests executed in this demo , should result
* in interrupts nesting at least 3 and probably 4 deep . This test is only
* included in build configurations that have the optimiser switched on . In
* optimised builds the count of high frequency ticks is used as the time base
* for the run time stats .
*
* * NOTE 1 * If LED5 is toggling every 5 seconds then all the demo application
* tasks are executing as expected and no errors have been reported in any
* tasks are executing as expected and no errors have been reported in any
* tasks . The toggle rate increasing to 200 ms indicates that at least one task
* has reported unexpected behaviour .
*
*
* * NOTE 2 * vApplicationSetupTimerInterrupt ( ) is called by the kernel to let
* the application set up a timer to generate the tick interrupt . In this
* example a compare match timer is used for this purpose .
* example a compare match timer is used for this purpose .
*
* * NOTE 3 * The CPU must be in Supervisor mode when the scheduler is started .
* The PowerON_Reset_PC ( ) supplied in resetprg . c with this demo has
* The PowerON_Reset_PC ( ) supplied in resetprg . c with this demo has
* Change_PSW_PM_to_UserMode ( ) commented out to ensure this is the case .
*
* * NOTE 4 * The IntQueue common demo tasks test interrupt nesting and make use
@ -109,7 +121,8 @@
*/
/* Standard includes. */
# include "string.h"
# include <string.h>
# include <stdio.h>
/* Hardware specific includes. */
# include "iodefine.h"
@ -133,7 +146,7 @@
# include "recmutex.h"
# include "flop.h"
/* Values that are passed into the reg test tasks using the task parameter. The
/* Values that are passed into the reg test tasks using the task parameter. The
tasks check that the values are passed in correctly . */
# define mainREG_TEST_1_PARAMETER ( 0x12121212UL )
# define mainREG_TEST_2_PARAMETER ( 0x12345678UL )
@ -150,6 +163,10 @@ tasks check that the values are passed in correctly. */
# define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )
# define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY )
/* The WEB server uses string handling functions, which in turn use a bit more
stack than most of the other tasks . */
# define mainuIP_STACK_SIZE ( configMINIMAL_STACK_SIZE * 3 )
/* The LED toggled by the check task. */
# define mainCHECK_LED ( 5 )
@ -159,14 +176,10 @@ file. */
# define mainNO_ERROR_CYCLE_TIME ( 5000 / portTICK_RATE_MS )
/* The rate at which mainCHECK_LED will toggle when an error has been reported
by at least one task . Controlled by the check task as described at the top of
by at least one task . Controlled by the check task as described at the top of
this file . */
# define mainERROR_CYCLE_TIME ( 200 / portTICK_RATE_MS )
/* The period of the peripheral clock in nano seconds. This is used to calculate
the jitter time in nano seconds as part of the high frequency timer test . The
clock driving the timer is divided by 8. */
# define mainNS_PER_CLOCK ( ( unsigned long ) ( ( 1.0 / ( ( double ) configPERIPHERAL_CLOCK_HZ ) / 8.0 ) * 1000000000.0 ) )
/*
* vApplicationMallocFailedHook ( ) will only be called if
@ -174,7 +187,7 @@ clock driving the timer is divided by 8. */
* function that will execute if a call to pvPortMalloc ( ) fails .
* pvPortMalloc ( ) is called internally by the kernel whenever a task , queue or
* semaphore is created . It is also called by various parts of the demo
* application .
* application .
*/
void vApplicationMallocFailedHook ( void ) ;
@ -192,8 +205,8 @@ void vApplicationMallocFailedHook( void );
void vApplicationIdleHook ( void ) ;
/*
* vApplicationStackOverflowHook ( ) will only be called if
* configCHECK_FOR_STACK_OVERFLOW is set to a non - zero value . The handle and
* vApplicationStackOverflowHook ( ) will only be called if
* configCHECK_FOR_STACK_OVERFLOW is set to a non - zero value . The handle and
* name of the offending task should be passed in the function parameters , but
* it is possible that the stack overflow will have corrupted these - in which
* case pxCurrentTCB can be inspected to find the same information .
@ -210,8 +223,8 @@ static void prvRegTest2Task( void *pvParameters );
* The actual implementation of the reg test functionality , which , because of
* the direct register access , have to be in assembly .
*/
extern void prvRegTest1Implementation ( void ) ;
extern void prvRegTest2Implementation ( void ) ;
static void prvRegTest1Implementation ( void ) __attribute__ ( ( naked ) ) ;
static void prvRegTest2Implementation ( void ) __attribute__ ( ( naked ) ) ;
/*
@ -219,12 +232,24 @@ extern void prvRegTest2Implementation( void );
*/
static void prvCheckTask ( void * pvParameters ) ;
/* Variables that are incremented on each iteration of the reg test tasks -
/*
* Contains the implementation of the WEB server .
*/
extern void vuIP_Task ( void * pvParameters ) ;
/*-----------------------------------------------------------*/
/* Variables that are incremented on each iteration of the reg test tasks -
provided the tasks have not reported any errors . The check task inspects these
variables to ensure they are still incrementing as expected . If a variable
variables to ensure they are still incrementing as expected . If a variable
stops incrementing then it is likely that its associate task has stalled . */
unsigned long ulRegTest1CycleCount = 0UL , ulRegTest2CycleCount = 0UL ;
/* The status message that is displayed at the bottom of the "task stats" web
page , which is served by the uIP task . This will report any errors picked up
by the reg test task . */
static const char * pcStatusMessage = NULL ;
/*-----------------------------------------------------------*/
void main ( void )
@ -242,6 +267,9 @@ extern void HardwareSetup( void );
xTaskCreate ( prvRegTest1Task , " RegTst1 " , configMINIMAL_STACK_SIZE , ( void * ) mainREG_TEST_1_PARAMETER , tskIDLE_PRIORITY , NULL ) ;
xTaskCreate ( prvRegTest2Task , " RegTst2 " , configMINIMAL_STACK_SIZE , ( void * ) mainREG_TEST_2_PARAMETER , tskIDLE_PRIORITY , NULL ) ;
/* The web server task. */
// xTaskCreate( vuIP_Task, "uIP", mainuIP_STACK_SIZE, NULL, mainuIP_TASK_PRIORITY, NULL );
/* Start the check task as described at the top of this file. */
xTaskCreate ( prvCheckTask , " Check " , configMINIMAL_STACK_SIZE * 3 , NULL , mainCHECK_TASK_PRIORITY , NULL ) ;
@ -265,7 +293,7 @@ extern void HardwareSetup( void );
/* Start the tasks running. */
vTaskStartScheduler ( ) ;
/* If all is well we will never reach here as the scheduler will now be
running . If we do reach here then it is likely that there was insufficient
heap available for the idle task to be created . */
@ -278,12 +306,9 @@ static void prvCheckTask( void *pvParameters )
static volatile unsigned long ulLastRegTest1CycleCount = 0UL , ulLastRegTest2CycleCount = 0UL ;
portTickType xNextWakeTime , xCycleFrequency = mainNO_ERROR_CYCLE_TIME ;
extern void vSetupHighFrequencyTimer ( void ) ;
extern volatile unsigned short usMaxJitter ;
volatile unsigned long ulActualJitter = 0 ;
static char cErrorText [ 100 ] ;
/* If this is being executed then the kernel has been started. Start the high
frequency timer test as described at the top of this file . This is only
frequency timer test as described at the top of this file . This is only
included in the optimised build configuration - otherwise it takes up too much
CPU time . */
# ifdef INCLUDE_HIGH_FREQUENCY_TIMER_TEST
@ -304,119 +329,100 @@ static char cErrorText[ 100 ];
/* Increase the rate at which this task cycles, which will increase the
rate at which mainCHECK_LED flashes to give visual feedback that an error
has occurred . */
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: GenQueue " ) ;
pcStatusMessage = " Error: GenQueue " ;
}
else if ( xAreQueuePeekTasksStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: QueuePeek " ) ;
pcStatusMessage = " Error: QueuePeek \r \n " ;
}
else if ( xAreBlockingQueuesStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: BlockQueue " ) ;
pcStatusMessage = " Error: BlockQueue \r \n " ;
}
else if ( xAreBlockTimeTestTasksStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: BlockTime " ) ;
pcStatusMessage = " Error: BlockTime \r \n " ;
}
else if ( xAreSemaphoreTasksStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: SemTest " ) ;
pcStatusMessage = " Error: SemTest \r \n " ;
}
else if ( xArePollingQueuesStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: PollQueue " ) ;
pcStatusMessage = " Error: PollQueue \r \n " ;
}
else if ( xIsCreateTaskStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: Death " ) ;
pcStatusMessage = " Error: Death \r \n " ;
}
else if ( xAreIntegerMathsTaskStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: IntMath " ) ;
pcStatusMessage = " Error: IntMath \r \n " ;
}
else if ( xAreRecursiveMutexTasksStillRunning ( ) ! = pdTRUE )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: RecMutex " ) ;
pcStatusMessage = " Error: RecMutex \r \n " ;
}
else if ( xAreIntQueueTasksStillRunning ( ) ! = pdPASS )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: IntQueue " ) ;
pcStatusMessage = " Error: IntQueue \r \n " ;
}
else if ( xAreMathsTaskStillRunning ( ) ! = pdPASS )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: Flop " ) ;
pcStatusMessage = " Error: Flop \r \n " ;
}
/* Check the reg test tasks are still cycling. They will stop incrementing
their loop counters if they encounter an error . */
if ( ulRegTest1CycleCount = = ulLastRegTest1CycleCount )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: RegTest1 " ) ;
pcStatusMessage = " Error: RegTest1 \r \n " ;
}
if ( ulRegTest2CycleCount = = ulLastRegTest2CycleCount )
{
xCycleFrequency = mainERROR_CYCLE_TIME ;
strcpy ( cErrorText , " Error: RegTest2 " ) ;
pcStatusMessage = " Error: RegTest2 \r \n " ;
}
ulLastRegTest1CycleCount = ulRegTest1CycleCount ;
ulLastRegTest2CycleCount = ulRegTest2CycleCount ;
/* Toggle the check LED to give an indication of the system status. If
the LED toggles every 5 seconds then everything is ok . A faster toggle
/* Toggle the check LED to give an indication of the system status. If
the LED toggles every 5 seconds then everything is ok . A faster toggle
indicates an error . */
vParTestToggleLED ( mainCHECK_LED ) ;
/* Calculate the maximum jitter experienced by the high frequency timer
test and print it out . It is ok to use printf without worrying about
mutual exclusion as it is not used anywhere else in this demo . */
//sprintf( cTempBuf, "%s [%fns]\n", "Max Jitter = ", ( ( float ) usMaxJitter ) * mainNS_PER_CLOCK );
ulActualJitter = ( ( unsigned long ) usMaxJitter ) * mainNS_PER_CLOCK ;
if ( xCycleFrequency = = mainERROR_CYCLE_TIME )
/* Ensure the LED toggles at a faster rate if an error has occurred. */
if ( pcStatusMessage ! = NULL )
{
/* Just for break point. */
portNOP ( ) ;
xCycleFrequency = mainERROR_CYCLE_TIME ;
}
}
}
/*-----------------------------------------------------------*/
/* The RX port uses this callback function to configure its tick interrupt.
/* The RX port uses this callback function to configure its tick interrupt.
This allows the application to choose the tick interrupt source . */
void vApplicationSetupTimerInterrupt ( void )
{
/* Enable compare match timer 0. */
MSTP ( CMT0 ) = 0 ;
/* Interrupt on compare match. */
CMT0 . CMCR . BIT . CMIE = 1 ;
/* Set the compare match value. */
CMT0 . CMCOR = ( unsigned short ) ( ( ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ ) - 1 ) / 8 ) ;
/* Divide the PCLK by 8. */
CMT0 . CMCR . BIT . CKS = 0 ;
/* Enable the interrupt... */
_IEN ( _CMT0_CMI0 ) = 1 ;
/* ...and set its priority to the application defined kernel priority. */
_IPR ( _CMT0_CMI0 ) = configKERNEL_INTERRUPT_PRIORITY ;
/* Start the timer. */
CMT . CMSTR0 . BIT . STR0 = 1 ;
}
@ -442,9 +448,6 @@ void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName
of this file . */
void vApplicationIdleHook ( void )
{
static volatile unsigned long ulIdleLoopCount = 0UL ;
ulIdleLoopCount + + ;
}
/*-----------------------------------------------------------*/
@ -460,9 +463,9 @@ static void prvRegTest1Task( void *pvParameters )
taskDISABLE_INTERRUPTS ( ) ;
}
}
/* This is an asm function that never returns. */
prvRegTest1Implementation ( ) ;
prvRegTest1Implementation ( ) ;
}
/*-----------------------------------------------------------*/
@ -484,7 +487,189 @@ static void prvRegTest2Task( void *pvParameters )
}
/*-----------------------------------------------------------*/
char * pcGetTaskStatusMessage ( void )
{
/* Not bothered about a critical section here although technically because of
the task priorities the pointer could change it will be atomic if not near
atomic and its not critical . */
if ( pcStatusMessage = = NULL )
{
return " All tasks running without error " ;
}
else
{
return ( char * ) pcStatusMessage ;
}
}
/*-----------------------------------------------------------*/
/* This function is explained in the comments at the top of this file. */
static void prvRegTest1Implementation ( void )
{
__asm volatile
(
/* Put a known value in each register. */
" MOV #1, R1 \n " \
" MOV #2, R2 \n " \
" MOV #3, R3 \n " \
" MOV #4, R4 \n " \
" MOV #5, R5 \n " \
" MOV #6, R6 \n " \
" MOV #7, R7 \n " \
" MOV #8, R8 \n " \
" MOV #9, R9 \n " \
" MOV #10, R10 \n " \
" MOV #11, R11 \n " \
" MOV #12, R12 \n " \
" MOV #13, R13 \n " \
" MOV #14, R14 \n " \
" MOV #15, R15 \n " \
/* Loop, checking each itteration that each register still contains the
expected value . */
" TestLoop1: \n " \
/* Push the registers that are going to get clobbered. */
" PUSHM R14-R15 \n " \
/* Increment the loop counter to show this task is still getting CPU time. */
" MOV #_ulRegTest1CycleCount, R14 \n " \
" MOV [ R14 ], R15 \n " \
" ADD #1, R15 \n " \
" MOV R15, [ R14 ] \n " \
/* Yield to extend the test coverage. Set the bit in the ITU SWINTR register. */
" MOV #1, R14 \n " \
" MOV #0872E0H, R15 \n " \
" MOV.B R14, [R15] \n " \
" NOP \n " \
" NOP \n " \
/* Restore the clobbered registers. */
" POPM R14-R15 \n " \
/* Now compare each register to ensure it still contains the value that was
set before this loop was entered . */
" CMP #1, R1 \n " \
" BNE RegTest1Error \n " \
" CMP #2, R2 \n " \
" BNE RegTest1Error \n " \
" CMP #3, R3 \n " \
" BNE RegTest1Error \n " \
" CMP #4, R4 \n " \
" BNE RegTest1Error \n " \
" CMP #5, R5 \n " \
" BNE RegTest1Error \n " \
" CMP #6, R6 \n " \
" BNE RegTest1Error \n " \
" CMP #7, R7 \n " \
" BNE RegTest1Error \n " \
" CMP #8, R8 \n " \
" BNE RegTest1Error \n " \
" CMP #9, R9 \n " \
" BNE RegTest1Error \n " \
" CMP #10, R10 \n " \
" BNE RegTest1Error \n " \
" CMP #11, R11 \n " \
" BNE RegTest1Error \n " \
" CMP #12, R12 \n " \
" BNE RegTest1Error \n " \
" CMP #13, R13 \n " \
" BNE RegTest1Error \n " \
" CMP #14, R14 \n " \
" BNE RegTest1Error \n " \
" CMP #15, R15 \n " \
" BNE RegTest1Error \n " \
/* All comparisons passed, start a new itteratio of this loop. */
" BRA TestLoop1 \n " \
" RegTest1Error: \n " \
/* A compare failed, just loop here so the loop counter stops incrementing
- causing the check task to indicate the error . */
" BRA RegTest1Error "
) ;
}
/*-----------------------------------------------------------*/
/* This function is explained in the comments at the top of this file. */
static void prvRegTest2Implementation ( void )
{
__asm volatile
(
/* Put a known value in each register. */
" MOV #10H, R1 \n " \
" MOV #20H, R2 \n " \
" MOV #30H, R3 \n " \
" MOV #40H, R4 \n " \
" MOV #50H, R5 \n " \
" MOV #60H, R6 \n " \
" MOV #70H, R7 \n " \
" MOV #80H, R8 \n " \
" MOV #90H, R9 \n " \
" MOV #100H, R10 \n " \
" MOV #110H, R11 \n " \
" MOV #120H, R12 \n " \
" MOV #130H, R13 \n " \
" MOV #140H, R14 \n " \
" MOV #150H, R15 \n " \
/* Loop, checking each itteration that each register still contains the
expected value . */
" TestLoop2: \n " \
/* Push the registers that are going to get clobbered. */
" PUSHM R14-R15 \n " \
/* Increment the loop counter to show this task is still getting CPU time. */
" MOV #_ulRegTest2CycleCount, R14 \n " \
" MOV [ R14 ], R15 \n " \
" ADD #1, R15 \n " \
" MOV R15, [ R14 ] \n " \
/* Restore the clobbered registers. */
" POPM R14-R15 \n " \
/* Now compare each register to ensure it still contains the value that was
set before this loop was entered . */
" CMP #10H, R1 \n " \
" BNE RegTest2Error \n " \
" CMP #20H, R2 \n " \
" BNE RegTest2Error \n " \
" CMP #30H, R3 \n " \
" BNE RegTest2Error \n " \
" CMP #40H, R4 \n " \
" BNE RegTest2Error \n " \
" CMP #50H, R5 \n " \
" BNE RegTest2Error \n " \
" CMP #60H, R6 \n " \
" BNE RegTest2Error \n " \
" CMP #70H, R7 \n " \
" BNE RegTest2Error \n " \
" CMP #80H, R8 \n " \
" BNE RegTest2Error \n " \
" CMP #90H, R9 \n " \
" BNE RegTest2Error \n " \
" CMP #100H, R10 \n " \
" BNE RegTest2Error \n " \
" CMP #110H, R11 \n " \
" BNE RegTest2Error \n " \
" CMP #120H, R12 \n " \
" BNE RegTest2Error \n " \
" CMP #130H, R13 \n " \
" BNE RegTest2Error \n " \
" CMP #140H, R14 \n " \
" BNE RegTest2Error \n " \
" CMP #150H, R15 \n " \
" BNE RegTest2Error \n " \
/* All comparisons passed, start a new itteratio of this loop. */
" BRA TestLoop2 \n " \
" RegTest2Error: \n " \
/* A compare failed, just loop here so the loop counter stops incrementing
- causing the check task to indicate the error . */
" BRA RegTest2Error "
) ;
}