]> git.sur5r.net Git - freertos/blob - Demo/PIC32MX_MPLAB/main.c
Ready for V5.2.0 release.
[freertos] / Demo / PIC32MX_MPLAB / main.c
1 /*\r
2         FreeRTOS.org V5.2.0 - Copyright (C) 2003-2009 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \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 \r
10         FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT\r
11         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
12         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for \r
13         more details.\r
14 \r
15         You should have received a copy of the GNU General Public License along \r
16         with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 \r
17         Temple Place, Suite 330, Boston, MA  02111-1307  USA.\r
18 \r
19         A special exception to the GPL is included to allow you to distribute a \r
20         combined work that includes FreeRTOS.org without being obliged to provide\r
21         the source code for any proprietary components.  See the licensing section\r
22         of http://www.FreeRTOS.org for full details.\r
23 \r
24 \r
25         ***************************************************************************\r
26         *                                                                         *\r
27         * Get the FreeRTOS eBook!  See http://www.FreeRTOS.org/Documentation      *\r
28         *                                                                         *\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
33         * .zip file.                                                              *\r
34         *                                                                         *\r
35         ***************************************************************************\r
36 \r
37         1 tab == 4 spaces!\r
38 \r
39         Please ensure to read the configuration and relevant port sections of the\r
40         online documentation.\r
41 \r
42         http://www.FreeRTOS.org - Documentation, latest information, license and\r
43         contact details.\r
44 \r
45         http://www.SafeRTOS.com - A version that is certified for use in safety\r
46         critical systems.\r
47 \r
48         http://www.OpenRTOS.com - Commercial support, development, porting,\r
49         licensing and training services.\r
50 */\r
51 \r
52 /*\r
53  * Creates all the demo application tasks, then starts the scheduler.  The WEB\r
54  * documentation provides more details of the standard demo application tasks.\r
55  * In addition to the standard demo tasks, the following tasks and tests are\r
56  * defined and/or created within this file:\r
57  *\r
58  * "LCD" task - the LCD task is a 'gatekeeper' task.  It is the only task that\r
59  * is permitted to access the display directly.  Other tasks wishing to write a\r
60  * message to the LCD send the message on a queue to the LCD task instead of\r
61  * accessing the LCD themselves.  The LCD task just blocks on the queue waiting\r
62  * for messages - waking and displaying the messages as they arrive.\r
63  *\r
64  * "Check" task -  This only executes every three seconds but has the highest\r
65  * priority so is guaranteed to get processor time.  Its main function is to \r
66  * check that all the standard demo tasks are still operational.  Should any \r
67  * unexpected behaviour within a demo task be discovered the check task will \r
68  * write an error to the LCD (via the LCD task).  If all the demo tasks are \r
69  * executing with their expected behaviour then the check task instead writes \r
70  * a count of the number of times the high frequency interrupt has incremented\r
71  * ulHighFrequencyTimerInterrupts - which is one in every 20,000 interrupts.\r
72  *\r
73  * "Register test" tasks - These tasks are used in part to test the kernel port.\r
74  * They set each processor register to a known value, then check that the \r
75  * register still contains that value.  Each of the tasks sets the registers\r
76  * to different values, and will get swapping in and out between setting and \r
77  * then subsequently checking the register values.  Discovery of an incorrect\r
78  * value would be indicative of an error in the task switching mechanism.\r
79  *\r
80  * By way of demonstration, the demo application defines \r
81  * configMAX_SYSCALL_INTERRUPT_PRIORITY to be 3, configKERNEL_INTERRUPT_PRIORITY \r
82  * to be 1, and all other interrupts as follows:\r
83  *\r
84  *      + The UART is allocated a priority of 2. This means it can interrupt the \r
85  *    RTOS tick, and can also safely use queues.\r
86  *  + Two timers are configured to generate interrupts just to test the nesting \r
87  *    and queue access mechanisms. These timers are allocated priorities 2 and 3 \r
88  *    respectively. Even though they both access the same two queues, the \r
89  *    priority 3 interrupt can safely interrupt the priority 2 interrupt. Both \r
90  *    can interrupt the RTOS tick.\r
91  *  + Finally a high frequency timer interrupt is configured to use priority 4 - \r
92  *    therefore kernel activity will never prevent the high frequency timer from \r
93  *    executing immediately that the interrupt is raised (within the limitations \r
94  *    of the hardware itself). It would not be safe to access a queue from this \r
95  *    interrupt as it is above configMAX_SYSCALL_INTERRUPT_PRIORITY. \r
96  *\r
97  * See the online documentation for this demo for more information on interrupt\r
98  * usage.\r
99  */\r
100 \r
101 /* Standard includes. */\r
102 #include <stdio.h>\r
103 \r
104 /* Scheduler includes. */\r
105 #include "FreeRTOS.h"\r
106 #include "task.h"\r
107 #include "queue.h"\r
108 \r
109 /* Demo application includes. */\r
110 #include "partest.h"\r
111 #include "blocktim.h"\r
112 #include "flash.h"\r
113 #include "semtest.h"\r
114 #include "GenQTest.h"\r
115 #include "QPeek.h"\r
116 #include "lcd.h"\r
117 #include "comtest2.h"\r
118 #include "timertest.h"\r
119 #include "IntQueue.h"\r
120 \r
121 #pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF\r
122 #pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_2\r
123 \r
124 /*-----------------------------------------------------------*/\r
125 \r
126 /* The rate at which the LED controlled by the 'check' task will flash when no\r
127 errors have been detected. */\r
128 #define mainNO_ERROR_PERIOD     ( 3000 / portTICK_RATE_MS )\r
129 \r
130 /* The rate at which the LED controlled by the 'check' task will flash when an\r
131 error has been detected. */\r
132 #define mainERROR_PERIOD        ( 500 / portTICK_RATE_MS )\r
133 \r
134 /* The priorities of the various demo application tasks. */\r
135 #define mainCHECK_TASK_PRIORITY                         ( tskIDLE_PRIORITY + 4 )\r
136 #define mainSEM_TEST_PRIORITY                           ( tskIDLE_PRIORITY + 1 )\r
137 #define mainBLOCK_Q_PRIORITY                            ( tskIDLE_PRIORITY + 2 )\r
138 #define mainCOM_TEST_PRIORITY                           ( tskIDLE_PRIORITY + 2 )\r
139 #define mainINTEGER_TASK_PRIORITY           ( tskIDLE_PRIORITY )\r
140 #define mainGEN_QUEUE_TASK_PRIORITY                     ( tskIDLE_PRIORITY )\r
141 \r
142 /* The LED controlled by the 'check' task. */\r
143 #define mainCHECK_LED                                           ( 7 )\r
144 \r
145 /* The LED used by the comtest tasks.  mainCOM_TEST_LED + 1 is also used.\r
146 See the comtest.c file for more information. */\r
147 #define mainCOM_TEST_LED                                        ( 4 )\r
148 \r
149 /* Baud rate used by the comtest tasks. */\r
150 #define mainCOM_TEST_BAUD_RATE                          ( 115200 )\r
151 \r
152 /* Misc. */\r
153 #define mainDONT_WAIT                                           ( 0 )\r
154 \r
155 /* Dimension the buffer used to hold the value of the high frequency timer \r
156 count when it is converted to a string. */\r
157 #define mainMAX_STRING_LENGTH                           ( 20 )\r
158 \r
159 /* The frequency at which the "fast interrupt test" interrupt will occur. */\r
160 #define mainTEST_INTERRUPT_FREQUENCY            ( 20000 )\r
161 \r
162 /* The number of timer clocks we expect to occur between each "fast\r
163 interrupt test" interrupt. */\r
164 #define mainEXPECTED_CLOCKS_BETWEEN_INTERRUPTS ( ( configCPU_CLOCK_HZ >> 1 ) / mainTEST_INTERRUPT_FREQUENCY )\r
165 \r
166 /* The number of nano seconds between each core clock. */\r
167 #define mainNS_PER_CLOCK ( ( unsigned portLONG ) ( ( 1.0 / ( double ) ( configCPU_CLOCK_HZ >> 1 ) ) * 1000000000.0 ) )\r
168 \r
169 /*-----------------------------------------------------------*/\r
170 \r
171 /*\r
172  * Setup the processor ready for the demo.\r
173  */\r
174 static void prvSetupHardware( void );\r
175 \r
176 /*\r
177  * Implements the 'check' task functionality as described at the top of this \r
178  * file. \r
179  */\r
180 static void prvCheckTask( void *pvParameters ) __attribute__((noreturn));\r
181 \r
182 /*\r
183  * Tasks that test the context switch mechanism by filling the processor \r
184  * registers with known values, then checking that the values contained\r
185  * within the registers is as expected.  The tasks are likely to get swapped\r
186  * in and out between setting the register values and checking the register\r
187  * values. */\r
188 static void prvTestTask1( void *pvParameters );\r
189 static void prvTestTask2( void *pvParameters );\r
190 \r
191 /*-----------------------------------------------------------*/\r
192 \r
193 /* The queue used to send messages to the LCD task. */\r
194 static xQueueHandle xLCDQueue;\r
195 \r
196 /* Flag used by prvTestTask1() and prvTestTask2() to indicate their status\r
197 (pass/fail). */\r
198 unsigned portLONG ulStatus1 = pdPASS;\r
199 \r
200 /* Variables incremented by prvTestTask1() and prvTestTask2() respectively on \r
201 each iteration of their function.  This is used to detect either task stopping\r
202 their execution.. */\r
203 unsigned portLONG ulRegTest1Cycles = 0, ulRegTest2Cycles = 0;\r
204 \r
205 /*-----------------------------------------------------------*/\r
206 \r
207 /*\r
208  * Create the demo tasks then start the scheduler.\r
209  */\r
210 int main( void )\r
211 {\r
212         /* Configure any hardware required for this demo. */\r
213         prvSetupHardware();\r
214 \r
215         /* Create the LCD task - this returns the queue to use when writing \r
216         messages to the LCD. */\r
217         xLCDQueue = xStartLCDTask();\r
218 \r
219         /* Create all the other standard demo tasks. */\r
220         vStartLEDFlashTasks( tskIDLE_PRIORITY );\r
221     vCreateBlockTimeTasks();\r
222     vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
223     vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );\r
224     vStartQueuePeekTasks();\r
225         vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
226         vStartInterruptQueueTasks();\r
227 \r
228         /* Create the tasks defined within this file. */\r
229         xTaskCreate( prvTestTask1, "Tst1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
230         xTaskCreate( prvTestTask2, "Tst2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
231 \r
232         /* prvCheckTask uses sprintf so requires more stack. */\r
233         xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
234 \r
235         /* Finally start the scheduler. */\r
236         vTaskStartScheduler();\r
237 \r
238         /* Will only reach here if there is insufficient heap available to start\r
239         the scheduler. */\r
240         return 0;\r
241 }\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 static void prvTestTask1( void *pvParameters )\r
245 {\r
246 extern void vRegTest1( unsigned long * );\r
247 \r
248         for( ;; )\r
249         {\r
250                 /* Perform the register test function. */\r
251                 vRegTest1( &ulStatus1 );\r
252 \r
253                 /* Increment the counter so the check task knows we are still \r
254                 running. */\r
255                 ulRegTest1Cycles++;\r
256         }\r
257 }\r
258 /*-----------------------------------------------------------*/\r
259 \r
260 static void prvTestTask2( void *pvParameters )\r
261 {\r
262 extern void vRegTest2( unsigned long * );\r
263 \r
264         for( ;; )\r
265         {\r
266                 /* Perform the register test function. */\r
267                 vRegTest2( &ulStatus1 );\r
268 \r
269                 /* Increment the counter so the check task knows we are still\r
270                 running. */\r
271                 ulRegTest2Cycles++;\r
272         }\r
273 }\r
274 /*-----------------------------------------------------------*/\r
275 \r
276 static void prvSetupHardware( void )\r
277 {\r
278         /* Set the system and peripheral bus speeds and enable the program cache*/\r
279     SYSTEMConfigPerformance( configCPU_CLOCK_HZ - 1 );\r
280         mOSCSetPBDIV( OSC_PB_DIV_2 );\r
281 \r
282         /* Setup to use the external interrupt controller. */\r
283     INTEnableSystemMultiVectoredInt();\r
284 \r
285         portDISABLE_INTERRUPTS();\r
286 \r
287         /* Setup the digital IO for the LED's. */\r
288         vParTestInitialise();\r
289 }\r
290 /*-----------------------------------------------------------*/\r
291 \r
292 static void prvCheckTask( void *pvParameters )\r
293 {\r
294 unsigned portLONG ulLastRegTest1Value = 0, ulLastRegTest2Value = 0, ulTicksToWait = mainNO_ERROR_PERIOD;\r
295 portTickType xLastExecutionTime;\r
296 \r
297 /* Buffer into which the high frequency timer count is written as a string. */\r
298 static portCHAR cStringBuffer[ mainMAX_STRING_LENGTH ];\r
299 \r
300 /* The count of the high frequency timer interrupts. */\r
301 extern unsigned portLONG ulHighFrequencyTimerInterrupts;\r
302 xLCDMessage xMessage = { ( 200 / portTICK_RATE_MS ), cStringBuffer };\r
303 \r
304         /* Setup the high frequency, high priority, timer test.  It is setup here\r
305         to ensure it does not fire before the scheduler is started. */\r
306         vSetupTimerTest( mainTEST_INTERRUPT_FREQUENCY );\r
307 \r
308         /* Initialise the variable used to control our iteration rate prior to\r
309         its first use. */\r
310         xLastExecutionTime = xTaskGetTickCount();\r
311 \r
312         for( ;; )\r
313         {\r
314                 /* Wait until it is time to run the tests again. */\r
315                 vTaskDelayUntil( &xLastExecutionTime, ulTicksToWait );\r
316 \r
317                 /* Has either register check 1 or 2 task discovered an error? */\r
318                 if( ulStatus1 != pdPASS )\r
319                 {\r
320                         ulTicksToWait = mainERROR_PERIOD;\r
321                         xMessage.pcMessage = "Error: Reg test1";\r
322                 }\r
323 \r
324                 /* Check that the register test 1 task is still running. */\r
325                 if( ulLastRegTest1Value == ulRegTest1Cycles )\r
326                 {\r
327                         ulTicksToWait = mainERROR_PERIOD;\r
328                         xMessage.pcMessage = "Error: Reg test2";\r
329                 }\r
330                 ulLastRegTest1Value = ulRegTest1Cycles;\r
331 \r
332                 \r
333                 /* Check that the register test 2 task is still running. */\r
334                 if( ulLastRegTest2Value == ulRegTest2Cycles )\r
335                 {\r
336                         ulTicksToWait = mainERROR_PERIOD;\r
337                         xMessage.pcMessage = "Error: Reg test3";\r
338                 }\r
339                 ulLastRegTest2Value = ulRegTest2Cycles;\r
340                 \r
341 \r
342                 /* Have any of the standard demo tasks detected an error in their \r
343                 operation? */\r
344                 if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
345                 {\r
346                         ulTicksToWait = mainERROR_PERIOD;\r
347                         xMessage.pcMessage = "Error: Gen Q";\r
348                 }\r
349                 else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
350                 {\r
351                         ulTicksToWait = mainERROR_PERIOD;\r
352                         xMessage.pcMessage = "Error: Q Peek";\r
353                 }\r
354                 else if( xAreComTestTasksStillRunning() != pdTRUE )\r
355                 {\r
356                         ulTicksToWait = mainERROR_PERIOD;\r
357                         xMessage.pcMessage = "Error: COM test";\r
358                 }\r
359                 else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
360                 {\r
361                         ulTicksToWait = mainERROR_PERIOD;\r
362                         xMessage.pcMessage = "Error: Blck time";\r
363                 }\r
364             else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
365             {\r
366                 ulTicksToWait = mainERROR_PERIOD;\r
367                         xMessage.pcMessage = "Error: Sem test";\r
368             }\r
369                 else if( xAreIntQueueTasksStillRunning() != pdTRUE )\r
370                 {\r
371                         ulTicksToWait = mainERROR_PERIOD;\r
372                         xMessage.pcMessage = "Error: Int queue";\r
373                 }\r
374 \r
375                 /* Write the ulHighFrequencyTimerInterrupts value to the string \r
376                 buffer.  It will only be displayed if no errors have been detected. */\r
377                 sprintf( cStringBuffer, "Pass %u", ( unsigned int ) ulHighFrequencyTimerInterrupts );\r
378 \r
379                 xQueueSend( xLCDQueue, &xMessage, mainDONT_WAIT );\r
380                 vParTestToggleLED( mainCHECK_LED );\r
381         }\r
382 }\r
383 /*-----------------------------------------------------------*/\r
384 \r
385 void vApplicationStackOverflowHook( void )\r
386 {\r
387         /* Look at pxCurrentTCB to see which task overflowed its stack. */\r
388         for( ;; );\r
389 }\r
390 /*-----------------------------------------------------------*/\r
391 \r
392 void _general_exception_handler( unsigned portLONG ulCause, unsigned portLONG ulStatus )\r
393 {\r
394         /* This overrides the definition provided by the kernel.  Other exceptions \r
395         should be handled here. */\r
396         for( ;; );\r
397 }\r
398 /*-----------------------------------------------------------*/\r
399 \r