2 FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
4 ***************************************************************************
\r
8 * + New to FreeRTOS, *
\r
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
\r
10 * + Looking for basic training, *
\r
11 * + Wanting to improve your FreeRTOS skills and productivity *
\r
13 * then take a look at the FreeRTOS books - available as PDF or paperback *
\r
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
\r
16 * http://www.FreeRTOS.org/Documentation *
\r
18 * A pdf reference manual is also available. Both are usually delivered *
\r
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
\r
20 * and 8pm GMT (although please allow up to 24 hours in case of *
\r
21 * exceptional circumstances). Thank you for your support! *
\r
23 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
\r
31 a combined work that includes FreeRTOS without being obliged to provide the
\r
32 source code for proprietary components outside of the FreeRTOS kernel.
\r
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
56 * Tests the behaviour of timers. Some timers are created before hte scheudler
\r
57 * is started, and some after.
\r
61 /* Scheduler include files. */
\r
62 #include "FreeRTOS.h"
\r
66 /* Demo program include files. */
\r
67 #include "TimerDemo.h"
\r
69 #if configTIMER_TASK_PRIORITY < 1
\r
70 #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
\r
73 #define tmrdemoDONT_BLOCK ( ( portTickType ) 0 )
\r
74 #define tmrdemoONE_SHOT_TIMER_FREQUENCY ( xBaseFrequency * ( portTickType ) 3 )
\r
75 #define trmdemoNUM_TIMER_RESETS ( ( unsigned char ) 10 )
\r
77 /*-----------------------------------------------------------*/
\r
79 static void prvFreeRunningTimerCallback( xTimerHandle pxExpiredTimer );
\r
80 static void prvTimerControlTask( void *pvParameters );
\r
82 /*-----------------------------------------------------------*/
\r
84 /* Flag that will be latched to pdFAIL should any unexpected behaviour be
\r
85 detected in any of the demo tests. */
\r
86 static volatile portBASE_TYPE xTestStatus = pdPASS;
\r
88 /* Counter that is incremented on each cycle of a test. This is used to
\r
89 detect a stalled task - a test that is no longer running. */
\r
90 static volatile unsigned portLONG ulLoopCounter = 0;
\r
92 xTimerHandle xFreeRunningTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
93 unsigned char ucFreeRunningTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
94 unsigned char ucOneShotTimerCounter = ( unsigned char ) 0;
\r
96 static portTickType xBaseFrequency = 0;
\r
98 /*-----------------------------------------------------------*/
\r
100 void vStartTimerDemoTask( portTickType xBaseFrequencyIn )
\r
102 portBASE_TYPE xTimer;
\r
104 xBaseFrequency = xBaseFrequencyIn;
\r
106 for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
\r
108 /* As the timer queue is not yet full, it should be possible to both create
\r
109 and start a timer. These timers are being started before the scheduler has
\r
110 been started, so their block times should get set to zero within the timer
\r
112 xFreeRunningTimers[ xTimer ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
113 ( ( xTimer + 1 ) * xBaseFrequency ),/* The period for the timer. The plus 1 ensures a period of zero is not specified. */
\r
114 pdTRUE, /* Autoreload is set to true. */
\r
115 ( void * ) xTimer, /* An identifier for the timer as all the free running timers use the same callback. */
\r
116 prvFreeRunningTimerCallback ); /* The callback to be called when the timer expires. */
\r
118 if( xFreeRunningTimers[ xTimer ] == NULL )
\r
120 xTestStatus = pdFAIL;
\r
124 /* The scheduler has not yet started, so the block period of
\r
125 portMAX_DELAY should just get set to zero in xTimerStart(). Also,
\r
126 the timer queue is not yet full so xTimerStart() should return
\r
128 if( xTimerStart( xFreeRunningTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
\r
130 xTestStatus = pdFAIL;
\r
135 /* The timers queue should now be full, so it should be possible to create
\r
136 another timer, but not possible to start it (the timer queue will not get
\r
137 drained until the scheduler has been started. */
\r
138 xFreeRunningTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
139 ( configTIMER_QUEUE_LENGTH * xBaseFrequency ), /* The period for the timer. */
\r
140 pdTRUE, /* Autoreload is set to true. */
\r
141 ( void * ) xTimer, /* An identifier for the timer as all the free running timers use the same callback. */
\r
142 prvFreeRunningTimerCallback ); /* The callback to be called when the timer expires. */
\r
144 if( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
\r
146 xTestStatus = pdFAIL;
\r
150 if( xTimerStart( xFreeRunningTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
\r
152 /* This time it would not be expected that the timer could be
\r
153 started at this point. */
\r
154 xTestStatus = pdFAIL;
\r
158 /* Create the task that will control and monitor the timers. This is
\r
159 created at a lower priority than the timer service task to ensure, as
\r
160 far as it is concerned, commands on timers are actioned immediately
\r
161 (sending a command to the timer service task will unblock the timer service
\r
162 task, which will then preempt this task). */
\r
163 if( xTestStatus != pdFAIL )
\r
165 xTaskCreate( prvTimerControlTask, ( signed portCHAR * ) "Tmr Ctl", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
\r
168 /*-----------------------------------------------------------*/
\r
170 static void prvFreeRunningTimerCallback( xTimerHandle pxExpiredTimer )
\r
172 portBASE_TYPE xTimerID;
\r
174 xTimerID = ( portBASE_TYPE ) pvTimerGetTimerID( pxExpiredTimer );
\r
175 if( xTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
\r
177 ( ucFreeRunningTimerCounters[ xTimerID ] )++;
\r
181 /* The timer ID appears to be unexpected (invalid). */
\r
182 xTestStatus = pdFAIL;
\r
185 /*-----------------------------------------------------------*/
\r
187 static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer )
\r
189 /* The parameter is not used in this case as only one timer uses this
\r
190 callback function. */
\r
191 ( void ) pxExpiredTimer;
\r
193 ucOneShotTimerCounter++;
\r
195 /*-----------------------------------------------------------*/
\r
197 static void prvTimerControlTask( void *pvParameters )
\r
199 portTickType xNextWakeTime;
\r
200 unsigned char ucTimer;
\r
201 unsigned char ucMaxAllowableValue, ucMinAllowableValue;
\r
202 xTimerHandle xOneShotTimer = NULL;
\r
204 ( void ) pvParameters;
\r
206 /* Create a one-shot timer for use later on in this test. */
\r
207 xOneShotTimer = xTimerCreate( "Oneshot Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
208 tmrdemoONE_SHOT_TIMER_FREQUENCY,/* The period for the timer. */
\r
209 pdFALSE, /* Don't autoreload - hence a one shot timer. */
\r
210 ( void * ) 0, /* The timer identifier. In this case this is not used as the timer has its own callback. */
\r
211 prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */
\r
213 if( xOneShotTimer == NULL )
\r
215 xTestStatus = pdFAIL;
\r
219 /*-----------------------------------------------------------*/
\r
220 /* Test 1 - ensure all the timers are in their expected initial state. This
\r
221 depends on the timer service task having a higher priority than this task. */
\r
223 /* Free running timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now
\r
224 be active, and free running timer configTIMER_QUEUE_LENGTH should not
\r
225 yet be active (it could not be started prior to the scheduler being
\r
227 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
229 if( xTimerIsTimerActive( xFreeRunningTimers[ ucTimer ] ) == pdFALSE )
\r
231 xTestStatus = pdFAIL;
\r
235 if( xTimerIsTimerActive( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
\r
237 xTestStatus = pdFAIL;
\r
242 /*-----------------------------------------------------------*/
\r
243 /* Test 2 - Check the free running timers expire at the expcted rates. */
\r
245 /* Initialise the next wake time value before the call to
\r
246 vTaskDelayUntil() as this is not really a periodic task. */
\r
247 xNextWakeTime = xTaskGetTickCount();
\r
249 /* Delaying for configTIMER_QUEUE_LENGTH * xBaseFrequency ticks
\r
250 should allow all the free running timers to expire at least once. */
\r
251 vTaskDelayUntil( &xNextWakeTime, ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBaseFrequency );
\r
253 /* Check that all the free running timers have called their callback
\r
254 function the expected number of times. */
\r
255 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
257 /* The timer in array position 0 should elapse every xBaseFrequency
\r
258 ticks, the timer in array position 1 should elapse every
\r
259 ( 2 * xBaseFrequency ) ticks, etc. This task blocked for
\r
260 configTIMER_QUEUE_LENGTH * xBaseFrequency, so the timer in array
\r
261 position 0 should have elapsed configTIMER_QUEUE_LENGTH times, the
\r
262 timer in array possition 1 should have elapsed
\r
263 ( configTIMER_QUEUE_LENGTH - 1 ) times, etc. */
\r
264 ucMaxAllowableValue = ( ( ( unsigned char ) configTIMER_QUEUE_LENGTH ) - ucTimer );
\r
265 ucMinAllowableValue = ( ( ( unsigned char ) configTIMER_QUEUE_LENGTH ) - ucTimer ) - 1;
\r
267 if( ( ucFreeRunningTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
\r
268 ( ucFreeRunningTimerCounters[ ucTimer ] > ucMaxAllowableValue )
\r
271 xTestStatus = pdFAIL;
\r
275 if( xTestStatus == pdPASS )
\r
277 /* No errors have been reported so increment the loop counter so
\r
278 the check task knows this task is still running. */
\r
285 /*-----------------------------------------------------------*/
\r
286 /* Test 3 - Check the free running timers can be stopped correctly, and
\r
287 correctly report their state. */
\r
289 /* Stop all the active timers. */
\r
290 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
292 /* The timer has not been stopped yet! */
\r
293 if( xTimerIsTimerActive( xFreeRunningTimers[ ucTimer ] ) == pdFALSE )
\r
295 xTestStatus = pdFAIL;
\r
298 /* Now stop the timer. This will appear to happen immediately to
\r
299 this task because this task is running at a priority below the
\r
300 timer service task. */
\r
301 xTimerStop( xFreeRunningTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
303 /* The timer should now be inactive. */
\r
304 if( xTimerIsTimerActive( xFreeRunningTimers[ ucTimer ] ) != pdFALSE )
\r
306 xTestStatus = pdFAIL;
\r
310 taskENTER_CRITICAL();
\r
312 /* The timer in array position configTIMER_QUEUE_LENGTH should not
\r
313 be active. The critical section is used to ensure the timer does
\r
314 not call its callback between the next line running and the array
\r
315 being cleared back to zero, as that would mask an error condition. */
\r
316 if( ucFreeRunningTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( unsigned char ) 0 )
\r
318 xTestStatus = pdFAIL;
\r
321 /* Clear the timer callback count. */
\r
322 memset( ( void * ) ucFreeRunningTimerCounters, 0, sizeof( ucFreeRunningTimerCounters ) );
\r
324 taskEXIT_CRITICAL();
\r
326 /* The timers are now all inactive, so this time, after delaying, none
\r
327 of the callback counters should have incremented. */
\r
328 vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBaseFrequency );
\r
329 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
331 if( ucFreeRunningTimerCounters[ ucTimer ] != ( unsigned char ) 0 )
\r
333 xTestStatus = pdFAIL;
\r
337 if( xTestStatus == pdPASS )
\r
339 /* No errors have been reported so increment the loop counter so
\r
340 the check task knows this task is still running. */
\r
346 /*-----------------------------------------------------------*/
\r
347 /* Test 4 - Check the one shot timer only calls its callback once after
\r
348 it has been started, and that it reports its state correctly. */
\r
350 /* The one shot timer should not be active yet. */
\r
351 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
353 xTestStatus = pdFAIL;
\r
356 if( ucOneShotTimerCounter != ( unsigned char ) 0 )
\r
358 xTestStatus = pdFAIL;
\r
361 /* Start the one shot timer and check that it reports its state
\r
363 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
364 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
366 xTestStatus = pdFAIL;
\r
369 /* Delay for three times as long as the one shot timer period, then
\r
370 check to ensure it has only called its callback once, and is now
\r
371 not in the active state. */
\r
372 vTaskDelay( tmrdemoONE_SHOT_TIMER_FREQUENCY * ( portTickType ) 3 );
\r
374 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
376 xTestStatus = pdFAIL;
\r
379 if( ucOneShotTimerCounter != ( unsigned char ) 1 )
\r
381 xTestStatus = pdFAIL;
\r
385 /* Reset the one shot timer callback count. */
\r
386 ucOneShotTimerCounter = ( unsigned char ) 0;
\r
389 if( xTestStatus == pdPASS )
\r
391 /* No errors have been reported so increment the loop counter so
\r
392 the check task knows this task is still running. */
\r
399 /*-----------------------------------------------------------*/
\r
400 /* Test 5 - Check all the timers can be reset while they are running. */
\r
402 /* Restart the one shot timer and check it reports its status
\r
404 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
405 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
407 xTestStatus = pdFAIL;
\r
410 /* Restart one of the free running timers and check that it reports its
\r
411 status correctly. */
\r
412 xTimerStart( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
413 if( xTimerIsTimerActive( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
415 xTestStatus = pdFAIL;
\r
418 for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )
\r
420 /* Delay for half as long as the one shot timer period, then
\r
421 reset it. It should never expire while this is done, so its callback
\r
422 count should never increment. */
\r
423 vTaskDelay( tmrdemoONE_SHOT_TIMER_FREQUENCY / 2 );
\r
425 /* Check both running timers are still active, but have not called their
\r
426 callback functions. */
\r
427 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
429 xTestStatus = pdFAIL;
\r
432 if( ucOneShotTimerCounter != ( unsigned char ) 0 )
\r
434 xTestStatus = pdFAIL;
\r
437 if( xTimerIsTimerActive( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
\r
439 xTestStatus = pdFAIL;
\r
442 if( ucFreeRunningTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( unsigned char ) 0 )
\r
444 xTestStatus = pdFAIL;
\r
447 /* Reset both running timers. */
\r
448 xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
449 xTimerReset( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
451 if( xTestStatus == pdPASS )
\r
453 /* No errors have been reported so increment the loop counter so
\r
454 the check task knows this task is still running. */
\r
459 /* Finally delay long enough for both running timers to expire. */
\r
460 vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBaseFrequency );
\r
462 /* The timers were not reset during the above delay period so should now
\r
463 both have called their callback functions. */
\r
464 if( ucOneShotTimerCounter != ( unsigned char ) 1 )
\r
466 xTestStatus = pdFAIL;
\r
469 if( ucFreeRunningTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
\r
471 xTestStatus = pdFAIL;
\r
474 /* The one shot timer should no longer be active, while the free running
\r
475 timer should still be active. */
\r
476 if( xTimerIsTimerActive( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
478 xTestStatus = pdFAIL;
\r
481 if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
\r
483 xTestStatus = pdFAIL;
\r
486 /* Stop the free running timer again. */
\r
487 xTimerStop( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
489 if( xTimerIsTimerActive( xFreeRunningTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
\r
491 xTestStatus = pdFAIL;
\r
494 /* Clear the timer callback counts, ready for another iteration of these
\r
496 ucFreeRunningTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( unsigned char ) 0;
\r
497 ucOneShotTimerCounter = ( unsigned char ) 0;
\r
499 if( xTestStatus == pdPASS )
\r
501 /* No errors have been reported so increment the loop counter so
\r
502 the check task knows this task is still running. */
\r
509 /*-----------------------------------------------------------*/
\r
510 /* Start the timers again to start all the tests over again. */
\r
513 /* Start the timers again. */
\r
514 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
516 /* The timer has not been started yet! */
\r
517 if( xTimerIsTimerActive( xFreeRunningTimers[ ucTimer ] ) != pdFALSE )
\r
519 xTestStatus = pdFAIL;
\r
522 /* Now start the timer. This will appear to happen immediately to
\r
523 this task because this task is running at a priority below the
\r
524 timer service task. */
\r
525 xTimerStart( xFreeRunningTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
527 /* The timer should now be active. */
\r
528 if( xTimerIsTimerActive( xFreeRunningTimers[ ucTimer ] ) == pdFALSE )
\r
530 xTestStatus = pdFAIL;
\r
534 if( xTestStatus == pdPASS )
\r
536 /* No errors have been reported so increment the loop counter so
\r
537 the check task knows this task is still running. */
\r
542 /*-----------------------------------------------------------*/
\r
544 /* This is called to check that the created task is still running and has not
\r
545 detected any errors. */
\r
546 portBASE_TYPE xAreTimerDemoTasksStillRunning( void )
\r
548 static unsigned portLONG ulLastLoopCounter = 0;
\r
550 /* If the demo task is still running then we expect the loopcounter to
\r
551 have incremented since this function was last called. */
\r
552 if( ulLastLoopCounter == ulLoopCounter )
\r
554 xTestStatus = pdFAIL;
\r
557 ulLastLoopCounter = ulLoopCounter;
\r
559 /* Errors detected in the task itself will have latched xTestStatus
\r
562 return xTestStatus;
\r