2 FreeRTOS.org V5.4.0 - Copyright (C) 2003-2009 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify it
\r
7 under the terms of the GNU General Public License (version 2) as published
\r
8 by the Free Software Foundation and modified by the FreeRTOS exception.
\r
9 **NOTE** The exception to the GPL is included to allow you to distribute a
\r
10 combined work that includes FreeRTOS.org without being obliged to provide
\r
11 the source code for any proprietary components. Alternative commercial
\r
12 license and support terms are also available upon request. See the
\r
13 licensing section of http://www.FreeRTOS.org for full details.
\r
15 FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT
\r
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
20 You should have received a copy of the GNU General Public License along
\r
21 with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59
\r
22 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\r
25 ***************************************************************************
\r
27 * Get the FreeRTOS eBook! See http://www.FreeRTOS.org/Documentation *
\r
29 * This is a concise, step by step, 'hands on' guide that describes both *
\r
30 * general multitasking concepts and FreeRTOS specifics. It presents and *
\r
31 * explains numerous examples that are written using the FreeRTOS API. *
\r
32 * Full source code for all the examples is provided in an accompanying *
\r
35 ***************************************************************************
\r
39 Please ensure to read the configuration and relevant port sections of the
\r
40 online documentation.
\r
42 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
45 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
48 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
49 licensing and training services.
\r
53 * Creates eight tasks, each of which loops continuously performing a
\r
54 * floating point calculation.
\r
56 * All the tasks run at the idle priority and never block or yield. This causes
\r
57 * all eight tasks to time slice with the idle task. Running at the idle priority
\r
58 * means that these tasks will get pre-empted any time another task is ready to run
\r
59 * or a time slice occurs. More often than not the pre-emption will occur mid
\r
60 * calculation, creating a good test of the schedulers context switch mechanism - a
\r
61 * calculation producing an unexpected result could be a symptom of a corruption in
\r
62 * the context of a task.
\r
64 * This file demonstrates the use of the task tag and traceTASK_SWITCHED_IN and
\r
65 * traceTASK_SWITCHED_OUT macros to save and restore the floating point context.
\r
71 /* Scheduler include files. */
\r
72 #include "FreeRTOS.h"
\r
75 /* Demo program include files. */
\r
78 /* Misc. definitions. */
\r
79 #define mathSTACK_SIZE configMINIMAL_STACK_SIZE
\r
80 #define mathNUMBER_OF_TASKS ( 8 )
\r
82 /* Four tasks, each of which performs a different floating point calculation.
\r
83 Each of the four is created twice. */
\r
84 static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
\r
85 static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
\r
86 static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
\r
87 static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
\r
89 /* These variables are used to check that all the tasks are still running. If a
\r
90 task gets a calculation wrong it will stop incrementing its check variable. */
\r
91 static volatile unsigned portSHORT usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
\r
93 /* Buffers into which the flop registers will be saved. There is a buffer for
\r
94 each task created within this file. Zeroing out this array is the normal and
\r
95 safe option as this will cause the task to start with all zeros in its flop
\r
97 static unsigned portLONG ulFlopRegisters[ mathNUMBER_OF_TASKS ][ portNO_FLOP_REGISTERS_TO_SAVE ];
\r
99 /*-----------------------------------------------------------*/
\r
101 void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
\r
103 xTaskHandle xTaskJustCreated;
\r
104 portBASE_TYPE x, y;
\r
106 /* Place known values into the buffers into which the flop registers are
\r
107 to be saved. This is for debug purposes only, it is not normally
\r
108 required. The last position in each array is left at zero as the status
\r
109 register will be loaded from there.
\r
111 It is intended that these values can be viewed being loaded into the
\r
112 flop registers when a task is started - however the Insight debugger
\r
113 does not seem to want to show the flop register values. */
\r
114 for( x = 0; x < mathNUMBER_OF_TASKS; x++ )
\r
116 for( y = 0; y < ( portNO_FLOP_REGISTERS_TO_SAVE - 1 ); y++ )
\r
118 ulFlopRegisters[ x ][ y ] = ( x + 1 );
\r
122 /* Create the first task - passing it the address of the check variable
\r
123 that it is going to increment. This check variable is used as an
\r
124 indication that the task is still running. */
\r
125 xTaskCreate( vCompetingMathTask1, ( signed portCHAR * ) "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, &xTaskJustCreated );
\r
127 /* The task tag value is a value that can be associated with a task, but
\r
128 is not used by the scheduler itself. Its use is down to the application so
\r
129 it makes a convenient place in this case to store the pointer to the buffer
\r
130 into which the flop context of the task will be stored. The first created
\r
131 task uses ulFlopRegisters[ 0 ], the second ulFlopRegisters[ 1 ], etc. */
\r
132 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 0 ][ 0 ] ) );
\r
134 /* Create another 7 tasks, allocating a buffer for each. */
\r
135 xTaskCreate( vCompetingMathTask2, ( signed portCHAR * ) "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, &xTaskJustCreated );
\r
136 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 1 ][ 0 ] ) );
\r
138 xTaskCreate( vCompetingMathTask3, ( signed portCHAR * ) "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, &xTaskJustCreated );
\r
139 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 2 ][ 0 ] ) );
\r
141 xTaskCreate( vCompetingMathTask4, ( signed portCHAR * ) "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, &xTaskJustCreated );
\r
142 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 3 ][ 0 ] ) );
\r
144 xTaskCreate( vCompetingMathTask1, ( signed portCHAR * ) "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, &xTaskJustCreated );
\r
145 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 4 ][ 0 ] ) );
\r
147 xTaskCreate( vCompetingMathTask2, ( signed portCHAR * ) "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, &xTaskJustCreated );
\r
148 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 5 ][ 0 ] ) );
\r
150 xTaskCreate( vCompetingMathTask3, ( signed portCHAR * ) "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, &xTaskJustCreated );
\r
151 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 6 ][ 0 ] ) );
\r
153 xTaskCreate( vCompetingMathTask4, ( signed portCHAR * ) "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, &xTaskJustCreated );
\r
154 vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 7 ][ 0 ] ) );
\r
156 /*-----------------------------------------------------------*/
\r
158 static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
\r
160 volatile portFLOAT ff1, ff2, ff3, ff4;
\r
161 volatile unsigned portSHORT *pusTaskCheckVariable;
\r
162 volatile portFLOAT fAnswer;
\r
163 portSHORT sError = pdFALSE;
\r
169 fAnswer = ( ff1 + ff2 ) * ff3;
\r
171 /* The variable this task increments to show it is still running is passed in
\r
172 as the parameter. */
\r
173 pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
\r
175 /* Keep performing a calculation and checking the result against a constant. */
\r
182 ff4 = ( ff1 + ff2 ) * ff3;
\r
184 #if configUSE_PREEMPTION == 0
\r
188 /* If the calculation does not match the expected constant, stop the
\r
189 increment of the check variable. */
\r
190 if( fabs( ff4 - fAnswer ) > 0.001F )
\r
195 if( sError == pdFALSE )
\r
197 /* If the calculation has always been correct, increment the check
\r
198 variable so we know this task is still running okay. */
\r
199 ( *pusTaskCheckVariable )++;
\r
202 #if configUSE_PREEMPTION == 0
\r
208 /*-----------------------------------------------------------*/
\r
210 static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
\r
212 volatile portFLOAT ff1, ff2, ff3, ff4;
\r
213 volatile unsigned portSHORT *pusTaskCheckVariable;
\r
214 volatile portFLOAT fAnswer;
\r
215 portSHORT sError = pdFALSE;
\r
221 fAnswer = ( ff1 / ff2 ) * ff3;
\r
224 /* The variable this task increments to show it is still running is passed in
\r
225 as the parameter. */
\r
226 pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
\r
228 /* Keep performing a calculation and checking the result against a constant. */
\r
235 ff4 = ( ff1 / ff2 ) * ff3;
\r
237 #if configUSE_PREEMPTION == 0
\r
241 /* If the calculation does not match the expected constant, stop the
\r
242 increment of the check variable. */
\r
243 if( fabs( ff4 - fAnswer ) > 0.001F )
\r
248 if( sError == pdFALSE )
\r
250 /* If the calculation has always been correct, increment the check
\r
251 variable so we know
\r
252 this task is still running okay. */
\r
253 ( *pusTaskCheckVariable )++;
\r
256 #if configUSE_PREEMPTION == 0
\r
261 /*-----------------------------------------------------------*/
\r
263 static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
\r
265 volatile portFLOAT *pfArray, fTotal1, fTotal2, fDifference;
\r
266 volatile unsigned portSHORT *pusTaskCheckVariable;
\r
267 const size_t xArraySize = 10;
\r
269 portSHORT sError = pdFALSE;
\r
271 /* The variable this task increments to show it is still running is passed in
\r
272 as the parameter. */
\r
273 pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
\r
275 pfArray = ( portFLOAT * ) pvPortMalloc( xArraySize * sizeof( portFLOAT ) );
\r
277 /* Keep filling an array, keeping a running total of the values placed in the
\r
278 array. Then run through the array adding up all the values. If the two totals
\r
279 do not match, stop the check variable from incrementing. */
\r
285 for( xPosition = 0; xPosition < xArraySize; xPosition++ )
\r
287 pfArray[ xPosition ] = ( portFLOAT ) xPosition + 5.5F;
\r
288 fTotal1 += ( portFLOAT ) xPosition + 5.5F;
\r
291 #if configUSE_PREEMPTION == 0
\r
295 for( xPosition = 0; xPosition < xArraySize; xPosition++ )
\r
297 fTotal2 += pfArray[ xPosition ];
\r
300 fDifference = fTotal1 - fTotal2;
\r
301 if( fabs( fDifference ) > 0.001F )
\r
306 #if configUSE_PREEMPTION == 0
\r
310 if( sError == pdFALSE )
\r
312 /* If the calculation has always been correct, increment the check
\r
313 variable so we know this task is still running okay. */
\r
314 ( *pusTaskCheckVariable )++;
\r
318 /*-----------------------------------------------------------*/
\r
320 static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
\r
322 volatile portFLOAT *pfArray, fTotal1, fTotal2, fDifference;
\r
323 volatile unsigned portSHORT *pusTaskCheckVariable;
\r
324 const size_t xArraySize = 10;
\r
326 portSHORT sError = pdFALSE;
\r
328 /* The variable this task increments to show it is still running is passed in
\r
329 as the parameter. */
\r
330 pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
\r
332 pfArray = ( portFLOAT * ) pvPortMalloc( xArraySize * sizeof( portFLOAT ) );
\r
334 /* Keep filling an array, keeping a running total of the values placed in the
\r
335 array. Then run through the array adding up all the values. If the two totals
\r
336 do not match, stop the check variable from incrementing. */
\r
342 for( xPosition = 0; xPosition < xArraySize; xPosition++ )
\r
344 pfArray[ xPosition ] = ( portFLOAT ) xPosition * 12.123F;
\r
345 fTotal1 += ( portFLOAT ) xPosition * 12.123F;
\r
348 #if configUSE_PREEMPTION == 0
\r
352 for( xPosition = 0; xPosition < xArraySize; xPosition++ )
\r
354 fTotal2 += pfArray[ xPosition ];
\r
357 fDifference = fTotal1 - fTotal2;
\r
358 if( fabs( fDifference ) > 0.001F )
\r
363 #if configUSE_PREEMPTION == 0
\r
367 if( sError == pdFALSE )
\r
369 /* If the calculation has always been correct, increment the check
\r
370 variable so we know this task is still running okay. */
\r
371 ( *pusTaskCheckVariable )++;
\r
375 /*-----------------------------------------------------------*/
\r
377 /* This is called to check that all the created tasks are still running. */
\r
378 portBASE_TYPE xAreMathsTaskStillRunning( void )
\r
380 /* Keep a history of the check variables so we know if they have been incremented
\r
381 since the last call. */
\r
382 static unsigned portSHORT usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
\r
383 portBASE_TYPE xReturn = pdTRUE, xTask;
\r
385 /* Check the maths tasks are still running by ensuring their check variables
\r
386 are still incrementing. */
\r
387 for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
\r
389 if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
\r
391 /* The check has not incremented so an error exists. */
\r
395 usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
\r