3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://www.FreeRTOS.org
23 * http://aws.amazon.com/freertos
29 * Creates all the demo application tasks, then starts the scheduler. The WEB
30 * documentation provides more details of the standard demo application tasks
31 * (which just exist to test the kernel port and provide an example of how to use
32 * each FreeRTOS API function).
34 * In addition to the standard demo tasks, the following tasks and tests are
35 * defined and/or created within this file:
37 * "LCD" task - the LCD task is a 'gatekeeper' task. It is the only task that
38 * is permitted to access the display directly. Other tasks wishing to write a
39 * message to the LCD send the message on a queue to the LCD task instead of
40 * accessing the LCD themselves. The LCD task just blocks on the queue waiting
41 * for messages - waking and displaying the messages as they arrive. The use
42 * of a gatekeeper in this manner permits both tasks and interrupts to write to
43 * the LCD without worrying about mutual exclusion. This is demonstrated by the
44 * check hook (see below) which sends messages to the display even though it
45 * executes from an interrupt context.
47 * "Check" hook - This only executes fully every five seconds from the tick
48 * hook. Its main function is to check that all the standard demo tasks are
49 * still operational. Should any unexpected behaviour be discovered within a
50 * demo task then the tick hook will write an error to the LCD (via the LCD task).
51 * If all the demo tasks are executing with their expected behaviour then the
52 * check task writes PASS to the LCD (again via the LCD task), as described above.
56 /* Scheduler includes. */
62 /* Demo app includes. */
70 #include "lcd_message.h"
77 /* Atmel library includes. */
79 #include <lcd/color.h>
84 /*-----------------------------------------------------------*/
86 /* The time between cycles of the 'check' functionality (defined within the
88 #define mainCHECK_DELAY ( ( TickType_t ) 5000 / portTICK_PERIOD_MS )
90 /* The LCD task uses the sprintf function so requires a little more stack too. */
91 #define mainLCD_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 )
93 /* Task priorities. */
94 #define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2 )
95 #define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
96 #define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )
97 #define mainLED_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
98 #define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )
99 #define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )
100 #define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )
102 /* The maximum number of message that can be waiting for display at any one
104 #define mainLCD_QUEUE_SIZE ( 3 )
106 /* Constants used by the comtest tasks. There isn't a spare LED so an invalid
108 #define mainBAUD_RATE ( 115200 )
109 #define mainCOM_TEST_LED ( 10 )
111 /*-----------------------------------------------------------*/
114 * Configure the hardware for the demo.
116 static void prvSetupHardware( void );
119 * The LCD gatekeeper task. Tasks wishing to write to the LCD do not access
120 * the LCD directly, but instead send the message to the LCD gatekeeper task.
122 static void prvLCDTask( void *pvParameters );
125 * Hook functions that can get called by the kernel. The 'check' functionality
126 * is implemented within the tick hook.
128 void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );
131 * The tick hook function as described in the comments at the top of this file.
132 * The tick hook is used to monitor all the standard demo tasks to look for
133 * errors. The tick hook is also used to demonstrate how the LCD gatekeeper
134 * task can be used to allow interrupts to write to the LCD.
136 void vApplicationTickHook( void );
139 /*-----------------------------------------------------------*/
141 /* The queue used to send messages to the LCD task. */
142 static QueueHandle_t xLCDQueue;
144 /*-----------------------------------------------------------*/
148 /* Prepare the hardware. */
151 /* Create the queue used by the LCD task. Messages for display on the LCD
152 are received via this queue. */
153 xLCDQueue = xQueueCreate( mainLCD_QUEUE_SIZE, sizeof( xLCDMessage ) );
155 /* Start the standard demo tasks. These do nothing other than test the
156 port and provide some APU usage examples. */
157 vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );
158 vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );
159 vStartRecursiveMutexTasks();
160 vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
161 vCreateBlockTimeTasks();
162 vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
163 vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
164 vStartQueuePeekTasks();
165 vStartLEDFlashTasks( mainLED_TASK_PRIORITY );
166 vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainBAUD_RATE, mainCOM_TEST_LED );
168 /* Start the tasks defined within this file/specific to this demo. */
169 xTaskCreate( prvLCDTask, "LCD", mainLCD_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
171 /* Start the scheduler. */
172 vTaskStartScheduler();
174 /* Will only get here if there was insufficient memory to create the idle
178 /*-----------------------------------------------------------*/
180 void prvSetupHardware( void )
182 /* Initialise the port used for the LED outputs. */
183 vParTestInitialise();
185 /*-----------------------------------------------------------*/
187 void vApplicationTickHook( void )
189 static xLCDMessage xMessage = { "PASS" };
190 static unsigned long ulTicksSinceLastDisplay = 0;
191 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
193 /* Called from every tick interrupt. Have enough ticks passed to make it
194 time to perform our health status check again? */
195 ulTicksSinceLastDisplay++;
196 if( ulTicksSinceLastDisplay >= mainCHECK_DELAY )
198 ulTicksSinceLastDisplay = 0;
200 /* Has an error been found in any task? */
201 if( xAreGenericQueueTasksStillRunning() != pdTRUE )
203 xMessage.pcMessage = "ERROR IN GEN Q";
205 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )
207 xMessage.pcMessage = "ERROR IN MATH";
209 else if( xAreBlockingQueuesStillRunning() != pdTRUE )
211 xMessage.pcMessage = "ERROR IN BLOCK Q";
213 else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
215 xMessage.pcMessage = "ERROR IN BLOCK TIME";
217 else if( xAreSemaphoreTasksStillRunning() != pdTRUE )
219 xMessage.pcMessage = "ERROR IN SEMAPHORE";
221 else if( xArePollingQueuesStillRunning() != pdTRUE )
223 xMessage.pcMessage = "ERROR IN POLL Q";
225 else if( xAreQueuePeekTasksStillRunning() != pdTRUE )
227 xMessage.pcMessage = "ERROR IN PEEK Q";
229 else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
231 xMessage.pcMessage = "ERROR IN REC MUTEX";
233 else if( xAreComTestTasksStillRunning() != pdTRUE )
235 xMessage.pcMessage = "ERROR IN COMTEST";
238 /* Send the message to the LCD gatekeeper for display. */
239 xHigherPriorityTaskWoken = pdFALSE;
240 xQueueSendFromISR( xLCDQueue, &xMessage, &xHigherPriorityTaskWoken );
243 /*-----------------------------------------------------------*/
245 void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
250 /* If the parameters have been corrupted then inspect pxCurrentTCB to
251 identify which task has overflowed its stack. */
254 /*-----------------------------------------------------------*/
256 static void prvLCDTask( void *pvParameters )
258 xLCDMessage xMessage;
259 unsigned long ulY = 0;
260 const unsigned long ulX = 5;
261 const unsigned long ulMaxY = 250, ulYIncrement = 22, ulWidth = 250, ulHeight = 20;;
263 /* Initialize LCD. */
266 LCDD_Fill( ( void * ) BOARD_LCD_BASE, COLOR_WHITE );
267 LCDD_DrawString( ( void * ) BOARD_LCD_BASE, 1, ulY + 3, " www.FreeRTOS.org", COLOR_BLACK );
271 /* Wait for a message from the check function (which is executed in
273 xQueueReceive( xLCDQueue, &xMessage, portMAX_DELAY );
275 /* Clear the space where the old message was. */
276 LCDD_DrawRectangle( ( void * ) BOARD_LCD_BASE, 0, ulY, ulWidth, ulHeight, COLOR_WHITE );
278 /* Increment to the next drawing position. */
281 /* Have the Y position moved past the end of the LCD? */
287 /* Draw a new rectangle, in which the message will be written. */
288 LCDD_DrawRectangle( ( void * ) BOARD_LCD_BASE, 0, ulY, ulWidth, ulHeight, COLOR_GREEN );
290 /* Write the message. */
291 LCDD_DrawString( ( void * ) BOARD_LCD_BASE, ulX, ulY + 3, xMessage.pcMessage, COLOR_BLACK );