]> begriffs open source - cmsis-freertos/blob - Demo/Common/Full/flop.c
Update README.md - branch main is now the base branch
[cmsis-freertos] / Demo / Common / Full / flop.c
1 /*
2  * FreeRTOS V202111.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*
29  * Changes from V1.2.3
30  *
31  + The created tasks now include calls to tskYIELD(), allowing them to be used
32  +    with the cooperative scheduler.
33  */
34
35 /**
36  * Creates eight tasks, each of which loops continuously performing an (emulated)
37  * floating point calculation.
38  *
39  * All the tasks run at the idle priority and never block or yield.  This causes
40  * all eight tasks to time slice with the idle task.  Running at the idle priority
41  * means that these tasks will get pre-empted any time another task is ready to run
42  * or a time slice occurs.  More often than not the pre-emption will occur mid
43  * calculation, creating a good test of the schedulers context switch mechanism - a
44  * calculation producing an unexpected result could be a symptom of a corruption in
45  * the context of a task.
46  *
47  * \page FlopC flop.c
48  * \ingroup DemoFiles
49  * <HR>
50  */
51
52 #include <stdlib.h>
53 #include <math.h>
54
55 /* Scheduler include files. */
56 #include "FreeRTOS.h"
57 #include "task.h"
58 #include "print.h"
59
60 /* Demo program include files. */
61 #include "flop.h"
62
63 #define mathSTACK_SIZE         ( ( unsigned short ) 512 )
64 #define mathNUMBER_OF_TASKS    ( 8 )
65
66 /* Four tasks, each of which performs a different floating point calculation.
67  * Each of the four is created twice. */
68 static void vCompetingMathTask1( void * pvParameters );
69 static void vCompetingMathTask2( void * pvParameters );
70 static void vCompetingMathTask3( void * pvParameters );
71 static void vCompetingMathTask4( void * pvParameters );
72
73 /* These variables are used to check that all the tasks are still running.  If a
74  * task gets a calculation wrong it will
75  * stop incrementing its check variable. */
76 static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
77
78 /*-----------------------------------------------------------*/
79
80 void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
81 {
82     xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
83     xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
84     xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
85     xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
86     xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
87     xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
88     xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
89     xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
90 }
91 /*-----------------------------------------------------------*/
92
93 static void vCompetingMathTask1( void * pvParameters )
94 {
95     portDOUBLE d1, d2, d3, d4;
96     volatile unsigned short * pusTaskCheckVariable;
97     const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
98     const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
99     const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
100     short sError = pdFALSE;
101
102     /* Queue a message for printing to say the task has started. */
103     vPrintDisplayMessage( &pcTaskStartMsg );
104
105     /* The variable this task increments to show it is still running is passed in
106      * as the parameter. */
107     pusTaskCheckVariable = ( unsigned short * ) pvParameters;
108
109     /* Keep performing a calculation and checking the result against a constant. */
110     for( ; ; )
111     {
112         d1 = 123.4567;
113         d2 = 2345.6789;
114         d3 = -918.222;
115
116         d4 = ( d1 + d2 ) * d3;
117
118         taskYIELD();
119
120         /* If the calculation does not match the expected constant, stop the
121          * increment of the check variable. */
122         if( fabs( d4 - dAnswer ) > 0.001 )
123         {
124             vPrintDisplayMessage( &pcTaskFailMsg );
125             sError = pdTRUE;
126         }
127
128         if( sError == pdFALSE )
129         {
130             /* If the calculation has always been correct, increment the check
131              * variable so we know this task is still running okay. */
132             ( *pusTaskCheckVariable )++;
133         }
134
135         taskYIELD();
136     }
137 }
138 /*-----------------------------------------------------------*/
139
140 static void vCompetingMathTask2( void * pvParameters )
141 {
142     portDOUBLE d1, d2, d3, d4;
143     volatile unsigned short * pusTaskCheckVariable;
144     const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
145     const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
146     const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
147     short sError = pdFALSE;
148
149     /* Queue a message for printing to say the task has started. */
150     vPrintDisplayMessage( &pcTaskStartMsg );
151
152     /* The variable this task increments to show it is still running is passed in
153      * as the parameter. */
154     pusTaskCheckVariable = ( unsigned short * ) pvParameters;
155
156     /* Keep performing a calculation and checking the result against a constant. */
157     for( ; ; )
158     {
159         d1 = -389.38;
160         d2 = 32498.2;
161         d3 = -2.0001;
162
163         d4 = ( d1 / d2 ) * d3;
164
165         taskYIELD();
166
167         /* If the calculation does not match the expected constant, stop the
168          * increment of the check variable. */
169         if( fabs( d4 - dAnswer ) > 0.001 )
170         {
171             vPrintDisplayMessage( &pcTaskFailMsg );
172             sError = pdTRUE;
173         }
174
175         if( sError == pdFALSE )
176         {
177             /* If the calculation has always been correct, increment the check
178              * variable so we know
179              * this task is still running okay. */
180             ( *pusTaskCheckVariable )++;
181         }
182
183         taskYIELD();
184     }
185 }
186 /*-----------------------------------------------------------*/
187
188 static void vCompetingMathTask3( void * pvParameters )
189 {
190     portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
191     volatile unsigned short * pusTaskCheckVariable;
192     const unsigned short usArraySize = 250;
193     unsigned short usPosition;
194     const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
195     const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
196     short sError = pdFALSE;
197
198     /* Queue a message for printing to say the task has started. */
199     vPrintDisplayMessage( &pcTaskStartMsg );
200
201     /* The variable this task increments to show it is still running is passed in
202      * as the parameter. */
203     pusTaskCheckVariable = ( unsigned short * ) pvParameters;
204
205     pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
206
207     /* Keep filling an array, keeping a running total of the values placed in the
208      * array.  Then run through the array adding up all the values.  If the two totals
209      * do not match, stop the check variable from incrementing. */
210     for( ; ; )
211     {
212         dTotal1 = 0.0;
213         dTotal2 = 0.0;
214
215         for( usPosition = 0; usPosition < usArraySize; usPosition++ )
216         {
217             pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
218             dTotal1 += ( portDOUBLE ) usPosition + 5.5;
219         }
220
221         taskYIELD();
222
223         for( usPosition = 0; usPosition < usArraySize; usPosition++ )
224         {
225             dTotal2 += pdArray[ usPosition ];
226         }
227
228         dDifference = dTotal1 - dTotal2;
229
230         if( fabs( dDifference ) > 0.001 )
231         {
232             vPrintDisplayMessage( &pcTaskFailMsg );
233             sError = pdTRUE;
234         }
235
236         taskYIELD();
237
238         if( sError == pdFALSE )
239         {
240             /* If the calculation has always been correct, increment the check
241              * variable so we know      this task is still running okay. */
242             ( *pusTaskCheckVariable )++;
243         }
244     }
245 }
246 /*-----------------------------------------------------------*/
247
248 static void vCompetingMathTask4( void * pvParameters )
249 {
250     portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
251     volatile unsigned short * pusTaskCheckVariable;
252     const unsigned short usArraySize = 250;
253     unsigned short usPosition;
254     const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
255     const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
256     short sError = pdFALSE;
257
258     /* Queue a message for printing to say the task has started. */
259     vPrintDisplayMessage( &pcTaskStartMsg );
260
261     /* The variable this task increments to show it is still running is passed in
262      * as the parameter. */
263     pusTaskCheckVariable = ( unsigned short * ) pvParameters;
264
265     pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
266
267     /* Keep filling an array, keeping a running total of the values placed in the
268      * array.  Then run through the array adding up all the values.  If the two totals
269      * do not match, stop the check variable from incrementing. */
270     for( ; ; )
271     {
272         dTotal1 = 0.0;
273         dTotal2 = 0.0;
274
275         for( usPosition = 0; usPosition < usArraySize; usPosition++ )
276         {
277             pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
278             dTotal1 += ( portDOUBLE ) usPosition * 12.123;
279         }
280
281         taskYIELD();
282
283         for( usPosition = 0; usPosition < usArraySize; usPosition++ )
284         {
285             dTotal2 += pdArray[ usPosition ];
286         }
287
288         dDifference = dTotal1 - dTotal2;
289
290         if( fabs( dDifference ) > 0.001 )
291         {
292             vPrintDisplayMessage( &pcTaskFailMsg );
293             sError = pdTRUE;
294         }
295
296         taskYIELD();
297
298         if( sError == pdFALSE )
299         {
300             /* If the calculation has always been correct, increment the check
301              * variable so we know      this task is still running okay. */
302             ( *pusTaskCheckVariable )++;
303         }
304     }
305 }
306 /*-----------------------------------------------------------*/
307
308 /* This is called to check that all the created tasks are still running. */
309 portBASE_TYPE xAreMathsTaskStillRunning( void )
310 {
311 /* Keep a history of the check variables so we know if they have been incremented
312  * since the last call. */
313     static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
314     portBASE_TYPE xReturn = pdTRUE, xTask;
315
316     /* Check the maths tasks are still running by ensuring their check variables
317      * are still incrementing. */
318     for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
319     {
320         if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
321         {
322             /* The check has not incremented so an error exists. */
323             xReturn = pdFALSE;
324         }
325
326         usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
327     }
328
329     return xReturn;
330 }