summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemo/main-full.c
blob: 70d5444441456eeae6a3b0d509d2bcf46abf032e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
/*
    FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that has become a de facto standard.             *
     *                                                                       *
     *    Help yourself get started quickly and support the FreeRTOS         *
     *    project by purchasing a FreeRTOS tutorial book, reference          *
     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
     *                                                                       *
     *    Thank you!                                                         *
     *                                                                       *
    ***************************************************************************

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.

    >>! NOTE: The modification to the GPL is included to allow you to distribute
    >>! a combined work that includes FreeRTOS without being obliged to provide
    >>! the source code for proprietary components outside of the FreeRTOS
    >>! kernel.

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available from the following
    link: http://www.freertos.org/a00114.html

    1 tab == 4 spaces!

    ***************************************************************************
     *                                                                       *
     *    Having a problem?  Start by reading the FAQ "My application does   *
     *    not run, what could be wrong?"                                     *
     *                                                                       *
     *    http://www.FreeRTOS.org/FAQHelp.html                               *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org - Documentation, books, training, latest versions,
    license and Real Time Engineers Ltd. contact details.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
*/

/* ****************************************************************************
 * main-blinky.c is included when the "Blinky" build configuration is used.
 * main-full.c is included when the "Full" build configuration is used.
 *
 * main-full.c creates a lot of demo and test tasks and timers,  and is
 * therefore very comprehensive but also complex.  If you would prefer a much
 * simpler project to get started with, then select the 'Blinky' build
 * configuration within the SDK Eclipse IDE.  See the documentation page for
 * this demo on the http://www.FreeRTOS.org web site for more information.
 * ****************************************************************************
 *
 * main() creates all the demo application tasks and timers, then starts the
 * scheduler.  The web documentation provides more details of the standard demo
 * application tasks, which provide no particular functionality, but do provide
 * a good example of how to use the FreeRTOS API.
 *
 * In addition to the standard demo tasks, the following tasks and tests are
 * defined and/or created within this file:
 *
 * TCP/IP ("lwIP") task - lwIP is used to create a basic web server.  The web
 * server uses server side includes (SSI) to generate tables of task statistics,
 * and run time statistics (run time statistics show how much processing time
 * each task has consumed).  See
 * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html
 * for details on setting up and using the embedded web server.
 *
 * "Reg test" tasks - These test the task context switch mechanism by first
 * filling the MicroBlaze registers with known values, before checking that each
 * register maintains the value that was written to it as the tasks are switched
 * in and out.  The two register test tasks do not use the same values, and
 * execute at a very low priority, to ensure they are pre-empted regularly.
 *
 * "Check" timer - The check timer period is initially set to five seconds.
 * The check timer callback function checks that all the standard demo tasks,
 * and the register check tasks, are not only still executing, but are executing
 * without reporting any errors.  If the check timer discovers that a task has
 * either stalled, or reported an error, then it changes its own period from
 * the initial five seconds, to just 200ms.  The check timer callback function
 * also toggles an LED each time it is called.  This provides a visual
 * indication of the system status:  If the LED toggles every five seconds then
 * no issues have been discovered.  If the LED toggles every 200ms then an issue
 * has been discovered with at least one task.  The last reported issue is
 * latched into the pcStatusMessage variable, and can also be viewed at the
 * bottom of the pages served by the embedded web server.
 *
 * ***NOTE*** This demo uses the standard comtest tasks, which has special
 * hardware requirements.  See
 * http://www.FreeRTOS.org/Free-RTOS-for-Xilinx-MicroBlaze-on-Spartan-6-FPGA.html
 * for more information.
 *
 * This file also includes example implementations of the
 * vApplicationIdleHook(), vApplicationStackOverflowHook(),
 * vApplicationMallocFailedHook(), vApplicationClearTimerInterrupt(), and
 * vApplicationSetupTimerInterrupt() callback (hook) functions.
 */

/* Standard includes. */
#include <string.h>
#include <stdio.h>

/* BSP includes. */
#include "xtmrctr.h"
#include "microblaze_exceptions_g.h"

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

/* Standard demo includes. */
#include "partest.h"
#include "flash.h"
#include "BlockQ.h"
#include "death.h"
#include "blocktim.h"
#include "semtest.h"
#include "PollQ.h"
#include "GenQTest.h"
#include "QPeek.h"
#include "recmutex.h"
#include "flop.h"
#include "dynamic.h"
#include "comtest_strings.h"
#include "TimerDemo.h"

/* lwIP includes. */
#include "lwip/tcpip.h"


/* Priorities at which the various tasks are created. */
#define mainQUEUE_POLL_PRIORITY		( tskIDLE_PRIORITY + 1 )
#define mainSEM_TEST_PRIORITY		( tskIDLE_PRIORITY + 2 )
#define mainBLOCK_Q_PRIORITY		( tskIDLE_PRIORITY + 1 )
#define mainCREATOR_TASK_PRIORITY   ( tskIDLE_PRIORITY + 3 )
#define mainFLASH_TASK_PRIORITY		( tskIDLE_PRIORITY + 1 )
#define mainCOM_TEST_PRIORITY		( tskIDLE_PRIORITY + 2 )
#define mainINTEGER_TASK_PRIORITY   ( tskIDLE_PRIORITY )
#define mainGEN_QUEUE_TASK_PRIORITY	( tskIDLE_PRIORITY )
#define mainFLOP_TASK_PRIORITY		( tskIDLE_PRIORITY )

/* The LED toggled by the check task. */
#define mainCHECK_LED				( 3 )

/* The rate at which mainCHECK_LED will toggle when all the tasks are running
without error.  See the description of the check timer in the comments at the
top of this file. */
#define mainNO_ERROR_CHECK_TIMER_PERIOD		( 5000 / portTICK_PERIOD_MS )

/* The rate at which mainCHECK_LED will toggle when an error has been reported
by at least one task.  See the description of the check timer in the comments at
the top of this file. */
#define mainERROR_CHECK_TIMER_PERIOD		( 200 / portTICK_PERIOD_MS )

/* A block time of zero simply means "don't block". */
#define mainDONT_BLOCK						( ( TickType_t ) 0 )

/* The LED used by the comtest tasks. See the comtest_strings.c file for more
information.  In this case an invalid LED number is provided as all four
available LEDs (LEDs 0 to 3) are already in use. */
#define mainCOM_TEST_LED			( 4 )

/* Baud rate used by the comtest tasks.  The baud rate used is actually fixed in
UARTLite IP when the hardware was built, but the standard serial init function
required a baud rate parameter to be provided - in this case it is just
ignored. */
#define mainCOM_TEST_BAUD_RATE				( XPAR_RS232_UART_1_BAUDRATE )

/* The timer test task generates a lot of timers that all use a different
period that is a multiple of the mainTIMER_TEST_PERIOD definition. */
#define mainTIMER_TEST_PERIOD			( 20 )

/*-----------------------------------------------------------*/

/*
 * The register test tasks as described in the comments at the top of this file.
 * The nature of the register test tasks means they have to be implemented in
 * assembler.
 */
extern void vRegisterTest1( void *pvParameters );
extern void vRegisterTest2( void *pvParameters );

/*
 * Defines the 'check' timer functionality as described at the top of this file.
 * This function is the callback function associated with the 'check' timer.
 */
static void vCheckTimerCallback( TimerHandle_t xTimer );

/*
 * Configure the interrupt controller, LED outputs and button inputs.
 */
static void prvSetupHardware( void );

/* Defined in lwIPApps.c. */
extern void lwIPAppsInit( void *pvArguments );

/*-----------------------------------------------------------*/

/* The check timer callback function sets pcStatusMessage to a string that
indicates the last reported error that it discovered. */
static const char *pcStatusMessage = NULL;

/* Structures that hold the state of the various peripherals used by this demo.
These are used by the Xilinx peripheral driver API functions.  In this case,
only the timer/counter is used directly within this file. */
static XTmrCtr xTimer0Instance;

/* The 'check' timer, as described at the top of this file. */
static TimerHandle_t xCheckTimer = NULL;

/* Used in the run time stats calculations. */
static unsigned long ulClocksPer10thOfAMilliSecond = 0UL;

/* Constants used to set up the AXI timer to generate ticks. */
static const unsigned char ucTimerCounterNumber = ( unsigned char ) 0U;
static const unsigned long ulCounterReloadValue = ( ( XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / configTICK_RATE_HZ ) - 1UL );

/*-----------------------------------------------------------*/

int main( void )
{
	/***************************************************************************
	This project includes a lot of demo and test tasks and timers,  and is
	therefore comprehensive, but complex.  If you would prefer a much simpler
	project to get started with, then select the 'Blinky' build configuration
	within the SDK Eclipse IDE.
	***************************************************************************/

	/* Configure the interrupt controller, LED outputs and button inputs. */
	prvSetupHardware();

	/* This call creates the TCP/IP thread. */
	tcpip_init( lwIPAppsInit, NULL );

	/* Start the reg test tasks, as described in the comments at the top of this
	file. */
	xTaskCreate( vRegisterTest1, "RegTst1", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );
	xTaskCreate( vRegisterTest2, "RegTst2", configMINIMAL_STACK_SIZE, ( void * ) 0, tskIDLE_PRIORITY, NULL );

	/* Create the standard demo tasks. */
	vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
	vCreateBlockTimeTasks();
	vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
	vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
	vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );
	vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );
	vStartQueuePeekTasks();
	vStartRecursiveMutexTasks();
	vStartComTestStringsTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );
	vStartDynamicPriorityTasks();
	vStartTimerDemoTask( mainTIMER_TEST_PERIOD );

	/* Note - the set of standard demo tasks contains two versions of
	vStartMathTasks.c.  One is defined in flop.c, and uses double precision
	floating point numbers and variables.  The other is defined in sp_flop.c,
	and uses single precision floating point numbers and variables.  The
	MicroBlaze floating point unit only handles single precision floating.
	Therefore, to test the floating point hardware, sp_flop.c should be included
	in this project. */
	vStartMathTasks( mainFLOP_TASK_PRIORITY );

	/* The suicide tasks must be created last as they need to know how many
	tasks were running prior to their creation.  This then allows them to
	ascertain whether or not the correct/expected number of tasks are running at
	any given time. */
	vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );

	/* Create the 'check' timer - the timer that periodically calls the
	check function as described in the comments at the top of this file.  Note
	that, for reasons stated in the comments within vApplicationIdleHook()
	(defined in this file), the check timer is not actually started	until after
	the scheduler has been started. */
	xCheckTimer = xTimerCreate( "Check timer", mainNO_ERROR_CHECK_TIMER_PERIOD, pdTRUE, ( void * ) 0, vCheckTimerCallback );

	/* Start the scheduler running.  From this point on, only tasks and
	interrupts will be executing. */
	vTaskStartScheduler();

	/* If all is well then the following line will never be reached.  If
	execution does reach here, then it is highly probably that the heap size
	is too small for the idle and/or timer tasks to be created within
	vTaskStartScheduler(). */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

static void vCheckTimerCallback( TimerHandle_t xTimer )
{
extern unsigned long ulRegTest1CycleCount, ulRegTest2CycleCount;
static volatile unsigned long ulLastRegTest1CycleCount = 0UL, ulLastRegTest2CycleCount = 0UL;
static long lErrorAlreadyLatched = pdFALSE;
TickType_t xExecutionRate = mainNO_ERROR_CHECK_TIMER_PERIOD;

	/* This is the callback function used by the 'check' timer, as described
	in the comments at the top of this file. */

	/* Don't overwrite any errors that have already been latched. */
	if( pcStatusMessage == NULL )
	{
		/* Check the standard demo tasks are running without error. */
		if( xAreGenericQueueTasksStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: GenQueue";
		}
		else if( xAreQueuePeekTasksStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: QueuePeek\r\n";
		}
		else if( xAreBlockingQueuesStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: BlockQueue\r\n";
		}
		else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: BlockTime\r\n";
		}
		else if( xAreSemaphoreTasksStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: SemTest\r\n";
		}
		else if( xArePollingQueuesStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: PollQueue\r\n";
		}
		else if( xIsCreateTaskStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: Death\r\n";
		}
		else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
		{
			pcStatusMessage = "Error: RecMutex\r\n";
		}
		else if( xAreMathsTaskStillRunning() != pdPASS )
		{
			pcStatusMessage = "Error: Flop\r\n";
		}
		else if( xAreComTestTasksStillRunning() != pdPASS )
		{
			pcStatusMessage = "Error: Comtest\r\n";
		}
		else if( xAreDynamicPriorityTasksStillRunning() != pdPASS )
		{
			pcStatusMessage = "Error: Dynamic\r\n";
		}
		else if( xAreTimerDemoTasksStillRunning( xExecutionRate ) != pdTRUE )
		{
			pcStatusMessage = "Error: TimerDemo";
		}
		else if( ulRegTest1CycleCount == ulLastRegTest1CycleCount )
		{
			/* Check the reg test tasks are still cycling.  They will stop
			incrementing their loop counters if they encounter an error. */
			pcStatusMessage = "Error: RegTest1\r\n";
		}
		else if( ulRegTest2CycleCount == ulLastRegTest2CycleCount )
		{
			pcStatusMessage = "Error: RegTest2\r\n";
		}
	}

	/* Store a local copy of the current reg test loop counters.  If these have
	not incremented the next time this callback function is executed then the
	reg test tasks have either stalled or discovered an error. */
	ulLastRegTest1CycleCount = ulRegTest1CycleCount;
	ulLastRegTest2CycleCount = ulRegTest2CycleCount;

	/* Toggle the check LED to give an indication of the system status.  If
	the LED toggles every 5 seconds then everything is ok.  A faster toggle
	indicates an error. */
	vParTestToggleLED( mainCHECK_LED );

	if( pcStatusMessage != NULL )
	{
		if( lErrorAlreadyLatched == pdFALSE )
		{
			/* An error has occurred, so change the period of the timer that
			calls this callback function.  This results in the LED toggling at
			a faster rate - giving the user visual feedback that something is not
			as it should be.  This function is called from the context of the
			timer service task so must ***not*** attempt to block while calling
			this function. */
			if( xTimerChangePeriod( xTimer, mainERROR_CHECK_TIMER_PERIOD, mainDONT_BLOCK ) == pdPASS )
			{
				/* If the command to change the timer period was sent to the
				timer command queue successfully, then latch the fact that the
				timer period has already been changed.  This is just done to
				prevent xTimerChangePeriod() being called on every execution of
				this function once an error has been discovered.  */
				lErrorAlreadyLatched = pdTRUE;
			}

			/* Update the xExecutionRate variable too as the rate at which this
			callback is executed has to be passed into the
			xAreTimerDemoTasksStillRunning() function. */
			xExecutionRate = mainERROR_CHECK_TIMER_PERIOD;
		}
	}
}
/*-----------------------------------------------------------*/

/* This is an application defined callback function used to install the tick
interrupt handler.  It is provided as an application callback because the kernel
will run on lots of different MicroBlaze and FPGA configurations - not all of
which will have the same timer peripherals defined or available.  This example
uses the AXI Timer 0.  If that is available on your hardware platform then this
example callback implementation should not require modification.   The name of
the interrupt handler that should be installed is vPortTickISR(), which the
function below declares as an extern. */
void vApplicationSetupTimerInterrupt( void )
{
portBASE_TYPE xStatus;
extern void vPortTickISR( void *pvUnused );

	/* Initialise the timer/counter. */
	xStatus = XTmrCtr_Initialize( &xTimer0Instance, XPAR_AXI_TIMER_0_DEVICE_ID );

	if( xStatus == XST_SUCCESS )
	{
		/* Install the tick interrupt handler as the timer ISR.
		*NOTE* The xPortInstallInterruptHandler() API function must be used for
		this purpose. */
		xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_TMRCTR_0_VEC_ID, vPortTickISR, NULL );
	}

	if( xStatus == pdPASS )
	{
		/* Enable the timer interrupt in the interrupt controller.
		*NOTE* The vPortEnableInterrupt() API function must be used for this
		purpose. */
		vPortEnableInterrupt( XPAR_INTC_0_TMRCTR_0_VEC_ID );

		/* Configure the timer interrupt handler. */
		XTmrCtr_SetHandler( &xTimer0Instance, ( void * ) vPortTickISR, NULL );

		/* Set the correct period for the timer. */
		XTmrCtr_SetResetValue( &xTimer0Instance, ucTimerCounterNumber, ulCounterReloadValue );

		/* Enable the interrupts.  Auto-reload mode is used to generate a
		periodic tick.  Note that interrupts are disabled when this function is
		called, so interrupts will not start to be processed until the first
		task has started to run. */
		XTmrCtr_SetOptions( &xTimer0Instance, ucTimerCounterNumber, ( XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION | XTC_DOWN_COUNT_OPTION ) );

		/* Start the timer. */
		XTmrCtr_Start( &xTimer0Instance, ucTimerCounterNumber );
	}

	/* Sanity check that the function executed as expected. */
	configASSERT( ( xStatus == pdPASS ) );
}
/*-----------------------------------------------------------*/

/* This is an application defined callback function used to clear whichever
interrupt was installed by the the vApplicationSetupTimerInterrupt() callback
function - in this case the interrupt generated by the AXI timer.  It is
provided as an application callback because the kernel will run on lots of
different MicroBlaze and FPGA configurations - not all of which will have the
same timer peripherals defined or available.  This example uses the AXI Timer 0.
If that is available on your hardware platform then this example callback
implementation should not require modification provided the example definition
of vApplicationSetupTimerInterrupt() is also not modified. */
void vApplicationClearTimerInterrupt( void )
{
unsigned long ulCSR;

	/* Clear the timer interrupt */
	ulCSR = XTmrCtr_GetControlStatusReg( XPAR_AXI_TIMER_0_BASEADDR, 0 );
	XTmrCtr_SetControlStatusReg( XPAR_AXI_TIMER_0_BASEADDR, 0, ulCSR );
}
/*-----------------------------------------------------------*/

void vApplicationMallocFailedHook( void )
{
	/* vApplicationMallocFailedHook() will only be called if
	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
	function that will get called if a call to pvPortMalloc() fails.
	pvPortMalloc() is called internally by the kernel whenever a task, queue or
	semaphore is created.  It is also called by various parts of the demo
	application.  If heap_1.c or heap_2.c are used, then the size of the heap
	available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
	FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
	to query the size of free heap space that remains (although it does not
	provide information on how the remaining heap might be fragmented). */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
	( void ) pcTaskName;
	( void ) pxTask;

	/* vApplicationStackOverflowHook() will only be called if
	configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2.  The handle and name
	of the offending task will be passed into the hook function via its
	parameters.  However, when a stack has overflowed, it is possible that the
	parameters will have been corrupted, in which case the pxCurrentTCB variable
	can be inspected directly. */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

void vApplicationIdleHook( void )
{
static long lCheckTimerStarted = pdFALSE;

	/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
	to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
	task.  It is essential that code added to this hook function never attempts
	to block in any way (for example, call xQueueReceive() with a block time
	specified, or call vTaskDelay()).  If the application makes use of the
	vTaskDelete() API function (as this demo application does) then it is also
	important that vApplicationIdleHook() is permitted to return to its calling
	function, because it is the responsibility of the idle task to clean up
	memory allocated by the kernel to any task that has since been deleted. */

	/* If the check timer has not already been started, then start it now.
	Normally, the xTimerStart() API function can be called immediately after the
	timer is created - how this demo application includes the timer demo tasks.
	The timer demo tasks, as part of their test function, deliberately fill up
	the timer command queue - meaning the check timer cannot be started until
	after the scheduler has been started - at which point the timer command
	queue will have been drained. */
	if( lCheckTimerStarted == pdFALSE )
	{
		xTimerStart( xCheckTimer, mainDONT_BLOCK );
		lCheckTimerStarted = pdTRUE;
	}
}
/*-----------------------------------------------------------*/

void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )
{
	( void ) xRegisterDump;

	/* If configINSTALL_EXCEPTION_HANDLERS is set to 1 in FreeRTOSConfig.h, then
	the kernel will	automatically install its own exception handlers before the
	kernel is started, if the application writer has not already caused them to
	be installed by calling either of the vPortExceptionsInstallHandlers()
	or xPortInstallInterruptHandler() API functions before that time.  The
	kernels exception handler populates an xPortRegisterDump structure with
	the processor state at the point that the exception was triggered - and also
	includes a strings that say what the exception cause was and which task was
	running at the time.  The exception handler then passes the populated
	xPortRegisterDump structure into vApplicationExceptionRegisterDump() to
	allow the application writer to perform any debugging that may be necessary.
	However, defining vApplicationExceptionRegisterDump() within the application
	itself is optional.  The kernel will use a default implementation if the
	application writer chooses not to provide their own. */
	for( ;; )
	{
		portNOP();
	}
}
/*-----------------------------------------------------------*/

static void prvSetupHardware( void )
{
	taskDISABLE_INTERRUPTS();

	/* Configure the LED outputs. */
	vParTestInitialise();

	/* Tasks inherit the exception and cache configuration of the MicroBlaze
	at the point that they are created. */
	#if MICROBLAZE_EXCEPTIONS_ENABLED == 1
		microblaze_enable_exceptions();
	#endif

	#if XPAR_MICROBLAZE_USE_ICACHE == 1
		microblaze_invalidate_icache();
		microblaze_enable_icache();
	#endif

	#if XPAR_MICROBLAZE_USE_DCACHE == 1
		microblaze_invalidate_dcache();
		microblaze_enable_dcache();
	#endif

}
/*-----------------------------------------------------------*/

void vMainConfigureTimerForRunTimeStats( void )
{
	/* How many times does the counter counter increment in 10ms? */
	ulClocksPer10thOfAMilliSecond = XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ / 10000UL;
}
/*-----------------------------------------------------------*/

unsigned long ulMainGetRunTimeCounterValue( void )
{
unsigned long ulTimerCounts1, ulTimerCounts2, ulTickCount, ulReturn;

	/* NOTE: This can get called from a yield, in which case interrupts are
	disabled, or from a tick ISR, in which case the effect is the same as if
	interrupts were disabled.  In either case, it is going to run atomically. */

	/* The timer is in down count mode.  How many clocks have passed since it
	was last reloaded? */
	ulTimerCounts1 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );

	/* How many times has it overflowed? */
	ulTickCount = xTaskGetTickCountFromISR();

	/* If this is being called from a yield, has the counter overflowed since
	it was read?  If that is the case then ulTickCounts will need incrementing
	again as it will not yet have been incremented from the tick interrupt. */
	ulTimerCounts2 = ulCounterReloadValue - XTmrCtr_GetValue( &xTimer0Instance, ucTimerCounterNumber );
	if( ulTimerCounts2 < ulTimerCounts1 )
	{
		/* There is a tick interrupt pending but the tick count not yet
		incremented. */
		ulTickCount++;

		/* Use the second timer reading. */
		ulTimerCounts1 = ulTimerCounts2;
	}

	/* Convert the tick count into tenths of a millisecond.  THIS ASSUMES
	configTICK_RATE_HZ is 1000! */
	ulReturn = ( ulTickCount * 10UL );

	/* Add on the number of tenths of a millisecond that have passed since the
	tick count last got updated. */
	ulReturn += ( ulTimerCounts1 / ulClocksPer10thOfAMilliSecond );

	/* Some crude rounding. */
	if( ( ulTimerCounts1 % ulClocksPer10thOfAMilliSecond ) > ( ulClocksPer10thOfAMilliSecond >> 1UL ) )
	{
		ulReturn++;
	}

	return ulReturn;
}
/*-----------------------------------------------------------*/

char *pcMainGetTaskStatusMessage( void )
{
char * pcReturn;

	if( pcStatusMessage == NULL )
	{
		pcReturn = ( char * ) "OK";
	}
	else
	{
		pcReturn = ( char * ) pcStatusMessage;
	}

	return pcReturn;
}