00001 /* 00002 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd. 00003 00004 *************************************************************************** 00005 * * 00006 * If you are: * 00007 * * 00008 * + New to FreeRTOS, * 00009 * + Wanting to learn FreeRTOS or multitasking in general quickly * 00010 * + Looking for basic training, * 00011 * + Wanting to improve your FreeRTOS skills and productivity * 00012 * * 00013 * then take a look at the FreeRTOS eBook * 00014 * * 00015 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * 00016 * http://www.FreeRTOS.org/Documentation * 00017 * * 00018 * A pdf reference manual is also available. Both are usually delivered * 00019 * to your inbox within 20 minutes to two hours when purchased between 8am * 00020 * and 8pm GMT (although please allow up to 24 hours in case of * 00021 * exceptional circumstances). Thank you for your support! * 00022 * * 00023 *************************************************************************** 00024 00025 This file is part of the FreeRTOS distribution. 00026 00027 FreeRTOS is free software; you can redistribute it and/or modify it under 00028 the terms of the GNU General Public License (version 2) as published by the 00029 Free Software Foundation AND MODIFIED BY the FreeRTOS exception. 00030 ***NOTE*** The exception to the GPL is included to allow you to distribute 00031 a combined work that includes FreeRTOS without being obliged to provide the 00032 source code for proprietary components outside of the FreeRTOS kernel. 00033 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT 00034 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00035 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00036 more details. You should have received a copy of the GNU General Public 00037 License and the FreeRTOS license exception along with FreeRTOS; if not it 00038 can be viewed here: http://www.freertos.org/a00114.html and also obtained 00039 by writing to Richard Barry, contact details for whom are available on the 00040 FreeRTOS WEB site. 00041 00042 1 tab == 4 spaces! 00043 00044 http://www.FreeRTOS.org - Documentation, latest information, license and 00045 contact details. 00046 00047 http://www.SafeRTOS.com - A version that is certified for use in safety 00048 critical systems. 00049 00050 http://www.OpenRTOS.com - Commercial support, development, porting, 00051 licensing and training services. 00052 */ 00053 00054 /* 00055 * The first test creates three tasks - two counter tasks (one continuous count 00056 * and one limited count) and one controller. A "count" variable is shared 00057 * between all three tasks. The two counter tasks should never be in a "ready" 00058 * state at the same time. The controller task runs at the same priority as 00059 * the continuous count task, and at a lower priority than the limited count 00060 * task. 00061 * 00062 * One counter task loops indefinitely, incrementing the shared count variable 00063 * on each iteration. To ensure it has exclusive access to the variable it 00064 * raises it's priority above that of the controller task before each 00065 * increment, lowering it again to it's original priority before starting the 00066 * next iteration. 00067 * 00068 * The other counter task increments the shared count variable on each 00069 * iteration of it's loop until the count has reached a limit of 0xff - at 00070 * which point it suspends itself. It will not start a new loop until the 00071 * controller task has made it "ready" again by calling vTaskResume (). 00072 * This second counter task operates at a higher priority than controller 00073 * task so does not need to worry about mutual exclusion of the counter 00074 * variable. 00075 * 00076 * The controller task is in two sections. The first section controls and 00077 * monitors the continuous count task. When this section is operational the 00078 * limited count task is suspended. Likewise, the second section controls 00079 * and monitors the limited count task. When this section is operational the 00080 * continuous count task is suspended. 00081 * 00082 * In the first section the controller task first takes a copy of the shared 00083 * count variable. To ensure mutual exclusion on the count variable it 00084 * suspends the continuous count task, resuming it again when the copy has been 00085 * taken. The controller task then sleeps for a fixed period - during which 00086 * the continuous count task will execute and increment the shared variable. 00087 * When the controller task wakes it checks that the continuous count task 00088 * has executed by comparing the copy of the shared variable with its current 00089 * value. This time, to ensure mutual exclusion, the scheduler itself is 00090 * suspended with a call to vTaskSuspendAll (). This is for demonstration 00091 * purposes only and is not a recommended technique due to its inefficiency. 00092 * 00093 * After a fixed number of iterations the controller task suspends the 00094 * continuous count task, and moves on to its second section. 00095 * 00096 * At the start of the second section the shared variable is cleared to zero. 00097 * The limited count task is then woken from it's suspension by a call to 00098 * vTaskResume (). As this counter task operates at a higher priority than 00099 * the controller task the controller task should not run again until the 00100 * shared variable has been counted up to the limited value causing the counter 00101 * task to suspend itself. The next line after vTaskResume () is therefore 00102 * a check on the shared variable to ensure everything is as expected. 00103 * 00104 * 00105 * The second test consists of a couple of very simple tasks that post onto a 00106 * queue while the scheduler is suspended. This test was added to test parts 00107 * of the scheduler not exercised by the first test. 00108 * 00109 */ 00110 00111 #include <stdlib.h> 00112 00113 /* Scheduler include files. */ 00114 #include "FreeRTOS.h" 00115 #include "task.h" 00116 #include "semphr.h" 00117 00118 /* Demo app include files. */ 00119 #include "dynamic.h" 00120 00121 /* Function that implements the "limited count" task as described above. */ 00122 static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters ); 00123 00124 /* Function that implements the "continuous count" task as described above. */ 00125 static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters ); 00126 00127 /* Function that implements the controller task as described above. */ 00128 static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters ); 00129 00130 static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters ); 00131 static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters ); 00132 00133 /* Demo task specific constants. */ 00134 #define priSTACK_SIZE ( configMINIMAL_STACK_SIZE ) 00135 #define priSLEEP_TIME ( ( portTickType ) 128 / portTICK_RATE_MS ) 00136 #define priLOOPS ( 5 ) 00137 #define priMAX_COUNT ( ( unsigned long ) 0xff ) 00138 #define priNO_BLOCK ( ( portTickType ) 0 ) 00139 #define priSUSPENDED_QUEUE_LENGTH ( 1 ) 00140 00141 /*-----------------------------------------------------------*/ 00142 00143 /* Handles to the two counter tasks. These could be passed in as parameters 00144 to the controller task to prevent them having to be file scope. */ 00145 static xTaskHandle xContinousIncrementHandle, xLimitedIncrementHandle; 00146 00147 /* The shared counter variable. This is passed in as a parameter to the two 00148 counter variables for demonstration purposes. */ 00149 static unsigned long ulCounter; 00150 00151 /* Variables used to check that the tasks are still operating without error. 00152 Each complete iteration of the controller task increments this variable 00153 provided no errors have been found. The variable maintaining the same value 00154 is therefore indication of an error. */ 00155 static volatile unsigned short usCheckVariable = ( unsigned short ) 0; 00156 static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE; 00157 static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE; 00158 00159 /* Queue used by the second test. */ 00160 xQueueHandle xSuspendedTestQueue; 00161 00162 /*-----------------------------------------------------------*/ 00163 /* 00164 * Start the three tasks as described at the top of the file. 00165 * Note that the limited count task is given a higher priority. 00166 */ 00167 void vStartDynamicPriorityTasks( void ) 00168 { 00169 xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) ); 00170 00171 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is 00172 in use. The queue registry is provided as a means for kernel aware 00173 debuggers to locate queues and has no purpose if a kernel aware debugger 00174 is not being used. The call to vQueueAddToRegistry() will be removed 00175 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00176 defined to be less than 1. */ 00177 vQueueAddToRegistry( xSuspendedTestQueue, ( signed char * ) "Suspended_Test_Queue" ); 00178 00179 xTaskCreate( vContinuousIncrementTask, ( signed char * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinousIncrementHandle ); 00180 xTaskCreate( vLimitedIncrementTask, ( signed char * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle ); 00181 xTaskCreate( vCounterControlTask, ( signed char * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); 00182 xTaskCreate( vQueueSendWhenSuspendedTask, ( signed char * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); 00183 xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed char * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); 00184 } 00185 /*-----------------------------------------------------------*/ 00186 00187 /* 00188 * Just loops around incrementing the shared variable until the limit has been 00189 * reached. Once the limit has been reached it suspends itself. 00190 */ 00191 static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters ) 00192 { 00193 unsigned long *pulCounter; 00194 00195 /* Take a pointer to the shared variable from the parameters passed into 00196 the task. */ 00197 pulCounter = ( unsigned long * ) pvParameters; 00198 00199 /* This will run before the control task, so the first thing it does is 00200 suspend - the control task will resume it when ready. */ 00201 vTaskSuspend( NULL ); 00202 00203 for( ;; ) 00204 { 00205 /* Just count up to a value then suspend. */ 00206 ( *pulCounter )++; 00207 00208 if( *pulCounter >= priMAX_COUNT ) 00209 { 00210 vTaskSuspend( NULL ); 00211 } 00212 } 00213 } 00214 /*-----------------------------------------------------------*/ 00215 00216 /* 00217 * Just keep counting the shared variable up. The control task will suspend 00218 * this task when it wants. 00219 */ 00220 static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters ) 00221 { 00222 unsigned long *pulCounter; 00223 unsigned portBASE_TYPE uxOurPriority; 00224 00225 /* Take a pointer to the shared variable from the parameters passed into 00226 the task. */ 00227 pulCounter = ( unsigned long * ) pvParameters; 00228 00229 /* Query our priority so we can raise it when exclusive access to the 00230 shared variable is required. */ 00231 uxOurPriority = uxTaskPriorityGet( NULL ); 00232 00233 for( ;; ) 00234 { 00235 /* Raise our priority above the controller task to ensure a context 00236 switch does not occur while we are accessing this variable. */ 00237 vTaskPrioritySet( NULL, uxOurPriority + 1 ); 00238 ( *pulCounter )++; 00239 vTaskPrioritySet( NULL, uxOurPriority ); 00240 } 00241 } 00242 /*-----------------------------------------------------------*/ 00243 00244 /* 00245 * Controller task as described above. 00246 */ 00247 static portTASK_FUNCTION( vCounterControlTask, pvParameters ) 00248 { 00249 unsigned long ulLastCounter; 00250 short sLoops; 00251 short sError = pdFALSE; 00252 00253 /* Just to stop warning messages. */ 00254 ( void ) pvParameters; 00255 00256 for( ;; ) 00257 { 00258 /* Start with the counter at zero. */ 00259 ulCounter = ( unsigned long ) 0; 00260 00261 /* First section : */ 00262 00263 /* Check the continuous count task is running. */ 00264 for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) 00265 { 00266 /* Suspend the continuous count task so we can take a mirror of the 00267 shared variable without risk of corruption. */ 00268 vTaskSuspend( xContinousIncrementHandle ); 00269 ulLastCounter = ulCounter; 00270 vTaskResume( xContinousIncrementHandle ); 00271 00272 /* Now delay to ensure the other task has processor time. */ 00273 vTaskDelay( priSLEEP_TIME ); 00274 00275 /* Check the shared variable again. This time to ensure mutual 00276 exclusion the whole scheduler will be locked. This is just for 00277 demo purposes! */ 00278 vTaskSuspendAll(); 00279 { 00280 if( ulLastCounter == ulCounter ) 00281 { 00282 /* The shared variable has not changed. There is a problem 00283 with the continuous count task so flag an error. */ 00284 sError = pdTRUE; 00285 } 00286 } 00287 xTaskResumeAll(); 00288 } 00289 00290 00291 /* Second section: */ 00292 00293 /* Suspend the continuous counter task so it stops accessing the shared variable. */ 00294 vTaskSuspend( xContinousIncrementHandle ); 00295 00296 /* Reset the variable. */ 00297 ulCounter = ( unsigned long ) 0; 00298 00299 /* Resume the limited count task which has a higher priority than us. 00300 We should therefore not return from this call until the limited count 00301 task has suspended itself with a known value in the counter variable. */ 00302 vTaskResume( xLimitedIncrementHandle ); 00303 00304 /* Does the counter variable have the expected value? */ 00305 if( ulCounter != priMAX_COUNT ) 00306 { 00307 sError = pdTRUE; 00308 } 00309 00310 if( sError == pdFALSE ) 00311 { 00312 /* If no errors have occurred then increment the check variable. */ 00313 portENTER_CRITICAL(); 00314 usCheckVariable++; 00315 portEXIT_CRITICAL(); 00316 } 00317 00318 /* Resume the continuous count task and do it all again. */ 00319 vTaskResume( xContinousIncrementHandle ); 00320 } 00321 } 00322 /*-----------------------------------------------------------*/ 00323 00324 static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters ) 00325 { 00326 static unsigned long ulValueToSend = ( unsigned long ) 0; 00327 00328 /* Just to stop warning messages. */ 00329 ( void ) pvParameters; 00330 00331 for( ;; ) 00332 { 00333 vTaskSuspendAll(); 00334 { 00335 /* We must not block while the scheduler is suspended! */ 00336 if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE ) 00337 { 00338 xSuspendedQueueSendError = pdTRUE; 00339 } 00340 } 00341 xTaskResumeAll(); 00342 00343 vTaskDelay( priSLEEP_TIME ); 00344 00345 ++ulValueToSend; 00346 } 00347 } 00348 /*-----------------------------------------------------------*/ 00349 00350 static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters ) 00351 { 00352 static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue; 00353 portBASE_TYPE xGotValue; 00354 00355 /* Just to stop warning messages. */ 00356 ( void ) pvParameters; 00357 00358 for( ;; ) 00359 { 00360 do 00361 { 00362 /* Suspending the scheduler here is fairly pointless and 00363 undesirable for a normal application. It is done here purely 00364 to test the scheduler. The inner xTaskResumeAll() should 00365 never return pdTRUE as the scheduler is still locked by the 00366 outer call. */ 00367 vTaskSuspendAll(); 00368 { 00369 vTaskSuspendAll(); 00370 { 00371 xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK ); 00372 } 00373 if( xTaskResumeAll() ) 00374 { 00375 xSuspendedQueueReceiveError = pdTRUE; 00376 } 00377 } 00378 xTaskResumeAll(); 00379 00380 #if configUSE_PREEMPTION == 0 00381 { 00382 taskYIELD(); 00383 } 00384 #endif 00385 00386 } while( xGotValue == pdFALSE ); 00387 00388 if( ulReceivedValue != ulExpectedValue ) 00389 { 00390 xSuspendedQueueReceiveError = pdTRUE; 00391 } 00392 00393 ++ulExpectedValue; 00394 } 00395 } 00396 /*-----------------------------------------------------------*/ 00397 00398 /* Called to check that all the created tasks are still running without error. */ 00399 portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void ) 00400 { 00401 /* Keep a history of the check variables so we know if it has been incremented 00402 since the last call. */ 00403 static unsigned short usLastTaskCheck = ( unsigned short ) 0; 00404 portBASE_TYPE xReturn = pdTRUE; 00405 00406 /* Check the tasks are still running by ensuring the check variable 00407 is still incrementing. */ 00408 00409 if( usCheckVariable == usLastTaskCheck ) 00410 { 00411 /* The check has not incremented so an error exists. */ 00412 xReturn = pdFALSE; 00413 } 00414 00415 if( xSuspendedQueueSendError == pdTRUE ) 00416 { 00417 xReturn = pdFALSE; 00418 } 00419 00420 if( xSuspendedQueueReceiveError == pdTRUE ) 00421 { 00422 xReturn = pdFALSE; 00423 } 00424 00425 usLastTaskCheck = usCheckVariable; 00426 return xReturn; 00427 }