]> git.sur5r.net Git - freertos/blob - Demo/PIC32MX_MPLAB/main.c
Add PIC32 code.
[freertos] / Demo / PIC32MX_MPLAB / main.c
1 /*\r
2         FreeRTOS.org V4.6.1 - Copyright (C) 2003-2007 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         See http://www.FreeRTOS.org for documentation, latest information, license\r
28         and contact details.  Please ensure to read the configuration and relevant\r
29         port sections of the online documentation.\r
30 \r
31         Also see http://www.SafeRTOS.com a version that has been certified for use\r
32         in safety critical systems, plus commercial licensing, development and\r
33         support options.\r
34         ***************************************************************************\r
35 */\r
36 \r
37 /*\r
38  * Creates all the demo application tasks, then starts the scheduler.  The WEB\r
39  * documentation provides more details of the standard demo application tasks.\r
40  * In addition to the standard demo tasks, the following tasks and tests are\r
41  * defined and/or created within this file:\r
42  *\r
43  * "Fast Interrupt Test" - A high frequency periodic interrupt is generated\r
44  * using a free running timer to demonstrate the use of the\r
45  * configKERNEL_INTERRUPT_PRIORITY configuration constant.  The interrupt\r
46  * service routine measures the number of processor clocks that occur between\r
47  * each interrupt - and in so doing measures the jitter in the interrupt timing.\r
48  * The maximum measured jitter time is latched in the ulMaxJitter variable, and\r
49  * displayed on the LCD display by the 'LCD' task as described below.  The\r
50  * fast interrupt is configured and handled in the timertest.c source file.\r
51  *\r
52  * "LCD" task - the LCD task is a 'gatekeeper' task.  It is the only task that\r
53  * is permitted to access the display directly.  Other tasks wishing to write a\r
54  * message to the LCD send the message on a queue to the LCD task instead of\r
55  * accessing the LCD themselves.  The LCD task just blocks on the queue waiting\r
56  * for messages - waking and displaying the messages as they arrive.\r
57  *\r
58  * "Check" task -  This only executes every three seconds but has the highest\r
59  * priority so is guaranteed to get processor time.  Its main function is to \r
60  * check that all the standard demo tasks are still operational.  Should any \r
61  * unexpected behaviour within a demo task be discovered the check task will \r
62  * write an error to the LCD (via the LCD task).  If all the demo tasks are \r
63  * executing with their expected behaviour then the check task writes the \r
64  * maximum jitter time to the LCD (as described above) - again via the LCD task.\r
65  *\r
66  * "Register test" tasks - These tasks are used in part to test the kernel port.\r
67  * They set each processor register to a known value, then check that the \r
68  * register still contains that value.  Each of the tasks sets the registers\r
69  * to different values, and will get swapping in and out between setting and \r
70  * then subsequently checking the register values.  Discovery of an incorrect\r
71  * value would be indicative of an error in the task switching mechanism.\r
72  */\r
73 \r
74 /* Standard includes. */\r
75 #include <stdio.h>\r
76 \r
77 /* Scheduler includes. */\r
78 #include "FreeRTOS.h"\r
79 #include "task.h"\r
80 #include "queue.h"\r
81 \r
82 /* Demo application includes. */\r
83 #include "partest.h"\r
84 #include "integer.h"\r
85 #include "blocktim.h"\r
86 #include "flash.h"\r
87 #include "semtest.h"\r
88 #include "GenQTest.h"\r
89 #include "QPeek.h"\r
90 #include "lcd.h"\r
91 #include "comtest2.h"\r
92 #include "timertest.h"\r
93 \r
94 #pragma config FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF\r
95 #pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_2\r
96 \r
97 /*-----------------------------------------------------------*/\r
98 \r
99 /* The rate at which the LED controlled by the 'check' task will flash when no\r
100 errors have been detected. */\r
101 #define mainNO_ERROR_PERIOD     ( 3000 / portTICK_RATE_MS )\r
102 \r
103 /* The rate at which the LED controlled by the 'check' task will flash when an\r
104 error has been detected. */\r
105 #define mainERROR_PERIOD        ( 500 )\r
106 \r
107 /* The priorities of the various demo application tasks. */\r
108 #define mainCHECK_TASK_PRIORITY                         ( tskIDLE_PRIORITY + 4 )\r
109 #define mainSEM_TEST_PRIORITY                           ( tskIDLE_PRIORITY + 1 )\r
110 #define mainBLOCK_Q_PRIORITY                            ( tskIDLE_PRIORITY + 2 )\r
111 #define mainCOM_TEST_PRIORITY                           ( tskIDLE_PRIORITY + 2 )\r
112 #define mainINTEGER_TASK_PRIORITY           ( tskIDLE_PRIORITY )\r
113 #define mainGEN_QUEUE_TASK_PRIORITY                     ( tskIDLE_PRIORITY )\r
114 \r
115 /* The LED controlled by the 'check' task. */\r
116 #define mainCHECK_LED                                           ( 7 )\r
117 \r
118 /* The LED used by the comtest tasks.  mainCOM_TEST_LED + 1 is also used.\r
119 See the comtest.c file for more information. */\r
120 #define mainCOM_TEST_LED                                        ( 4 )\r
121 \r
122 /* Baud rate used by the comtest tasks. */\r
123 #define mainCOM_TEST_BAUD_RATE                          ( 115200 )\r
124 \r
125 /* Misc. */\r
126 #define mainDONT_WAIT                                           ( 0 )\r
127 \r
128 /* Dimension the buffer used to hold the value of the maximum jitter time when\r
129 it is converted to a string. */\r
130 #define mainMAX_STRING_LENGTH                           ( 20 )\r
131 \r
132 /* The frequency at which the "fast interrupt test" interrupt will occur. */\r
133 #define mainTEST_INTERRUPT_FREQUENCY            ( 20000 )\r
134 \r
135 /* The number of timer clocks we expect to occur between each "fast\r
136 interrupt test" interrupt. */\r
137 #define mainEXPECTED_CLOCKS_BETWEEN_INTERRUPTS ( ( configCPU_CLOCK_HZ >> 1 ) / mainTEST_INTERRUPT_FREQUENCY )\r
138 \r
139 /* The number of nano seconds between each core clock. */\r
140 #define mainNS_PER_CLOCK ( ( unsigned portLONG ) ( ( 1.0 / ( double ) ( configCPU_CLOCK_HZ >> 1 ) ) * 1000000000.0 ) )\r
141 \r
142 /*-----------------------------------------------------------*/\r
143 \r
144 /*\r
145  * Setup the processor ready for the demo.\r
146  */\r
147 static void prvSetupHardware( void );\r
148 \r
149 /*\r
150  * Implements the 'check' task functionality as described at the top of this \r
151  * file. \r
152  */\r
153 static void prvCheckTask( void *pvParameters ) __attribute__((noreturn));\r
154 \r
155 /*\r
156  * Tasks that test the context switch mechanism by filling the processor \r
157  * registers with known values, then checking that the values contained\r
158  * within the registers is as expected.  The tasks are likely to get swapped\r
159  * in and out between setting the register values and checking the register\r
160  * values. */\r
161 static void prvTestTask1( void *pvParameters );\r
162 static void prvTestTask2( void *pvParameters );\r
163 \r
164 /*-----------------------------------------------------------*/\r
165 \r
166 /* The queue used to send messages to the LCD task. */\r
167 static xQueueHandle xLCDQueue;\r
168 \r
169 /* Flag used by prvTestTask1() and prvTestTask2() to indicate their status\r
170 (pass/fail). */\r
171 unsigned portLONG ulStatus1 = pdPASS;\r
172 \r
173 /* Variables incremented by prvTestTask1() and prvTestTask2() respectively on \r
174 each iteration of their function.  This is used to detect either task stopping\r
175 their execution.. */\r
176 unsigned portLONG ulRegTest1Cycles = 0, ulRegTest2Cycles = 0;\r
177 \r
178 /*-----------------------------------------------------------*/\r
179 \r
180 \r
181 /*\r
182  * Create the demo tasks then start the scheduler.\r
183  */\r
184 int main( void )\r
185 {\r
186         /* Configure any hardware required for this demo. */\r
187         prvSetupHardware();\r
188 \r
189         /* Create the LCD task - this returns the queue to use when writing \r
190         messages to the LCD. */\r
191         xLCDQueue = xStartLCDTask();\r
192 \r
193         /* Create all the other standard demo tasks. */\r
194         vStartLEDFlashTasks( tskIDLE_PRIORITY );\r
195     vCreateBlockTimeTasks();\r
196     vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
197     vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );\r
198     vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );\r
199     vStartQueuePeekTasks();\r
200         vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
201 \r
202         /* Create the tasks defined within this file. */\r
203         xTaskCreate( prvTestTask1, "Tst1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
204         xTaskCreate( prvTestTask2, "Tst2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
205 \r
206         /* prvCheckTask uses sprintf so requires more stack. */\r
207         xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE * 2, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
208 \r
209         /* Setup the high frequency, high priority, timer test. */\r
210         vSetupTimerTest( mainTEST_INTERRUPT_FREQUENCY );\r
211 \r
212         /* Finally start the scheduler. */\r
213         vTaskStartScheduler();\r
214 \r
215         /* Will only reach here if there is insufficient heap available to start\r
216         the scheduler. */\r
217         return 0;\r
218 }\r
219 /*-----------------------------------------------------------*/\r
220 \r
221 static void prvTestTask1( void *pvParameters )\r
222 {\r
223 extern void vRegTest1( unsigned long * );\r
224 \r
225         for( ;; )\r
226         {\r
227                 /* Perform the register test function. */\r
228                 vRegTest1( &ulStatus1 );\r
229 \r
230                 /* Increment the counter so the check task knows we are still \r
231                 running. */\r
232                 ulRegTest1Cycles++;\r
233         }\r
234 }\r
235 /*-----------------------------------------------------------*/\r
236 \r
237 static void prvTestTask2( void *pvParameters )\r
238 {\r
239 extern void vRegTest2( unsigned long * );\r
240 \r
241         for( ;; )\r
242         {\r
243                 /* Perform the register test function. */\r
244                 vRegTest2( &ulStatus1 );\r
245 \r
246                 /* Increment the counter so the check task knows we are still\r
247                 running. */\r
248                 ulRegTest2Cycles++;\r
249         }\r
250 }\r
251 /*-----------------------------------------------------------*/\r
252 \r
253 static void prvSetupHardware( void )\r
254 {\r
255         /* Set the system and peripheral bus speeds and enable the program cache*/\r
256     SYSTEMConfigPerformance( configCPU_CLOCK_HZ );\r
257 \r
258         /* Setup to use the external interrupt controller. */\r
259     INTEnableSystemMultiVectoredInt();\r
260 \r
261         portDISABLE_INTERRUPTS();\r
262 \r
263         /* Setup the digital IO for the LED's. */\r
264         vParTestInitialise();\r
265 }\r
266 /*-----------------------------------------------------------*/\r
267 \r
268 static void prvCheckTask( void *pvParameters )\r
269 {\r
270 unsigned portLONG ulLastRegTest1Value = 0, ulLastRegTest2Value = 0, ulTicksToWait = mainNO_ERROR_PERIOD;\r
271 portTickType xLastExecutionTime;\r
272 \r
273 /* Buffer into which the maximum jitter time is written as a string. */\r
274 static portCHAR cStringBuffer[ mainMAX_STRING_LENGTH ];\r
275 \r
276 /* The maximum jitter time measured by the fast interrupt test. */\r
277 extern unsigned portLONG ulMaxJitter ;\r
278 xLCDMessage xMessage = { ( 200 / portTICK_RATE_MS ), cStringBuffer };\r
279 \r
280         /* Initialise the variable used to control our iteration rate prior to\r
281         its first use. */\r
282         xLastExecutionTime = xTaskGetTickCount();\r
283 \r
284         for( ;; )\r
285         {\r
286                 /* Wait until it is time to run the tests again. */\r
287                 vTaskDelayUntil( &xLastExecutionTime, ulTicksToWait );\r
288 \r
289                 /* Has either register check 1 or 2 task discovered an error? */\r
290                 if( ulStatus1 != pdPASS )\r
291                 {\r
292                         ulTicksToWait = mainERROR_PERIOD;\r
293                         xMessage.pcMessage = "Error: Reg test1";\r
294                 }\r
295 \r
296                 /* Check that the register test 1 task is still running. */\r
297                 if( ulLastRegTest1Value == ulRegTest1Cycles )\r
298                 {\r
299                         ulTicksToWait = mainERROR_PERIOD;\r
300                         xMessage.pcMessage = "Error: Reg test2";\r
301                 }\r
302                 ulLastRegTest1Value = ulRegTest1Cycles;\r
303 \r
304                 \r
305                 /* Check that the register test 2 task is still running. */\r
306                 if( ulLastRegTest2Value == ulRegTest2Cycles )\r
307                 {\r
308                         ulTicksToWait = mainERROR_PERIOD;\r
309                         xMessage.pcMessage = "Error: Reg test3";\r
310                 }\r
311                 ulLastRegTest2Value = ulRegTest2Cycles;\r
312                 \r
313 \r
314                 /* Have any of the standard demo tasks detected an error in their \r
315                 operation? */\r
316                 if( xAreGenericQueueTasksStillRunning() != pdTRUE )\r
317                 {\r
318                         ulTicksToWait = mainERROR_PERIOD;\r
319                         xMessage.pcMessage = "Error: Gen Q";\r
320                 }\r
321                 else if( xAreQueuePeekTasksStillRunning() != pdTRUE )\r
322                 {\r
323                         ulTicksToWait = mainERROR_PERIOD;\r
324                         xMessage.pcMessage = "Error: Q Peek";\r
325                 }\r
326                 else if( xAreComTestTasksStillRunning() != pdTRUE )\r
327                 {\r
328                         ulTicksToWait = mainERROR_PERIOD;\r
329                         xMessage.pcMessage = "Error: COM test";\r
330                 }\r
331                 else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
332                 {\r
333                         ulTicksToWait = mainERROR_PERIOD;\r
334                         xMessage.pcMessage = "Error: Blck time";\r
335                 }\r
336             else if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
337             {\r
338                 ulTicksToWait = mainERROR_PERIOD;\r
339                         xMessage.pcMessage = "Error: Sem test";\r
340             }\r
341             else if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
342             {\r
343                 ulTicksToWait = mainERROR_PERIOD;\r
344                         xMessage.pcMessage = "Error: Int math";\r
345             }\r
346 \r
347                 /* Write the max jitter time to the string buffer.  It will only be \r
348                 displayed if no errors have been detected. */\r
349                 sprintf( cStringBuffer, "%dns max jitter", ( int ) ( ( ulMaxJitter - mainEXPECTED_CLOCKS_BETWEEN_INTERRUPTS ) * mainNS_PER_CLOCK ) );\r
350 \r
351                 xQueueSend( xLCDQueue, &xMessage, mainDONT_WAIT );\r
352                 vParTestToggleLED( mainCHECK_LED );\r
353         }\r
354 }\r
355 /*-----------------------------------------------------------*/\r
356 \r
357 void vApplicationGeneralExceptionHandler( unsigned portLONG ulCause, unsigned portLONG ulStatus )\r
358 {\r
359         /* This overrides the definition provided by the kernel.  Other exceptions \r
360         should be handled here. */\r
361         for( ;; );\r
362 }\r