/*\r
- FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.\r
-\r
- This file is part of the FreeRTOS.org distribution.\r
-\r
- FreeRTOS.org is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; either version 2 of the License, or\r
- (at your option) any later version.\r
-\r
- FreeRTOS.org is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with FreeRTOS.org; if not, write to the Free Software\r
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-\r
- A special exception to the GPL can be applied should you wish to distribute\r
- a combined work that includes FreeRTOS.org, without being obliged to provide\r
- the source code for any proprietary components. See the licensing section \r
- of http://www.FreeRTOS.org for full details of how and when the exception\r
- can be applied.\r
-\r
- ***************************************************************************\r
- See http://www.FreeRTOS.org for documentation, latest information, license \r
- and contact details. Please ensure to read the configuration and relevant \r
- port sections of the online documentation.\r
- ***************************************************************************\r
+ FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
+ \r
+\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS tutorial books are available in pdf and paperback. *\r
+ * Complete, revised, and edited pdf reference manuals are also *\r
+ * available. *\r
+ * *\r
+ * Purchasing FreeRTOS documentation will not only help you, by *\r
+ * ensuring you get running as quickly as possible and with an *\r
+ * in-depth knowledge of how to use FreeRTOS, it will also help *\r
+ * the FreeRTOS project to continue with its mission of providing *\r
+ * professional grade, cross platform, de facto standard solutions *\r
+ * for microcontrollers - completely free of charge! *\r
+ * *\r
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
+ * *\r
+ * Thank you for using FreeRTOS, and thank you for your support! *\r
+ * *\r
+ ***************************************************************************\r
+\r
+\r
+ This file is part of the FreeRTOS distribution.\r
+\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+ >>>NOTE<<< The modification to the GPL is included to allow you to\r
+ distribute a combined work that includes FreeRTOS without being obliged to\r
+ provide the source code for proprietary components outside of the FreeRTOS\r
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+ more details. You should have received a copy of the GNU General Public\r
+ License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+ by writing to Richard Barry, contact details for whom are available on the\r
+ FreeRTOS WEB site.\r
+\r
+ 1 tab == 4 spaces!\r
+\r
+ http://www.FreeRTOS.org - Documentation, latest information, license and\r
+ contact details.\r
+\r
+ http://www.SafeRTOS.com - A version that is certified for use in safety\r
+ critical systems.\r
+\r
+ http://www.OpenRTOS.com - Commercial support, development, porting,\r
+ licensing and training services.\r
*/\r
\r
/*\r
* Creates all the demo application tasks, then starts the scheduler. The WEB\r
* documentation provides more details of the standard demo application tasks.\r
- * In addition to the standard demo tasks, the following tasks are defined\r
- * within this file:\r
- * \r
- * "Register test" tasks - These tasks first set all the general purpose \r
- * registers to a known value (with each register containing a different value)\r
- * then test each general purpose register to ensure it still contains the\r
- * set value. There are two register test tasks, with different values being\r
- * used by each. The register test tasks will be preempted frequently due to\r
- * their low priority. Setting then testing the value of each register in this\r
- * manner ensures the context of the tasks is being correctly saved and then\r
- * restored as the preemptive context switches occur. An error is flagged\r
- * should any register be found to contain an unexpected value. In addition\r
- * the register test tasks maintain a count of the number of times they cycle, \r
- * so an error can also be flagged should the cycle count not increment as\r
- * expected (indicating the the tasks are not executing at all).\r
+ * In addition to the standard demo tasks, the following tasks and tests are\r
+ * defined and/or created within this file:\r
*\r
+ * "Fast Interrupt Test" - A high frequency periodic interrupt is generated\r
+ * using a free running timer to demonstrate the use of the \r
+ * configKERNEL_INTERRUPT_PRIORITY configuration constant. The interrupt \r
+ * service routine measures the number of processor clocks that occur between\r
+ * each interrupt - and in so doing measures the jitter in the interrupt \r
+ * timing. The maximum measured jitter time is latched in the usMaxJitter \r
+ * variable, and displayed on the LCD by the 'Check' as described below. \r
+ * The fast interrupt is configured and handled in the timer_test.c source \r
+ * file.\r
+ *\r
+ * "LCD" task - the LCD task is a 'gatekeeper' task. It is the only task that\r
+ * is permitted to access the LCD directly. Other tasks wishing to write a\r
+ * message to the LCD send the message on a queue to the LCD task instead of \r
+ * accessing the LCD themselves. The LCD task just blocks on the queue waiting \r
+ * for messages - waking and displaying the messages as they arrive. The LCD\r
+ * task is defined in lcd.c. \r
+ * \r
* "Check" task - This only executes every three seconds but has the highest \r
* priority so is guaranteed to get processor time. Its main function is to \r
- * check that all the other tasks are still operational. Each task maintains a \r
- * unique count that is incremented each time the task successfully completes \r
- * its function. Should any error occur within such a task the count is \r
- * permanently halted. The check task inspects the count of each task to \r
- * ensure it has changed since the last time the check task executed. If all \r
- * the count variables have changed all the tasks are still executing error \r
- * free, and the check task toggles the onboard LED. Should any task contain \r
- * an error at any time check task cycle frequency is increased to 500ms, \r
- * causing the LED toggle rate to increase from 3 seconds to 500ms and in so\r
- * doing providing visual feedback that an error has occurred.\r
- *\r
+ * check that all the standard demo tasks are still operational. Should any\r
+ * unexpected behaviour within a demo task be discovered the 'check' task will\r
+ * write "FAIL #n" to the LCD (via the LCD task). If all the demo tasks are \r
+ * executing with their expected behaviour then the check task writes the max\r
+ * jitter time to the LCD (again via the LCD task), as described above.\r
*/\r
\r
+/* Standard includes. */\r
+#include <stdio.h>\r
+\r
/* Scheduler includes. */\r
#include "FreeRTOS.h"\r
#include "task.h"\r
+#include "queue.h"\r
#include "croutine.h"\r
\r
/* Demo application includes. */\r
#include "integer.h"\r
#include "comtest2.h"\r
#include "partest.h"\r
+#include "lcd.h"\r
+#include "timertest.h"\r
\r
/* Demo task priorities. */\r
#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
#define mainCHECK_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
#define mainCOM_TEST_PRIORITY ( 2 )\r
\r
-/* Delay between check task cycles when an error has/has not been detected. */\r
-#define mainNO_ERROR_DELAY ( ( portTickType ) 3000 / portTICK_RATE_MS )\r
-#define mainERROR_DELAY ( ( portTickType ) 500 / portTICK_RATE_MS )\r
+/* The check task may require a bit more stack as it calls sprintf(). */\r
+#define mainCHECK_TAKS_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 )\r
+\r
+/* The execution period of the check task. */\r
+#define mainCHECK_TASK_PERIOD ( ( portTickType ) 3000 / portTICK_RATE_MS )\r
\r
/* The number of flash co-routines to create. */\r
-#define mainNUM_FLASH_COROUTINES ( 3 )\r
+#define mainNUM_FLASH_COROUTINES ( 5 )\r
\r
/* Baud rate used by the comtest tasks. */\r
#define mainCOM_TEST_BAUD_RATE ( 19200 )\r
\r
/* The LED used by the comtest tasks. mainCOM_TEST_LED + 1 is also used.\r
See the comtest.c file for more information. */\r
-#define mainCOM_TEST_LED ( 4 )\r
+#define mainCOM_TEST_LED ( 6 )\r
\r
-/* The LED used by the check task. */\r
-#define mainCHECK_LED ( 7 )\r
+/* The frequency at which the "fast interrupt test" interrupt will occur. */\r
+#define mainTEST_INTERRUPT_FREQUENCY ( 20000 )\r
\r
-/*-----------------------------------------------------------*/\r
+/* The number of processor clocks we expect to occur between each "fast\r
+interrupt test" interrupt. */\r
+#define mainEXPECTED_CLOCKS_BETWEEN_INTERRUPTS ( configCPU_CLOCK_HZ / mainTEST_INTERRUPT_FREQUENCY )\r
\r
-/*\r
- * The register test tasks as described at the top of this file. \r
- */ \r
-void xRegisterTest1( void *pvParameters );\r
-void xRegisterTest2( void *pvParameters );\r
+/* The number of nano seconds between each processor clock. */\r
+#define mainNS_PER_CLOCK ( ( unsigned short ) ( ( 1.0 / ( double ) configCPU_CLOCK_HZ ) * 1000000000.0 ) )\r
+\r
+/* Dimension the buffer used to hold the value of the maximum jitter time when\r
+it is converted to a string. */\r
+#define mainMAX_STRING_LENGTH ( 20 )\r
+\r
+/*-----------------------------------------------------------*/\r
\r
/*\r
* The check task as described at the top of this file.\r
\r
/*-----------------------------------------------------------*/\r
\r
-/* Variables used to detect errors within the register test tasks. */\r
-static volatile unsigned portSHORT usTest1CycleCounter = 0, usTest2CycleCounter = 0;\r
-static unsigned portSHORT usPreviousTest1Count = 0, usPreviousTest2Count = 0;\r
-\r
-/* Set to pdTRUE should an error be detected in any of the standard demo tasks\r
-or tasks defined within this file. */\r
-static unsigned portSHORT usErrorDetected = pdFALSE;\r
+/* The queue used to send messages to the LCD task. */\r
+static xQueueHandle xLCDQueue;\r
\r
/*-----------------------------------------------------------*/\r
\r
vCreateBlockTimeTasks();\r
\r
/* Create the test tasks defined within this file. */\r
- xTaskCreate( xRegisterTest1, "Reg1", configMINIMAL_STACK_SIZE, ( void * ) &usTest1CycleCounter, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( xRegisterTest2, "Reg2", configMINIMAL_STACK_SIZE, ( void * ) &usTest2CycleCounter, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
+ xTaskCreate( vCheckTask, ( signed char * ) "Check", mainCHECK_TAKS_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
+\r
+ /* Start the task that will control the LCD. This returns the handle\r
+ to the queue used to write text out to the task. */\r
+ xLCDQueue = xStartLCDTask();\r
+\r
+ /* Start the high frequency interrupt test. */\r
+ vSetupTimerTest( mainTEST_INTERRUPT_FREQUENCY );\r
\r
/* Finally start the scheduler. */\r
vTaskStartScheduler();\r
\r
static void vCheckTask( void *pvParameters )\r
{\r
-portTickType xLastExecutionTime;\r
+/* Used to wake the task at the correct frequency. */\r
+portTickType xLastExecutionTime; \r
+\r
+/* The maximum jitter time measured by the fast interrupt test. */\r
+extern unsigned short usMaxJitter ;\r
+\r
+/* Buffer into which the maximum jitter time is written as a string. */\r
+static char cStringBuffer[ mainMAX_STRING_LENGTH ];\r
\r
-/* Start with the no error delay. The long delay will cause the LED to flash\r
-slowly. */\r
-portTickType xDelay = mainNO_ERROR_DELAY;\r
+/* The message that is sent on the queue to the LCD task. The first\r
+parameter is the minimum time (in ticks) that the message should be\r
+left on the LCD without being overwritten. The second parameter is a pointer\r
+to the message to display itself. */\r
+xLCDMessage xMessage = { 0, cStringBuffer };\r
+\r
+/* Set to pdTRUE should an error be detected in any of the standard demo tasks. */\r
+unsigned short usErrorDetected = pdFALSE;\r
\r
/* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
works correctly. */\r
for( ;; )\r
{\r
/* Wait until it is time for the next cycle. */\r
- vTaskDelayUntil( &xLastExecutionTime, xDelay );\r
+ vTaskDelayUntil( &xLastExecutionTime, mainCHECK_TASK_PERIOD );\r
\r
/* Has an error been found in any of the standard demo tasks? */\r
\r
if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
{\r
usErrorDetected = pdTRUE;\r
+ sprintf( cStringBuffer, "FAIL #1" );\r
}\r
\r
if( xAreComTestTasksStillRunning() != pdTRUE )\r
{\r
usErrorDetected = pdTRUE;\r
+ sprintf( cStringBuffer, "FAIL #2" );\r
}\r
\r
if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
{\r
usErrorDetected = pdTRUE;\r
+ sprintf( cStringBuffer, "FAIL #3" );\r
}\r
\r
if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
{\r
usErrorDetected = pdTRUE;\r
+ sprintf( cStringBuffer, "FAIL #4" );\r
}\r
\r
-\r
- /* Are the register test tasks still cycling? */\r
-\r
- if( usTest1CycleCounter == usPreviousTest1Count )\r
- {\r
- usErrorDetected = pdTRUE;\r
- }\r
-\r
- if( usTest2CycleCounter == usPreviousTest2Count )\r
- {\r
- usErrorDetected = pdTRUE;\r
- }\r
-\r
- usPreviousTest2Count = usTest2CycleCounter;\r
- usPreviousTest1Count = usTest1CycleCounter;\r
-\r
- \r
- /* If an error has been detected in any task then the delay will be\r
- reduced to increase the cycle rate of this task. This has the effect\r
- of causing the LED to flash much faster giving a visual indication of\r
- the error condition. */\r
- if( usErrorDetected != pdFALSE )\r
+ if( usErrorDetected == pdFALSE )\r
{\r
- xDelay = mainERROR_DELAY;\r
+ /* No errors have been discovered, so display the maximum jitter\r
+ timer discovered by the "fast interrupt test". */\r
+ sprintf( cStringBuffer, "%dns max jitter", ( short ) ( usMaxJitter - mainEXPECTED_CLOCKS_BETWEEN_INTERRUPTS ) * mainNS_PER_CLOCK );\r
}\r
\r
- /* Finally, toggle the LED before returning to delay to wait for the\r
- next cycle. */\r
- vParTestToggleLED( mainCHECK_LED );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void xRegisterTest1( void *pvParameters )\r
-{\r
-/* This static so as not to use the frame pointer. They are volatile\r
-also to avoid it being stored in a register that we clobber during the test. */\r
-static unsigned portSHORT * volatile pusParameter;\r
-\r
- /* The variable incremented by this task is passed in as the parameter\r
- even though it is defined within this file. This is just to test the\r
- parameter passing mechanism. */\r
- pusParameter = pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Increment the variable to show this task is still cycling. */\r
- ( *pusParameter )++;\r
-\r
- /* Set the w registers to known values, then check that each register\r
- contains the expected value. See the explanation at the top of this\r
- file for more information. */\r
- asm volatile( "mov.w #0x0101, W0 \n" \\r
- "mov.w #0x0102, W1 \n" \\r
- "mov.w #0x0103, W2 \n" \\r
- "mov.w #0x0104, W3 \n" \\r
- "mov.w #0x0105, W4 \n" \\r
- "mov.w #0x0106, W5 \n" \\r
- "mov.w #0x0107, W6 \n" \\r
- "mov.w #0x0108, W7 \n" \\r
- "mov.w #0x0109, W8 \n" \\r
- "mov.w #0x010a, W9 \n" \\r
- "mov.w #0x010b, W10 \n" \\r
- "mov.w #0x010c, W11 \n" \\r
- "mov.w #0x010d, W12 \n" \\r
- "mov.w #0x010e, W13 \n" \\r
- "mov.w #0x010f, W14 \n" \\r
- "sub #0x0101, W0 \n" \\r
- "cp0.w W0 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0102, W1 \n" \\r
- "cp0.w W1 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0103, W2 \n" \\r
- "cp0.w W2 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0104, W3 \n" \\r
- "cp0.w W3 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0105, W4 \n" \\r
- "cp0.w W4 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0106, W5 \n" \\r
- "cp0.w W5 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0107, W6 \n" \\r
- "cp0.w W6 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0108, W7 \n" \\r
- "cp0.w W7 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x0109, W8 \n" \\r
- "cp0.w W8 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010a, W9 \n" \\r
- "cp0.w W9 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010b, W10 \n" \\r
- "cp0.w W10 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010c, W11 \n" \\r
- "cp0.w W11 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010d, W12 \n" \\r
- "cp0.w W12 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010e, W13 \n" \\r
- "cp0.w W13 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "sub #0x010f, W14 \n" \\r
- "cp0.w W14 \n" \\r
- "bra NZ, ERROR_TEST1 \n" \\r
- "bra NO_ERROR1 \n" \\r
- "ERROR_TEST1: \n" \\r
- "mov.w #1, W0 \n" \\r
- "mov.w W0, _usErrorDetected\n" \\r
- "NO_ERROR1: \n" );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void xRegisterTest2( void *pvParameters )\r
-{\r
-/* This static so as not to use the frame pointer. They are volatile\r
-also to avoid it being stored in a register that we clobber during the test. */\r
-static unsigned portSHORT * volatile pusParameter;\r
-\r
- /* The variable incremented by this task is passed in as the parameter\r
- even though it is defined within this file. This is just to test the\r
- parameter passing mechanism. */\r
- pusParameter = pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Increment the variable to show this task is still cycling. */\r
- ( *pusParameter )++;\r
-\r
- /* Set the w registers to known values, then check that each register\r
- contains the expected value. See the explanation at the top of this\r
- file for more information. */\r
- asm volatile( "mov.w #0x0100, W0 \n" \\r
- "mov.w #0x0101, W1 \n" \\r
- "mov.w #0x0102, W2 \n" \\r
- "mov.w #0x0103, W3 \n" \\r
- "mov.w #0x0104, W4 \n" \\r
- "mov.w #0x0105, W5 \n" \\r
- "mov.w #0x0106, W6 \n" \\r
- "mov.w #0x0107, W7 \n" \\r
- "mov.w #0x0108, W8 \n" \\r
- "mov.w #0x0109, W9 \n" \\r
- "mov.w #0x010a, W10 \n" \\r
- "mov.w #0x010b, W11 \n" \\r
- "mov.w #0x010c, W12 \n" \\r
- "mov.w #0x010d, W13 \n" \\r
- "mov.w #0x010e, W14 \n" \\r
- "sub #0x0100, W0 \n" \\r
- "cp0.w W0 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0101, W1 \n" \\r
- "cp0.w W1 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0102, W2 \n" \\r
- "cp0.w W2 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0103, W3 \n" \\r
- "cp0.w W3 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0104, W4 \n" \\r
- "cp0.w W4 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0105, W5 \n" \\r
- "cp0.w W5 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0106, W6 \n" \\r
- "cp0.w W6 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0107, W7 \n" \\r
- "cp0.w W7 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0108, W8 \n" \\r
- "cp0.w W8 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x0109, W9 \n" \\r
- "cp0.w W9 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x010a, W10 \n" \\r
- "cp0.w W10 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x010b, W11 \n" \\r
- "cp0.w W11 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x010c, W12 \n" \\r
- "cp0.w W12 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x010d, W13 \n" \\r
- "cp0.w W13 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "sub #0x010e, W14 \n" \\r
- "cp0.w W14 \n" \\r
- "bra NZ, ERROR_TEST2 \n" \\r
- "bra NO_ERROR2 \n" \\r
- "ERROR_TEST2: \n" \\r
- "mov.w #1, W0 \n" \\r
- "mov.w W0, _usErrorDetected\n" \\r
- "NO_ERROR2: \n" );\r
+ /* Send the message to the LCD gatekeeper for display. */\r
+ xQueueSend( xLCDQueue, &xMessage, portMAX_DELAY );\r
}\r
}\r
/*-----------------------------------------------------------*/\r