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