]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LM3S811_KEIL/main.c
ffccc86dedb0e6398b7b1b8705cdd672b99b5960
[freertos] / FreeRTOS / Demo / CORTEX_LM3S811_KEIL / 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 /* Newer library version. */\r
137 extern void UARTConfigSetExpClk(unsigned long ulBase, unsigned long ulUARTClk, unsigned long ulBaud, unsigned long ulConfig);\r
138 /*-----------------------------------------------------------*/\r
139 \r
140 int main( void )\r
141 {\r
142         /* Configure the clocks, UART and GPIO. */\r
143         prvSetupHardware();\r
144 \r
145         /* Create the semaphore used to wake the button handler task from the GPIO\r
146         ISR. */\r
147         vSemaphoreCreateBinary( xButtonSemaphore );\r
148         xSemaphoreTake( xButtonSemaphore, 0 );\r
149 \r
150         /* Create the queue used to pass message to vPrintTask. */\r
151         xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( char * ) );\r
152 \r
153         /* Start the standard demo tasks. */\r
154         vStartIntegerMathTasks( tskIDLE_PRIORITY );\r
155         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
156         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
157         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );\r
158 \r
159         /* Start the tasks defined within the file. */\r
160         xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );\r
161         xTaskCreate( vButtonHandlerTask, "Status", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY + 1, NULL );\r
162         xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );\r
163 \r
164         /* Start the scheduler. */\r
165         vTaskStartScheduler();\r
166 \r
167         /* Will only get here if there was insufficient heap to start the \r
168         scheduler. */\r
169 \r
170         return 0;\r
171 }\r
172 /*-----------------------------------------------------------*/\r
173 \r
174 static void vCheckTask( void *pvParameters )\r
175 {\r
176 portBASE_TYPE xErrorOccurred = pdFALSE;\r
177 TickType_t xLastExecutionTime;\r
178 const char *pcPassMessage = "PASS";\r
179 const char *pcFailMessage = "FAIL";\r
180 \r
181         /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()\r
182         works correctly. */\r
183         xLastExecutionTime = xTaskGetTickCount();\r
184 \r
185         for( ;; )\r
186         {\r
187                 /* Perform this check every mainCHECK_DELAY milliseconds. */\r
188                 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );\r
189 \r
190                 /* Has an error been found in any task? */\r
191 \r
192                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
193                 {\r
194                         xErrorOccurred = pdTRUE;\r
195                 }\r
196         \r
197                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
198                 {\r
199                         xErrorOccurred = pdTRUE;\r
200                 }\r
201         \r
202                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
203                 {\r
204                         xErrorOccurred = pdTRUE;\r
205                 }\r
206 \r
207                 if( xAreBlockingQueuesStillRunning() != pdTRUE )\r
208                 {\r
209                         xErrorOccurred = pdTRUE;\r
210                 }\r
211 \r
212                 /* Send either a pass or fail message.  If an error is found it is\r
213                 never cleared again.  We do not write directly to the LCD, but instead\r
214                 queue a message for display by the print task. */\r
215                 if( xErrorOccurred == pdTRUE )\r
216                 {\r
217                         xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );\r
218                 }\r
219                 else\r
220                 {\r
221                         xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );\r
222                 }\r
223         }\r
224 }\r
225 /*-----------------------------------------------------------*/\r
226 \r
227 static void prvSetupHardware( void )\r
228 {\r
229         /* Setup the PLL. */\r
230         SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );\r
231 \r
232         /* Setup the push button. */\r
233         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);\r
234     GPIODirModeSet(GPIO_PORTC_BASE, mainPUSH_BUTTON, GPIO_DIR_MODE_IN);\r
235         GPIOIntTypeSet( GPIO_PORTC_BASE, mainPUSH_BUTTON,GPIO_FALLING_EDGE );\r
236         IntPrioritySet( INT_GPIOC, configKERNEL_INTERRUPT_PRIORITY );\r
237         GPIOPinIntEnable( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
238         IntEnable( INT_GPIOC );\r
239 \r
240 \r
241 \r
242         /* Enable the UART.  */\r
243         SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);\r
244         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);\r
245 \r
246         /* Set GPIO A0 and A1 as peripheral function.  They are used to output the\r
247         UART signals. */\r
248         GPIODirModeSet( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_DIR_MODE_HW );\r
249 \r
250         /* Configure the UART for 8-N-1 operation. */\r
251         UARTConfigSetExpClk( UART0_BASE, SysCtlClockGet(), mainBAUD_RATE, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE );\r
252 \r
253         /* We don't want to use the fifo.  This is for test purposes to generate\r
254         as many interrupts as possible. */\r
255         HWREG( UART0_BASE + UART_O_LCR_H ) &= ~mainFIFO_SET;\r
256 \r
257         /* Enable Tx interrupts. */\r
258         HWREG( UART0_BASE + UART_O_IM ) |= UART_INT_TX;\r
259         IntPrioritySet( INT_UART0, configKERNEL_INTERRUPT_PRIORITY );\r
260         IntEnable( INT_UART0 );\r
261 \r
262 \r
263         /* Initialise the LCD> */\r
264     OSRAMInit( false );\r
265     OSRAMStringDraw("www.FreeRTOS.org", 0, 0);\r
266         OSRAMStringDraw("LM3S811 demo", 16, 1);\r
267 }\r
268 /*-----------------------------------------------------------*/\r
269 \r
270 static void vButtonHandlerTask( void *pvParameters )\r
271 {\r
272 const char *pcInterruptMessage = "Int";\r
273 \r
274         for( ;; )\r
275         {\r
276                 /* Wait for a GPIO interrupt to wake this task. */\r
277                 while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );\r
278 \r
279                 /* Start the Tx of the message on the UART. */\r
280                 UARTIntDisable( UART0_BASE, UART_INT_TX );\r
281                 {\r
282                         pcNextChar = cMessage;\r
283 \r
284                         /* Send the first character. */\r
285                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
286                         {\r
287                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
288                         }\r
289 \r
290                         pcNextChar++;\r
291                 }\r
292                 UARTIntEnable(UART0_BASE, UART_INT_TX);\r
293 \r
294                 /* Queue a message for the print task to display on the LCD. */\r
295                 xQueueSend( xPrintQueue, &pcInterruptMessage, portMAX_DELAY );\r
296 \r
297                 /* Make sure we don't process bounces. */\r
298                 vTaskDelay( mainDEBOUNCE_DELAY );\r
299                 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
300         }\r
301 }\r
302 \r
303 /*-----------------------------------------------------------*/\r
304 \r
305 void vUART_ISR(void)\r
306 {\r
307 unsigned long ulStatus;\r
308 \r
309         /* What caused the interrupt. */\r
310         ulStatus = UARTIntStatus( UART0_BASE, pdTRUE );\r
311 \r
312         /* Clear the interrupt. */\r
313         UARTIntClear( UART0_BASE, ulStatus );\r
314 \r
315         /* Was a Tx interrupt pending? */\r
316         if( ulStatus & UART_INT_TX )\r
317         {\r
318                 /* Send the next character in the string.  We are not using the FIFO. */\r
319                 if( *pcNextChar != NULL )\r
320                 {\r
321                         if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )\r
322                         {\r
323                                 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;\r
324                         }\r
325                         pcNextChar++;\r
326                 }\r
327         }\r
328 }\r
329 /*-----------------------------------------------------------*/\r
330 \r
331 void vGPIO_ISR( void )\r
332 {\r
333 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
334 \r
335         /* Clear the interrupt. */\r
336         GPIOPinIntClear( GPIO_PORTC_BASE, mainPUSH_BUTTON );\r
337 \r
338         /* Wake the button handler task. */\r
339         xSemaphoreGiveFromISR( xButtonSemaphore, &xHigherPriorityTaskWoken );\r
340         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
341 }\r
342 /*-----------------------------------------------------------*/\r
343 \r
344 static void vPrintTask( void *pvParameters )\r
345 {\r
346 char *pcMessage;\r
347 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;\r
348 \r
349         for( ;; )\r
350         {\r
351                 /* Wait for a message to arrive. */\r
352                 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );\r
353 \r
354                 /* Write the message to the LCD. */\r
355                 uxRow++;\r
356                 uxLine++;\r
357                 OSRAMClear();\r
358                 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);\r
359         }\r
360 }\r
361 \r