]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LM3S811_KEIL/main.c
Ready for V5.1.1 release.
[freertos] / Demo / CORTEX_LM3S811_KEIL / 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 /*\r
52  * This project contains an application demonstrating the use of the \r
53  * FreeRTOS.org mini real time scheduler on the Luminary Micro LM3S811 Eval\r
54  * board.  See http://www.FreeRTOS.org for more information.\r
55  *\r
56  * main() simply sets up the hardware, creates all the demo application tasks, \r
57  * then starts the scheduler.  http://www.freertos.org/a00102.html provides\r
58  * more information on the standard demo tasks. \r
59  *\r
60  * In addition to a subset of the standard demo application tasks, main.c also\r
61  * defines the following tasks: \r
62  *\r
63  * + A 'Print' task.  The print task is the only task permitted to access the\r
64  * LCD - thus ensuring mutual exclusion and consistent access to the resource.\r
65  * Other tasks do not access the LCD directly, but instead send the text they\r
66  * wish to display to the print task.  The print task spends most of its time\r
67  * blocked - only waking when a message is queued for display.\r
68  *\r
69  * + A 'Button handler' task.  The eval board contains a user push button that\r
70  * is configured to generate interrupts.  The interrupt handler uses a \r
71  * semaphore to wake the button handler task - demonstrating how the priority \r
72  * mechanism can be used to defer interrupt processing to the task level.  The\r
73  * button handler task sends a message both to the LCD (via the print task) and\r
74  * the UART where it can be viewed using a dumb terminal (via the UART to USB\r
75  * converter on the eval board).  NOTES:  The dumb terminal must be closed in \r
76  * order to reflash the microcontroller.  A very basic interrupt driven UART\r
77  * driver is used that does not use the FIFO.  19200 baud is used.\r
78  *\r
79  * + A 'check' task.  The check task only executes every five seconds but has a\r
80  * high priority so is guaranteed to get processor time.  Its function is to\r
81  * check that all the other tasks are still operational and that no errors have\r
82  * been detected at any time.  If no errors have every been detected 'PASS' is\r
83  * written to the display (via the print task) - if an error has ever been\r
84  * detected the message is changed to 'FAIL'.  The position of the message is\r
85  * changed for each write.\r
86  */\r
87 \r
88 \r
89 \r
90 /* Environment includes. */\r
91 #include "DriverLib.h"\r
92 \r
93 /* Scheduler includes. */\r
94 #include "FreeRTOS.h"\r
95 #include "task.h"\r
96 #include "queue.h"\r
97 #include "semphr.h"\r
98 \r
99 /* Demo app includes. */\r
100 #include "integer.h"\r
101 #include "PollQ.h"\r
102 #include "semtest.h"\r
103 #include "BlockQ.h"\r
104 \r
105 /* Delay between cycles of the 'check' task. */\r
106 #define mainCHECK_DELAY                                         ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
107 \r
108 /* UART configuration - note this does not use the FIFO so is not very \r
109 efficient. */\r
110 #define mainBAUD_RATE                           ( 19200 )\r
111 #define mainFIFO_SET                            ( 0x10 )\r
112 \r
113 /* Demo task priorities. */\r
114 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
115 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
116 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
117 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 2 )\r
118 \r
119 /* Demo board specifics. */\r
120 #define mainPUSH_BUTTON             GPIO_PIN_4\r
121 \r
122 /* Misc. */\r
123 #define mainQUEUE_SIZE                          ( 3 )\r
124 #define mainDEBOUNCE_DELAY                      ( ( portTickType ) 150 / portTICK_RATE_MS )\r
125 #define mainNO_DELAY                            ( ( portTickType ) 0 )\r
126 /*\r
127  * Configure the processor and peripherals for this demo. \r
128  */\r
129 static void prvSetupHardware( void );\r
130 \r
131 /*\r
132  * The 'check' task, as described at the top of this file.\r
133  */\r
134 static void vCheckTask( void *pvParameters );\r
135 \r
136 /*\r
137  * The task that is woken by the ISR that processes GPIO interrupts originating\r
138  * from the push button.\r
139  */\r
140 static void vButtonHandlerTask( void *pvParameters );\r
141 \r
142 /*\r
143  * The task that controls access to the LCD.\r
144  */\r
145 static void vPrintTask( void *pvParameter );\r
146 \r
147 /* String that is transmitted on the UART. */\r
148 static portCHAR *cMessage = "Task woken by button interrupt! --- ";\r
149 static volatile portCHAR *pcNextChar;\r
150 \r
151 /* The semaphore used to wake the button handler task from within the GPIO\r
152 interrupt handler. */\r
153 xSemaphoreHandle xButtonSemaphore;\r
154 \r
155 /* The queue used to send strings to the print task for display on the LCD. */\r
156 xQueueHandle xPrintQueue;\r
157 \r
158 /* Newer library version. */\r
159 extern void UARTConfigSetExpClk(unsigned long ulBase, unsigned long ulUARTClk, unsigned long ulBaud, unsigned long ulConfig);\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         UARTConfigSetExpClk( UART0_BASE, SysCtlClockGet(), 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 != NULL )\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         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
363 }\r
364 /*-----------------------------------------------------------*/\r
365 \r
366 static void vPrintTask( void *pvParameters )\r
367 {\r
368 portCHAR *pcMessage;\r
369 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;\r
370 \r
371         for( ;; )\r
372         {\r
373                 /* Wait for a message to arrive. */\r
374                 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );\r
375 \r
376                 /* Write the message to the LCD. */\r
377                 uxRow++;\r
378                 uxLine++;\r
379                 OSRAMClear();\r
380                 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);\r
381         }\r
382 }\r
383 \r