1 |
582 |
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 |
|
|
/*
|
56 |
|
|
* This file demonstrates the use of FreeRTOS-MPU. It creates tasks in both
|
57 |
|
|
* User mode and Privileged mode, and using both the original xTaskCreate() and
|
58 |
|
|
* the new xTaskCreateRestricted() API functions. The purpose of each created
|
59 |
|
|
* task is documented in the comments above the task function prototype (in
|
60 |
|
|
* this file), with the task behaviour demonstrated and documented within the
|
61 |
|
|
* task function itself. In addition a queue is used to demonstrate passing
|
62 |
|
|
* data between protected/restricted tasks as well as passing data between an
|
63 |
|
|
* interrupt and a protected/restricted task.
|
64 |
|
|
*/
|
65 |
|
|
|
66 |
|
|
|
67 |
|
|
|
68 |
|
|
/* Standard includes. */
|
69 |
|
|
#include <string.h>
|
70 |
|
|
#include <__cross_studio_io.h>
|
71 |
|
|
|
72 |
|
|
/* Scheduler includes. */
|
73 |
|
|
#include "FreeRTOS.h"
|
74 |
|
|
#include "task.h"
|
75 |
|
|
#include "queue.h"
|
76 |
|
|
#include "semphr.h"
|
77 |
|
|
|
78 |
|
|
/* Hardware library includes. */
|
79 |
|
|
#include "hw_types.h"
|
80 |
|
|
#include "hw_sysctl.h"
|
81 |
|
|
#include "sysctl.h"
|
82 |
|
|
|
83 |
|
|
/*-----------------------------------------------------------*/
|
84 |
|
|
|
85 |
|
|
/* Misc constants. */
|
86 |
|
|
#define mainDONT_BLOCK ( 0 )
|
87 |
|
|
|
88 |
|
|
/* Definitions for the messages that can be sent to the check task. */
|
89 |
|
|
#define mainREG_TEST_1_STILL_EXECUTING ( 0 )
|
90 |
|
|
#define mainREG_TEST_2_STILL_EXECUTING ( 1 )
|
91 |
|
|
#define mainPRINT_SYSTEM_STATUS ( 2 )
|
92 |
|
|
|
93 |
|
|
/* GCC specifics. */
|
94 |
|
|
#define mainALIGN_TO( x ) __attribute__((aligned(x)))
|
95 |
|
|
|
96 |
|
|
|
97 |
|
|
/*-----------------------------------------------------------*/
|
98 |
|
|
/* Prototypes for functions that implement tasks. -----------*/
|
99 |
|
|
/*-----------------------------------------------------------*/
|
100 |
|
|
|
101 |
|
|
/*
|
102 |
|
|
* Prototype for the reg test tasks. Amongst other things, these fill the CPU
|
103 |
|
|
* registers with known values before checking that the registers still contain
|
104 |
|
|
* the expected values. Each of the two tasks use different values so an error
|
105 |
|
|
* in the context switch mechanism can be caught. Both reg test tasks execute
|
106 |
|
|
* at the idle priority so will get preempted regularly. Each task repeatedly
|
107 |
|
|
* sends a message on a queue so long as it remains functioning correctly. If
|
108 |
|
|
* an error is detected within the task the task is simply deleted.
|
109 |
|
|
*/
|
110 |
|
|
static void prvRegTest1Task( void *pvParameters );
|
111 |
|
|
static void prvRegTest2Task( void *pvParameters );
|
112 |
|
|
|
113 |
|
|
/*
|
114 |
|
|
* Prototype for the check task. The check task demonstrates various features
|
115 |
|
|
* of the MPU before entering a loop where it waits for messages to arrive on a
|
116 |
|
|
* queue.
|
117 |
|
|
*
|
118 |
|
|
* Two types of messages can be processes:
|
119 |
|
|
*
|
120 |
|
|
* 1) "I'm Alive" messages sent from the reg test tasks, indicating that the
|
121 |
|
|
* task is still operational.
|
122 |
|
|
*
|
123 |
|
|
* 2) "Print Status commands" sent periodically by the tick hook function (and
|
124 |
|
|
* therefore from within an interrupt) which command the check task to write
|
125 |
|
|
* either pass or fail to the terminal, depending on the status of the reg
|
126 |
|
|
* test tasks.
|
127 |
|
|
*/
|
128 |
|
|
static void prvCheckTask( void *pvParameters );
|
129 |
|
|
|
130 |
|
|
/*
|
131 |
|
|
* Prototype for a task created in User mode using the original vTaskCreate()
|
132 |
|
|
* API function. The task demonstrates the characteristics of such a task,
|
133 |
|
|
* before simply deleting itself.
|
134 |
|
|
*/
|
135 |
|
|
static void prvOldStyleUserModeTask( void *pvParameters );
|
136 |
|
|
|
137 |
|
|
/*
|
138 |
|
|
* Prototype for a task created in Privileged mode using the original
|
139 |
|
|
* vTaskCreate() API function. The task demonstrates the characteristics of
|
140 |
|
|
* such a task, before simply deleting itself.
|
141 |
|
|
*/
|
142 |
|
|
static void prvOldStylePrivilegedModeTask( void *pvParameters );
|
143 |
|
|
|
144 |
|
|
|
145 |
|
|
/*-----------------------------------------------------------*/
|
146 |
|
|
/* Prototypes for other misc functions. --------------------*/
|
147 |
|
|
/*-----------------------------------------------------------*/
|
148 |
|
|
|
149 |
|
|
/*
|
150 |
|
|
* Just configures any clocks and IO necessary.
|
151 |
|
|
*/
|
152 |
|
|
static void prvSetupHardware( void );
|
153 |
|
|
|
154 |
|
|
/*
|
155 |
|
|
* Simply deletes the calling task. The function is provided only because it
|
156 |
|
|
* is simpler to call from asm code than the normal vTaskDelete() API function.
|
157 |
|
|
* It has the noinline attribute because it is called from asm code.
|
158 |
|
|
*/
|
159 |
|
|
static void prvDeleteMe( void ) __attribute__((noinline));
|
160 |
|
|
|
161 |
|
|
/*
|
162 |
|
|
* Used by both reg test tasks to send messages to the check task. The message
|
163 |
|
|
* just lets the check task know that the task is still functioning correctly.
|
164 |
|
|
* If a reg test task detects an error it will delete itself, and in so doing
|
165 |
|
|
* prevent itself from sending any more 'I'm Alive' messages to the check task.
|
166 |
|
|
*/
|
167 |
|
|
static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber );
|
168 |
|
|
|
169 |
|
|
/*
|
170 |
|
|
* The check task is created with access to three memory regions (plus its
|
171 |
|
|
* stack). Each memory region is configured with different parameters and
|
172 |
|
|
* prvTestMemoryRegions() demonstrates what can and cannot be accessed for each
|
173 |
|
|
* region. prvTestMemoryRegions() also demonstrates a task that was created
|
174 |
|
|
* as a privileged task settings its own privilege level down to that of a user
|
175 |
|
|
* task.
|
176 |
|
|
*/
|
177 |
|
|
static void prvTestMemoryRegions( void );
|
178 |
|
|
|
179 |
|
|
/*-----------------------------------------------------------*/
|
180 |
|
|
|
181 |
|
|
/* The handle of the queue used to communicate between tasks and between tasks
|
182 |
|
|
and interrupts. Note that this is a file scope variable that falls outside of
|
183 |
|
|
any MPU region. As such other techniques have to be used to allow the tasks
|
184 |
|
|
to gain access to the queue. See the comments in the tasks themselves for
|
185 |
|
|
further information. */
|
186 |
|
|
static xQueueHandle xFileScopeCheckQueue = NULL;
|
187 |
|
|
|
188 |
|
|
|
189 |
|
|
/*-----------------------------------------------------------*/
|
190 |
|
|
/* Data used by the 'check' task. ---------------------------*/
|
191 |
|
|
/*-----------------------------------------------------------*/
|
192 |
|
|
|
193 |
|
|
/* Define the constants used to allocate the check task stack. Note that the
|
194 |
|
|
stack size is defined in words, not bytes. */
|
195 |
|
|
#define mainCHECK_TASK_STACK_SIZE_WORDS 128
|
196 |
|
|
#define mainCHECK_TASK_STACK_ALIGNMENT ( mainCHECK_TASK_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) )
|
197 |
|
|
|
198 |
|
|
/* Declare the stack that will be used by the check task. The kernel will
|
199 |
|
|
automatically create an MPU region for the stack. The stack alignment must
|
200 |
|
|
match its size, so if 128 words are reserved for the stack then it must be
|
201 |
|
|
aligned to ( 128 * 4 ) bytes. */
|
202 |
|
|
static portSTACK_TYPE xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] mainALIGN_TO( mainCHECK_TASK_STACK_ALIGNMENT );
|
203 |
|
|
|
204 |
|
|
/* Declare three arrays - an MPU region will be created for each array
|
205 |
|
|
using the xTaskParameters structure below. THIS IS JUST TO DEMONSTRATE THE
|
206 |
|
|
MPU FUNCTIONALITY, the data is not used by the check tasks primary function
|
207 |
|
|
of monitoring the reg test tasks and printing out status information.
|
208 |
|
|
|
209 |
|
|
Note that the arrays allocate slightly more RAM than is actually assigned to
|
210 |
|
|
the MPU region. This is to permit writes off the end of the array to be
|
211 |
|
|
detected even when the arrays are placed in adjacent memory locations (with no
|
212 |
|
|
gaps between them). The align size must be a power of two. */
|
213 |
|
|
#define mainREAD_WRITE_ARRAY_SIZE 130
|
214 |
|
|
#define mainREAD_WRITE_ALIGN_SIZE 128
|
215 |
|
|
char cReadWriteArray[ mainREAD_WRITE_ARRAY_SIZE ] mainALIGN_TO( mainREAD_WRITE_ALIGN_SIZE );
|
216 |
|
|
|
217 |
|
|
#define mainREAD_ONLY_ARRAY_SIZE 260
|
218 |
|
|
#define mainREAD_ONLY_ALIGN_SIZE 256
|
219 |
|
|
char cReadOnlyArray[ mainREAD_ONLY_ARRAY_SIZE ] mainALIGN_TO( mainREAD_ONLY_ALIGN_SIZE );
|
220 |
|
|
|
221 |
|
|
#define mainPRIVILEGED_ONLY_ACCESS_ARRAY_SIZE 130
|
222 |
|
|
#define mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE 128
|
223 |
|
|
char cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] mainALIGN_TO( mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE );
|
224 |
|
|
|
225 |
|
|
/* Fill in a xTaskParameters structure to define the check task - this is the
|
226 |
|
|
structure passed to the xTaskCreateRestricted() function. */
|
227 |
|
|
static const xTaskParameters xCheckTaskParameters =
|
228 |
|
|
{
|
229 |
|
|
prvCheckTask, /* pvTaskCode - the function that implements the task. */
|
230 |
|
|
( signed char * ) "Check", /* pcName */
|
231 |
|
|
mainCHECK_TASK_STACK_SIZE_WORDS, /* usStackDepth - defined in words, not bytes. */
|
232 |
|
|
( void * ) 0x12121212, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */
|
233 |
|
|
( tskIDLE_PRIORITY + 1 ) | portPRIVILEGE_BIT,/* uxPriority - this is the highest priority task in the system. The task is created in privileged mode to demonstrate accessing the privileged only data. */
|
234 |
|
|
xCheckTaskStack, /* puxStackBuffer - the array to use as the task stack, as declared above. */
|
235 |
|
|
|
236 |
|
|
/* xRegions - In this case the xRegions array is used to create MPU regions
|
237 |
|
|
for all three of the arrays declared directly above. Each MPU region is
|
238 |
|
|
created with different parameters. Again, THIS IS JUST TO DEMONSTRATE THE
|
239 |
|
|
MPU FUNCTIONALITY, the data is not used by the check tasks primary function
|
240 |
|
|
of monitoring the reg test tasks and printing out status information.*/
|
241 |
|
|
{
|
242 |
|
|
/* Base address Length Parameters */
|
243 |
|
|
{ cReadWriteArray, mainREAD_WRITE_ALIGN_SIZE, portMPU_REGION_READ_WRITE },
|
244 |
|
|
{ cReadOnlyArray, mainREAD_ONLY_ALIGN_SIZE, portMPU_REGION_READ_ONLY },
|
245 |
|
|
{ cPrivilegedOnlyAccessArray, mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE, portMPU_REGION_PRIVILEGED_READ_WRITE }
|
246 |
|
|
}
|
247 |
|
|
};
|
248 |
|
|
|
249 |
|
|
/* Three MPU regions are defined for use by the 'check' task when the task is
|
250 |
|
|
created. These are only used to demonstrate the MPU features and are not
|
251 |
|
|
actually necessary for the check task to fulfill its primary purpose. Instead
|
252 |
|
|
the MPU regions are replaced with those defined by xAltRegions prior to the
|
253 |
|
|
check task receiving any data on the queue or printing any messages to the
|
254 |
|
|
debug console. The region configured by xAltRegions just gives the check task
|
255 |
|
|
access to the debug variables that form part of the Rowley library, and are
|
256 |
|
|
accessed within the debug_printf() function. */
|
257 |
|
|
extern unsigned long dbgCntrlWord_mempoll;
|
258 |
|
|
static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
|
259 |
|
|
{
|
260 |
|
|
/* Base address Length Parameters */
|
261 |
|
|
{ ( void * ) &dbgCntrlWord_mempoll, 32, portMPU_REGION_READ_WRITE },
|
262 |
|
|
{ 0, 0, 0 },
|
263 |
|
|
{ 0, 0, 0 }
|
264 |
|
|
};
|
265 |
|
|
|
266 |
|
|
|
267 |
|
|
|
268 |
|
|
/*-----------------------------------------------------------*/
|
269 |
|
|
/* Data used by the 'reg test' tasks. -----------------------*/
|
270 |
|
|
/*-----------------------------------------------------------*/
|
271 |
|
|
|
272 |
|
|
/* Define the constants used to allocate the reg test task stacks. Note that
|
273 |
|
|
that stack size is defined in words, not bytes. */
|
274 |
|
|
#define mainREG_TEST_STACK_SIZE_WORDS 128
|
275 |
|
|
#define mainREG_TEST_STACK_ALIGNMENT ( mainREG_TEST_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) )
|
276 |
|
|
|
277 |
|
|
/* Declare the stacks that will be used by the reg test tasks. The kernel will
|
278 |
|
|
automatically create an MPU region for the stack. The stack alignment must
|
279 |
|
|
match its size, so if 128 words are reserved for the stack then it must be
|
280 |
|
|
aligned to ( 128 * 4 ) bytes. */
|
281 |
|
|
static portSTACK_TYPE xRegTest1Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT );
|
282 |
|
|
static portSTACK_TYPE xRegTest2Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT );
|
283 |
|
|
|
284 |
|
|
/* Fill in a xTaskParameters structure per reg test task to define the tasks. */
|
285 |
|
|
static const xTaskParameters xRegTest1Parameters =
|
286 |
|
|
{
|
287 |
|
|
prvRegTest1Task, /* pvTaskCode - the function that implements the task. */
|
288 |
|
|
( signed char * ) "RegTest1", /* pcName */
|
289 |
|
|
mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */
|
290 |
|
|
( void * ) 0x12345678, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */
|
291 |
|
|
tskIDLE_PRIORITY | portPRIVILEGE_BIT, /* uxPriority - note that this task is created with privileges to demonstrate one method of passing a queue handle into the task. */
|
292 |
|
|
xRegTest1Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */
|
293 |
|
|
{ /* xRegions - this task does not use any non-stack data hence all members are zero. */
|
294 |
|
|
/* Base address Length Parameters */
|
295 |
|
|
{ 0x00, 0x00, 0x00 },
|
296 |
|
|
{ 0x00, 0x00, 0x00 },
|
297 |
|
|
{ 0x00, 0x00, 0x00 }
|
298 |
|
|
}
|
299 |
|
|
};
|
300 |
|
|
/*-----------------------------------------------------------*/
|
301 |
|
|
|
302 |
|
|
static xTaskParameters xRegTest2Parameters =
|
303 |
|
|
{
|
304 |
|
|
prvRegTest2Task, /* pvTaskCode - the function that implements the task. */
|
305 |
|
|
( signed char * ) "RegTest2", /* pcName */
|
306 |
|
|
mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */
|
307 |
|
|
( void * ) NULL, /* pvParameters - this task uses the parameter to pass in a queue handle, but the queue is not created yet. */
|
308 |
|
|
tskIDLE_PRIORITY, /* uxPriority */
|
309 |
|
|
xRegTest2Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */
|
310 |
|
|
{ /* xRegions - this task does not use any non-stack data hence all members are zero. */
|
311 |
|
|
/* Base address Length Parameters */
|
312 |
|
|
{ 0x00, 0x00, 0x00 },
|
313 |
|
|
{ 0x00, 0x00, 0x00 },
|
314 |
|
|
{ 0x00, 0x00, 0x00 }
|
315 |
|
|
}
|
316 |
|
|
};
|
317 |
|
|
|
318 |
|
|
/*-----------------------------------------------------------*/
|
319 |
|
|
|
320 |
|
|
int main( void )
|
321 |
|
|
{
|
322 |
|
|
prvSetupHardware();
|
323 |
|
|
|
324 |
|
|
/* Create the queue used to pass "I'm alive" messages to the check task. */
|
325 |
|
|
xFileScopeCheckQueue = xQueueCreate( 1, sizeof( unsigned long ) );
|
326 |
|
|
|
327 |
|
|
/* One check task uses the task parameter to receive the queue handle.
|
328 |
|
|
This allows the file scope variable to be accessed from within the task.
|
329 |
|
|
The pvParameters member of xRegTest2Parameters can only be set after the
|
330 |
|
|
queue has been created so is set here. */
|
331 |
|
|
xRegTest2Parameters.pvParameters = xFileScopeCheckQueue;
|
332 |
|
|
|
333 |
|
|
/* Create the three test tasks. Handles to the created tasks are not
|
334 |
|
|
required, hence the second parameter is NULL. */
|
335 |
|
|
xTaskCreateRestricted( &xRegTest1Parameters, NULL );
|
336 |
|
|
xTaskCreateRestricted( &xRegTest2Parameters, NULL );
|
337 |
|
|
xTaskCreateRestricted( &xCheckTaskParameters, NULL );
|
338 |
|
|
|
339 |
|
|
/* Create the tasks that are created using the original xTaskCreate() API
|
340 |
|
|
function. */
|
341 |
|
|
xTaskCreate( prvOldStyleUserModeTask, /* The function that implements the task. */
|
342 |
|
|
( signed char * ) "Task1", /* Text name for the task. */
|
343 |
|
|
100, /* Stack depth in words. */
|
344 |
|
|
NULL, /* Task parameters. */
|
345 |
|
|
3, /* Priority and mode (user in this case). */
|
346 |
|
|
NULL /* Handle. */
|
347 |
|
|
);
|
348 |
|
|
|
349 |
|
|
xTaskCreate( prvOldStylePrivilegedModeTask, /* The function that implements the task. */
|
350 |
|
|
( signed char * ) "Task2", /* Text name for the task. */
|
351 |
|
|
100, /* Stack depth in words. */
|
352 |
|
|
NULL, /* Task parameters. */
|
353 |
|
|
( 3 | portPRIVILEGE_BIT ), /* Priority and mode. */
|
354 |
|
|
NULL /* Handle. */
|
355 |
|
|
);
|
356 |
|
|
|
357 |
|
|
/* Start the scheduler. */
|
358 |
|
|
vTaskStartScheduler();
|
359 |
|
|
|
360 |
|
|
/* Will only get here if there was insufficient memory to create the idle
|
361 |
|
|
task. */
|
362 |
|
|
for( ;; );
|
363 |
|
|
return 0;
|
364 |
|
|
}
|
365 |
|
|
/*-----------------------------------------------------------*/
|
366 |
|
|
|
367 |
|
|
static void prvCheckTask( void *pvParameters )
|
368 |
|
|
{
|
369 |
|
|
/* This task is created in privileged mode so can access the file scope
|
370 |
|
|
queue variable. Take a stack copy of this before the task is set into user
|
371 |
|
|
mode. Once that task is in user mode the file scope queue variable will no
|
372 |
|
|
longer be accessible but the stack copy will. */
|
373 |
|
|
xQueueHandle xQueue = xFileScopeCheckQueue;
|
374 |
|
|
long lMessage;
|
375 |
|
|
unsigned long ulStillAliveCounts[ 2 ] = { 0 };
|
376 |
|
|
const char *pcStatusMessage = "PASS\r\n";
|
377 |
|
|
|
378 |
|
|
/* Just to remove compiler warning. */
|
379 |
|
|
( void ) pvParameters;
|
380 |
|
|
|
381 |
|
|
/* Print out the amount of free heap space so configTOTAL_HEAP_SIZE can be
|
382 |
|
|
tuned. The heap size is set to be very small in this example and will need
|
383 |
|
|
to be increased before many more tasks, queues or semaphores can be
|
384 |
|
|
created. */
|
385 |
|
|
debug_printf( "There are %d bytes of unused heap space.\r\n", xPortGetFreeHeapSize() );
|
386 |
|
|
|
387 |
|
|
/* Demonstrate how the various memory regions can and can't be accessed.
|
388 |
|
|
The task privilege level is set down to user mode within this function. */
|
389 |
|
|
prvTestMemoryRegions();
|
390 |
|
|
|
391 |
|
|
/* Change the memory regions allocated to this task to those initially
|
392 |
|
|
set up for demonstration purposes to those actually required by the task. */
|
393 |
|
|
vTaskAllocateMPURegions( NULL, xAltRegions );
|
394 |
|
|
|
395 |
|
|
/* This loop performs the main function of the task, which is blocking
|
396 |
|
|
on a message queue then processing each message as it arrives. */
|
397 |
|
|
for( ;; )
|
398 |
|
|
{
|
399 |
|
|
/* Wait for the next message to arrive. */
|
400 |
|
|
xQueueReceive( xQueue, &lMessage, portMAX_DELAY );
|
401 |
|
|
|
402 |
|
|
switch( lMessage )
|
403 |
|
|
{
|
404 |
|
|
case mainREG_TEST_1_STILL_EXECUTING :
|
405 |
|
|
/* Message from task 1, so task 1 must still be executing. */
|
406 |
|
|
( ulStillAliveCounts[ 0 ] )++;
|
407 |
|
|
break;
|
408 |
|
|
|
409 |
|
|
case mainREG_TEST_2_STILL_EXECUTING :
|
410 |
|
|
/* Message from task 2, so task 2 must still be executing. */
|
411 |
|
|
( ulStillAliveCounts[ 1 ] )++;
|
412 |
|
|
break;
|
413 |
|
|
|
414 |
|
|
case mainPRINT_SYSTEM_STATUS :
|
415 |
|
|
/* Message from tick hook, time to print out the system
|
416 |
|
|
status. If messages has stopped arriving from either reg
|
417 |
|
|
test task then the status must be set to fail. */
|
418 |
|
|
if( ( ulStillAliveCounts[ 0 ] == 0 ) || ( ulStillAliveCounts[ 1 ] == 0 ) )
|
419 |
|
|
{
|
420 |
|
|
/* One or both of the test tasks are no longer sending
|
421 |
|
|
'still alive' messages. */
|
422 |
|
|
pcStatusMessage = "FAIL\r\n";
|
423 |
|
|
}
|
424 |
|
|
|
425 |
|
|
/* Print a pass/fail message to the terminal. This will be
|
426 |
|
|
visible in the CrossWorks IDE. */
|
427 |
|
|
debug_printf( pcStatusMessage );
|
428 |
|
|
|
429 |
|
|
/* Reset the count of 'still alive' messages. */
|
430 |
|
|
memset( ulStillAliveCounts, 0x00, sizeof( ulStillAliveCounts ) );
|
431 |
|
|
break;
|
432 |
|
|
|
433 |
|
|
default :
|
434 |
|
|
/* Something unexpected happened. Delete this task so the
|
435 |
|
|
error is apparent (no output will be displayed). */
|
436 |
|
|
prvDeleteMe();
|
437 |
|
|
break;
|
438 |
|
|
}
|
439 |
|
|
}
|
440 |
|
|
}
|
441 |
|
|
/*-----------------------------------------------------------*/
|
442 |
|
|
|
443 |
|
|
static void prvTestMemoryRegions( void )
|
444 |
|
|
{
|
445 |
|
|
long l;
|
446 |
|
|
char cTemp;
|
447 |
|
|
|
448 |
|
|
/* The check task (from which this function is called) is created in the
|
449 |
|
|
Privileged mode. The privileged array can be both read from and written
|
450 |
|
|
to while this task is privileged. */
|
451 |
|
|
cPrivilegedOnlyAccessArray[ 0 ] = 'a';
|
452 |
|
|
if( cPrivilegedOnlyAccessArray[ 0 ] != 'a' )
|
453 |
|
|
{
|
454 |
|
|
/* Something unexpected happened. Delete this task so the error is
|
455 |
|
|
apparent (no output will be displayed). */
|
456 |
|
|
prvDeleteMe();
|
457 |
|
|
}
|
458 |
|
|
|
459 |
|
|
/* Writing off the end of the RAM allocated to this task will *NOT* cause a
|
460 |
|
|
protection fault because the task is still executing in a privileged mode.
|
461 |
|
|
Uncomment the following to test. */
|
462 |
|
|
/*cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] = 'a';*/
|
463 |
|
|
|
464 |
|
|
/* Now set the task into user mode. */
|
465 |
|
|
portSWITCH_TO_USER_MODE();
|
466 |
|
|
|
467 |
|
|
/* Accessing the privileged only array will now cause a fault. Uncomment
|
468 |
|
|
the following line to test. */
|
469 |
|
|
/*cPrivilegedOnlyAccessArray[ 0 ] = 'a';*/
|
470 |
|
|
|
471 |
|
|
/* The read/write array can still be successfully read and written. */
|
472 |
|
|
for( l = 0; l < mainREAD_WRITE_ALIGN_SIZE; l++ )
|
473 |
|
|
{
|
474 |
|
|
cReadWriteArray[ l ] = 'a';
|
475 |
|
|
if( cReadWriteArray[ l ] != 'a' )
|
476 |
|
|
{
|
477 |
|
|
/* Something unexpected happened. Delete this task so the error is
|
478 |
|
|
apparent (no output will be displayed). */
|
479 |
|
|
prvDeleteMe();
|
480 |
|
|
}
|
481 |
|
|
}
|
482 |
|
|
|
483 |
|
|
/* But attempting to read or write off the end of the RAM allocated to this
|
484 |
|
|
task will cause a fault. Uncomment either of the following two lines to
|
485 |
|
|
test. */
|
486 |
|
|
/* cReadWriteArray[ 0 ] = cReadWriteArray[ -1 ]; */
|
487 |
|
|
/* cReadWriteArray[ mainREAD_WRITE_ALIGN_SIZE ] = 0x00; */
|
488 |
|
|
|
489 |
|
|
/* The read only array can be successfully read... */
|
490 |
|
|
for( l = 0; l < mainREAD_ONLY_ALIGN_SIZE; l++ )
|
491 |
|
|
{
|
492 |
|
|
cTemp = cReadOnlyArray[ l ];
|
493 |
|
|
}
|
494 |
|
|
|
495 |
|
|
/* ...but cannot be written. Uncomment the following line to test. */
|
496 |
|
|
/* cReadOnlyArray[ 0 ] = 'a'; */
|
497 |
|
|
|
498 |
|
|
/* Writing to the first and last locations in the stack array should not
|
499 |
|
|
cause a protection fault. Note that doing this will cause the kernel to
|
500 |
|
|
detect a stack overflow if configCHECK_FOR_STACK_OVERFLOW is greater than
|
501 |
|
|
1. */
|
502 |
|
|
xCheckTaskStack[ 0 ] = 0;
|
503 |
|
|
xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS - 1 ] = 0;
|
504 |
|
|
|
505 |
|
|
/* Writing off either end of the stack array should cause a protection
|
506 |
|
|
fault, uncomment either of the following two lines to test. */
|
507 |
|
|
/* xCheckTaskStack[ -1 ] = 0; */
|
508 |
|
|
/* xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] = 0; */
|
509 |
|
|
}
|
510 |
|
|
/*-----------------------------------------------------------*/
|
511 |
|
|
|
512 |
|
|
static void prvRegTest1Task( void *pvParameters )
|
513 |
|
|
{
|
514 |
|
|
/* This task is created in privileged mode so can access the file scope
|
515 |
|
|
queue variable. Take a stack copy of this before the task is set into user
|
516 |
|
|
mode. Once this task is in user mode the file scope queue variable will no
|
517 |
|
|
longer be accessible but the stack copy will. */
|
518 |
|
|
xQueueHandle xQueue = xFileScopeCheckQueue;
|
519 |
|
|
|
520 |
|
|
/* Now the queue handle has been obtained the task can switch to user
|
521 |
|
|
mode. This is just one method of passing a handle into a protected
|
522 |
|
|
task, the other reg test task uses the task parameter instead. */
|
523 |
|
|
portSWITCH_TO_USER_MODE();
|
524 |
|
|
|
525 |
|
|
/* First check that the parameter value is as expected. */
|
526 |
|
|
if( pvParameters != ( void * ) 0x12345678 )
|
527 |
|
|
{
|
528 |
|
|
/* Error detected. Delete the task so it stops communicating with
|
529 |
|
|
the check task. */
|
530 |
|
|
prvDeleteMe();
|
531 |
|
|
}
|
532 |
|
|
|
533 |
|
|
|
534 |
|
|
for( ;; )
|
535 |
|
|
{
|
536 |
|
|
/* This task tests the kernel context switch mechanism by reading and
|
537 |
|
|
writing directly to registers - which requires the test to be written
|
538 |
|
|
in assembly code. */
|
539 |
|
|
__asm volatile
|
540 |
|
|
(
|
541 |
|
|
" MOV R4, #104 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */
|
542 |
|
|
" MOV R5, #105 \n"
|
543 |
|
|
" MOV R6, #106 \n"
|
544 |
|
|
" MOV R8, #108 \n"
|
545 |
|
|
" MOV R9, #109 \n"
|
546 |
|
|
" MOV R10, #110 \n"
|
547 |
|
|
" MOV R11, #111 \n"
|
548 |
|
|
"reg1loop: \n"
|
549 |
|
|
" MOV R0, #100 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */
|
550 |
|
|
" MOV R1, #101 \n"
|
551 |
|
|
" MOV R2, #102 \n"
|
552 |
|
|
" MOV R3, #103 \n"
|
553 |
|
|
" MOV R12, #112 \n"
|
554 |
|
|
" SVC #1 \n" /* Yield just to increase test coverage. */
|
555 |
|
|
" CMP R0, #100 \n" /* Check all the registers still contain their expected values. */
|
556 |
|
|
" BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task. */
|
557 |
|
|
" CMP R1, #101 \n"
|
558 |
|
|
" BNE prvDeleteMe \n"
|
559 |
|
|
" CMP R2, #102 \n"
|
560 |
|
|
" BNE prvDeleteMe \n"
|
561 |
|
|
" CMP R3, #103 \n"
|
562 |
|
|
" BNE prvDeleteMe \n"
|
563 |
|
|
" CMP R4, #104 \n"
|
564 |
|
|
" BNE prvDeleteMe \n"
|
565 |
|
|
" CMP R5, #105 \n"
|
566 |
|
|
" BNE prvDeleteMe \n"
|
567 |
|
|
" CMP R6, #106 \n"
|
568 |
|
|
" BNE prvDeleteMe \n"
|
569 |
|
|
" CMP R8, #108 \n"
|
570 |
|
|
" BNE prvDeleteMe \n"
|
571 |
|
|
" CMP R9, #109 \n"
|
572 |
|
|
" BNE prvDeleteMe \n"
|
573 |
|
|
" CMP R10, #110 \n"
|
574 |
|
|
" BNE prvDeleteMe \n"
|
575 |
|
|
" CMP R11, #111 \n"
|
576 |
|
|
" BNE prvDeleteMe \n"
|
577 |
|
|
" CMP R12, #112 \n"
|
578 |
|
|
" BNE prvDeleteMe \n"
|
579 |
|
|
:::"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10", "r11", "r12"
|
580 |
|
|
);
|
581 |
|
|
|
582 |
|
|
/* Send mainREG_TEST_1_STILL_EXECUTING to the check task to indicate that this
|
583 |
|
|
task is still functioning. */
|
584 |
|
|
prvSendImAlive( xQueue, mainREG_TEST_1_STILL_EXECUTING );
|
585 |
|
|
|
586 |
|
|
/* Go back to check all the register values again. */
|
587 |
|
|
__asm volatile( " B reg1loop " );
|
588 |
|
|
}
|
589 |
|
|
}
|
590 |
|
|
/*-----------------------------------------------------------*/
|
591 |
|
|
|
592 |
|
|
static void prvRegTest2Task( void *pvParameters )
|
593 |
|
|
{
|
594 |
|
|
/* The queue handle is passed in as the task parameter. This is one method of
|
595 |
|
|
passing data into a protected task, the other reg test task uses a different
|
596 |
|
|
method. */
|
597 |
|
|
xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
|
598 |
|
|
|
599 |
|
|
for( ;; )
|
600 |
|
|
{
|
601 |
|
|
/* This task tests the kernel context switch mechanism by reading and
|
602 |
|
|
writing directly to registers - which requires the test to be written
|
603 |
|
|
in assembly code. */
|
604 |
|
|
__asm volatile
|
605 |
|
|
(
|
606 |
|
|
" MOV R4, #4 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */
|
607 |
|
|
" MOV R5, #5 \n"
|
608 |
|
|
" MOV R6, #6 \n"
|
609 |
|
|
" MOV R8, #8 \n" /* Frame pointer is omitted as it must not be changed. */
|
610 |
|
|
" MOV R9, #9 \n"
|
611 |
|
|
" MOV R10, 10 \n"
|
612 |
|
|
" MOV R11, #11 \n"
|
613 |
|
|
"reg2loop: \n"
|
614 |
|
|
" MOV R0, #13 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */
|
615 |
|
|
" MOV R1, #1 \n"
|
616 |
|
|
" MOV R2, #2 \n"
|
617 |
|
|
" MOV R3, #3 \n"
|
618 |
|
|
" MOV R12, #12 \n"
|
619 |
|
|
" CMP R0, #13 \n" /* Check all the registers still contain their expected values. */
|
620 |
|
|
" BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task */
|
621 |
|
|
" CMP R1, #1 \n"
|
622 |
|
|
" BNE prvDeleteMe \n"
|
623 |
|
|
" CMP R2, #2 \n"
|
624 |
|
|
" BNE prvDeleteMe \n"
|
625 |
|
|
" CMP R3, #3 \n"
|
626 |
|
|
" BNE prvDeleteMe \n"
|
627 |
|
|
" CMP R4, #4 \n"
|
628 |
|
|
" BNE prvDeleteMe \n"
|
629 |
|
|
" CMP R5, #5 \n"
|
630 |
|
|
" BNE prvDeleteMe \n"
|
631 |
|
|
" CMP R6, #6 \n"
|
632 |
|
|
" BNE prvDeleteMe \n"
|
633 |
|
|
" CMP R8, #8 \n"
|
634 |
|
|
" BNE prvDeleteMe \n"
|
635 |
|
|
" CMP R9, #9 \n"
|
636 |
|
|
" BNE prvDeleteMe \n"
|
637 |
|
|
" CMP R10, #10 \n"
|
638 |
|
|
" BNE prvDeleteMe \n"
|
639 |
|
|
" CMP R11, #11 \n"
|
640 |
|
|
" BNE prvDeleteMe \n"
|
641 |
|
|
" CMP R12, #12 \n"
|
642 |
|
|
" BNE prvDeleteMe \n"
|
643 |
|
|
:::"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10", "r11", "r12"
|
644 |
|
|
);
|
645 |
|
|
|
646 |
|
|
/* Send mainREG_TEST_2_STILL_EXECUTING to the check task to indicate that this
|
647 |
|
|
task is still functioning. */
|
648 |
|
|
prvSendImAlive( xQueue, mainREG_TEST_2_STILL_EXECUTING );
|
649 |
|
|
|
650 |
|
|
/* Go back to check all the register values again. */
|
651 |
|
|
__asm volatile( " B reg2loop " );
|
652 |
|
|
}
|
653 |
|
|
}
|
654 |
|
|
/*-----------------------------------------------------------*/
|
655 |
|
|
|
656 |
|
|
void vApplicationIdleHook( void )
|
657 |
|
|
{
|
658 |
|
|
extern unsigned long __SRAM_segment_end__[];
|
659 |
|
|
extern unsigned long __privileged_data_start__[];
|
660 |
|
|
extern unsigned long __privileged_data_end__[];
|
661 |
|
|
extern unsigned long __FLASH_segment_start__[];
|
662 |
|
|
extern unsigned long __FLASH_segment_end__[];
|
663 |
|
|
volatile unsigned long *pul;
|
664 |
|
|
volatile unsigned long ulReadData;
|
665 |
|
|
|
666 |
|
|
/* The idle task, and therefore this function, run in Supervisor mode and
|
667 |
|
|
can therefore access all memory. Try reading from corners of flash and
|
668 |
|
|
RAM to ensure a memory fault does not occur.
|
669 |
|
|
|
670 |
|
|
Start with the edges of the privileged data area. */
|
671 |
|
|
pul = __privileged_data_start__;
|
672 |
|
|
ulReadData = *pul;
|
673 |
|
|
pul = __privileged_data_end__ - 1;
|
674 |
|
|
ulReadData = *pul;
|
675 |
|
|
|
676 |
|
|
/* Next the standard SRAM area. */
|
677 |
|
|
pul = __SRAM_segment_end__ - 1;
|
678 |
|
|
ulReadData = *pul;
|
679 |
|
|
|
680 |
|
|
/* And the standard Flash area - the start of which is marked for
|
681 |
|
|
privileged access only. */
|
682 |
|
|
pul = __FLASH_segment_start__;
|
683 |
|
|
ulReadData = *pul;
|
684 |
|
|
pul = __FLASH_segment_end__ - 1;
|
685 |
|
|
ulReadData = *pul;
|
686 |
|
|
|
687 |
|
|
/* Reading off the end of Flash or SRAM space should cause a fault.
|
688 |
|
|
Uncomment one of the following two pairs of lines to test. */
|
689 |
|
|
|
690 |
|
|
/* pul = __FLASH_segment_end__ + 4;
|
691 |
|
|
ulReadData = *pul; */
|
692 |
|
|
|
693 |
|
|
/* pul = __SRAM_segment_end__ + 1;
|
694 |
|
|
ulReadData = *pul; */
|
695 |
|
|
}
|
696 |
|
|
/*-----------------------------------------------------------*/
|
697 |
|
|
|
698 |
|
|
static void prvOldStyleUserModeTask( void *pvParameters )
|
699 |
|
|
{
|
700 |
|
|
extern unsigned long __privileged_data_start__[];
|
701 |
|
|
extern unsigned long __privileged_data_end__[];
|
702 |
|
|
extern unsigned long __SRAM_segment_end__[];
|
703 |
|
|
extern unsigned long __privileged_functions_end__[];
|
704 |
|
|
extern unsigned long __FLASH_segment_start__[];
|
705 |
|
|
extern unsigned long __FLASH_segment_end__[];
|
706 |
|
|
const volatile unsigned long *pulStandardPeripheralRegister = ( volatile unsigned long * ) 0x400FC0C4; /* PCONP */
|
707 |
|
|
volatile unsigned long *pul;
|
708 |
|
|
volatile unsigned long ulReadData;
|
709 |
|
|
|
710 |
|
|
/* The following lines are commented out to prevent the unused variable
|
711 |
|
|
compiler warnings when the tests that use the variable are also commented out.
|
712 |
|
|
extern unsigned long __privileged_functions_start__[];
|
713 |
|
|
const volatile unsigned long *pulSystemPeripheralRegister = ( volatile unsigned long * ) 0xe000e014; */
|
714 |
|
|
|
715 |
|
|
( void ) pvParameters;
|
716 |
|
|
|
717 |
|
|
/* This task is created in User mode using the original xTaskCreate() API
|
718 |
|
|
function. It should have access to all Flash and RAM except that marked
|
719 |
|
|
as Privileged access only. Reading from the start and end of the non-
|
720 |
|
|
privileged RAM should not cause a problem (the privileged RAM is the first
|
721 |
|
|
block at the bottom of the RAM memory). */
|
722 |
|
|
pul = __privileged_data_end__ + 1;
|
723 |
|
|
ulReadData = *pul;
|
724 |
|
|
pul = __SRAM_segment_end__ - 1;
|
725 |
|
|
ulReadData = *pul;
|
726 |
|
|
|
727 |
|
|
/* Likewise reading from the start and end of the non-privileged Flash
|
728 |
|
|
should not be a problem (the privileged Flash is the first block at the
|
729 |
|
|
bottom of the Flash memory). */
|
730 |
|
|
pul = __privileged_functions_end__ + 1;
|
731 |
|
|
ulReadData = *pul;
|
732 |
|
|
pul = __FLASH_segment_end__ - 1;
|
733 |
|
|
ulReadData = *pul;
|
734 |
|
|
|
735 |
|
|
/* Standard peripherals are accessible. */
|
736 |
|
|
ulReadData = *pulStandardPeripheralRegister;
|
737 |
|
|
|
738 |
|
|
/* System peripherals are not accessible. Uncomment the following line
|
739 |
|
|
to test. Also uncomment the declaration of pulSystemPeripheralRegister
|
740 |
|
|
at the top of this function. */
|
741 |
|
|
/* ulReadData = *pulSystemPeripheralRegister; */
|
742 |
|
|
|
743 |
|
|
/* Reading from anywhere inside the privileged Flash or RAM should cause a
|
744 |
|
|
fault. This can be tested by uncommenting any of the following pairs of
|
745 |
|
|
lines. Also uncomment the declaration of __privileged_functions_start__
|
746 |
|
|
at the top of this function. */
|
747 |
|
|
|
748 |
|
|
/* pul = __privileged_functions_start__;
|
749 |
|
|
ulReadData = *pul; */
|
750 |
|
|
|
751 |
|
|
/* pul = __privileged_functions_end__ - 1;
|
752 |
|
|
ulReadData = *pul; */
|
753 |
|
|
|
754 |
|
|
/* pul = __privileged_data_start__;
|
755 |
|
|
ulReadData = *pul; */
|
756 |
|
|
|
757 |
|
|
/* pul = __privileged_data_end__ - 1;
|
758 |
|
|
ulReadData = *pul; */
|
759 |
|
|
|
760 |
|
|
/* Must not just run off the end of a task function, so delete this task.
|
761 |
|
|
Note that because this task was created using xTaskCreate() the stack was
|
762 |
|
|
allocated dynamically and I have not included any code to free it again. */
|
763 |
|
|
vTaskDelete( NULL );
|
764 |
|
|
}
|
765 |
|
|
/*-----------------------------------------------------------*/
|
766 |
|
|
|
767 |
|
|
static void prvOldStylePrivilegedModeTask( void *pvParameters )
|
768 |
|
|
{
|
769 |
|
|
extern unsigned long __privileged_data_start__[];
|
770 |
|
|
extern unsigned long __privileged_data_end__[];
|
771 |
|
|
extern unsigned long __SRAM_segment_end__[];
|
772 |
|
|
extern unsigned long __privileged_functions_start__[];
|
773 |
|
|
extern unsigned long __privileged_functions_end__[];
|
774 |
|
|
extern unsigned long __FLASH_segment_start__[];
|
775 |
|
|
extern unsigned long __FLASH_segment_end__[];
|
776 |
|
|
volatile unsigned long *pul;
|
777 |
|
|
volatile unsigned long ulReadData;
|
778 |
|
|
const volatile unsigned long *pulSystemPeripheralRegister = ( volatile unsigned long * ) 0xe000e014; /* Systick */
|
779 |
|
|
const volatile unsigned long *pulStandardPeripheralRegister = ( volatile unsigned long * ) 0x400FC0C4; /* PCONP */
|
780 |
|
|
|
781 |
|
|
( void ) pvParameters;
|
782 |
|
|
|
783 |
|
|
/* This task is created in Privileged mode using the original xTaskCreate()
|
784 |
|
|
API function. It should have access to all Flash and RAM including that
|
785 |
|
|
marked as Privileged access only. So reading from the start and end of the
|
786 |
|
|
non-privileged RAM should not cause a problem (the privileged RAM is the
|
787 |
|
|
first block at the bottom of the RAM memory). */
|
788 |
|
|
pul = __privileged_data_end__ + 1;
|
789 |
|
|
ulReadData = *pul;
|
790 |
|
|
pul = __SRAM_segment_end__ - 1;
|
791 |
|
|
ulReadData = *pul;
|
792 |
|
|
|
793 |
|
|
/* Likewise reading from the start and end of the non-privileged Flash
|
794 |
|
|
should not be a problem (the privileged Flash is the first block at the
|
795 |
|
|
bottom of the Flash memory). */
|
796 |
|
|
pul = __privileged_functions_end__ + 1;
|
797 |
|
|
ulReadData = *pul;
|
798 |
|
|
pul = __FLASH_segment_end__ - 1;
|
799 |
|
|
ulReadData = *pul;
|
800 |
|
|
|
801 |
|
|
/* Reading from anywhere inside the privileged Flash or RAM should also
|
802 |
|
|
not be a problem. */
|
803 |
|
|
pul = __privileged_functions_start__;
|
804 |
|
|
ulReadData = *pul;
|
805 |
|
|
pul = __privileged_functions_end__ - 1;
|
806 |
|
|
ulReadData = *pul;
|
807 |
|
|
pul = __privileged_data_start__;
|
808 |
|
|
ulReadData = *pul;
|
809 |
|
|
pul = __privileged_data_end__ - 1;
|
810 |
|
|
ulReadData = *pul;
|
811 |
|
|
|
812 |
|
|
/* Finally, accessing both System and normal peripherals should both be
|
813 |
|
|
possible. */
|
814 |
|
|
ulReadData = *pulSystemPeripheralRegister;
|
815 |
|
|
ulReadData = *pulStandardPeripheralRegister;
|
816 |
|
|
|
817 |
|
|
/* Must not just run off the end of a task function, so delete this task.
|
818 |
|
|
Note that because this task was created using xTaskCreate() the stack was
|
819 |
|
|
allocated dynamically and I have not included any code to free it again. */
|
820 |
|
|
vTaskDelete( NULL );
|
821 |
|
|
}
|
822 |
|
|
/*-----------------------------------------------------------*/
|
823 |
|
|
|
824 |
|
|
static void prvDeleteMe( void )
|
825 |
|
|
{
|
826 |
|
|
vTaskDelete( NULL );
|
827 |
|
|
}
|
828 |
|
|
/*-----------------------------------------------------------*/
|
829 |
|
|
|
830 |
|
|
static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber )
|
831 |
|
|
{
|
832 |
|
|
if( xHandle != NULL )
|
833 |
|
|
{
|
834 |
|
|
xQueueSend( xHandle, &ulTaskNumber, mainDONT_BLOCK );
|
835 |
|
|
}
|
836 |
|
|
}
|
837 |
|
|
/*-----------------------------------------------------------*/
|
838 |
|
|
|
839 |
|
|
static void prvSetupHardware( void )
|
840 |
|
|
{
|
841 |
|
|
/* If running on Rev A2 silicon, turn the LDO voltage up to 2.75V. This is
|
842 |
|
|
a workaround to allow the PLL to operate reliably. */
|
843 |
|
|
if( DEVICE_IS_REVA2 )
|
844 |
|
|
{
|
845 |
|
|
SysCtlLDOSet( SYSCTL_LDO_2_75V );
|
846 |
|
|
}
|
847 |
|
|
|
848 |
|
|
/* Set the clocking to run from the PLL at 50 MHz */
|
849 |
|
|
SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ );
|
850 |
|
|
}
|
851 |
|
|
/*-----------------------------------------------------------*/
|
852 |
|
|
|
853 |
|
|
void vApplicationTickHook( void )
|
854 |
|
|
{
|
855 |
|
|
static unsigned long ulCallCount;
|
856 |
|
|
const unsigned long ulCallsBetweenSends = 5000 / portTICK_RATE_MS;
|
857 |
|
|
const unsigned long ulMessage = mainPRINT_SYSTEM_STATUS;
|
858 |
|
|
portBASE_TYPE xDummy;
|
859 |
|
|
|
860 |
|
|
/* If configUSE_TICK_HOOK is set to 1 then this function will get called
|
861 |
|
|
from each RTOS tick. It is called from the tick interrupt and therefore
|
862 |
|
|
will be executing in the privileged state. */
|
863 |
|
|
|
864 |
|
|
ulCallCount++;
|
865 |
|
|
|
866 |
|
|
/* Is it time to print out the pass/fail message again? */
|
867 |
|
|
if( ulCallCount >= ulCallsBetweenSends )
|
868 |
|
|
{
|
869 |
|
|
ulCallCount = 0;
|
870 |
|
|
|
871 |
|
|
/* Send a message to the check task to command it to check that all
|
872 |
|
|
the tasks are still running then print out the status.
|
873 |
|
|
|
874 |
|
|
This is running in an ISR so has to use the "FromISR" version of
|
875 |
|
|
xQueueSend(). Because it is in an ISR it is running with privileges
|
876 |
|
|
so can access xFileScopeCheckQueue directly. */
|
877 |
|
|
xQueueSendFromISR( xFileScopeCheckQueue, &ulMessage, &xDummy );
|
878 |
|
|
}
|
879 |
|
|
}
|
880 |
|
|
/*-----------------------------------------------------------*/
|
881 |
|
|
|
882 |
|
|
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
|
883 |
|
|
{
|
884 |
|
|
/* If configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2 then this
|
885 |
|
|
function will automatically get called if a task overflows its stack. */
|
886 |
|
|
( void ) pxTask;
|
887 |
|
|
( void ) pcTaskName;
|
888 |
|
|
for( ;; );
|
889 |
|
|
}
|
890 |
|
|
/*-----------------------------------------------------------*/
|
891 |
|
|
|
892 |
|
|
void vApplicationMallocFailedHook( void )
|
893 |
|
|
{
|
894 |
|
|
/* If configUSE_MALLOC_FAILED_HOOK is set to 1 then this function will
|
895 |
|
|
be called automatically if a call to pvPortMalloc() fails. pvPortMalloc()
|
896 |
|
|
is called automatically when a task, queue or semaphore is created. */
|
897 |
|
|
for( ;; );
|
898 |
|
|
}
|
899 |
|
|
/*-----------------------------------------------------------*/
|
900 |
|
|
|
901 |
|
|
/* Just to keep the linker happy. */
|
902 |
|
|
void __error__( char *pcFilename, unsigned long ulLine )
|
903 |
|
|
{
|
904 |
|
|
( void ) pcFilename;
|
905 |
|
|
( void ) ulLine;
|
906 |
|
|
for( ;; );
|
907 |
|
|
}
|
908 |
|
|
/*-----------------------------------------------------------*/
|
909 |
|
|
|
910 |
|
|
/* Just to keep the linker happy. */
|
911 |
|
|
int uipprintf( const char *fmt, ... )
|
912 |
|
|
{
|
913 |
|
|
( void ) fmt;
|
914 |
|
|
return( 0 );
|
915 |
|
|
}
|
916 |
|
|
/*-----------------------------------------------------------*/
|
917 |
|
|
|
918 |
|
|
void hard_fault_handler(unsigned int * hardfault_args)
|
919 |
|
|
{
|
920 |
|
|
volatile unsigned int stacked_r0;
|
921 |
|
|
volatile unsigned int stacked_r1;
|
922 |
|
|
volatile unsigned int stacked_r2;
|
923 |
|
|
volatile unsigned int stacked_r3;
|
924 |
|
|
volatile unsigned int stacked_r12;
|
925 |
|
|
volatile unsigned int stacked_lr;
|
926 |
|
|
volatile unsigned int stacked_pc;
|
927 |
|
|
volatile unsigned int stacked_psr;
|
928 |
|
|
|
929 |
|
|
stacked_r0 = ((unsigned long) hardfault_args[0]);
|
930 |
|
|
stacked_r1 = ((unsigned long) hardfault_args[1]);
|
931 |
|
|
stacked_r2 = ((unsigned long) hardfault_args[2]);
|
932 |
|
|
stacked_r3 = ((unsigned long) hardfault_args[3]);
|
933 |
|
|
|
934 |
|
|
stacked_r12 = ((unsigned long) hardfault_args[4]);
|
935 |
|
|
stacked_lr = ((unsigned long) hardfault_args[5]);
|
936 |
|
|
stacked_pc = ((unsigned long) hardfault_args[6]);
|
937 |
|
|
stacked_psr = ((unsigned long) hardfault_args[7]);
|
938 |
|
|
|
939 |
|
|
/* Inspect stacked_pc to locate the offending instruction. */
|
940 |
|
|
for( ;; );
|
941 |
|
|
}
|
942 |
|
|
/*-----------------------------------------------------------*/
|
943 |
|
|
|
944 |
|
|
void Fault_ISR( void ) __attribute__((naked));
|
945 |
|
|
void Fault_ISR( void )
|
946 |
|
|
{
|
947 |
|
|
__asm volatile
|
948 |
|
|
(
|
949 |
|
|
" tst lr, #4 \n"
|
950 |
|
|
" ite eq \n"
|
951 |
|
|
" mrseq r0, msp \n"
|
952 |
|
|
" mrsne r0, psp \n"
|
953 |
|
|
" ldr r1, [r0, #24] \n"
|
954 |
|
|
" ldr r2, handler_address_const \n"
|
955 |
|
|
" bx r2 \n"
|
956 |
|
|
" handler_address_const: .word hard_fault_handler \n"
|
957 |
|
|
);
|
958 |
|
|
}
|
959 |
|
|
/*-----------------------------------------------------------*/
|
960 |
|
|
|
961 |
|
|
void MPU_Fault_ISR( void ) __attribute__((naked));
|
962 |
|
|
void MPU_Fault_ISR( void )
|
963 |
|
|
{
|
964 |
|
|
__asm volatile
|
965 |
|
|
(
|
966 |
|
|
" tst lr, #4 \n"
|
967 |
|
|
" ite eq \n"
|
968 |
|
|
" mrseq r0, msp \n"
|
969 |
|
|
" mrsne r0, psp \n"
|
970 |
|
|
" ldr r1, [r0, #24] \n"
|
971 |
|
|
" ldr r2, handler_address_const \n"
|
972 |
|
|
" bx r2 \n"
|
973 |
|
|
" handler2_address_const: .word hard_fault_handler \n"
|
974 |
|
|
);
|
975 |
|
|
}
|
976 |
|
|
/*-----------------------------------------------------------*/
|