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