]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemo/main-full.c
d4eba1bc4e3e16db608acf9336f8eb07dd8ed7d5
[freertos] / FreeRTOS / Demo / MicroBlaze_Spartan-6_EthernetLite / SDKProjects / RTOSDemo / main-full.c
1 /*\r
2     FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS provides completely free yet professionally developed,    *\r
10      *    robust, strictly quality controlled, supported, and cross          *\r
11      *    platform software that has become a de facto standard.             *\r
12      *                                                                       *\r
13      *    Help yourself get started quickly and support the FreeRTOS         *\r
14      *    project by purchasing a FreeRTOS tutorial book, reference          *\r
15      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
16      *                                                                       *\r
17      *    Thank you!                                                         *\r
18      *                                                                       *\r
19     ***************************************************************************\r
20 \r
21     This file is part of the FreeRTOS distribution.\r
22 \r
23     FreeRTOS is free software; you can redistribute it and/or modify it under\r
24     the terms of the GNU General Public License (version 2) as published by the\r
25     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
26 \r
27     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
28     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
29     >>!   obliged to provide the source code for proprietary components     !<<\r
30     >>!   outside of the FreeRTOS kernel.                                   !<<\r
31 \r
32     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
33     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
34     FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
35     link: http://www.freertos.org/a00114.html\r
36 \r
37     1 tab == 4 spaces!\r
38 \r
39     ***************************************************************************\r
40      *                                                                       *\r
41      *    Having a problem?  Start by reading the FAQ "My application does   *\r
42      *    not run, what could be wrong?"                                     *\r
43      *                                                                       *\r
44      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
45      *                                                                       *\r
46     ***************************************************************************\r
47 \r
48     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
49     license and Real Time Engineers Ltd. contact details.\r
50 \r
51     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
52     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
53     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
54 \r
55     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
56     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
57     licenses offer ticketed support, indemnification and middleware.\r
58 \r
59     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
60     engineered and independently SIL3 certified version for use in safety and\r
61     mission critical applications that require provable dependability.\r
62 \r
63     1 tab == 4 spaces!\r
64 */\r
65 \r
66 /* ****************************************************************************\r
67  * main-blinky.c is included when the "Blinky" build configuration is used.\r
68  * main-full.c is included when the "Full" build configuration is used.\r
69  *\r
70  * main-full.c creates a lot of demo and test tasks and timers,  and is\r
71  * therefore very comprehensive but also complex.  If you would prefer a much\r
72  * simpler project to get started with, then select the 'Blinky' build\r
73  * configuration within the SDK Eclipse IDE.  See the documentation page for\r
74  * this demo on the http://www.FreeRTOS.org web site for more information.\r
75  * ****************************************************************************\r
76  *\r
77  * main() creates all the demo application tasks and timers, then starts the\r
78  * scheduler.  The web documentation provides more details of the standard demo\r
79  * application tasks, which provide no particular functionality, but do provide\r
80  * a good example of how to use the FreeRTOS API.\r
81  *\r
82  * In addition to the standard demo tasks, the following tasks and tests are\r
83  * defined and/or created within this file:\r
84  *\r
85  * TCP/IP ("lwIP") task - lwIP is used to create a basic web server.  The web\r
86  * server uses server side includes (SSI) to generate tables of task statistics,\r
87  * and run time statistics (run time statistics show how much processing time\r
88  * each task has consumed).  See\r
89  * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html\r
90  * for details on setting up and using the embedded web server.\r
91  *\r
92  * "Reg test" tasks - These test the task context switch mechanism by first\r
93  * filling the MicroBlaze registers with known values, before checking that each\r
94  * register maintains the value that was written to it as the tasks are switched\r
95  * in and out.  The two register test tasks do not use the same values, and\r
96  * execute at a very low priority, to ensure they are pre-empted regularly.\r
97  *\r
98  * "Check" timer - The check timer period is initially set to five seconds.\r
99  * The check timer callback function checks that all the standard demo tasks,\r
100  * and the register check tasks, are not only still executing, but are executing\r
101  * without reporting any errors.  If the check timer discovers that a task has\r
102  * either stalled, or reported an error, then it changes its own period from\r
103  * the initial five seconds, to just 200ms.  The check timer callback function\r
104  * also toggles an LED each time it is called.  This provides a visual\r
105  * indication of the system status:  If the LED toggles every five seconds then\r
106  * no issues have been discovered.  If the LED toggles every 200ms then an issue\r
107  * has been discovered with at least one task.  The last reported issue is\r
108  * latched into the pcStatusMessage variable, and can also be viewed at the\r
109  * bottom of the pages served by the embedded web server.\r
110  *\r
111  * ***NOTE*** This demo uses the standard comtest tasks, which has special\r
112  * hardware requirements.  See\r
113  * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html\r
114  * for more information.\r
115  *\r
116  * This file also includes example implementations of the\r
117  * vApplicationIdleHook(), vApplicationStackOverflowHook(),\r
118  * vApplicationMallocFailedHook(), vApplicationClearTimerInterrupt(), and\r
119  * vApplicationSetupTimerInterrupt() callback (hook) functions.\r
120  */\r
121 \r
122 /* Standard includes. */\r
123 #include <string.h>\r
124 #include <stdio.h>\r
125 \r
126 /* BSP includes. */\r
127 #include "xtmrctr.h"\r
128 #include "microblaze_exceptions_g.h"\r
129 \r
130 /* Kernel includes. */\r
131 #include "FreeRTOS.h"\r
132 #include "task.h"\r
133 #include "timers.h"\r
134 \r
135 /* Standard demo includes. */\r
136 #include "partest.h"\r
137 #include "flash.h"\r
138 #include "BlockQ.h"\r
139 #include "death.h"\r
140 #include "blocktim.h"\r
141 #include "semtest.h"\r
142 #include "PollQ.h"\r
143 #include "GenQTest.h"\r
144 #include "QPeek.h"\r
145 #include "recmutex.h"\r
146 #include "flop.h"\r
147 #include "dynamic.h"\r
148 #include "comtest_strings.h"\r
149 #include "TimerDemo.h"\r
150 \r
151 /* lwIP includes. */\r
152 #include "lwip/tcpip.h"\r
153 \r
154 \r
155 /* Priorities at which the various tasks are created. */\r
156 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 1 )\r
157 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
158 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 1 )\r
159 #define mainCREATOR_TASK_PRIORITY   ( tskIDLE_PRIORITY + 3 )\r
160 #define mainFLASH_TASK_PRIORITY         ( tskIDLE_PRIORITY + 1 )\r
161 #define mainCOM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
162 #define mainINTEGER_TASK_PRIORITY   ( tskIDLE_PRIORITY )\r
163 #define mainGEN_QUEUE_TASK_PRIORITY     ( tskIDLE_PRIORITY )\r
164 #define mainFLOP_TASK_PRIORITY          ( tskIDLE_PRIORITY )\r
165 \r
166 /* The LED toggled by the check task. */\r
167 #define mainCHECK_LED                           ( 3 )\r
168 \r
169 /* The rate at which mainCHECK_LED will toggle when all the tasks are running\r
170 without error.  See the description of the check timer in the comments at the\r
171 top of this file. */\r
172 #define mainNO_ERROR_CHECK_TIMER_PERIOD         ( 5000 / portTICK_PERIOD_MS )\r
173 \r
174 /* The rate at which mainCHECK_LED will toggle when an error has been reported\r
175 by at least one task.  See the description of the check timer in the comments at\r
176 the top of this file. */\r
177 #define mainERROR_CHECK_TIMER_PERIOD            ( 200 / portTICK_PERIOD_MS )\r
178 \r
179 /* A block time of zero simply means "don't block". */\r
180 #define mainDONT_BLOCK                                          ( ( TickType_t ) 0 )\r
181 \r
182 /* The LED used by the comtest tasks. See the comtest_strings.c file for more\r
183 information.  In this case an invalid LED number is provided as all four\r
184 available LEDs (LEDs 0 to 3) are already in use. */\r
185 #define mainCOM_TEST_LED                        ( 4 )\r
186 \r
187 /* Baud rate used by the comtest tasks.  The baud rate used is actually fixed in\r
188 UARTLite IP when the hardware was built, but the standard serial init function\r
189 required a baud rate parameter to be provided - in this case it is just\r
190 ignored. */\r
191 #define mainCOM_TEST_BAUD_RATE                          ( XPAR_RS232_UART_1_BAUDRATE )\r
192 \r
193 /* The timer test task generates a lot of timers that all use a different\r
194 period that is a multiple of the mainTIMER_TEST_PERIOD definition. */\r
195 #define mainTIMER_TEST_PERIOD                   ( 20 )\r
196 \r
197 /*-----------------------------------------------------------*/\r
198 \r
199 /*\r
200  * The register test tasks as described in the comments at the top of this file.\r
201  * The nature of the register test tasks means they have to be implemented in\r
202  * assembler.\r
203  */\r
204 extern void vRegisterTest1( void *pvParameters );\r
205 extern void vRegisterTest2( void *pvParameters );\r
206 \r
207 /*\r
208  * Defines the 'check' timer functionality as described at the top of this file.\r
209  * This function is the callback function associated with the 'check' timer.\r
210  */\r
211 static void vCheckTimerCallback( TimerHandle_t xTimer );\r
212 \r
213 /*\r
214  * Configure the interrupt controller, LED outputs and button inputs.\r
215  */\r
216 static void prvSetupHardware( void );\r
217 \r
218 /* Defined in lwIPApps.c. */\r
219 extern void lwIPAppsInit( void *pvArguments );\r
220 \r
221 /*-----------------------------------------------------------*/\r
222 \r
223 /* The check timer callback function sets pcStatusMessage to a string that\r
224 indicates the last reported error that it discovered. */\r
225 static const char *pcStatusMessage = NULL;\r
226 \r
227 /* Structures that hold the state of the various peripherals used by this demo.\r
228 These are used by the Xilinx peripheral driver API functions.  In this case,\r
229 only the timer/counter is used directly within this file. */\r
230 static XTmrCtr xTimer0Instance;\r
231 \r
232 /* The 'check' timer, as described at the top of this file. */\r
233 static TimerHandle_t xCheckTimer = NULL;\r
234 \r
235 /* Used in the run time stats calculations. */\r
236 static unsigned long ulClocksPer10thOfAMilliSecond = 0UL;\r
237 \r
238 /* Constants used to set up the AXI timer to generate ticks. */\r
239 static const unsigned char ucTimerCounterNumber = ( unsigned char ) 0U;\r
240 static const unsigned long ulCounterReloadValue = ( ( XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / configTICK_RATE_HZ ) - 1UL );\r
241 \r
242 /*-----------------------------------------------------------*/\r
243 \r
244 int main( void )\r
245 {\r
246         /***************************************************************************\r
247         This project includes a lot of demo and test tasks and timers,  and is\r
248         therefore comprehensive, but complex.  If you would prefer a much simpler\r
249         project to get started with, then select the 'Blinky' build configuration\r
250         within the SDK Eclipse IDE.\r
251         ***************************************************************************/\r
252 \r
253         /* Configure the interrupt controller, LED outputs and button inputs. */\r
254         prvSetupHardware();\r
255 \r
256         /* This call creates the TCP/IP thread. */\r
257         tcpip_init( lwIPAppsInit, NULL );\r
258 \r
259         /* Start the reg test tasks, as described in the comments at the top of this\r
260         file. */\r
261         xTaskCreate( vRegisterTest1, "RegTst1", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );\r
262         xTaskCreate( vRegisterTest2, "RegTst2", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );\r
263 \r
264         /* Create the standard demo tasks. */\r
265         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
266         vCreateBlockTimeTasks();\r
267         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
268         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
269         vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );\r
270         vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );\r
271         vStartQueuePeekTasks();\r
272         vStartRecursiveMutexTasks();\r
273         vStartComTestStringsTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
274         vStartDynamicPriorityTasks();\r
275         vStartTimerDemoTask( mainTIMER_TEST_PERIOD );\r
276 \r
277         /* Note - the set of standard demo tasks contains two versions of\r
278         vStartMathTasks.c.  One is defined in flop.c, and uses double precision\r
279         floating point numbers and variables.  The other is defined in sp_flop.c,\r
280         and uses single precision floating point numbers and variables.  The\r
281         MicroBlaze floating point unit only handles single precision floating.\r
282         Therefore, to test the floating point hardware, sp_flop.c should be included\r
283         in this project. */\r
284         vStartMathTasks( mainFLOP_TASK_PRIORITY );\r
285 \r
286         /* The suicide tasks must be created last as they need to know how many\r
287         tasks were running prior to their creation.  This then allows them to\r
288         ascertain whether or not the correct/expected number of tasks are running at\r
289         any given time. */\r
290         vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );\r
291 \r
292         /* Create the 'check' timer - the timer that periodically calls the\r
293         check function as described in the comments at the top of this file.  Note\r
294         that, for reasons stated in the comments within vApplicationIdleHook()\r
295         (defined in this file), the check timer is not actually started until after\r
296         the scheduler has been started. */\r
297         xCheckTimer = xTimerCreate( "Check timer", mainNO_ERROR_CHECK_TIMER_PERIOD, pdTRUE, ( void * ) 0, vCheckTimerCallback );\r
298 \r
299         /* Start the scheduler running.  From this point on, only tasks and\r
300         interrupts will be executing. */\r
301         vTaskStartScheduler();\r
302 \r
303         /* If all is well then the following line will never be reached.  If\r
304         execution does reach here, then it is highly probably that the heap size\r
305         is too small for the idle and/or timer tasks to be created within\r
306         vTaskStartScheduler(). */\r
307         taskDISABLE_INTERRUPTS();\r
308         for( ;; );\r
309 }\r
310 /*-----------------------------------------------------------*/\r
311 \r
312 static void vCheckTimerCallback( TimerHandle_t xTimer )\r
313 {\r
314 extern unsigned long ulRegTest1CycleCount, ulRegTest2CycleCount;\r
315 static volatile unsigned long ulLastRegTest1CycleCount = 0UL, ulLastRegTest2CycleCount = 0UL;\r
316 static long lErrorAlreadyLatched = pdFALSE;\r
317 TickType_t xExecutionRate = mainNO_ERROR_CHECK_TIMER_PERIOD;\r
318 \r
319         /* This is the callback function used by the 'check' timer, as described\r
320         in the comments at the top of this file. */\r
321 \r
322         /* Don't overwrite any errors that have already been latched. */\r
323         if( pcStatusMessage == NULL )\r
324         {\r
325                 /* Check the standard demo tasks are running without error. */\r
326                 if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
327                 {\r
328                         pcStatusMessage = "Error: GenQueue";\r
329                 }\r
330                 else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
331                 {\r
332                         pcStatusMessage = "Error: QueuePeek\r\n";\r
333                 }\r
334                 else if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
335                 {\r
336                         pcStatusMessage = "Error: BlockQueue\r\n";\r
337                 }\r
338                 else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
339                 {\r
340                         pcStatusMessage = "Error: BlockTime\r\n";\r
341                 }\r
342                 else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
343                 {\r
344                         pcStatusMessage = "Error: SemTest\r\n";\r
345                 }\r
346                 else if( xArePollingQueuesStillRunning() != pdTRUE )\r
347                 {\r
348                         pcStatusMessage = "Error: PollQueue\r\n";\r
349                 }\r
350                 else if( xIsCreateTaskStillRunning() != pdTRUE )\r
351                 {\r
352                         pcStatusMessage = "Error: Death\r\n";\r
353                 }\r
354                 else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )\r
355                 {\r
356                         pcStatusMessage = "Error: RecMutex\r\n";\r
357                 }\r
358                 else if( xAreMathsTaskStillRunning() != pdPASS )\r
359                 {\r
360                         pcStatusMessage = "Error: Flop\r\n";\r
361                 }\r
362                 else if( xAreComTestTasksStillRunning() != pdPASS )\r
363                 {\r
364                         pcStatusMessage = "Error: Comtest\r\n";\r
365                 }\r
366                 else if( xAreDynamicPriorityTasksStillRunning() != pdPASS )\r
367                 {\r
368                         pcStatusMessage = "Error: Dynamic\r\n";\r
369                 }\r
370                 else if( xAreTimerDemoTasksStillRunning( xExecutionRate ) != pdTRUE )\r
371                 {\r
372                         pcStatusMessage = "Error: TimerDemo";\r
373                 }\r
374                 else if( ulRegTest1CycleCount == ulLastRegTest1CycleCount )\r
375                 {\r
376                         /* Check the reg test tasks are still cycling.  They will stop\r
377                         incrementing their loop counters if they encounter an error. */\r
378                         pcStatusMessage = "Error: RegTest1\r\n";\r
379                 }\r
380                 else if( ulRegTest2CycleCount == ulLastRegTest2CycleCount )\r
381                 {\r
382                         pcStatusMessage = "Error: RegTest2\r\n";\r
383                 }\r
384         }\r
385 \r
386         /* Store a local copy of the current reg test loop counters.  If these have\r
387         not incremented the next time this callback function is executed then the\r
388         reg test tasks have either stalled or discovered an error. */\r
389         ulLastRegTest1CycleCount = ulRegTest1CycleCount;\r
390         ulLastRegTest2CycleCount = ulRegTest2CycleCount;\r
391 \r
392         /* Toggle the check LED to give an indication of the system status.  If\r
393         the LED toggles every 5 seconds then everything is ok.  A faster toggle\r
394         indicates an error. */\r
395         vParTestToggleLED( mainCHECK_LED );\r
396 \r
397         if( pcStatusMessage != NULL )\r
398         {\r
399                 if( lErrorAlreadyLatched == pdFALSE )\r
400                 {\r
401                         /* An error has occurred, so change the period of the timer that\r
402                         calls this callback function.  This results in the LED toggling at\r
403                         a faster rate - giving the user visual feedback that something is not\r
404                         as it should be.  This function is called from the context of the\r
405                         timer service task so must ***not*** attempt to block while calling\r
406                         this function. */\r
407                         if( xTimerChangePeriod( xTimer, mainERROR_CHECK_TIMER_PERIOD, mainDONT_BLOCK ) == pdPASS )\r
408                         {\r
409                                 /* If the command to change the timer period was sent to the\r
410                                 timer command queue successfully, then latch the fact that the\r
411                                 timer period has already been changed.  This is just done to\r
412                                 prevent xTimerChangePeriod() being called on every execution of\r
413                                 this function once an error has been discovered.  */\r
414                                 lErrorAlreadyLatched = pdTRUE;\r
415                         }\r
416 \r
417                         /* Update the xExecutionRate variable too as the rate at which this\r
418                         callback is executed has to be passed into the\r
419                         xAreTimerDemoTasksStillRunning() function. */\r
420                         xExecutionRate = mainERROR_CHECK_TIMER_PERIOD;\r
421                 }\r
422         }\r
423 }\r
424 /*-----------------------------------------------------------*/\r
425 \r
426 /* This is an application defined callback function used to install the tick\r
427 interrupt handler.  It is provided as an application callback because the kernel\r
428 will run on lots of different MicroBlaze and FPGA configurations - not all of\r
429 which will have the same timer peripherals defined or available.  This example\r
430 uses the AXI Timer 0.  If that is available on your hardware platform then this\r
431 example callback implementation should not require modification.   The name of\r
432 the interrupt handler that should be installed is vPortTickISR(), which the\r
433 function below declares as an extern. */\r
434 void vApplicationSetupTimerInterrupt( void )\r
435 {\r
436 portBASE_TYPE xStatus;\r
437 extern void vPortTickISR( void *pvUnused );\r
438 \r
439         /* Initialise the timer/counter. */\r
440         xStatus = XTmrCtr_Initialize( &xTimer0Instance, XPAR_AXI_TIMER_0_DEVICE_ID );\r
441 \r
442         if( xStatus == XST_SUCCESS )\r
443         {\r
444                 /* Install the tick interrupt handler as the timer ISR.\r
445                 *NOTE* The xPortInstallInterruptHandler() API function must be used for\r
446                 this purpose. */\r
447                 xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_TMRCTR_0_VEC_ID, vPortTickISR, NULL );\r
448         }\r
449 \r
450         if( xStatus == pdPASS )\r
451         {\r
452                 /* Enable the timer interrupt in the interrupt controller.\r
453                 *NOTE* The vPortEnableInterrupt() API function must be used for this\r
454                 purpose. */\r
455                 vPortEnableInterrupt( XPAR_INTC_0_TMRCTR_0_VEC_ID );\r
456 \r
457                 /* Configure the timer interrupt handler. */\r
458                 XTmrCtr_SetHandler( &xTimer0Instance, ( void * ) vPortTickISR, NULL );\r
459 \r
460                 /* Set the correct period for the timer. */\r
461                 XTmrCtr_SetResetValue( &xTimer0Instance, ucTimerCounterNumber, ulCounterReloadValue );\r
462 \r
463                 /* Enable the interrupts.  Auto-reload mode is used to generate a\r
464                 periodic tick.  Note that interrupts are disabled when this function is\r
465                 called, so interrupts will not start to be processed until the first\r
466                 task has started to run. */\r
467                 XTmrCtr_SetOptions( &xTimer0Instance, ucTimerCounterNumber, ( XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION | XTC_DOWN_COUNT_OPTION ) );\r
468 \r
469                 /* Start the timer. */\r
470                 XTmrCtr_Start( &xTimer0Instance, ucTimerCounterNumber );\r
471         }\r
472 \r
473         /* Sanity check that the function executed as expected. */\r
474         configASSERT( ( xStatus == pdPASS ) );\r
475 }\r
476 /*-----------------------------------------------------------*/\r
477 \r
478 /* This is an application defined callback function used to clear whichever\r
479 interrupt was installed by the the vApplicationSetupTimerInterrupt() callback\r
480 function - in this case the interrupt generated by the AXI timer.  It is\r
481 provided as an application callback because the kernel will run on lots of\r
482 different MicroBlaze and FPGA configurations - not all of which will have the\r
483 same timer peripherals defined or available.  This example uses the AXI Timer 0.\r
484 If that is available on your hardware platform then this example callback\r
485 implementation should not require modification provided the example definition\r
486 of vApplicationSetupTimerInterrupt() is also not modified. */\r
487 void vApplicationClearTimerInterrupt( void )\r
488 {\r
489 unsigned long ulCSR;\r
490 \r
491         /* Clear the timer interrupt */\r
492         ulCSR = XTmrCtr_GetControlStatusReg( XPAR_AXI_TIMER_0_BASEADDR, 0 );\r
493         XTmrCtr_SetControlStatusReg( XPAR_AXI_TIMER_0_BASEADDR, 0, ulCSR );\r
494 }\r
495 /*-----------------------------------------------------------*/\r
496 \r
497 void vApplicationMallocFailedHook( void )\r
498 {\r
499         /* vApplicationMallocFailedHook() will only be called if\r
500         configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook\r
501         function that will get called if a call to pvPortMalloc() fails.\r
502         pvPortMalloc() is called internally by the kernel whenever a task, queue or\r
503         semaphore is created.  It is also called by various parts of the demo\r
504         application.  If heap_1.c or heap_2.c are used, then the size of the heap\r
505         available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in\r
506         FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used\r
507         to query the size of free heap space that remains (although it does not\r
508         provide information on how the remaining heap might be fragmented). */\r
509         taskDISABLE_INTERRUPTS();\r
510         for( ;; );\r
511 }\r
512 /*-----------------------------------------------------------*/\r
513 \r
514 void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )\r
515 {\r
516         ( void ) pcTaskName;\r
517         ( void ) pxTask;\r
518 \r
519         /* vApplicationStackOverflowHook() will only be called if\r
520         configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2.  The handle and name\r
521         of the offending task will be passed into the hook function via its\r
522         parameters.  However, when a stack has overflowed, it is possible that the\r
523         parameters will have been corrupted, in which case the pxCurrentTCB variable\r
524         can be inspected directly. */\r
525         taskDISABLE_INTERRUPTS();\r
526         for( ;; );\r
527 }\r
528 /*-----------------------------------------------------------*/\r
529 \r
530 void vApplicationIdleHook( void )\r
531 {\r
532 static long lCheckTimerStarted = pdFALSE;\r
533 \r
534         /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set\r
535         to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle\r
536         task.  It is essential that code added to this hook function never attempts\r
537         to block in any way (for example, call xQueueReceive() with a block time\r
538         specified, or call vTaskDelay()).  If the application makes use of the\r
539         vTaskDelete() API function (as this demo application does) then it is also\r
540         important that vApplicationIdleHook() is permitted to return to its calling\r
541         function, because it is the responsibility of the idle task to clean up\r
542         memory allocated by the kernel to any task that has since been deleted. */\r
543 \r
544         /* If the check timer has not already been started, then start it now.\r
545         Normally, the xTimerStart() API function can be called immediately after the\r
546         timer is created - how this demo application includes the timer demo tasks.\r
547         The timer demo tasks, as part of their test function, deliberately fill up\r
548         the timer command queue - meaning the check timer cannot be started until\r
549         after the scheduler has been started - at which point the timer command\r
550         queue will have been drained. */\r
551         if( lCheckTimerStarted == pdFALSE )\r
552         {\r
553                 xTimerStart( xCheckTimer, mainDONT_BLOCK );\r
554                 lCheckTimerStarted = pdTRUE;\r
555         }\r
556 }\r
557 /*-----------------------------------------------------------*/\r
558 \r
559 void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )\r
560 {\r
561         ( void ) xRegisterDump;\r
562 \r
563         /* If configINSTALL_EXCEPTION_HANDLERS is set to 1 in FreeRTOSConfig.h, then\r
564         the kernel will automatically install its own exception handlers before the\r
565         kernel is started, if the application writer has not already caused them to\r
566         be installed by calling either of the vPortExceptionsInstallHandlers()\r
567         or xPortInstallInterruptHandler() API functions before that time.  The\r
568         kernels exception handler populates an xPortRegisterDump structure with\r
569         the processor state at the point that the exception was triggered - and also\r
570         includes a strings that say what the exception cause was and which task was\r
571         running at the time.  The exception handler then passes the populated\r
572         xPortRegisterDump structure into vApplicationExceptionRegisterDump() to\r
573         allow the application writer to perform any debugging that may be necessary.\r
574         However, defining vApplicationExceptionRegisterDump() within the application\r
575         itself is optional.  The kernel will use a default implementation if the\r
576         application writer chooses not to provide their own. */\r
577         for( ;; )\r
578         {\r
579                 portNOP();\r
580         }\r
581 }\r
582 /*-----------------------------------------------------------*/\r
583 \r
584 static void prvSetupHardware( void )\r
585 {\r
586         taskDISABLE_INTERRUPTS();\r
587 \r
588         /* Configure the LED outputs. */\r
589         vParTestInitialise();\r
590 \r
591         /* Tasks inherit the exception and cache configuration of the MicroBlaze\r
592         at the point that they are created. */\r
593         #if MICROBLAZE_EXCEPTIONS_ENABLED == 1\r
594                 microblaze_enable_exceptions();\r
595         #endif\r
596 \r
597         #if XPAR_MICROBLAZE_USE_ICACHE == 1\r
598                 microblaze_invalidate_icache();\r
599                 microblaze_enable_icache();\r
600         #endif\r
601 \r
602         #if XPAR_MICROBLAZE_USE_DCACHE == 1\r
603                 microblaze_invalidate_dcache();\r
604                 microblaze_enable_dcache();\r
605         #endif\r
606 \r
607 }\r
608 /*-----------------------------------------------------------*/\r
609 \r
610 void vMainConfigureTimerForRunTimeStats( void )\r
611 {\r
612         /* How many times does the counter counter increment in 10ms? */\r
613         ulClocksPer10thOfAMilliSecond = XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / 10000UL;\r
614 }\r
615 /*-----------------------------------------------------------*/\r
616 \r
617 unsigned long ulMainGetRunTimeCounterValue( void )\r
618 {\r
619 unsigned long ulTimerCounts1, ulTimerCounts2, ulTickCount, ulReturn;\r
620 \r
621         /* NOTE: This can get called from a yield, in which case interrupts are\r
622         disabled, or from a tick ISR, in which case the effect is the same as if\r
623         interrupts were disabled.  In either case, it is going to run atomically. */\r
624 \r
625         /* The timer is in down count mode.  How many clocks have passed since it\r
626         was last reloaded? */\r
627         ulTimerCounts1 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );\r
628 \r
629         /* How many times has it overflowed? */\r
630         ulTickCount = xTaskGetTickCountFromISR();\r
631 \r
632         /* If this is being called from a yield, has the counter overflowed since\r
633         it was read?  If that is the case then ulTickCounts will need incrementing\r
634         again as it will not yet have been incremented from the tick interrupt. */\r
635         ulTimerCounts2 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );\r
636         if( ulTimerCounts2 < ulTimerCounts1 )\r
637         {\r
638                 /* There is a tick interrupt pending but the tick count not yet\r
639                 incremented. */\r
640                 ulTickCount++;\r
641 \r
642                 /* Use the second timer reading. */\r
643                 ulTimerCounts1 = ulTimerCounts2;\r
644         }\r
645 \r
646         /* Convert the tick count into tenths of a millisecond.  THIS ASSUMES\r
647         configTICK_RATE_HZ is 1000! */\r
648         ulReturn = ( ulTickCount * 10UL );\r
649 \r
650         /* Add on the number of tenths of a millisecond that have passed since the\r
651         tick count last got updated. */\r
652         ulReturn += ( ulTimerCounts1 / ulClocksPer10thOfAMilliSecond );\r
653 \r
654         /* Some crude rounding. */\r
655         if( ( ulTimerCounts1 % ulClocksPer10thOfAMilliSecond ) > ( ulClocksPer10thOfAMilliSecond >> 1UL ) )\r
656         {\r
657                 ulReturn++;\r
658         }\r
659 \r
660         return ulReturn;\r
661 }\r
662 /*-----------------------------------------------------------*/\r
663 \r
664 char *pcMainGetTaskStatusMessage( void )\r
665 {\r
666 char * pcReturn;\r
667 \r
668         if( pcStatusMessage == NULL )\r
669         {\r
670                 pcReturn = ( char * ) "OK";\r
671         }\r
672         else\r
673         {\r
674                 pcReturn = ( char * ) pcStatusMessage;\r
675         }\r
676 \r
677         return pcReturn;\r
678 }\r
679 \r
680 \r
681 \r