]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_GCC/main.c
Ready for V5.2.0 release.
[freertos] / Demo / CORTEX_LM3S811_GCC / 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 /*\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