]> git.sur5r.net Git - freertos/blob - Demo/ARM7_LPC2138_Rowley/main.c
Ready for V5.2.0 release.
[freertos] / Demo / ARM7_LPC2138_Rowley / 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  * This file contains a demo created to execute on the Rowley Associates\r
54  * LPC2138 CrossFire development board.\r
55  *\r
56  * main() creates all the demo application tasks, then starts the scheduler.  \r
57  * The WEB documentation provides more details of the standard demo application \r
58  * tasks.\r
59  * \r
60  * Main.c also creates a task called "Check".  This only executes every few \r
61  * seconds but has a high priority so is guaranteed to get processor time.  \r
62  * Its function is to check that all the other tasks are still operational.\r
63  * Each standard demo task maintains a unique count that is incremented each \r
64  * time the task successfully completes its function.  Should any error occur \r
65  * within such a task the count is permanently halted.  The check task inspects \r
66  * the count of each task to ensure it has changed since the last time the \r
67  * check task executed.  If all the count variables have changed all the tasks \r
68  * are still executing error free, and the check task writes "PASS" to the\r
69  * CrossStudio terminal IO window.  Should any task contain an error at any time \r
70  * the error is latched and "FAIL" written to the terminal IO window.\r
71  *\r
72  * Finally, main() sets up an interrupt service routine and task to handle\r
73  * pushes of the button that is built into the CrossFire board.  When the button\r
74  * is pushed the ISR wakes the button task - which generates a table of task\r
75  * status information which is also displayed on the terminal IO window. \r
76  *\r
77  * A print task is defined to ensure exclusive and consistent access to the \r
78  * terminal IO.  This is the only task that is allowed to access the terminal.\r
79  * The check and button task therefore do not access the terminal directly but \r
80  * instead pass a pointer to the message they wish to display to the print task.\r
81  */\r
82 \r
83 /* Standard includes. */\r
84 #include <__cross_studio_io.h>\r
85 \r
86 /* Scheduler includes. */\r
87 #include "FreeRTOS.h"\r
88 #include "task.h"\r
89 #include "queue.h"\r
90 #include "semphr.h"\r
91 \r
92 /* Demo app includes. */\r
93 #include "BlockQ.h"\r
94 #include "death.h"\r
95 #include "dynamic.h"\r
96 #include "integer.h"\r
97 #include "PollQ.h"\r
98 #include "blocktim.h"\r
99 #include "recmutex.h"\r
100 \r
101 /* Hardware configuration definitions. */\r
102 #define mainBUS_CLK_FULL                                        ( ( unsigned portCHAR ) 0x01 )\r
103 #define mainLED_BIT                                                     0x80000000\r
104 #define mainP0_14__EINT_1                                       ( 2 << 28 )\r
105 #define mainEINT_1_EDGE_SENSITIVE                       2\r
106 #define mainEINT_1_FALLING_EDGE_SENSITIVE       0\r
107 #define mainEINT_1_CHANNEL                                      15\r
108 #define mainEINT_1_VIC_CHANNEL_BIT                      ( 1 << mainEINT_1_CHANNEL )\r
109 #define mainEINT_1_ENABLE_BIT                           ( 1 << 5 )\r
110 \r
111 /* Demo application definitions. */\r
112 #define mainQUEUE_SIZE                                          ( 3 )\r
113 #define mainLED_DELAY                                           ( ( portTickType ) 500 / portTICK_RATE_MS )\r
114 #define mainERROR_LED_DELAY                                     ( ( portTickType ) 50 / portTICK_RATE_MS )\r
115 #define mainCHECK_DELAY                                         ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
116 #define mainLIST_BUFFER_SIZE                            2048\r
117 #define mainNO_DELAY                                            ( 0 )\r
118 #define mainSHORT_DELAY                                         ( 150 / portTICK_RATE_MS )\r
119 \r
120 /* Task priorities. */\r
121 #define mainLED_TASK_PRIORITY                           ( tskIDLE_PRIORITY + 2 )\r
122 #define mainQUEUE_POLL_PRIORITY                         ( tskIDLE_PRIORITY + 2 )\r
123 #define mainCHECK_TASK_PRIORITY                         ( tskIDLE_PRIORITY + 3 )\r
124 #define mainSEM_TEST_PRIORITY                           ( tskIDLE_PRIORITY + 1 )\r
125 #define mainBLOCK_Q_PRIORITY                            ( tskIDLE_PRIORITY + 2 )\r
126 #define mainPRINT_TASK_PRIORITY                         ( tskIDLE_PRIORITY + 0 )\r
127 \r
128 /*-----------------------------------------------------------*/\r
129 \r
130 /* The semaphore used to wake the button task from within the external interrupt\r
131 handler. */\r
132 xSemaphoreHandle xButtonSemaphore;\r
133 \r
134 /* The queue that is used to send message to vPrintTask for display in the \r
135 terminal output window. */\r
136 xQueueHandle xPrintQueue;\r
137 \r
138 /* The rate at which the LED will toggle.  The toggle rate increases if an\r
139 error is detected in any task. */\r
140 static portTickType xLED_Delay = mainLED_DELAY;\r
141 /*-----------------------------------------------------------*/\r
142 \r
143 /*\r
144  * Simply flashes the on board LED every mainLED_DELAY milliseconds.\r
145  */\r
146 static void vLEDTask( void *pvParameters );\r
147 \r
148 /*\r
149  * Checks the status of all the demo tasks then prints a message to the\r
150  * CrossStudio terminal IO windows.  The message will be either PASS or FAIL\r
151  * depending on the status of the demo applications tasks.  A FAIL status will\r
152  * be latched.\r
153  *\r
154  * Messages are not written directly to the terminal, but passed to vPrintTask\r
155  * via a queue.\r
156  */\r
157 static void vCheckTask( void *pvParameters );\r
158 \r
159 /*\r
160  * Controls all terminal output.  If a task wants to send a message to the\r
161  * terminal IO it posts a pointer to the text to vPrintTask via a queue.  This\r
162  * ensures serial access to the terminal IO.\r
163  */\r
164 static void vPrintTask( void *pvParameter );\r
165 \r
166 /*\r
167  * Simply waits for an interrupt to be generated from the built in button, then\r
168  * generates a table of tasks states that is then written by vPrintTask to the\r
169  * terminal output window within CrossStudio.\r
170  */\r
171 static void vButtonHandlerTask( void *pvParameters );\r
172 \r
173 /*-----------------------------------------------------------*/\r
174 \r
175 int main( void )\r
176 {\r
177         /* Setup the peripheral bus to be the same as the PLL output. */\r
178         VPBDIV = mainBUS_CLK_FULL;\r
179 \r
180         /* Create the queue used to pass message to vPrintTask. */\r
181         xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( portCHAR * ) );\r
182 \r
183         /* Create the semaphore used to wake vButtonHandlerTask(). */\r
184         vSemaphoreCreateBinary( xButtonSemaphore );\r
185         xSemaphoreTake( xButtonSemaphore, 0 );\r
186 \r
187         /* Start the standard demo tasks. */\r
188         vStartIntegerMathTasks( tskIDLE_PRIORITY );\r
189         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
190         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
191         vStartDynamicPriorityTasks();\r
192         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
193 \r
194         #if configUSE_PREEMPTION == 1\r
195         {\r
196                 /* The timing of console output when not using the preemptive \r
197                 scheduler causes the block time tests to detect a timing problem. */\r
198                 vCreateBlockTimeTasks();\r
199         }\r
200         #endif\r
201 \r
202     vStartRecursiveMutexTasks();\r
203 \r
204         /* Start the tasks defined within this file. */\r
205         xTaskCreate( vLEDTask, "LED", configMINIMAL_STACK_SIZE, NULL, mainLED_TASK_PRIORITY, NULL );\r
206     xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
207     xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainPRINT_TASK_PRIORITY, NULL );\r
208     xTaskCreate( vButtonHandlerTask, "Button", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
209 \r
210         /* Start the scheduler. */\r
211         vTaskStartScheduler();\r
212 \r
213         /* The scheduler should now be running, so we will only ever reach here if we\r
214         ran out of heap space. */\r
215 \r
216         return 0;\r
217 }\r
218 /*-----------------------------------------------------------*/\r
219 \r
220 static void vLEDTask( void *pvParameters )\r
221 {\r
222         /* Configure IO. */\r
223         IO0DIR |= mainLED_BIT;\r
224         IO0SET = mainLED_BIT;\r
225 \r
226         for( ;; )\r
227         {\r
228                 /* Not very exiting - just delay... */\r
229                 vTaskDelay( xLED_Delay );\r
230 \r
231                 /* ...set the IO ... */\r
232         IO0CLR = mainLED_BIT;\r
233 \r
234                 /* ...delay again... */\r
235                 vTaskDelay( xLED_Delay );\r
236 \r
237                 /* ...then clear the IO. */\r
238                 IO0SET = mainLED_BIT;\r
239         }\r
240 }\r
241 /*-----------------------------------------------------------*/\r
242 \r
243 static void vCheckTask( void *pvParameters )\r
244 {\r
245 portBASE_TYPE xErrorOccurred = pdFALSE;\r
246 portTickType xLastExecutionTime;\r
247 const portCHAR * const pcPassMessage = "PASS\n";\r
248 const portCHAR * const pcFailMessage = "FAIL\n";\r
249 \r
250         /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
251         works correctly. */\r
252         xLastExecutionTime = xTaskGetTickCount();\r
253 \r
254         for( ;; )\r
255         {\r
256                 /* Perform this check every mainCHECK_DELAY milliseconds. */\r
257                 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );\r
258 \r
259                 /* Has an error been found in any task? */\r
260 \r
261                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
262                 {\r
263                         xErrorOccurred = pdTRUE;\r
264                 }\r
265         \r
266                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
267                 {\r
268                         xErrorOccurred = pdTRUE;\r
269                 }\r
270         \r
271                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
272                 {\r
273                         xErrorOccurred = pdTRUE;\r
274                 }\r
275         \r
276                 if( xAreDynamicPriorityTasksStillRunning() != pdTRUE )\r
277                 {\r
278                         xErrorOccurred = pdTRUE;\r
279                 }\r
280         \r
281                 if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
282                 {\r
283                         xErrorOccurred = pdTRUE;\r
284                 }\r
285 \r
286                 #if configUSE_PREEMPTION == 1\r
287                 {\r
288                         /* The timing of console output when not using the preemptive \r
289                         scheduler causes the block time tests to detect a timing problem. */\r
290                         if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )\r
291                         {\r
292                                 xErrorOccurred = pdTRUE;\r
293                         }\r
294                 }\r
295                 #endif\r
296 \r
297                 if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )\r
298                 {\r
299                         xErrorOccurred = pdTRUE;\r
300                 }\r
301 \r
302                 /* Send either a pass or fail message.  If an error is found it is\r
303                 never cleared again. */\r
304                 if( xErrorOccurred == pdTRUE )\r
305                 {\r
306                         xLED_Delay = mainERROR_LED_DELAY;\r
307                         xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );\r
308                 }\r
309                 else\r
310                 {\r
311                         xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );\r
312                 }\r
313         }\r
314 }\r
315 /*-----------------------------------------------------------*/\r
316 \r
317 static void vPrintTask( void *pvParameters )\r
318 {\r
319 portCHAR *pcMessage;\r
320 \r
321         for( ;; )\r
322         {\r
323                 /* Wait for a message to arrive. */\r
324                 while( xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY ) != pdPASS );\r
325 \r
326                 /* Write the message to the terminal IO. */\r
327                 #ifndef NDEBUG\r
328                         debug_printf( "%s", pcMessage );\r
329                 #endif\r
330         }\r
331 }\r
332 /*-----------------------------------------------------------*/\r
333 \r
334 static void vButtonHandlerTask( void *pvParameters )\r
335 {\r
336 static portCHAR cListBuffer[ mainLIST_BUFFER_SIZE ];\r
337 const portCHAR *pcList = &( cListBuffer[ 0 ] );\r
338 const portCHAR * const pcHeader = "\nTask          State  Priority  Stack       #\n************************************************";\r
339 extern void (vButtonISRWrapper) ( void );\r
340 \r
341         /* Configure the interrupt. */\r
342         portENTER_CRITICAL();   \r
343         {\r
344                 /* Configure P0.14 to generate interrupts. */\r
345                 PINSEL0 |= mainP0_14__EINT_1; \r
346                 EXTMODE = mainEINT_1_EDGE_SENSITIVE;\r
347                 EXTPOLAR = mainEINT_1_FALLING_EDGE_SENSITIVE;\r
348 \r
349                 /* Setup the VIC for EINT 1. */\r
350                 VICIntSelect &= ~mainEINT_1_VIC_CHANNEL_BIT;\r
351                 VICIntEnable |= mainEINT_1_VIC_CHANNEL_BIT;\r
352                 VICVectAddr1 = ( portLONG ) vButtonISRWrapper;\r
353                 VICVectCntl1 = mainEINT_1_ENABLE_BIT | mainEINT_1_CHANNEL;\r
354         }\r
355         portEXIT_CRITICAL();\r
356 \r
357         for( ;; )\r
358         {\r
359                 /* For debouncing, wait a while then clear the semaphore. */\r
360                 vTaskDelay( mainSHORT_DELAY );\r
361                 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
362 \r
363                 /* Wait for an interrupt. */\r
364                 xSemaphoreTake( xButtonSemaphore, portMAX_DELAY );\r
365 \r
366                 /* Send the column headers to the print task for display. */\r
367                 xQueueSend( xPrintQueue, &pcHeader, portMAX_DELAY );\r
368 \r
369                 /* Create the list of task states. */\r
370                 vTaskList( cListBuffer );\r
371 \r
372                 /* Send the task status information to the print task for display. */\r
373                 xQueueSend( xPrintQueue, &pcList, portMAX_DELAY );\r
374         }\r
375 }\r
376 /*-----------------------------------------------------------*/\r
377 \r
378 \r
379 \r
380 \r
381 \r
382 \r
383 \r