]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_GCC/main.c
Prepare for V5.3.0 release.
[freertos] / Demo / CORTEX_LM3S811_GCC / main.c
1 /*\r
2         FreeRTOS.org V5.3.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         **NOTE** The exception to the GPL is included to allow you to distribute a\r
10         combined work that includes FreeRTOS.org without being obliged to provide\r
11         the source code for any proprietary components.  Alternative commercial\r
12         license and support terms are also available upon request.  See the \r
13         licensing section of http://www.FreeRTOS.org for full details.\r
14 \r
15         FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT\r
16         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
17         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
18         more details.\r
19 \r
20         You should have received a copy of the GNU General Public License along\r
21         with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59\r
22         Temple Place, Suite 330, Boston, MA  02111-1307  USA.\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 /*\r
54  * This project contains an application demonstrating the use of the\r
55  * FreeRTOS.org mini real time scheduler on the Luminary Micro LM3S811 Eval\r
56  * board.  See http://www.FreeRTOS.org for more information.\r
57  *\r
58  * main() simply sets up the hardware, creates all the demo application tasks,\r
59  * then starts the scheduler.  http://www.freertos.org/a00102.html provides\r
60  * more information on the standard demo tasks.\r
61  *\r
62  * In addition to a subset of the standard demo application tasks, main.c also\r
63  * defines the following tasks:\r
64  *\r
65  * + A 'Print' task.  The print task is the only task permitted to access the\r
66  * LCD - thus ensuring mutual exclusion and consistent access to the resource.\r
67  * Other tasks do not access the LCD directly, but instead send the text they\r
68  * wish to display to the print task.  The print task spends most of its time\r
69  * blocked - only waking when a message is queued for display.\r
70  *\r
71  * + A 'Button handler' task.  The eval board contains a user push button that\r
72  * is configured to generate interrupts.  The interrupt handler uses a\r
73  * semaphore to wake the button handler task - demonstrating how the priority\r
74  * mechanism can be used to defer interrupt processing to the task level.  The\r
75  * button handler task sends a message both to the LCD (via the print task) and\r
76  * the UART where it can be viewed using a dumb terminal (via the UART to USB\r
77  * converter on the eval board).  NOTES:  The dumb terminal must be closed in\r
78  * order to reflash the microcontroller.  A very basic interrupt driven UART\r
79  * driver is used that does not use the FIFO.  19200 baud is used.\r
80  *\r
81  * + A 'check' task.  The check task only executes every five seconds but has a\r
82  * high priority so is guaranteed to get processor time.  Its function is to\r
83  * check that all the other tasks are still operational and that no errors have\r
84  * been detected at any time.  If no errors have every been detected 'PASS' is\r
85  * written to the display (via the print task) - if an error has ever been\r
86  * detected the message is changed to 'FAIL'.  The position of the message is\r
87  * changed for each write.\r
88  */\r
89 \r
90 \r
91 \r
92 /* Environment includes. */\r
93 #include "DriverLib.h"\r
94 \r
95 /* Scheduler includes. */\r
96 #include "FreeRTOS.h"\r
97 #include "task.h"\r
98 #include "queue.h"\r
99 #include "semphr.h"\r
100 \r
101 /* Demo app includes. */\r
102 #include "integer.h"\r
103 #include "PollQ.h"\r
104 #include "semtest.h"\r
105 #include "BlockQ.h"\r
106 \r
107 /* Delay between cycles of the 'check' task. */\r
108 #define mainCHECK_DELAY                                         ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
109 \r
110 /* UART configuration - note this does not use the FIFO so is not very\r
111 efficient. */\r
112 #define mainBAUD_RATE                           ( 19200 )\r
113 #define mainFIFO_SET                            ( 0x10 )\r
114 \r
115 /* Demo task priorities. */\r
116 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
117 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
118 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
119 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 2 )\r
120 \r
121 /* Demo board specifics. */\r
122 #define mainPUSH_BUTTON             GPIO_PIN_4\r
123 \r
124 /* Misc. */\r
125 #define mainQUEUE_SIZE                          ( 3 )\r
126 #define mainDEBOUNCE_DELAY                      ( ( portTickType ) 150 / portTICK_RATE_MS )\r
127 #define mainNO_DELAY                            ( ( portTickType ) 0 )\r
128 /*\r
129  * Configure the processor and peripherals for this demo.\r
130  */\r
131 static void prvSetupHardware( void );\r
132 \r
133 /*\r
134  * The 'check' task, as described at the top of this file.\r
135  */\r
136 static void vCheckTask( void *pvParameters );\r
137 \r
138 /*\r
139  * The task that is woken by the ISR that processes GPIO interrupts originating\r
140  * from the push button.\r
141  */\r
142 static void vButtonHandlerTask( void *pvParameters );\r
143 \r
144 /*\r
145  * The task that controls access to the LCD.\r
146  */\r
147 static void vPrintTask( void *pvParameter );\r
148 \r
149 /* String that is transmitted on the UART. */\r
150 static portCHAR *cMessage = "Task woken by button interrupt! --- ";\r
151 static volatile portCHAR *pcNextChar;\r
152 \r
153 /* The semaphore used to wake the button handler task from within the GPIO\r
154 interrupt handler. */\r
155 xSemaphoreHandle xButtonSemaphore;\r
156 \r
157 /* The queue used to send strings to the print task for display on the LCD. */\r
158 xQueueHandle xPrintQueue;\r
159 \r
160 /*-----------------------------------------------------------*/\r
161 \r
162 int main( void )\r
163 {\r
164         /* Configure the clocks, UART and GPIO. */\r
165         prvSetupHardware();\r
166 \r
167         /* Create the semaphore used to wake the button handler task from the GPIO\r
168         ISR. */\r
169         vSemaphoreCreateBinary( xButtonSemaphore );\r
170         xSemaphoreTake( xButtonSemaphore, 0 );\r
171 \r
172         /* Create the queue used to pass message to vPrintTask. */\r
173         xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( portCHAR * ) );\r
174 \r
175         /* Start the standard demo tasks. */\r
176         vStartIntegerMathTasks( tskIDLE_PRIORITY );\r
177         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
178         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
179         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
180 \r
181         /* Start the tasks defined within the file. */\r
182         xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
183         xTaskCreate( vButtonHandlerTask, "Status", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY + 1, NULL );\r
184         xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );\r
185 \r
186         /* Start the scheduler. */\r
187         vTaskStartScheduler();\r
188 \r
189         /* Will only get here if there was insufficient heap to start the\r
190         scheduler. */\r
191 \r
192         return 0;\r
193 }\r
194 /*-----------------------------------------------------------*/\r
195 \r
196 static void vCheckTask( void *pvParameters )\r
197 {\r
198 portBASE_TYPE xErrorOccurred = pdFALSE;\r
199 portTickType xLastExecutionTime;\r
200 const portCHAR *pcPassMessage = "PASS";\r
201 const portCHAR *pcFailMessage = "FAIL";\r
202 \r
203         /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
204         works correctly. */\r
205         xLastExecutionTime = xTaskGetTickCount();\r
206 \r
207         for( ;; )\r
208         {\r
209                 /* Perform this check every mainCHECK_DELAY milliseconds. */\r
210                 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );\r
211 \r
212                 /* Has an error been found in any task? */\r
213 \r
214                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
215                 {\r
216                         xErrorOccurred = pdTRUE;\r
217                 }\r
218         \r
219                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
220                 {\r
221                         xErrorOccurred = pdTRUE;\r
222                 }\r
223         \r
224                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
225                 {\r
226                         xErrorOccurred = pdTRUE;\r
227                 }\r
228 \r
229                 if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
230                 {\r
231                         xErrorOccurred = pdTRUE;\r
232                 }\r
233 \r
234                 /* Send either a pass or fail message.  If an error is found it is\r
235                 never cleared again.  We do not write directly to the LCD, but instead\r
236                 queue a message for display by the print task. */\r
237                 if( xErrorOccurred == pdTRUE )\r
238                 {\r
239                         xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );\r
240                 }\r
241                 else\r
242                 {\r
243                         xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );\r
244                 }\r
245         }\r
246 }\r
247 /*-----------------------------------------------------------*/\r
248 \r
249 static void prvSetupHardware( void )\r
250 {\r
251         /* Setup the PLL. */\r
252         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
253 \r
254         /* Setup the push button. */\r
255         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);\r
256     GPIODirModeSet(GPIO_PORTC_BASE, mainPUSH_BUTTON, GPIO_DIR_MODE_IN);\r
257         GPIOIntTypeSet( GPIO_PORTC_BASE, mainPUSH_BUTTON,GPIO_FALLING_EDGE );\r
258         IntPrioritySet( INT_GPIOC, configKERNEL_INTERRUPT_PRIORITY );\r
259         GPIOPinIntEnable( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
260         IntEnable( INT_GPIOC );\r
261 \r
262 \r
263 \r
264         /* Enable the UART.  */\r
265         SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);\r
266         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);\r
267 \r
268         /* Set GPIO A0 and A1 as peripheral function.  They are used to output the\r
269         UART signals. */\r
270         GPIODirModeSet( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_DIR_MODE_HW );\r
271 \r
272         /* Configure the UART for 8-N-1 operation. */\r
273         UARTConfigSet( UART0_BASE, mainBAUD_RATE, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE );\r
274 \r
275         /* We don't want to use the fifo.  This is for test purposes to generate\r
276         as many interrupts as possible. */\r
277         HWREG( UART0_BASE + UART_O_LCR_H ) &= ~mainFIFO_SET;\r
278 \r
279         /* Enable Tx interrupts. */\r
280         HWREG( UART0_BASE + UART_O_IM ) |= UART_INT_TX;\r
281         IntPrioritySet( INT_UART0, configKERNEL_INTERRUPT_PRIORITY );\r
282         IntEnable( INT_UART0 );\r
283 \r
284 \r
285         /* Initialise the LCD> */\r
286     OSRAMInit( false );\r
287     OSRAMStringDraw("www.FreeRTOS.org", 0, 0);\r
288         OSRAMStringDraw("LM3S811 demo", 16, 1);\r
289 }\r
290 /*-----------------------------------------------------------*/\r
291 \r
292 static void vButtonHandlerTask( void *pvParameters )\r
293 {\r
294 const portCHAR *pcInterruptMessage = "Int";\r
295 \r
296         for( ;; )\r
297         {\r
298                 /* Wait for a GPIO interrupt to wake this task. */\r
299                 while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );\r
300 \r
301                 /* Start the Tx of the message on the UART. */\r
302                 UARTIntDisable( UART0_BASE, UART_INT_TX );\r
303                 {\r
304                         pcNextChar = cMessage;\r
305 \r
306                         /* Send the first character. */\r
307                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
308                         {\r
309                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
310                         }\r
311 \r
312                         pcNextChar++;\r
313                 }\r
314                 UARTIntEnable(UART0_BASE, UART_INT_TX);\r
315 \r
316                 /* Queue a message for the print task to display on the LCD. */\r
317                 xQueueSend( xPrintQueue, &pcInterruptMessage, portMAX_DELAY );\r
318 \r
319                 /* Make sure we don't process bounces. */\r
320                 vTaskDelay( mainDEBOUNCE_DELAY );\r
321                 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
322         }\r
323 }\r
324 \r
325 /*-----------------------------------------------------------*/\r
326 \r
327 void vUART_ISR(void)\r
328 {\r
329 unsigned portLONG ulStatus;\r
330 \r
331         /* What caused the interrupt. */\r
332         ulStatus = UARTIntStatus( UART0_BASE, pdTRUE );\r
333 \r
334         /* Clear the interrupt. */\r
335         UARTIntClear( UART0_BASE, ulStatus );\r
336 \r
337         /* Was a Tx interrupt pending? */\r
338         if( ulStatus & UART_INT_TX )\r
339         {\r
340                 /* Send the next character in the string.  We are not using the FIFO. */\r
341                 if( *pcNextChar != 0 )\r
342                 {\r
343                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
344                         {\r
345                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
346                         }\r
347                         pcNextChar++;\r
348                 }\r
349         }\r
350 }\r
351 /*-----------------------------------------------------------*/\r
352 \r
353 void vGPIO_ISR( void )\r
354 {\r
355 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
356 \r
357         /* Clear the interrupt. */\r
358         GPIOPinIntClear(GPIO_PORTC_BASE, mainPUSH_BUTTON);\r
359 \r
360         /* Wake the button handler task. */\r
361         xSemaphoreGiveFromISR( xButtonSemaphore, &xHigherPriorityTaskWoken );\r
362 \r
363         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
364 }\r
365 /*-----------------------------------------------------------*/\r
366 \r
367 static void vPrintTask( void *pvParameters )\r
368 {\r
369 portCHAR *pcMessage;\r
370 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;\r
371 \r
372         for( ;; )\r
373         {\r
374                 /* Wait for a message to arrive. */\r
375                 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );\r
376 \r
377                 /* Write the message to the LCD. */\r
378                 uxRow++;\r
379                 uxLine++;\r
380                 OSRAMClear();\r
381                 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);\r
382         }\r
383 }\r
384 \r