]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LM3S811_KEIL/main.c
Add additional critical section to the default tickless implementations.
[freertos] / FreeRTOS / Demo / CORTEX_LM3S811_KEIL / main.c
1 /*\r
2     FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
5 \r
6     ***************************************************************************\r
7      *                                                                       *\r
8      *    FreeRTOS provides completely free yet professionally developed,    *\r
9      *    robust, strictly quality controlled, supported, and cross          *\r
10      *    platform software that has become a de facto standard.             *\r
11      *                                                                       *\r
12      *    Help yourself get started quickly and support the FreeRTOS         *\r
13      *    project by purchasing a FreeRTOS tutorial book, reference          *\r
14      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
15      *                                                                       *\r
16      *    Thank you!                                                         *\r
17      *                                                                       *\r
18     ***************************************************************************\r
19 \r
20     This file is part of the FreeRTOS distribution.\r
21 \r
22     FreeRTOS is free software; you can redistribute it and/or modify it under\r
23     the terms of the GNU General Public License (version 2) as published by the\r
24     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
25 \r
26     >>! NOTE: The modification to the GPL is included to allow you to distribute\r
27     >>! a combined work that includes FreeRTOS without being obliged to provide\r
28     >>! the source code for proprietary components outside of the FreeRTOS\r
29     >>! kernel.\r
30 \r
31     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
32     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
33     FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
34     link: http://www.freertos.org/a00114.html\r
35 \r
36     1 tab == 4 spaces!\r
37 \r
38     ***************************************************************************\r
39      *                                                                       *\r
40      *    Having a problem?  Start by reading the FAQ "My application does   *\r
41      *    not run, what could be wrong?"                                     *\r
42      *                                                                       *\r
43      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
44      *                                                                       *\r
45     ***************************************************************************\r
46 \r
47     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
48     license and Real Time Engineers Ltd. contact details.\r
49 \r
50     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
51     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
52     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
53 \r
54     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
55     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
56     licenses offer ticketed support, indemnification and middleware.\r
57 \r
58     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
59     engineered and independently SIL3 certified version for use in safety and\r
60     mission critical applications that require provable dependability.\r
61 \r
62     1 tab == 4 spaces!\r
63 */\r
64 \r
65 \r
66 /*\r
67  * This project contains an application demonstrating the use of the \r
68  * FreeRTOS.org mini real time scheduler on the Luminary Micro LM3S811 Eval\r
69  * board.  See http://www.FreeRTOS.org for more information.\r
70  *\r
71  * main() simply sets up the hardware, creates all the demo application tasks, \r
72  * then starts the scheduler.  http://www.freertos.org/a00102.html provides\r
73  * more information on the standard demo tasks. \r
74  *\r
75  * In addition to a subset of the standard demo application tasks, main.c also\r
76  * defines the following tasks: \r
77  *\r
78  * + A 'Print' task.  The print task is the only task permitted to access the\r
79  * LCD - thus ensuring mutual exclusion and consistent access to the resource.\r
80  * Other tasks do not access the LCD directly, but instead send the text they\r
81  * wish to display to the print task.  The print task spends most of its time\r
82  * blocked - only waking when a message is queued for display.\r
83  *\r
84  * + A 'Button handler' task.  The eval board contains a user push button that\r
85  * is configured to generate interrupts.  The interrupt handler uses a \r
86  * semaphore to wake the button handler task - demonstrating how the priority \r
87  * mechanism can be used to defer interrupt processing to the task level.  The\r
88  * button handler task sends a message both to the LCD (via the print task) and\r
89  * the UART where it can be viewed using a dumb terminal (via the UART to USB\r
90  * converter on the eval board).  NOTES:  The dumb terminal must be closed in \r
91  * order to reflash the microcontroller.  A very basic interrupt driven UART\r
92  * driver is used that does not use the FIFO.  19200 baud is used.\r
93  *\r
94  * + A 'check' task.  The check task only executes every five seconds but has a\r
95  * high priority so is guaranteed to get processor time.  Its function is to\r
96  * check that all the other tasks are still operational and that no errors have\r
97  * been detected at any time.  If no errors have every been detected 'PASS' is\r
98  * written to the display (via the print task) - if an error has ever been\r
99  * detected the message is changed to 'FAIL'.  The position of the message is\r
100  * changed for each write.\r
101  */\r
102 \r
103 \r
104 \r
105 /* Environment includes. */\r
106 #include "DriverLib.h"\r
107 \r
108 /* Scheduler includes. */\r
109 #include "FreeRTOS.h"\r
110 #include "task.h"\r
111 #include "queue.h"\r
112 #include "semphr.h"\r
113 \r
114 /* Demo app includes. */\r
115 #include "integer.h"\r
116 #include "PollQ.h"\r
117 #include "semtest.h"\r
118 #include "BlockQ.h"\r
119 \r
120 /* Delay between cycles of the 'check' task. */\r
121 #define mainCHECK_DELAY                                         ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
122 \r
123 /* UART configuration - note this does not use the FIFO so is not very \r
124 efficient. */\r
125 #define mainBAUD_RATE                           ( 19200 )\r
126 #define mainFIFO_SET                            ( 0x10 )\r
127 \r
128 /* Demo task priorities. */\r
129 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
130 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
131 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
132 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 2 )\r
133 \r
134 /* Demo board specifics. */\r
135 #define mainPUSH_BUTTON             GPIO_PIN_4\r
136 \r
137 /* Misc. */\r
138 #define mainQUEUE_SIZE                          ( 3 )\r
139 #define mainDEBOUNCE_DELAY                      ( ( portTickType ) 150 / portTICK_RATE_MS )\r
140 #define mainNO_DELAY                            ( ( portTickType ) 0 )\r
141 /*\r
142  * Configure the processor and peripherals for this demo. \r
143  */\r
144 static void prvSetupHardware( void );\r
145 \r
146 /*\r
147  * The 'check' task, as described at the top of this file.\r
148  */\r
149 static void vCheckTask( void *pvParameters );\r
150 \r
151 /*\r
152  * The task that is woken by the ISR that processes GPIO interrupts originating\r
153  * from the push button.\r
154  */\r
155 static void vButtonHandlerTask( void *pvParameters );\r
156 \r
157 /*\r
158  * The task that controls access to the LCD.\r
159  */\r
160 static void vPrintTask( void *pvParameter );\r
161 \r
162 /* String that is transmitted on the UART. */\r
163 static char *cMessage = "Task woken by button interrupt! --- ";\r
164 static volatile char *pcNextChar;\r
165 \r
166 /* The semaphore used to wake the button handler task from within the GPIO\r
167 interrupt handler. */\r
168 xSemaphoreHandle xButtonSemaphore;\r
169 \r
170 /* The queue used to send strings to the print task for display on the LCD. */\r
171 xQueueHandle xPrintQueue;\r
172 \r
173 /* Newer library version. */\r
174 extern void UARTConfigSetExpClk(unsigned long ulBase, unsigned long ulUARTClk, unsigned long ulBaud, unsigned long ulConfig);\r
175 /*-----------------------------------------------------------*/\r
176 \r
177 int main( void )\r
178 {\r
179         /* Configure the clocks, UART and GPIO. */\r
180         prvSetupHardware();\r
181 \r
182         /* Create the semaphore used to wake the button handler task from the GPIO\r
183         ISR. */\r
184         vSemaphoreCreateBinary( xButtonSemaphore );\r
185         xSemaphoreTake( xButtonSemaphore, 0 );\r
186 \r
187         /* Create the queue used to pass message to vPrintTask. */\r
188         xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( char * ) );\r
189 \r
190         /* Start the standard demo tasks. */\r
191         vStartIntegerMathTasks( tskIDLE_PRIORITY );\r
192         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
193         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
194         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
195 \r
196         /* Start the tasks defined within the file. */\r
197         xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
198         xTaskCreate( vButtonHandlerTask, "Status", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY + 1, NULL );\r
199         xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );\r
200 \r
201         /* Start the scheduler. */\r
202         vTaskStartScheduler();\r
203 \r
204         /* Will only get here if there was insufficient heap to start the \r
205         scheduler. */\r
206 \r
207         return 0;\r
208 }\r
209 /*-----------------------------------------------------------*/\r
210 \r
211 static void vCheckTask( void *pvParameters )\r
212 {\r
213 portBASE_TYPE xErrorOccurred = pdFALSE;\r
214 portTickType xLastExecutionTime;\r
215 const char *pcPassMessage = "PASS";\r
216 const char *pcFailMessage = "FAIL";\r
217 \r
218         /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
219         works correctly. */\r
220         xLastExecutionTime = xTaskGetTickCount();\r
221 \r
222         for( ;; )\r
223         {\r
224                 /* Perform this check every mainCHECK_DELAY milliseconds. */\r
225                 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );\r
226 \r
227                 /* Has an error been found in any task? */\r
228 \r
229                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
230                 {\r
231                         xErrorOccurred = pdTRUE;\r
232                 }\r
233         \r
234                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
235                 {\r
236                         xErrorOccurred = pdTRUE;\r
237                 }\r
238         \r
239                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
240                 {\r
241                         xErrorOccurred = pdTRUE;\r
242                 }\r
243 \r
244                 if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
245                 {\r
246                         xErrorOccurred = pdTRUE;\r
247                 }\r
248 \r
249                 /* Send either a pass or fail message.  If an error is found it is\r
250                 never cleared again.  We do not write directly to the LCD, but instead\r
251                 queue a message for display by the print task. */\r
252                 if( xErrorOccurred == pdTRUE )\r
253                 {\r
254                         xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );\r
255                 }\r
256                 else\r
257                 {\r
258                         xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );\r
259                 }\r
260         }\r
261 }\r
262 /*-----------------------------------------------------------*/\r
263 \r
264 static void prvSetupHardware( void )\r
265 {\r
266         /* Setup the PLL. */\r
267         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
268 \r
269         /* Setup the push button. */\r
270         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);\r
271     GPIODirModeSet(GPIO_PORTC_BASE, mainPUSH_BUTTON, GPIO_DIR_MODE_IN);\r
272         GPIOIntTypeSet( GPIO_PORTC_BASE, mainPUSH_BUTTON,GPIO_FALLING_EDGE );\r
273         IntPrioritySet( INT_GPIOC, configKERNEL_INTERRUPT_PRIORITY );\r
274         GPIOPinIntEnable( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
275         IntEnable( INT_GPIOC );\r
276 \r
277 \r
278 \r
279         /* Enable the UART.  */\r
280         SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);\r
281         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);\r
282 \r
283         /* Set GPIO A0 and A1 as peripheral function.  They are used to output the\r
284         UART signals. */\r
285         GPIODirModeSet( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_DIR_MODE_HW );\r
286 \r
287         /* Configure the UART for 8-N-1 operation. */\r
288         UARTConfigSetExpClk( UART0_BASE, SysCtlClockGet(), mainBAUD_RATE, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE );\r
289 \r
290         /* We don't want to use the fifo.  This is for test purposes to generate\r
291         as many interrupts as possible. */\r
292         HWREG( UART0_BASE + UART_O_LCR_H ) &= ~mainFIFO_SET;\r
293 \r
294         /* Enable Tx interrupts. */\r
295         HWREG( UART0_BASE + UART_O_IM ) |= UART_INT_TX;\r
296         IntPrioritySet( INT_UART0, configKERNEL_INTERRUPT_PRIORITY );\r
297         IntEnable( INT_UART0 );\r
298 \r
299 \r
300         /* Initialise the LCD> */\r
301     OSRAMInit( false );\r
302     OSRAMStringDraw("www.FreeRTOS.org", 0, 0);\r
303         OSRAMStringDraw("LM3S811 demo", 16, 1);\r
304 }\r
305 /*-----------------------------------------------------------*/\r
306 \r
307 static void vButtonHandlerTask( void *pvParameters )\r
308 {\r
309 const char *pcInterruptMessage = "Int";\r
310 \r
311         for( ;; )\r
312         {\r
313                 /* Wait for a GPIO interrupt to wake this task. */\r
314                 while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );\r
315 \r
316                 /* Start the Tx of the message on the UART. */\r
317                 UARTIntDisable( UART0_BASE, UART_INT_TX );\r
318                 {\r
319                         pcNextChar = cMessage;\r
320 \r
321                         /* Send the first character. */\r
322                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
323                         {\r
324                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
325                         }\r
326 \r
327                         pcNextChar++;\r
328                 }\r
329                 UARTIntEnable(UART0_BASE, UART_INT_TX);\r
330 \r
331                 /* Queue a message for the print task to display on the LCD. */\r
332                 xQueueSend( xPrintQueue, &pcInterruptMessage, portMAX_DELAY );\r
333 \r
334                 /* Make sure we don't process bounces. */\r
335                 vTaskDelay( mainDEBOUNCE_DELAY );\r
336                 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
337         }\r
338 }\r
339 \r
340 /*-----------------------------------------------------------*/\r
341 \r
342 void vUART_ISR(void)\r
343 {\r
344 unsigned long ulStatus;\r
345 \r
346         /* What caused the interrupt. */\r
347         ulStatus = UARTIntStatus( UART0_BASE, pdTRUE );\r
348 \r
349         /* Clear the interrupt. */\r
350         UARTIntClear( UART0_BASE, ulStatus );\r
351 \r
352         /* Was a Tx interrupt pending? */\r
353         if( ulStatus & UART_INT_TX )\r
354         {\r
355                 /* Send the next character in the string.  We are not using the FIFO. */\r
356                 if( *pcNextChar != NULL )\r
357                 {\r
358                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
359                         {\r
360                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
361                         }\r
362                         pcNextChar++;\r
363                 }\r
364         }\r
365 }\r
366 /*-----------------------------------------------------------*/\r
367 \r
368 void vGPIO_ISR( void )\r
369 {\r
370 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
371 \r
372         /* Clear the interrupt. */\r
373         GPIOPinIntClear( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
374 \r
375         /* Wake the button handler task. */\r
376         xSemaphoreGiveFromISR( xButtonSemaphore, &xHigherPriorityTaskWoken );\r
377         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
378 }\r
379 /*-----------------------------------------------------------*/\r
380 \r
381 static void vPrintTask( void *pvParameters )\r
382 {\r
383 char *pcMessage;\r
384 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;\r
385 \r
386         for( ;; )\r
387         {\r
388                 /* Wait for a message to arrive. */\r
389                 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );\r
390 \r
391                 /* Write the message to the LCD. */\r
392                 uxRow++;\r
393                 uxLine++;\r
394                 OSRAMClear();\r
395                 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);\r
396         }\r
397 }\r
398 \r