1 |
586 |
jeremybenn |
/*
|
2 |
|
|
FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
|
3 |
|
|
|
4 |
|
|
***************************************************************************
|
5 |
|
|
* *
|
6 |
|
|
* If you are: *
|
7 |
|
|
* *
|
8 |
|
|
* + New to FreeRTOS, *
|
9 |
|
|
* + Wanting to learn FreeRTOS or multitasking in general quickly *
|
10 |
|
|
* + Looking for basic training, *
|
11 |
|
|
* + Wanting to improve your FreeRTOS skills and productivity *
|
12 |
|
|
* *
|
13 |
|
|
* then take a look at the FreeRTOS books - available as PDF or paperback *
|
14 |
|
|
* *
|
15 |
|
|
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
|
16 |
|
|
* http://www.FreeRTOS.org/Documentation *
|
17 |
|
|
* *
|
18 |
|
|
* A pdf reference manual is also available. Both are usually delivered *
|
19 |
|
|
* to your inbox within 20 minutes to two hours when purchased between 8am *
|
20 |
|
|
* and 8pm GMT (although please allow up to 24 hours in case of *
|
21 |
|
|
* exceptional circumstances). Thank you for your support! *
|
22 |
|
|
* *
|
23 |
|
|
***************************************************************************
|
24 |
|
|
|
25 |
|
|
This file is part of the FreeRTOS distribution.
|
26 |
|
|
|
27 |
|
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
28 |
|
|
the terms of the GNU General Public License (version 2) as published by the
|
29 |
|
|
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
30 |
|
|
***NOTE*** The exception to the GPL is included to allow you to distribute
|
31 |
|
|
a combined work that includes FreeRTOS without being obliged to provide the
|
32 |
|
|
source code for proprietary components outside of the FreeRTOS kernel.
|
33 |
|
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
34 |
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
35 |
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
36 |
|
|
more details. You should have received a copy of the GNU General Public
|
37 |
|
|
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
38 |
|
|
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
39 |
|
|
by writing to Richard Barry, contact details for whom are available on the
|
40 |
|
|
FreeRTOS WEB site.
|
41 |
|
|
|
42 |
|
|
1 tab == 4 spaces!
|
43 |
|
|
|
44 |
|
|
http://www.FreeRTOS.org - Documentation, latest information, license and
|
45 |
|
|
contact details.
|
46 |
|
|
|
47 |
|
|
http://www.SafeRTOS.com - A version that is certified for use in safety
|
48 |
|
|
critical systems.
|
49 |
|
|
|
50 |
|
|
http://www.OpenRTOS.com - Commercial support, development, porting,
|
51 |
|
|
licensing and training services.
|
52 |
|
|
*/
|
53 |
|
|
|
54 |
|
|
/*
|
55 |
|
|
* Tests the floating point context save and restore mechanism.
|
56 |
|
|
*
|
57 |
|
|
* Two tasks are created - each of which is allocated a buffer of
|
58 |
|
|
* portNO_FLOP_REGISTERS_TO_SAVE 32bit variables into which the flop context
|
59 |
|
|
* of the task is saved when the task is switched out, and from which the
|
60 |
|
|
* flop context of the task is restored when the task is switch in. Prior to
|
61 |
|
|
* the tasks being created each position in the two buffers is filled with a
|
62 |
|
|
* unique value - this way the flop context of each task is different.
|
63 |
|
|
*
|
64 |
|
|
* The two test tasks never block so are always in either the Running or
|
65 |
|
|
* Ready state. They execute at the lowest priority so will get pre-empted
|
66 |
|
|
* regularly, although the yield frequently so will not get much execution
|
67 |
|
|
* time. The lack of execution time is not a problem as its only the
|
68 |
|
|
* switching in and out that is being tested.
|
69 |
|
|
*
|
70 |
|
|
* Whenever a task is moved from the Ready to the Running state its flop
|
71 |
|
|
* context will be loaded from the buffer, but while the task is in the
|
72 |
|
|
* Running state the buffer is not used and can contain any value - in this
|
73 |
|
|
* case and for test purposes the task itself clears the buffer to zero.
|
74 |
|
|
* The next time the task is moved out of the Running state into the
|
75 |
|
|
* Ready state the flop context will once more get saved to the buffer -
|
76 |
|
|
* overwriting the zeros.
|
77 |
|
|
*
|
78 |
|
|
* Therefore whenever the task is not in the Running state its buffer contains
|
79 |
|
|
* the most recent values of its floating point registers - the zeroing out
|
80 |
|
|
* of the buffer while the task was executing being used to ensure the values
|
81 |
|
|
* the buffer contains are not stale.
|
82 |
|
|
*
|
83 |
|
|
* When neither test task is in the Running state the buffers should contain
|
84 |
|
|
* the unique values allocated before the tasks were created. If so then
|
85 |
|
|
* the floating point context has been maintained. This check is performed
|
86 |
|
|
* by the 'check' task (defined in main.c) by calling
|
87 |
|
|
* xAreFlopRegisterTestsStillRunning().
|
88 |
|
|
*
|
89 |
|
|
* The test tasks also increment a value each time they execute.
|
90 |
|
|
* xAreFlopRegisterTestsStillRunning() also checks that this value has changed
|
91 |
|
|
* since it last ran to ensure the test tasks are still getting processing time.
|
92 |
|
|
*/
|
93 |
|
|
|
94 |
|
|
/* Standard includes files. */
|
95 |
|
|
#include <string.h>
|
96 |
|
|
|
97 |
|
|
/* Scheduler include files. */
|
98 |
|
|
#include "FreeRTOS.h"
|
99 |
|
|
#include "task.h"
|
100 |
|
|
|
101 |
|
|
/*-----------------------------------------------------------*/
|
102 |
|
|
|
103 |
|
|
#define flopNUMBER_OF_TASKS 2
|
104 |
|
|
#define flopSTART_VALUE ( 0x1 )
|
105 |
|
|
|
106 |
|
|
/*-----------------------------------------------------------*/
|
107 |
|
|
|
108 |
|
|
/* The two test tasks as described at the top of this file. */
|
109 |
|
|
static void vFlopTest1( void *pvParameters );
|
110 |
|
|
static void vFlopTest2( void *pvParameters );
|
111 |
|
|
|
112 |
|
|
/*-----------------------------------------------------------*/
|
113 |
|
|
|
114 |
|
|
/* Buffers into which the flop registers will be saved. There is a buffer for
|
115 |
|
|
both tasks. */
|
116 |
|
|
static volatile unsigned long ulFlopRegisters[ flopNUMBER_OF_TASKS ][ portNO_FLOP_REGISTERS_TO_SAVE ];
|
117 |
|
|
|
118 |
|
|
/* Variables that are incremented by the tasks to indicate that they are still
|
119 |
|
|
running. */
|
120 |
|
|
static volatile unsigned long ulFlop1CycleCount = 0, ulFlop2CycleCount = 0;
|
121 |
|
|
|
122 |
|
|
/*-----------------------------------------------------------*/
|
123 |
|
|
|
124 |
|
|
void vStartFlopRegTests( void )
|
125 |
|
|
{
|
126 |
|
|
xTaskHandle xTaskJustCreated;
|
127 |
|
|
unsigned portBASE_TYPE x, y, z = flopSTART_VALUE;
|
128 |
|
|
|
129 |
|
|
/* Fill the arrays into which the flop registers are to be saved with
|
130 |
|
|
known values. These are the values that will be written to the flop
|
131 |
|
|
registers when the tasks start, and as the tasks do not perform any
|
132 |
|
|
flop operations the values should never change. Each position in the
|
133 |
|
|
buffer contains a different value so the flop context of each task
|
134 |
|
|
will be different. */
|
135 |
|
|
for( x = 0; x < flopNUMBER_OF_TASKS; x++ )
|
136 |
|
|
{
|
137 |
|
|
for( y = 0; y < ( portNO_FLOP_REGISTERS_TO_SAVE - 1); y++ )
|
138 |
|
|
{
|
139 |
|
|
ulFlopRegisters[ x ][ y ] = z;
|
140 |
|
|
z++;
|
141 |
|
|
}
|
142 |
|
|
}
|
143 |
|
|
|
144 |
|
|
|
145 |
|
|
/* Create the first task. */
|
146 |
|
|
xTaskCreate( vFlopTest1, ( signed char * ) "flop1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskJustCreated );
|
147 |
|
|
|
148 |
|
|
/* The task tag value is a value that can be associated with a task, but
|
149 |
|
|
is not used by the scheduler itself. Its use is down to the application so
|
150 |
|
|
it makes a convenient place in this case to store the pointer to the buffer
|
151 |
|
|
into which the flop context of the task will be stored. The first created
|
152 |
|
|
task uses ulFlopRegisters[ 0 ], the second ulFlopRegisters[ 1 ]. */
|
153 |
|
|
vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 0 ][ 0 ] ) );
|
154 |
|
|
|
155 |
|
|
/* Do the same for the second task. */
|
156 |
|
|
xTaskCreate( vFlopTest2, ( signed char * ) "flop2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskJustCreated );
|
157 |
|
|
vTaskSetApplicationTaskTag( xTaskJustCreated, ( void * ) &( ulFlopRegisters[ 1 ][ 0 ] ) );
|
158 |
|
|
}
|
159 |
|
|
/*-----------------------------------------------------------*/
|
160 |
|
|
|
161 |
|
|
static void vFlopTest1( void *pvParameters )
|
162 |
|
|
{
|
163 |
|
|
/* Just to remove compiler warning. */
|
164 |
|
|
( void ) pvParameters;
|
165 |
|
|
|
166 |
|
|
for( ;; )
|
167 |
|
|
{
|
168 |
|
|
/* The values from the buffer should have now been written to the flop
|
169 |
|
|
registers. Clear the buffer to ensure the same values then get written
|
170 |
|
|
back the next time the task runs. Being preempted during this memset
|
171 |
|
|
could cause the test to fail, hence the critical section. */
|
172 |
|
|
portENTER_CRITICAL();
|
173 |
|
|
memset( ( void * ) ulFlopRegisters[ 0 ], 0x00, ( portNO_FLOP_REGISTERS_TO_SAVE * sizeof( unsigned portBASE_TYPE ) ) );
|
174 |
|
|
portEXIT_CRITICAL();
|
175 |
|
|
|
176 |
|
|
/* We don't have to do anything other than indicate that we are
|
177 |
|
|
still running. */
|
178 |
|
|
ulFlop1CycleCount++;
|
179 |
|
|
taskYIELD();
|
180 |
|
|
}
|
181 |
|
|
}
|
182 |
|
|
/*-----------------------------------------------------------*/
|
183 |
|
|
|
184 |
|
|
static void vFlopTest2( void *pvParameters )
|
185 |
|
|
{
|
186 |
|
|
/* Just to remove compiler warning. */
|
187 |
|
|
( void ) pvParameters;
|
188 |
|
|
|
189 |
|
|
for( ;; )
|
190 |
|
|
{
|
191 |
|
|
/* The values from the buffer should have now been written to the flop
|
192 |
|
|
registers. Clear the buffer to ensure the same values then get written
|
193 |
|
|
back the next time the task runs. */
|
194 |
|
|
portENTER_CRITICAL();
|
195 |
|
|
memset( ( void * ) ulFlopRegisters[ 1 ], 0x00, ( portNO_FLOP_REGISTERS_TO_SAVE * sizeof( unsigned portBASE_TYPE ) ) );
|
196 |
|
|
portEXIT_CRITICAL();
|
197 |
|
|
|
198 |
|
|
/* We don't have to do anything other than indicate that we are
|
199 |
|
|
still running. */
|
200 |
|
|
ulFlop2CycleCount++;
|
201 |
|
|
taskYIELD();
|
202 |
|
|
}
|
203 |
|
|
}
|
204 |
|
|
/*-----------------------------------------------------------*/
|
205 |
|
|
|
206 |
|
|
portBASE_TYPE xAreFlopRegisterTestsStillRunning( void )
|
207 |
|
|
{
|
208 |
|
|
portBASE_TYPE xReturn = pdPASS;
|
209 |
|
|
unsigned portBASE_TYPE x, y, z = flopSTART_VALUE;
|
210 |
|
|
static unsigned long ulLastFlop1CycleCount = 0, ulLastFlop2CycleCount = 0;
|
211 |
|
|
|
212 |
|
|
/* Called from the 'check' task.
|
213 |
|
|
|
214 |
|
|
The flop tasks cannot be currently running, check their saved registers
|
215 |
|
|
are as expected. The tests tasks do not perform any flop operations so
|
216 |
|
|
their registers should be as per their initial setting. */
|
217 |
|
|
for( x = 0; x < flopNUMBER_OF_TASKS; x++ )
|
218 |
|
|
{
|
219 |
|
|
for( y = 0; y < ( portNO_FLOP_REGISTERS_TO_SAVE - 1 ); y++ )
|
220 |
|
|
{
|
221 |
|
|
if( ulFlopRegisters[ x ][ y ] != z )
|
222 |
|
|
{
|
223 |
|
|
xReturn = pdFAIL;
|
224 |
|
|
break;
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
z++;
|
228 |
|
|
}
|
229 |
|
|
}
|
230 |
|
|
|
231 |
|
|
/* Check both tasks have actually been swapped in and out since this function
|
232 |
|
|
last executed. */
|
233 |
|
|
if( ulFlop1CycleCount == ulLastFlop1CycleCount )
|
234 |
|
|
{
|
235 |
|
|
xReturn = pdFAIL;
|
236 |
|
|
}
|
237 |
|
|
|
238 |
|
|
if( ulFlop2CycleCount == ulLastFlop2CycleCount )
|
239 |
|
|
{
|
240 |
|
|
xReturn = pdFAIL;
|
241 |
|
|
}
|
242 |
|
|
|
243 |
|
|
ulLastFlop1CycleCount = ulFlop1CycleCount;
|
244 |
|
|
ulLastFlop2CycleCount = ulFlop2CycleCount;
|
245 |
|
|
|
246 |
|
|
return xReturn;
|
247 |
|
|
}
|
248 |
|
|
|