2 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd.
\r
4 This file is part of the FreeRTOS distribution.
\r
6 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
7 the terms of the GNU General Public License (version 2) as published by the
\r
8 Free Software Foundation and modified by the FreeRTOS exception.
\r
9 **NOTE** The exception to the GPL is included to allow you to distribute a
\r
10 combined work that includes FreeRTOS without being obliged to provide the
\r
11 source code for proprietary components outside of the FreeRTOS kernel.
\r
12 Alternative commercial license and support terms are also available upon
\r
13 request. See the licensing section of http://www.FreeRTOS.org for full
\r
16 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
21 You should have received a copy of the GNU General Public License along
\r
22 with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
\r
23 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\r
26 ***************************************************************************
\r
28 * The FreeRTOS eBook and reference manual are available to purchase for a *
\r
29 * small fee. Help yourself get started quickly while also helping the *
\r
30 * FreeRTOS project! See http://www.FreeRTOS.org/Documentation for details *
\r
32 ***************************************************************************
\r
36 Please ensure to read the configuration and relevant port sections of the
\r
37 online documentation.
\r
39 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
42 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
45 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
46 licensing and training services.
\r
51 * This project contains an application demonstrating the use of the
\r
52 * FreeRTOS.org mini real time scheduler on the Luminary Micro LM3S811 Eval
\r
53 * board. See http://www.FreeRTOS.org for more information.
\r
55 * main() simply sets up the hardware, creates all the demo application tasks,
\r
56 * then starts the scheduler. http://www.freertos.org/a00102.html provides
\r
57 * more information on the standard demo tasks.
\r
59 * In addition to a subset of the standard demo application tasks, main.c also
\r
60 * defines the following tasks:
\r
62 * + A 'Print' task. The print task is the only task permitted to access the
\r
63 * LCD - thus ensuring mutual exclusion and consistent access to the resource.
\r
64 * Other tasks do not access the LCD directly, but instead send the text they
\r
65 * wish to display to the print task. The print task spends most of its time
\r
66 * blocked - only waking when a message is queued for display.
\r
68 * + A 'Button handler' task. The eval board contains a user push button that
\r
69 * is configured to generate interrupts. The interrupt handler uses a
\r
70 * semaphore to wake the button handler task - demonstrating how the priority
\r
71 * mechanism can be used to defer interrupt processing to the task level. The
\r
72 * button handler task sends a message both to the LCD (via the print task) and
\r
73 * the UART where it can be viewed using a dumb terminal (via the UART to USB
\r
74 * converter on the eval board). NOTES: The dumb terminal must be closed in
\r
75 * order to reflash the microcontroller. A very basic interrupt driven UART
\r
76 * driver is used that does not use the FIFO. 19200 baud is used.
\r
78 * + A 'check' task. The check task only executes every five seconds but has a
\r
79 * high priority so is guaranteed to get processor time. Its function is to
\r
80 * check that all the other tasks are still operational and that no errors have
\r
81 * been detected at any time. If no errors have every been detected 'PASS' is
\r
82 * written to the display (via the print task) - if an error has ever been
\r
83 * detected the message is changed to 'FAIL'. The position of the message is
\r
84 * changed for each write.
\r
89 /* Environment includes. */
\r
90 #include "DriverLib.h"
\r
92 /* Scheduler includes. */
\r
93 #include "FreeRTOS.h"
\r
98 /* Demo app includes. */
\r
99 #include "integer.h"
\r
101 #include "semtest.h"
\r
102 #include "BlockQ.h"
\r
104 /* Delay between cycles of the 'check' task. */
\r
105 #define mainCHECK_DELAY ( ( portTickType ) 5000 / portTICK_RATE_MS )
\r
107 /* UART configuration - note this does not use the FIFO so is not very
\r
109 #define mainBAUD_RATE ( 19200 )
\r
110 #define mainFIFO_SET ( 0x10 )
\r
112 /* Demo task priorities. */
\r
113 #define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
114 #define mainCHECK_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )
\r
115 #define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
116 #define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
118 /* Demo board specifics. */
\r
119 #define mainPUSH_BUTTON GPIO_PIN_4
\r
122 #define mainQUEUE_SIZE ( 3 )
\r
123 #define mainDEBOUNCE_DELAY ( ( portTickType ) 150 / portTICK_RATE_MS )
\r
124 #define mainNO_DELAY ( ( portTickType ) 0 )
\r
126 * Configure the processor and peripherals for this demo.
\r
128 static void prvSetupHardware( void );
\r
131 * The 'check' task, as described at the top of this file.
\r
133 static void vCheckTask( void *pvParameters );
\r
136 * The task that is woken by the ISR that processes GPIO interrupts originating
\r
137 * from the push button.
\r
139 static void vButtonHandlerTask( void *pvParameters );
\r
142 * The task that controls access to the LCD.
\r
144 static void vPrintTask( void *pvParameter );
\r
146 /* String that is transmitted on the UART. */
\r
147 static portCHAR *cMessage = "Task woken by button interrupt! --- ";
\r
148 static volatile portCHAR *pcNextChar;
\r
150 /* The semaphore used to wake the button handler task from within the GPIO
\r
151 interrupt handler. */
\r
152 xSemaphoreHandle xButtonSemaphore;
\r
154 /* The queue used to send strings to the print task for display on the LCD. */
\r
155 xQueueHandle xPrintQueue;
\r
157 /*-----------------------------------------------------------*/
\r
161 /* Configure the clocks, UART and GPIO. */
\r
162 prvSetupHardware();
\r
164 /* Create the semaphore used to wake the button handler task from the GPIO
\r
166 vSemaphoreCreateBinary( xButtonSemaphore );
\r
167 xSemaphoreTake( xButtonSemaphore, 0 );
\r
169 /* Create the queue used to pass message to vPrintTask. */
\r
170 xPrintQueue = xQueueCreate( mainQUEUE_SIZE, sizeof( portCHAR * ) );
\r
172 /* Start the standard demo tasks. */
\r
173 vStartIntegerMathTasks( tskIDLE_PRIORITY );
\r
174 vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
\r
175 vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
\r
176 vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
\r
178 /* Start the tasks defined within the file. */
\r
179 xTaskCreate( vCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
\r
180 xTaskCreate( vButtonHandlerTask, "Status", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY + 1, NULL );
\r
181 xTaskCreate( vPrintTask, "Print", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );
\r
183 /* Start the scheduler. */
\r
184 vTaskStartScheduler();
\r
186 /* Will only get here if there was insufficient heap to start the
\r
191 /*-----------------------------------------------------------*/
\r
193 static void vCheckTask( void *pvParameters )
\r
195 portBASE_TYPE xErrorOccurred = pdFALSE;
\r
196 portTickType xLastExecutionTime;
\r
197 const portCHAR *pcPassMessage = "PASS";
\r
198 const portCHAR *pcFailMessage = "FAIL";
\r
200 /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil()
\r
201 works correctly. */
\r
202 xLastExecutionTime = xTaskGetTickCount();
\r
206 /* Perform this check every mainCHECK_DELAY milliseconds. */
\r
207 vTaskDelayUntil( &xLastExecutionTime, mainCHECK_DELAY );
\r
209 /* Has an error been found in any task? */
\r
211 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )
\r
213 xErrorOccurred = pdTRUE;
\r
216 if( xArePollingQueuesStillRunning() != pdTRUE )
\r
218 xErrorOccurred = pdTRUE;
\r
221 if( xAreSemaphoreTasksStillRunning() != pdTRUE )
\r
223 xErrorOccurred = pdTRUE;
\r
226 if( xAreBlockingQueuesStillRunning() != pdTRUE )
\r
228 xErrorOccurred = pdTRUE;
\r
231 /* Send either a pass or fail message. If an error is found it is
\r
232 never cleared again. We do not write directly to the LCD, but instead
\r
233 queue a message for display by the print task. */
\r
234 if( xErrorOccurred == pdTRUE )
\r
236 xQueueSend( xPrintQueue, &pcFailMessage, portMAX_DELAY );
\r
240 xQueueSend( xPrintQueue, &pcPassMessage, portMAX_DELAY );
\r
244 /*-----------------------------------------------------------*/
\r
246 static void prvSetupHardware( void )
\r
248 /* Setup the PLL. */
\r
249 SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ );
\r
251 /* Setup the push button. */
\r
252 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
\r
253 GPIODirModeSet(GPIO_PORTC_BASE, mainPUSH_BUTTON, GPIO_DIR_MODE_IN);
\r
254 GPIOIntTypeSet( GPIO_PORTC_BASE, mainPUSH_BUTTON,GPIO_FALLING_EDGE );
\r
255 IntPrioritySet( INT_GPIOC, configKERNEL_INTERRUPT_PRIORITY );
\r
256 GPIOPinIntEnable( GPIO_PORTC_BASE, mainPUSH_BUTTON );
\r
257 IntEnable( INT_GPIOC );
\r
261 /* Enable the UART. */
\r
262 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
\r
263 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
\r
265 /* Set GPIO A0 and A1 as peripheral function. They are used to output the
\r
267 GPIODirModeSet( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_DIR_MODE_HW );
\r
269 /* Configure the UART for 8-N-1 operation. */
\r
270 UARTConfigSet( UART0_BASE, mainBAUD_RATE, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE );
\r
272 /* We don't want to use the fifo. This is for test purposes to generate
\r
273 as many interrupts as possible. */
\r
274 HWREG( UART0_BASE + UART_O_LCR_H ) &= ~mainFIFO_SET;
\r
276 /* Enable Tx interrupts. */
\r
277 HWREG( UART0_BASE + UART_O_IM ) |= UART_INT_TX;
\r
278 IntPrioritySet( INT_UART0, configKERNEL_INTERRUPT_PRIORITY );
\r
279 IntEnable( INT_UART0 );
\r
282 /* Initialise the LCD> */
\r
283 OSRAMInit( false );
\r
284 OSRAMStringDraw("www.FreeRTOS.org", 0, 0);
\r
285 OSRAMStringDraw("LM3S811 demo", 16, 1);
\r
287 /*-----------------------------------------------------------*/
\r
289 static void vButtonHandlerTask( void *pvParameters )
\r
291 const portCHAR *pcInterruptMessage = "Int";
\r
295 /* Wait for a GPIO interrupt to wake this task. */
\r
296 while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );
\r
298 /* Start the Tx of the message on the UART. */
\r
299 UARTIntDisable( UART0_BASE, UART_INT_TX );
\r
301 pcNextChar = cMessage;
\r
303 /* Send the first character. */
\r
304 if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )
\r
306 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;
\r
311 UARTIntEnable(UART0_BASE, UART_INT_TX);
\r
313 /* Queue a message for the print task to display on the LCD. */
\r
314 xQueueSend( xPrintQueue, &pcInterruptMessage, portMAX_DELAY );
\r
316 /* Make sure we don't process bounces. */
\r
317 vTaskDelay( mainDEBOUNCE_DELAY );
\r
318 xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );
\r
322 /*-----------------------------------------------------------*/
\r
324 void vUART_ISR(void)
\r
326 unsigned portLONG ulStatus;
\r
328 /* What caused the interrupt. */
\r
329 ulStatus = UARTIntStatus( UART0_BASE, pdTRUE );
\r
331 /* Clear the interrupt. */
\r
332 UARTIntClear( UART0_BASE, ulStatus );
\r
334 /* Was a Tx interrupt pending? */
\r
335 if( ulStatus & UART_INT_TX )
\r
337 /* Send the next character in the string. We are not using the FIFO. */
\r
338 if( *pcNextChar != 0 )
\r
340 if( !( HWREG( UART0_BASE + UART_O_FR ) & UART_FR_TXFF ) )
\r
342 HWREG( UART0_BASE + UART_O_DR ) = *pcNextChar;
\r
348 /*-----------------------------------------------------------*/
\r
350 void vGPIO_ISR( void )
\r
352 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
354 /* Clear the interrupt. */
\r
355 GPIOPinIntClear(GPIO_PORTC_BASE, mainPUSH_BUTTON);
\r
357 /* Wake the button handler task. */
\r
358 xSemaphoreGiveFromISR( xButtonSemaphore, &xHigherPriorityTaskWoken );
\r
360 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r
362 /*-----------------------------------------------------------*/
\r
364 static void vPrintTask( void *pvParameters )
\r
366 portCHAR *pcMessage;
\r
367 unsigned portBASE_TYPE uxLine = 0, uxRow = 0;
\r
371 /* Wait for a message to arrive. */
\r
372 xQueueReceive( xPrintQueue, &pcMessage, portMAX_DELAY );
\r
374 /* Write the message to the LCD. */
\r
378 OSRAMStringDraw( pcMessage, uxLine & 0x3f, uxRow & 0x01);
\r