]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LM3S811_GCC/main.c
21440a4d72c1a687413a5dfd928bf0d94cfddf35
[freertos] / FreeRTOS / Demo / CORTEX_LM3S811_GCC / main.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 /*\r
30  * This project contains an application demonstrating the use of the\r
31  * FreeRTOS.org mini real time scheduler on the Luminary Micro LM3S811 Eval\r
32  * board.  See http://www.FreeRTOS.org for more information.\r
33  *\r
34  * main() simply sets up the hardware, creates all the demo application tasks,\r
35  * then starts the scheduler.  http://www.freertos.org/a00102.html provides\r
36  * more information on the standard demo tasks.\r
37  *\r
38  * In addition to a subset of the standard demo application tasks, main.c also\r
39  * defines the following tasks:\r
40  *\r
41  * + A 'Print' task.  The print task is the only task permitted to access the\r
42  * LCD - thus ensuring mutual exclusion and consistent access to the resource.\r
43  * Other tasks do not access the LCD directly, but instead send the text they\r
44  * wish to display to the print task.  The print task spends most of its time\r
45  * blocked - only waking when a message is queued for display.\r
46  *\r
47  * + A 'Button handler' task.  The eval board contains a user push button that\r
48  * is configured to generate interrupts.  The interrupt handler uses a\r
49  * semaphore to wake the button handler task - demonstrating how the priority\r
50  * mechanism can be used to defer interrupt processing to the task level.  The\r
51  * button handler task sends a message both to the LCD (via the print task) and\r
52  * the UART where it can be viewed using a dumb terminal (via the UART to USB\r
53  * converter on the eval board).  NOTES:  The dumb terminal must be closed in\r
54  * order to reflash the microcontroller.  A very basic interrupt driven UART\r
55  * driver is used that does not use the FIFO.  19200 baud is used.\r
56  *\r
57  * + A 'check' task.  The check task only executes every five seconds but has a\r
58  * high priority so is guaranteed to get processor time.  Its function is to\r
59  * check that all the other tasks are still operational and that no errors have\r
60  * been detected at any time.  If no errors have every been detected 'PASS' is\r
61  * written to the display (via the print task) - if an error has ever been\r
62  * detected the message is changed to 'FAIL'.  The position of the message is\r
63  * changed for each write.\r
64  */\r
65 \r
66 \r
67 \r
68 /* Environment includes. */\r
69 #include "DriverLib.h"\r
70 \r
71 /* Scheduler includes. */\r
72 #include "FreeRTOS.h"\r
73 #include "task.h"\r
74 #include "queue.h"\r
75 #include "semphr.h"\r
76 \r
77 /* Demo app includes. */\r
78 #include "integer.h"\r
79 #include "PollQ.h"\r
80 #include "semtest.h"\r
81 #include "BlockQ.h"\r
82 \r
83 /* Delay between cycles of the 'check' task. */\r
84 #define mainCHECK_DELAY                                         ( ( TickType_t ) 5000 / portTICK_PERIOD_MS )\r
85 \r
86 /* UART configuration - note this does not use the FIFO so is not very\r
87 efficient. */\r
88 #define mainBAUD_RATE                           ( 19200 )\r
89 #define mainFIFO_SET                            ( 0x10 )\r
90 \r
91 /* Demo task priorities. */\r
92 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
93 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
94 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
95 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 2 )\r
96 \r
97 /* Demo board specifics. */\r
98 #define mainPUSH_BUTTON             GPIO_PIN_4\r
99 \r
100 /* Misc. */\r
101 #define mainQUEUE_SIZE                          ( 3 )\r
102 #define mainDEBOUNCE_DELAY                      ( ( TickType_t ) 150 / portTICK_PERIOD_MS )\r
103 #define mainNO_DELAY                            ( ( TickType_t ) 0 )\r
104 /*\r
105  * Configure the processor and peripherals for this demo.\r
106  */\r
107 static void prvSetupHardware( void );\r
108 \r
109 /*\r
110  * The 'check' task, as described at the top of this file.\r
111  */\r
112 static void vCheckTask( void *pvParameters );\r
113 \r
114 /*\r
115  * The task that is woken by the ISR that processes GPIO interrupts originating\r
116  * from the push button.\r
117  */\r
118 static void vButtonHandlerTask( void *pvParameters );\r
119 \r
120 /*\r
121  * The task that controls access to the LCD.\r
122  */\r
123 static void vPrintTask( void *pvParameter );\r
124 \r
125 /* String that is transmitted on the UART. */\r
126 static char *cMessage = "Task woken by button interrupt! --- ";\r
127 static volatile char *pcNextChar;\r
128 \r
129 /* The semaphore used to wake the button handler task from within the GPIO\r
130 interrupt handler. */\r
131 SemaphoreHandle_t xButtonSemaphore;\r
132 \r
133 /* The queue used to send strings to the print task for display on the LCD. */\r
134 QueueHandle_t xPrintQueue;\r
135 \r
136 /*-----------------------------------------------------------*/\r
137 \r
138 int main( void )\r
139 {\r
140         /* Configure the clocks, UART and GPIO. */\r
141         prvSetupHardware();\r
142 \r
143         /* Create the semaphore used to wake the button handler task from the GPIO\r
144         ISR. */\r
145         vSemaphoreCreateBinary( xButtonSemaphore );\r
146         xSemaphoreTake( xButtonSemaphore, 0 );\r
147 \r
148         /* Create the queue used to pass message to vPrintTask. */\r
149         xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( char * ) );\r
150 \r
151         /* Start the standard demo tasks. */\r
152         vStartIntegerMathTasks( tskIDLE_PRIORITY );\r
153         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
154         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
155         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
156 \r
157         /* Start the tasks defined within the file. */\r
158         xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
159         xTaskCreate( vButtonHandlerTask, "Status", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY + 1, NULL );\r
160         xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );\r
161 \r
162         /* Start the scheduler. */\r
163         vTaskStartScheduler();\r
164 \r
165         /* Will only get here if there was insufficient heap to start the\r
166         scheduler. */\r
167 \r
168         return 0;\r
169 }\r
170 /*-----------------------------------------------------------*/\r
171 \r
172 static void vCheckTask( void *pvParameters )\r
173 {\r
174 portBASE_TYPE xErrorOccurred = pdFALSE;\r
175 TickType_t xLastExecutionTime;\r
176 const char *pcPassMessage = "PASS";\r
177 const char *pcFailMessage = "FAIL";\r
178 \r
179         /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
180         works correctly. */\r
181         xLastExecutionTime = xTaskGetTickCount();\r
182 \r
183         for( ;; )\r
184         {\r
185                 /* Perform this check every mainCHECK_DELAY milliseconds. */\r
186                 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );\r
187 \r
188                 /* Has an error been found in any task? */\r
189 \r
190                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
191                 {\r
192                         xErrorOccurred = pdTRUE;\r
193                 }\r
194         \r
195                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
196                 {\r
197                         xErrorOccurred = pdTRUE;\r
198                 }\r
199         \r
200                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
201                 {\r
202                         xErrorOccurred = pdTRUE;\r
203                 }\r
204 \r
205                 if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
206                 {\r
207                         xErrorOccurred = pdTRUE;\r
208                 }\r
209 \r
210                 /* Send either a pass or fail message.  If an error is found it is\r
211                 never cleared again.  We do not write directly to the LCD, but instead\r
212                 queue a message for display by the print task. */\r
213                 if( xErrorOccurred == pdTRUE )\r
214                 {\r
215                         xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );\r
216                 }\r
217                 else\r
218                 {\r
219                         xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );\r
220                 }\r
221         }\r
222 }\r
223 /*-----------------------------------------------------------*/\r
224 \r
225 static void prvSetupHardware( void )\r
226 {\r
227         /* Setup the PLL. */\r
228         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
229 \r
230         /* Setup the push button. */\r
231         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);\r
232     GPIODirModeSet(GPIO_PORTC_BASE, mainPUSH_BUTTON, GPIO_DIR_MODE_IN);\r
233         GPIOIntTypeSet( GPIO_PORTC_BASE, mainPUSH_BUTTON,GPIO_FALLING_EDGE );\r
234         IntPrioritySet( INT_GPIOC, configKERNEL_INTERRUPT_PRIORITY );\r
235         GPIOPinIntEnable( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
236         IntEnable( INT_GPIOC );\r
237 \r
238 \r
239 \r
240         /* Enable the UART.  */\r
241         SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);\r
242         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);\r
243 \r
244         /* Set GPIO A0 and A1 as peripheral function.  They are used to output the\r
245         UART signals. */\r
246         GPIODirModeSet( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_DIR_MODE_HW );\r
247 \r
248         /* Configure the UART for 8-N-1 operation. */\r
249         UARTConfigSet( UART0_BASE, mainBAUD_RATE, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE );\r
250 \r
251         /* We don't want to use the fifo.  This is for test purposes to generate\r
252         as many interrupts as possible. */\r
253         HWREG( UART0_BASE + UART_O_LCR_H ) &= ~mainFIFO_SET;\r
254 \r
255         /* Enable Tx interrupts. */\r
256         HWREG( UART0_BASE + UART_O_IM ) |= UART_INT_TX;\r
257         IntPrioritySet( INT_UART0, configKERNEL_INTERRUPT_PRIORITY );\r
258         IntEnable( INT_UART0 );\r
259 \r
260 \r
261         /* Initialise the LCD> */\r
262     OSRAMInit( false );\r
263     OSRAMStringDraw("www.FreeRTOS.org", 0, 0);\r
264         OSRAMStringDraw("LM3S811 demo", 16, 1);\r
265 }\r
266 /*-----------------------------------------------------------*/\r
267 \r
268 static void vButtonHandlerTask( void *pvParameters )\r
269 {\r
270 const char *pcInterruptMessage = "Int";\r
271 \r
272         for( ;; )\r
273         {\r
274                 /* Wait for a GPIO interrupt to wake this task. */\r
275                 while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );\r
276 \r
277                 /* Start the Tx of the message on the UART. */\r
278                 UARTIntDisable( UART0_BASE, UART_INT_TX );\r
279                 {\r
280                         pcNextChar = cMessage;\r
281 \r
282                         /* Send the first character. */\r
283                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
284                         {\r
285                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
286                         }\r
287 \r
288                         pcNextChar++;\r
289                 }\r
290                 UARTIntEnable(UART0_BASE, UART_INT_TX);\r
291 \r
292                 /* Queue a message for the print task to display on the LCD. */\r
293                 xQueueSend( xPrintQueue, &pcInterruptMessage, portMAX_DELAY );\r
294 \r
295                 /* Make sure we don't process bounces. */\r
296                 vTaskDelay( mainDEBOUNCE_DELAY );\r
297                 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
298         }\r
299 }\r
300 \r
301 /*-----------------------------------------------------------*/\r
302 \r
303 void vUART_ISR(void)\r
304 {\r
305 unsigned long ulStatus;\r
306 \r
307         /* What caused the interrupt. */\r
308         ulStatus = UARTIntStatus( UART0_BASE, pdTRUE );\r
309 \r
310         /* Clear the interrupt. */\r
311         UARTIntClear( UART0_BASE, ulStatus );\r
312 \r
313         /* Was a Tx interrupt pending? */\r
314         if( ulStatus & UART_INT_TX )\r
315         {\r
316                 /* Send the next character in the string.  We are not using the FIFO. */\r
317                 if( *pcNextChar != 0 )\r
318                 {\r
319                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
320                         {\r
321                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
322                         }\r
323                         pcNextChar++;\r
324                 }\r
325         }\r
326 }\r
327 /*-----------------------------------------------------------*/\r
328 \r
329 void vGPIO_ISR( void )\r
330 {\r
331 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
332 \r
333         /* Clear the interrupt. */\r
334         GPIOPinIntClear(GPIO_PORTC_BASE, mainPUSH_BUTTON);\r
335 \r
336         /* Wake the button handler task. */\r
337         xSemaphoreGiveFromISR( xButtonSemaphore, &xHigherPriorityTaskWoken );\r
338 \r
339         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
340 }\r
341 /*-----------------------------------------------------------*/\r
342 \r
343 static void vPrintTask( void *pvParameters )\r
344 {\r
345 char *pcMessage;\r
346 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;\r
347 \r
348         for( ;; )\r
349         {\r
350                 /* Wait for a message to arrive. */\r
351                 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );\r
352 \r
353                 /* Write the message to the LCD. */\r
354                 uxRow++;\r
355                 uxLine++;\r
356                 OSRAMClear();\r
357                 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);\r
358         }\r
359 }\r
360 \r