* In addition to the standard demo tasks, the following tasks and tests are\r
* defined and/or created within this file:\r
*\r
- * TCP/IP ("lwIP") task - TBD _RB_\r
+ * TCP/IP ("lwIP") task - lwIP is used to create a basic web server. The web\r
+ * server uses server side includes (SSI) to generate tables of task statistics,\r
+ * and run time statistics (run time statistics show how much processing time\r
+ * each task has consumed). See\r
+ * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html\r
+ * for details on setting up and using the embedded web server.\r
*\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
+ * 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,\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
+ * latched into the pcStatusMessage variable, and can also be viewed at the\r
+ * bottom of the pages served by the embedded web server.\r
*\r
- * This file also includes example implementations of the vApplicationTickHook(),\r
+ * ***NOTE*** This demo uses the standard comtest tasks, which has special\r
+ * hardware requirements. See\r
+ * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html\r
+ * for more information.\r
+ *\r
+ * This file also includes example implementations of the\r
* vApplicationIdleHook(), vApplicationStackOverflowHook(),\r
* vApplicationMallocFailedHook(), vApplicationClearTimerInterrupt(), and\r
* vApplicationSetupTimerInterrupt() callback (hook) functions.\r
\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 mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
+#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-#define mainuIP_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
#define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )\r
/* The 'check' timer, as described at the top of this file. */\r
static xTimerHandle xCheckTimer = NULL;\r
\r
+/* Used in the run time stats calculations. */\r
+static unsigned long ulClocksPer10thOfAMilliSecond = 0UL;\r
+\r
+/* Constants used to set up the AXI timer to generate ticks. */\r
+static const unsigned char ucTimerCounterNumber = ( unsigned char ) 0U;\r
+static const unsigned long ulCounterReloadValue = ( ( XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / configTICK_RATE_HZ ) - 1UL );\r
+\r
/*-----------------------------------------------------------*/\r
\r
int main( void )\r
/* This is the callback function used by the 'check' timer, as described\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
- pcStatusMessage = "Error: GenQueue";\r
- }\r
- else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: QueuePeek\r\n";\r
- }\r
- else if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: BlockQueue\r\n";\r
- }\r
- else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: BlockTime\r\n";\r
- }\r
- else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: SemTest\r\n";\r
- }\r
- else if( xArePollingQueuesStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: PollQueue\r\n";\r
- }\r
- else if( xIsCreateTaskStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: Death\r\n";\r
- }\r
- else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )\r
- {\r
- pcStatusMessage = "Error: RecMutex\r\n";\r
- }\r
- else if( xAreMathsTaskStillRunning() != pdPASS )\r
- {\r
- pcStatusMessage = "Error: Flop\r\n";\r
- }\r
- else if( xAreComTestTasksStillRunning() != pdPASS )\r
- {\r
- pcStatusMessage = "Error: Comtest\r\n";\r
- }\r
- else if( xAreDynamicPriorityTasksStillRunning() != pdPASS )\r
- {\r
- pcStatusMessage = "Error: Dynamic\r\n";\r
- }\r
- else if( xAreTimerDemoTasksStillRunning( xExecutionRate ) != pdTRUE )\r
+ /* Don't overwrite any errors that have already been latched. */\r
+ if( pcStatusMessage == NULL )\r
{\r
- pcStatusMessage = "Error: TimerDemo";\r
- }\r
- else if( ulRegTest1CycleCount == ulLastRegTest1CycleCount )\r
- {\r
- /* Check the reg test tasks are still cycling. They will stop\r
- incrementing their loop counters if they encounter an error. */\r
- pcStatusMessage = "Error: RegTest1\r\n";\r
- }\r
- else if( ulRegTest2CycleCount == ulLastRegTest2CycleCount )\r
- {\r
- pcStatusMessage = "Error: RegTest2\r\n";\r
+ /* Check the standard demo tasks are running without error. */\r
+ if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: GenQueue";\r
+ }\r
+ else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: QueuePeek\r\n";\r
+ }\r
+ else if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: BlockQueue\r\n";\r
+ }\r
+ else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: BlockTime\r\n";\r
+ }\r
+ else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: SemTest\r\n";\r
+ }\r
+ else if( xArePollingQueuesStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: PollQueue\r\n";\r
+ }\r
+ else if( xIsCreateTaskStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: Death\r\n";\r
+ }\r
+ else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: RecMutex\r\n";\r
+ }\r
+ else if( xAreMathsTaskStillRunning() != pdPASS )\r
+ {\r
+ pcStatusMessage = "Error: Flop\r\n";\r
+ }\r
+ else if( xAreComTestTasksStillRunning() != pdPASS )\r
+ {\r
+ pcStatusMessage = "Error: Comtest\r\n";\r
+ }\r
+ else if( xAreDynamicPriorityTasksStillRunning() != pdPASS )\r
+ {\r
+ pcStatusMessage = "Error: Dynamic\r\n";\r
+ }\r
+ else if( xAreTimerDemoTasksStillRunning( xExecutionRate ) != pdTRUE )\r
+ {\r
+ pcStatusMessage = "Error: TimerDemo";\r
+ }\r
+ else if( ulRegTest1CycleCount == ulLastRegTest1CycleCount )\r
+ {\r
+ /* Check the reg test tasks are still cycling. They will stop\r
+ incrementing their loop counters if they encounter an error. */\r
+ pcStatusMessage = "Error: RegTest1\r\n";\r
+ }\r
+ else if( ulRegTest2CycleCount == ulLastRegTest2CycleCount )\r
+ {\r
+ pcStatusMessage = "Error: RegTest2\r\n";\r
+ }\r
}\r
\r
/* Store a local copy of the current reg test loop counters. If these have\r
void vApplicationSetupTimerInterrupt( void )\r
{\r
portBASE_TYPE xStatus;\r
-const unsigned char ucTimerCounterNumber = ( unsigned char ) 0U;\r
-const unsigned long ulCounterValue = ( ( XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / configTICK_RATE_HZ ) - 1UL );\r
extern void vPortTickISR( void *pvUnused );\r
\r
/* Initialise the timer/counter. */\r
XTmrCtr_SetHandler( &xTimer0Instance, ( void * ) vPortTickISR, NULL );\r
\r
/* Set the correct period for the timer. */\r
- XTmrCtr_SetResetValue( &xTimer0Instance, ucTimerCounterNumber, ulCounterValue );\r
+ XTmrCtr_SetResetValue( &xTimer0Instance, ucTimerCounterNumber, ulCounterReloadValue );\r
\r
/* Enable the interrupts. Auto-reload mode is used to generate a\r
periodic tick. Note that interrupts are disabled when this function is\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
void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )\r
{\r
( void ) xRegisterDump;\r
\r
void vMainConfigureTimerForRunTimeStats( void )\r
{\r
-unsigned long ulRunTimeStatsDivisor;\r
-\r
/* How many times does the counter counter increment in 10ms? */\r
- ulRunTimeStatsDivisor = 0UL / 1000UL; //_RB_\r
+ ulClocksPer10thOfAMilliSecond = XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / 10000UL;\r
}\r
/*-----------------------------------------------------------*/\r
\r
unsigned long ulMainGetRunTimeCounterValue( void )\r
{\r
-unsigned long ulReturn, ulCurrentCount;\r
+unsigned long ulTimerCounts1, ulTimerCounts2, ulTickCount, ulReturn;\r
+\r
+ /* NOTE: This can get called from a yield, in which case interrupts are\r
+ disabled, or from a tick ISR, in which case the effect is the same as if\r
+ interrupts were disabled. In either case, it is going to run atomically. */\r
+\r
+ /* The timer is in down count mode. How many clocks have passed since it\r
+ was last reloaded? */\r
+ ulTimerCounts1 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );\r
+\r
+ /* How many times has it overflowed? */\r
+ ulTickCount = xTaskGetTickCountFromISR();\r
+\r
+ /* If this is being called from a yield, has the counter overflowed since\r
+ it was read? If that is the case then ulTickCounts will need incrementing\r
+ again as it will not yet have been incremented from the tick interrupt. */
+ ulTimerCounts2 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );\r
+ if( ulTimerCounts2 < ulTimerCounts1 )\r
+ {\r
+ /* There is a tick interrupt pending but the tick count not yet\r
+ incremented. */\r
+ ulTickCount++;\r
+\r
+ /* Use the second timer reading. */\r
+ ulTimerCounts1 = ulTimerCounts2;\r
+ }\r
\r
- ulCurrentCount = 0UL;\r
- ulReturn = 0UL;\r
+ /* Convert the tick count into tenths of a millisecond. THIS ASSUMES\r
+ configTICK_RATE_HZ is 1000! */\r
+ ulReturn = ( ulTickCount * 10UL );\r
+\r
+ /* Add on the number of tenths of a millisecond that have passed since the\r
+ tick count last got updated. */\r
+ ulReturn += ( ulTimerCounts1 / ulClocksPer10thOfAMilliSecond );\r
+\r
+ /* Some crude rounding. */\r
+ if( ( ulTimerCounts1 % ulClocksPer10thOfAMilliSecond ) > ( ulClocksPer10thOfAMilliSecond >> 1UL ) )\r
+ {\r
+ ulReturn++;\r
+ }\r
\r
return ulReturn;\r
}\r
\r
char *pcMainGetTaskStatusMessage( void )\r
{\r
- return ( char * ) pcStatusMessage;\r
+char * pcReturn;\r
+\r
+ if( pcStatusMessage == NULL )\r
+ {\r
+ pcReturn = ( char * ) "OK";\r
+ }\r
+ else\r
+ {\r
+ pcReturn = ( char * ) pcStatusMessage;\r
+ }\r
+\r
+ return pcReturn;\r
}\r
\r
\r