*/\r
\r
/* ****************************************************************************\r
- * This project includes a lot of demo and test tasks, and is therefore complex.\r
- * If you would prefer a much simpler project to get started with, then select\r
- * the 'Blinky' build configuration within the SDK Eclipse IDE.\r
+ * main-blinky.c is included when the "Blinky" build configuration is used.\r
+ * main-full.c is included when the "Full" build configuration is used.\r
+ *\r
+ * main-full.c creates a lot of demo and test tasks and timers, and is \r
+ * therefore very comprehensive but also complex. If you would prefer a much \r
+ * simpler project to get started with, then select the 'Blinky' build \r
+ * configuration within the SDK Eclipse IDE. See the documentation page for\r
+ * this demo on the http://www.FreeRTOS.org web site for more information.\r
* ****************************************************************************\r
*\r
- * main() creates all the demo application tasks, then starts the scheduler. \r
- * The web documentation provides more details of the standard demo application \r
- * tasks, which provide no particular functionality, but do provide a good \r
- * example of how to use the FreeRTOS API. \r
+ * main() creates all the demo application tasks and timers, then starts the \r
+ * scheduler. The web documentation provides more details of the standard demo \r
+ * application tasks, which provide no particular functionality, but do provide \r
+ * a good example of how to use the FreeRTOS API. \r
*\r
* In addition to the standard demo tasks, the following tasks and tests are\r
* defined and/or created within this file:\r
*\r
- * Webserver ("lwIP") task - TBD _RB_\r
+ * TCP/IP ("lwIP") task - TBD _RB_\r
*\r
- * "Reg test" tasks - These fill the registers with known values, then check\r
- * that each register still contains its expected value. Each task uses\r
- * different values. The tasks run with very low priority so get preempted\r
- * very frequently. A check variable is incremented on each iteration of the\r
- * test loop. A register containing an unexpected value is indicative of an\r
- * error in the context switching mechanism and will result in a branch to a\r
- * null loop - which in turn will prevent the check variable from incrementing\r
- * any further and allow the check timer (described below) to determine that an\r
- * error has occurred. The nature of the reg test tasks necessitates that they\r
- * are written in assembly code.\r
+ * "Reg test" tasks - These test the task context switch mechanism by first \r
+ * filling the MicroBlaze registers with known values, before checking that each\r
+ * register maintains the value that was written to it as the tasks are switched\r
+ * in and out. The two register test tasks do not use the same values, and\r
+ * execute at a very low priority to ensure they are pre-empted regularly.\r
*\r
* "Check" timer - The check timer period is initially set to five seconds. \r
- * The check timer callback function checks that all the standard demo tasks are \r
- * functioning as expected, without error. If an error is discovered in any \r
- * standard demo task, then the check timer period is shortened to 200ms. The\r
- * check timer callback function also toggles an LED each time it is called. \r
- * Therefore, if the LED toggles every five seconds, all the tasks are\r
- * functioning as expected, without any error conditions being detected. If the\r
- * LED toggles every 200ms then an error has been discovered in at least one\r
- * task. \r
+ * The check timer callback function checks that all the standard demo tasks,\r
+ * and the register check tasks, are not only still execution, but are executing\r
+ * without reporting any errors. If the check timer discovers that a task has\r
+ * either stalled or reported an error, then it changes its own period from\r
+ * the inital five seconds, to just 200ms. The check timer callback function \r
+ * also toggles an LED each time it is called. This provides a visual\r
+ * indication of the system status: If the LED toggles every five seconds then\r
+ * no issues have been discovered. If the LED toggles every 200ms then an issue\r
+ * has been discovered with at least one task. The last reported issue is\r
+ * latched into the pcStatusMessage variable.\r
*\r
* This file also includes example implementations of the vApplicationTickHook(),\r
* vApplicationIdleHook(), vApplicationStackOverflowHook(),\r
#include "comtest_strings.h"\r
#include "TimerDemo.h"\r
\r
-/* Priorities at which the tasks are created. */\r
+/* Priorities at which the various tasks are created. */\r
#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
\r
-/* The WEB server uses string handling functions, which in turn use a bit more\r
-stack than most of the other tasks. */\r
-#define mainuIP_STACK_SIZE ( configMINIMAL_STACK_SIZE * 3 )\r
-\r
/* The LED toggled by the check task. */\r
#define mainCHECK_LED ( 3 )\r
\r
/* The rate at which mainCHECK_LED will toggle when all the tasks are running\r
-without error. Controlled by the check task as described at the top of this\r
-file. */\r
+without error. See the description of the check timer in the comments at the\r
+top of this file. */\r
#define mainNO_ERROR_CHECK_TIMER_PERIOD ( 5000 / portTICK_RATE_MS )\r
\r
/* The rate at which mainCHECK_LED will toggle when an error has been reported\r
-by at least one task. Controlled by the check task as described at the top of\r
-this file. */\r
+by at least one task. See the description of the check timer in the comments at \r
+the top of this file. */\r
#define mainERROR_CHECK_TIMER_PERIOD ( 200 / portTICK_RATE_MS )\r
\r
-/* A block time of zero means "don't block". */
+/* A block time of zero simply means "don't block". */
#define mainDONT_BLOCK ( ( portTickType ) 0 )\r
\r
-/* The LED used by the comtest tasks. See the comtest.c file for more\r
+/* The LED used by the comtest tasks. See the comtest_strings.c file for more\r
information. In this case an invalid LED number is provided as all four\r
-available LEDs are already in use. */\r
+available LEDs (LEDs 0 to 3) are already in use. */\r
#define mainCOM_TEST_LED ( 4 )\r
\r
-/* Baud rate used by the comtest tasks. This is actually fixed in the hardware\r
-when the hardware was built, but the standard serial init function required a\r
-baud rate parameter. */\r
+/* Baud rate used by the comtest tasks. The baud rate used is actually fixed in \r
+UARTLite IP when the hardware was built, but the standard serial init function \r
+required a baud rate parameter to be provided - in this case it is just \r
+ignored. */\r
#define mainCOM_TEST_BAUD_RATE ( XPAR_RS232_UART_1_BAUDRATE )\r
\r
+/* The timer test task generates a lot of timers that all use a different \r
+period that is a multiple of the mainTIMER_TEST_PERIOD definition. */\r
#define mainTIMER_TEST_PERIOD ( 20 )\r
\r
-/*\r
- * vApplicationMallocFailedHook() will only be called if\r
- * configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook\r
- * function that will execute if a call to pvPortMalloc() fails.\r
- * pvPortMalloc() is called internally by the kernel whenever a task, queue or\r
- * semaphore is created. It is also called by various parts of the demo\r
- * application.\r
- */\r
-void vApplicationMallocFailedHook( void );\r
-\r
-/*\r
- * vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1\r
- * in FreeRTOSConfig.h. It is a hook function that is called on each iteration\r
- * of the idle task. It is essential that code added to this hook function\r
- * never attempts to block in any way (for example, call xQueueReceive() with\r
- * a block time specified). If the application makes use of the vTaskDelete()\r
- * API function (as this demo application does) then it is also important that\r
- * vApplicationIdleHook() is permitted to return to its calling function because\r
- * it is the responsibility of the idle task to clean up memory allocated by the\r
- * kernel to any task that has since been deleted.\r
- */\r
-void vApplicationIdleHook( void );\r
-\r
-/*\r
- * vApplicationStackOverflowHook() will only be called if\r
- * configCHECK_FOR_STACK_OVERFLOW is set to a non-zero value. The handle and\r
- * name of the offending task should be passed in the function parameters, but\r
- * it is possible that the stack overflow will have corrupted these - in which\r
- * case pxCurrentTCB can be inspected to find the same information.\r
- */\r
-void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName );\r
+/*-----------------------------------------------------------*/\r
\r
/*\r
- * The reg test tasks as described at the top of this file.\r
+ * The register test tasks as described in the comments at the top of this file.\r
+ * The nature of the register test tasks means they have to be implemented in\r
+ * assembler.\r
*/\r
extern void vRegisterTest1( void *pvParameters );\r
extern void vRegisterTest2( void *pvParameters );\r
\r
/*\r
- * Defines the 'check' functionality as described at the top of this file. This\r
- * function is the callback function for the 'check' timer.\r
+ * Defines the 'check' timer functionality as described at the top of this file. \r
+ * This function is the callback function associated with the 'check' timer.\r
*/\r
static void vCheckTimerCallback( xTimerHandle xTimer );\r
\r
-\r
+/* \r
+ * Configure the interrupt controller, LED outputs and button inputs. \r
+ */\r
static void prvSetupHardware( void );\r
\r
-\r
/*-----------------------------------------------------------*/\r
\r
-/* The status message that is displayed at the bottom of the "task stats" web\r
-page, which is served by the uIP task. This will report any errors picked up\r
-by the reg test task. */\r
+/* The check timer callback function sets pcStatusMessage to a string that\r
+indicates the last reported error that it discovered. */\r
static const char *pcStatusMessage = NULL;\r
\r
+/* Structures that hold the state of the various peripherals used by this demo.\r
+These are used by the Xilinx peripheral driver API functions. In this case,\r
+only the timer/counter is used directly within this file. */\r
static XTmrCtr xTimer0Instance;\r
\r
/* The 'check' timer, as described at the top of this file. */\r
\r
int main( void )\r
{\r
- /* *************************************************************************\r
- This project includes a lot of demo and test tasks, and is therefore complex.\r
- If you would prefer a much simpler project to get started with, then select\r
- the 'Blinky' build configuration within the SDK Eclipse IDE.\r
+ /***************************************************************************\r
+ This project includes a lot of demo and test tasks and timers, and is \r
+ therefore comprehensive, but complex. If you would prefer a much simpler \r
+ project to get started with, then select the 'Blinky' build configuration \r
+ within the SDK Eclipse IDE.\r
***************************************************************************/\r
\r
/* Configure the interrupt controller, LED outputs and button inputs. */\r
prvSetupHardware();\r
\r
- /* Start the reg test tasks which test the context switching mechanism. */\r
+ /* Start the reg test tasks, as described in the comments at the top of this\r
+ file. */\r
xTaskCreate( vRegisterTest1, ( const signed char * const ) "RegTst1", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );\r
xTaskCreate( vRegisterTest2, ( const signed char * const ) "RegTst2", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );\r
\r
\r
/* Note - the set of standard demo tasks contains two versions of\r
vStartMathTasks.c. One is defined in flop.c, and uses double precision\r
- floating point numbers and variables. The other is defined in sp_flop.c\r
+ floating point numbers and variables. The other is defined in sp_flop.c,\r
and uses single precision floating point numbers and variables. The\r
MicroBlaze floating point unit only handles single precision floating.\r
- Therefore, to test the floating point unit, sp_flop.c should be included\r
+ Therefore, to test the floating point hardware, sp_flop.c should be included\r
in this project. */\r
vStartMathTasks( mainFLOP_TASK_PRIORITY );\r
\r
/* The suicide tasks must be created last as they need to know how many\r
- tasks were running prior to their creation in order to ascertain whether\r
- or not the correct/expected number of tasks are running at any given time. */\r
+ tasks were running prior to their creation. This then allows them to \r
+ ascertain whether or not the correct/expected number of tasks are running at \r
+ any given time. */\r
vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );\r
\r
/* Create the 'check' timer - the timer that periodically calls the\r
- check function as described at the top of this file. Note that, for\r
- the reasons stated in the comments above the call to\r
- vStartTimerDemoTask(), that the check timer is not actually started\r
- until after the scheduler has been started. */\r
+ check function as described in the comments at the top of this file. Note \r
+ that, for reasons stated in the comments within vApplicationIdleHook()\r
+ (defined in this file), the check timer is not actually started until after \r
+ the scheduler has been started. */\r
xCheckTimer = xTimerCreate( ( const signed char * ) "Check timer", mainNO_ERROR_CHECK_TIMER_PERIOD, pdTRUE, ( void * ) 0, vCheckTimerCallback );\r
\r
- /* Start the tasks running. */\r
+ /* Start the scheduler running. From this point on, only tasks and \r
+ interrupts will be executing. */\r
vTaskStartScheduler();\r
\r
- /* If all is well we will never reach here as the scheduler will now be\r
- running. If we do reach here then it is likely that there was insufficient\r
- heap available for the idle task to be created. */\r
+ /* If all is well then the following line will never be reached. If\r
+ execution does reach here, then it is highly probably that the heap size\r
+ is too small for the idle and/or timer tasks to be created within \r
+ vTaskStartScheduler(). */\r
taskDISABLE_INTERRUPTS();\r
for( ;; );\r
}\r
portTickType xExecutionRate = mainNO_ERROR_CHECK_TIMER_PERIOD;\r
\r
/* This is the callback function used by the 'check' timer, as described\r
- at the top of this file. */\r
+ in the comments at the top of this file. */\r
\r
/* Check the standard demo tasks are running without error. */\r
if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
{\r
- /* Increase the rate at which this task cycles, which will increase the\r
- rate at which mainCHECK_LED flashes to give visual feedback that an error\r
- has occurred. */\r
pcStatusMessage = "Error: GenQueue";\r
}\r
else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
pcStatusMessage = "Error: RegTest2\r\n";\r
}\r
\r
+ /* Store a local copy of the current reg test loop counters. If these have\r
+ not incremented the next time this callback function is executed then the\r
+ reg test tasks have either stalled or discovered an error. */\r
ulLastRegTest1CycleCount = ulRegTest1CycleCount;\r
ulLastRegTest2CycleCount = ulRegTest2CycleCount;\r
\r
{\r
if( lErrorAlreadyLatched == pdFALSE )\r
{\r
- /* Ensure the LED toggles at a faster rate if an error has occurred.\r
- This is called from a timer callback so must not attempt to block. */
- xTimerChangePeriod( xTimer, mainERROR_CHECK_TIMER_PERIOD, mainDONT_BLOCK );\r
-\r
- /* Update the xExecutionRate variable as the rate at which this\r
+ /* An error has occurred, so change the period of the timer that\r
+ calls this callback function. This results in the LED toggling at\r
+ a faster rate - giving the user visual feedback that something is not\r
+ as it should be. This function is called from the context of the\r
+ timer service task so must ***not*** attempt to block while calling\r
+ this function. */
+ if( xTimerChangePeriod( xTimer, mainERROR_CHECK_TIMER_PERIOD, mainDONT_BLOCK ) == pdPASS )\r
+ {\r
+ /* If the command to change the timer period was sent to the\r
+ timer command queue successfully, then latch the fact that the\r
+ timer period has already been changed. This is just done to\r
+ prevent xTimerChangePeriod() being called on every execution of\r
+ this function once an error has been discovered. */\r
+ lErrorAlreadyLatched = pdTRUE;\r
+ }\r
+\r
+ /* Update the xExecutionRate variable too as the rate at which this\r
callback is executed has to be passed into the\r
xAreTimerDemoTasksStillRunning() function. */\r
xExecutionRate = mainERROR_CHECK_TIMER_PERIOD;\r
-\r
- /* Just to ensure the timer period is not changed on each execution\r
- of the callback. */
- lErrorAlreadyLatched = pdTRUE;\r
}\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
+/* This is an application defined callback function used to install the tick\r
+interrupt handler. It is provided as an application callback because the kernel\r
+will run on lots of different MicroBlaze and FPGA configurations - not all of\r
+which will have the same timer peripherals defined or available. This example\r
+uses the AXI Timer 0. If that is available on your hardware platform then this\r
+example callback implementation should not require modification. The name of\r
+the interrupt handler that should be installed is vTickISR(), which the function\r
+below declares as an extern. */\r
void vApplicationSetupTimerInterrupt( void )\r
{\r
portBASE_TYPE xStatus;\r
\r
if( xStatus == XST_SUCCESS )\r
{\r
- /* Install the tick interrupt handler as the timer ISR. */\r
+ /* Install the tick interrupt handler as the timer ISR. \r
+ *NOTE* The xPortInstallInterruptHandler() API function must be used for\r
+ this purpose. */\r
xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_TMRCTR_0_VEC_ID, vTickISR, NULL );\r
}\r
\r
if( xStatus == pdPASS )\r
{\r
+ /* Enable the timer interrupt in the interrupt controller.\r
+ *NOTE* The vPortEnableInterrupt() API function must be used for this\r
+ purpose. */\r
vPortEnableInterrupt( XPAR_INTC_0_TMRCTR_0_VEC_ID );\r
\r
/* Configure the timer interrupt handler. */\r
XTmrCtr_Start( &xTimer0Instance, ucTimerCounterNumber );\r
}\r
\r
+ /* Sanity check that the function executed as expected. */\r
configASSERT( ( xStatus == pdPASS ) );\r
}\r
/*-----------------------------------------------------------*/\r
\r
+/* This is an application defined callback function used to clear whichever\r
+interrupt was installed by the the vApplicationSetupTimerInterrupt() callback\r
+function - in this case the interrupt generated by the AXI timer. It is \r
+provided as an application callback because the kernel will run on lots of \r
+different MicroBlaze and FPGA configurations - not all of which will have the \r
+same timer peripherals defined or available. This example uses the AXI Timer 0. \r
+If that is available on your hardware platform then this example callback \r
+implementation should not require modification provided the example definition\r
+of vApplicationSetupTimerInterrupt() is also not modified. */\r
void vApplicationClearTimerInterrupt( void )\r
{\r
unsigned long ulCSR;\r
}\r
/*-----------------------------------------------------------*/\r
\r
-/* This function is explained by the comments above its prototype at the top\r
-of this file. */\r
void vApplicationMallocFailedHook( void )\r
{\r
+ /* vApplicationMallocFailedHook() will only be called if\r
+ configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook\r
+ function that will get called if a call to pvPortMalloc() fails. \r
+ pvPortMalloc() is called internally by the kernel whenever a task, queue or\r
+ semaphore is created. It is also called by various parts of the demo\r
+ application. If heap_1.c or heap_2.c are used, then the size of the heap\r
+ available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in\r
+ FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used\r
+ to query the size of free heap space that remains (although it does not\r
+ provide information on how the remaining heap might be fragmented). */\r
taskDISABLE_INTERRUPTS();\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
\r
-/* This function is explained by the comments above its prototype at the top\r
-of this file. */\r
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )\r
{\r
+ /* vApplicationStackOverflowHook() will only be called if\r
+ configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2. The handle and name\r
+ of the offending task will be passed into the hook function via its \r
+ parameters. However, when a stack has overflowed, it is possible that the\r
+ parameters will have been corrupted, in which case the pxCurrentTCB variable\r
+ can be inspected directly. */\r
taskDISABLE_INTERRUPTS();\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
\r
-/* This function is explained by the comments above its prototype at the top\r
-of this file. */\r
void vApplicationIdleHook( void )\r
{\r
static long lCheckTimerStarted = pdFALSE;\r
\r
+ /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set \r
+ to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle \r
+ task. It is essential that code added to this hook function never attempts \r
+ to block in any way (for example, call xQueueReceive() with a block time \r
+ specified, or call vTaskDelay()). If the application makes use of the \r
+ vTaskDelete() API function (as this demo application does) then it is also \r
+ important that vApplicationIdleHook() is permitted to return to its calling \r
+ function, because it is the responsibility of the idle task to clean up \r
+ memory allocated by the kernel to any task that has since been deleted. */\r
+\r
+ /* If the check timer has not already been started, then start it now.\r
+ Normally, the xTimerStart() API function can be called immediately after the\r
+ timer is created - how this demo application includes the timer demo tasks.\r
+ The timer demo tasks, as part of their test function, deliberately fill up\r
+ the timer command queue - meaning the check timer cannot be started until\r
+ after the scheduler has been started - at which point the timer command\r
+ queue will have been drained. */\r
if( lCheckTimerStarted == pdFALSE )\r
{\r
- xTimerStart( xCheckTimer, mainDONT_BLOCK ); //_RB_ comment why this is done here.\r
+ xTimerStart( xCheckTimer, mainDONT_BLOCK ); \r
lCheckTimerStarted = pdTRUE;\r
}\r
}\r
\r
void vApplicationTickHook( void )\r
{\r
+ /* vApplicationTickHook() will only be called if configUSE_TICK_HOOK is set\r
+ to 1 in FreeRTOSConfig.h. It executes from an interrupt context so must\r
+ not use any FreeRTOS API functions that do not end in ...FromISR(). */\r
+\r
/* Call the periodic timer test, which tests the timer API functions that\r
can be called from an ISR. */\r
vTimerPeriodicISRTests();\r
}\r
/*-----------------------------------------------------------*/\r
\r
-char *pcGetTaskStatusMessage( void )\r
+void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )\r
{\r
- /* Not bothered about a critical section here although technically because of\r
- the task priorities the pointer could change it will be atomic if not near\r
- atomic and its not critical. */\r
- if( pcStatusMessage == NULL )\r
- {\r
- return "All tasks running without error";\r
- }\r
- else\r
+ /* If configINSTALL_EXCEPTION_HANDLERS is set to 1 in FreeRTOSConfig.h, then \r
+ the kernel will automatically install its own exception handlers before the \r
+ kernel is started, if the application writer has not already caused them to \r
+ be installed by calling either of the vPortExceptionsInstallHandlers() \r
+ or xPortInstallInterruptHandler() API functions before that time. The \r
+ kernels exception handler populates an xPortRegisterDump structure with\r
+ the processor state at the point that the exception was triggered - and also\r
+ includes a strings that say what the exception cause was and which task was\r
+ running at the time. The exception handler then passes the populated\r
+ xPortRegisterDump structure into vApplicationExceptionRegisterDump() to\r
+ allow the application writer to perform any debugging that may be necessary.\r
+ However, defining vApplicationExceptionRegisterDump() within the application\r
+ itself is optional. The kernel will use a default implementation if the\r
+ application writer chooses not to provide their own. */\r
+ for( ;; )\r
{\r
- return ( char * ) pcStatusMessage;\r
+ portNOP();\r
}\r
}\r
/*-----------------------------------------------------------*/\r
static void prvSetupHardware( void )\r
{\r
taskDISABLE_INTERRUPTS();\r
+ \r
+ /* Configure the LED outputs. */\r
vParTestInitialise();\r
\r
+ /* Tasks inherit the exception and cache configuration of the MicroBlaze\r
+ at the point that they are created. */\r
#if MICROBLAZE_EXCEPTIONS_ENABLED == 1\r
microblaze_enable_exceptions();\r
#endif\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )\r
-{\r
- for( ;; )\r
- {\r
- portNOP();\r
- }\r
-}\r
-\r