2 FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\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 modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or 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 the scheduler
\r
57 * is started, and some after.
\r
60 /* Standard includes. */
\r
63 /* Scheduler include files. */
\r
64 #include "FreeRTOS.h"
\r
68 /* Demo program include files. */
\r
69 #include "TimerDemo.h"
\r
71 #if ( configTIMER_TASK_PRIORITY < 1 )
\r
72 #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
\r
75 #define tmrdemoDONT_BLOCK ( ( portTickType ) 0 )
\r
76 #define tmrdemoONE_SHOT_TIMER_PERIOD ( xBasePeriod * ( portTickType ) 3 )
\r
77 #define trmdemoNUM_TIMER_RESETS ( ( unsigned char ) 10 )
\r
79 /*-----------------------------------------------------------*/
\r
81 /* The callback functions used by the timers. These each increment a counter
\r
82 to indicate which timer has expired. The auto-reload timers that are used by
\r
83 the test task (as opposed to being used from an ISR) all share the same
\r
84 prvAutoReloadTimerCallback() callback function, and use the ID of the
\r
85 pxExpiredTimer parameter passed into that function to know which counter to
\r
86 increment. The other timers all have their own unique callback function and
\r
87 simply increment their counters without using the callback function parameter. */
\r
88 static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );
\r
89 static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer );
\r
90 static void prvTimerTestTask( void *pvParameters );
\r
91 static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );
\r
92 static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer );
\r
94 /* The test functions used by the timer test task. These manipulate the auto
\r
95 reload and one shot timers in various ways, then delay, then inspect the timers
\r
96 to ensure they have behaved as expected. */
\r
97 static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
\r
98 static void prvTest2_CheckTaskAndTimersInitialState( void );
\r
99 static void prvTest3_CheckAutoReloadExpireRates( void );
\r
100 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
\r
101 static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
\r
102 static void prvTest6_CheckAutoReloadResetBehaviour( void );
\r
103 static void prvResetStartConditionsForNextIteration( void );
\r
105 /*-----------------------------------------------------------*/
\r
107 /* Flag that will be latched to pdFAIL should any unexpected behaviour be
\r
108 detected in any of the demo tests. */
\r
109 static volatile portBASE_TYPE xTestStatus = pdPASS;
\r
111 /* Counter that is incremented on each cycle of a test. This is used to
\r
112 detect a stalled task - a test that is no longer running. */
\r
113 static volatile unsigned long ulLoopCounter = 0;
\r
115 /* A set of auto reload timers - each of which use the same callback function.
\r
116 The callback function uses the timer ID to index into, and then increment, a
\r
117 counter in the ucAutoReloadTimerCounters[] array. The auto reload timers
\r
118 referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */
\r
119 static xTimerHandle xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
120 static unsigned char ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
122 /* The one shot timer is configured to use a callback function that increments
\r
123 ucOneShotTimerCounter each time it gets called. */
\r
124 static xTimerHandle xOneShotTimer = NULL;
\r
125 static unsigned char ucOneShotTimerCounter = ( unsigned char ) 0;
\r
127 /* The ISR reload timer is controlled from the tick hook to exercise the timer
\r
128 API functions that can be used from an ISR. It is configured to increment
\r
129 ucISRReloadTimerCounter each time its callback function is executed. */
\r
130 static xTimerHandle xISRAutoReloadTimer = NULL;
\r
131 static unsigned char ucISRAutoReloadTimerCounter = ( unsigned char ) 0;
\r
133 /* The ISR one shot timer is controlled from the tick hook to exercise the timer
\r
134 API functions that can be used from an ISR. It is configured to increment
\r
135 ucISRReloadTimerCounter each time its callback function is executed. */
\r
136 static xTimerHandle xISROneShotTimer = NULL;
\r
137 static unsigned char ucISROneShotTimerCounter = ( unsigned char ) 0;
\r
139 /* The period of all the timers are a multiple of the base period. The base
\r
140 period is configured by the parameter to vStartTimerDemoTask(). */
\r
141 static portTickType xBasePeriod = 0;
\r
143 /*-----------------------------------------------------------*/
\r
145 void vStartTimerDemoTask( portTickType xBasePeriodIn )
\r
147 /* Start with the timer and counter arrays clear - this is only necessary
\r
148 where the compiler does not clear them automatically on start up. */
\r
149 memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
\r
150 memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
\r
152 /* Store the period from which all the timer periods will be generated from
\r
154 xBasePeriod = xBasePeriodIn;
\r
156 /* Create a set of timers for use by this demo/test. */
\r
157 prvTest1_CreateTimersWithoutSchedulerRunning();
\r
159 /* Create the task that will control and monitor the timers. This is
\r
160 created at a lower priority than the timer service task to ensure, as
\r
161 far as it is concerned, commands on timers are actioned immediately
\r
162 (sending a command to the timer service task will unblock the timer service
\r
163 task, which will then preempt this task). */
\r
164 if( xTestStatus != pdFAIL )
\r
166 xTaskCreate( prvTimerTestTask, ( signed portCHAR * ) "Tmr Tst", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
\r
169 /*-----------------------------------------------------------*/
\r
171 static void prvTimerTestTask( void *pvParameters )
\r
173 ( void ) pvParameters;
\r
175 /* Create a one-shot timer for use later on in this test. */
\r
176 xOneShotTimer = xTimerCreate( ( const signed char * ) "Oneshot Timer",/* Text name to facilitate debugging. The kernel does not use this itself. */
\r
177 tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */
\r
178 pdFALSE, /* Don't auto-reload - hence a one shot timer. */
\r
179 ( void * ) 0, /* The timer identifier. In this case this is not used as the timer has its own callback. */
\r
180 prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */
\r
182 if( xOneShotTimer == NULL )
\r
184 xTestStatus = pdFAIL;
\r
185 configASSERT( xTestStatus );
\r
189 /* Ensure all the timers are in their expected initial state. This
\r
190 depends on the timer service task having a higher priority than this task. */
\r
191 prvTest2_CheckTaskAndTimersInitialState();
\r
195 /* Check the auto reload timers expire at the expected/correct rates. */
\r
196 prvTest3_CheckAutoReloadExpireRates();
\r
198 /* Check the auto reload timers can be stopped correctly, and correctly
\r
199 report their state. */
\r
200 prvTest4_CheckAutoReloadTimersCanBeStopped();
\r
202 /* Check the one shot timer only calls its callback once after it has been
\r
203 started, and that it reports its state correctly. */
\r
204 prvTest5_CheckBasicOneShotTimerBehaviour();
\r
206 /* Check timer reset behaviour. */
\r
207 prvTest6_CheckAutoReloadResetBehaviour();
\r
209 /* Start the timers again to restart all the tests over again. */
\r
210 prvResetStartConditionsForNextIteration();
\r
213 /*-----------------------------------------------------------*/
\r
215 /* This is called to check that the created task is still running and has not
\r
216 detected any errors. */
\r
217 portBASE_TYPE xAreTimerDemoTasksStillRunning( portTickType xCycleFrequency )
\r
219 static unsigned long ulLastLoopCounter = 0UL;
\r
220 portTickType xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;
\r
221 static portTickType xIterationsWithoutCounterIncrement = ( portTickType ) 0, xLastCycleFrequency;
\r
223 if( xLastCycleFrequency != xCycleFrequency )
\r
225 /* The cycle frequency has probably become much faster due to an error
\r
226 elsewhere. Start counting Iterations again. */
\r
227 xIterationsWithoutCounterIncrement = ( portTickType ) 0;
\r
228 xLastCycleFrequency = xCycleFrequency;
\r
231 /* Calculate the maximum number of times that it is permissible for this
\r
232 function to be called without ulLoopCounter being incremented. This is
\r
233 necessary because the tests in this file block for extended periods, and the
\r
234 block period might be longer than the time between calls to this function. */
\r
235 xMaxBlockTimeUsedByTheseTests = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
\r
236 xLoopCounterIncrementTimeMax = xMaxBlockTimeUsedByTheseTests / xCycleFrequency;
\r
238 /* If the demo task is still running then we expect the loopcounter to
\r
239 have incremented every xLoopCounterIncrementTimeMax calls. */
\r
240 if( ulLastLoopCounter == ulLoopCounter )
\r
242 xIterationsWithoutCounterIncrement++;
\r
243 if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
\r
245 /* The tests appear to be no longer running (stalled). */
\r
246 xTestStatus = pdFAIL;
\r
247 configASSERT( xTestStatus );
\r
252 /* ulLoopCounter changed, so the count of times this function was called
\r
253 without a change can be reset to zero. */
\r
254 xIterationsWithoutCounterIncrement = ( portTickType ) 0;
\r
257 ulLastLoopCounter = ulLoopCounter;
\r
259 /* Errors detected in the task itself will have latched xTestStatus
\r
262 return xTestStatus;
\r
264 /*-----------------------------------------------------------*/
\r
266 static void prvTest1_CreateTimersWithoutSchedulerRunning( void )
\r
268 unsigned portBASE_TYPE xTimer;
\r
270 for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
\r
272 /* As the timer queue is not yet full, it should be possible to both create
\r
273 and start a timer. These timers are being started before the scheduler has
\r
274 been started, so their block times should get set to zero within the timer
\r
276 xAutoReloadTimers[ xTimer ] = xTimerCreate( ( const signed char * )"FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
277 ( ( xTimer + ( portTickType ) 1 ) * xBasePeriod ),/* The period for the timer. The plus 1 ensures a period of zero is not specified. */
\r
278 pdTRUE, /* Auto-reload is set to true. */
\r
279 ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
\r
280 prvAutoReloadTimerCallback ); /* The callback to be called when the timer expires. */
\r
282 if( xAutoReloadTimers[ xTimer ] == NULL )
\r
284 xTestStatus = pdFAIL;
\r
285 configASSERT( xTestStatus );
\r
289 /* The scheduler has not yet started, so the block period of
\r
290 portMAX_DELAY should just get set to zero in xTimerStart(). Also,
\r
291 the timer queue is not yet full so xTimerStart() should return
\r
293 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
\r
295 xTestStatus = pdFAIL;
\r
296 configASSERT( xTestStatus );
\r
301 /* The timers queue should now be full, so it should be possible to create
\r
302 another timer, but not possible to start it (the timer queue will not get
\r
303 drained until the scheduler has been started. */
\r
304 xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( ( const signed char * ) "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
305 ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */
\r
306 pdTRUE, /* Auto-reload is set to true. */
\r
307 ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
\r
308 prvAutoReloadTimerCallback ); /* The callback executed when the timer expires. */
\r
310 if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
\r
312 xTestStatus = pdFAIL;
\r
313 configASSERT( xTestStatus );
\r
317 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
\r
319 /* This time it would not be expected that the timer could be
\r
320 started at this point. */
\r
321 xTestStatus = pdFAIL;
\r
322 configASSERT( xTestStatus );
\r
326 /* Create the timers that are used from the tick interrupt to test the timer
\r
327 API functions that can be called from an ISR. */
\r
328 xISRAutoReloadTimer = xTimerCreate( ( const signed char * ) "ISR AR", /* The text name given to the timer. */
\r
329 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
\r
330 pdTRUE, /* This is an auto reload timer. */
\r
331 ( void * ) NULL, /* The identifier is not required. */
\r
332 prvISRAutoReloadTimerCallback ); /* The callback that is executed when the timer expires. */
\r
334 xISROneShotTimer = xTimerCreate( ( const signed char * ) "ISR OS", /* The text name given to the timer. */
\r
335 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
\r
336 pdFALSE, /* This is a one shot timer. */
\r
337 ( void * ) NULL, /* The identifier is not required. */
\r
338 prvISROneShotTimerCallback ); /* The callback that is executed when the timer expires. */
\r
340 if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )
\r
342 xTestStatus = pdFAIL;
\r
343 configASSERT( xTestStatus );
\r
346 /*-----------------------------------------------------------*/
\r
348 static void prvTest2_CheckTaskAndTimersInitialState( void )
\r
350 unsigned char ucTimer;
\r
352 /* Ensure all the timers are in their expected initial state. This depends
\r
353 on the timer service task having a higher priority than this task.
\r
355 auto reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
\r
356 and auto reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
\r
357 could not be started prior to the scheduler being started when it was
\r
359 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
361 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
363 xTestStatus = pdFAIL;
\r
364 configASSERT( xTestStatus );
\r
368 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
\r
370 xTestStatus = pdFAIL;
\r
371 configASSERT( xTestStatus );
\r
374 /*-----------------------------------------------------------*/
\r
376 static void prvTest3_CheckAutoReloadExpireRates( void )
\r
378 unsigned char ucMaxAllowableValue, ucMinAllowableValue, ucTimer;
\r
379 portTickType xBlockPeriod, xTimerPeriod, xExpectedNumber;
\r
381 /* Check the auto reload timers expire at the expected rates. */
\r
384 /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
\r
385 all the auto reload timers to expire at least once. */
\r
386 xBlockPeriod = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
\r
387 vTaskDelay( xBlockPeriod );
\r
389 /* Check that all the auto reload timers have called their callback
\r
390 function the expected number of times. */
\r
391 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
393 /* The expected number of expiries is equal to the block period divided
\r
394 by the timer period. */
\r
395 xTimerPeriod = ( ( ( portTickType ) ucTimer + ( portTickType ) 1 ) * xBasePeriod );
\r
396 xExpectedNumber = xBlockPeriod / xTimerPeriod;
\r
398 ucMaxAllowableValue = ( ( unsigned char ) xExpectedNumber ) ;
\r
399 ucMinAllowableValue = ( ( unsigned char ) xExpectedNumber - ( unsigned char ) 1 );
\r
401 if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
\r
402 ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )
\r
405 xTestStatus = pdFAIL;
\r
406 configASSERT( xTestStatus );
\r
410 if( xTestStatus == pdPASS )
\r
412 /* No errors have been reported so increment the loop counter so the
\r
413 check task knows this task is still running. */
\r
417 /*-----------------------------------------------------------*/
\r
419 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
\r
421 unsigned char ucTimer;
\r
423 /* Check the auto reload timers can be stopped correctly, and correctly
\r
424 report their state. */
\r
426 /* Stop all the active timers. */
\r
427 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
429 /* The timer has not been stopped yet! */
\r
430 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
432 xTestStatus = pdFAIL;
\r
433 configASSERT( xTestStatus );
\r
436 /* Now stop the timer. This will appear to happen immediately to
\r
437 this task because this task is running at a priority below the
\r
438 timer service task. */
\r
439 xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
441 /* The timer should now be inactive. */
\r
442 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
\r
444 xTestStatus = pdFAIL;
\r
445 configASSERT( xTestStatus );
\r
449 taskENTER_CRITICAL();
\r
451 /* The timer in array position configTIMER_QUEUE_LENGTH should not
\r
452 be active. The critical section is used to ensure the timer does
\r
453 not call its callback between the next line running and the array
\r
454 being cleared back to zero, as that would mask an error condition. */
\r
455 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( unsigned char ) 0 )
\r
457 xTestStatus = pdFAIL;
\r
458 configASSERT( xTestStatus );
\r
461 /* Clear the timer callback count. */
\r
462 memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );
\r
464 taskEXIT_CRITICAL();
\r
466 /* The timers are now all inactive, so this time, after delaying, none
\r
467 of the callback counters should have incremented. */
\r
468 vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
\r
469 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
471 if( ucAutoReloadTimerCounters[ ucTimer ] != ( unsigned char ) 0 )
\r
473 xTestStatus = pdFAIL;
\r
474 configASSERT( xTestStatus );
\r
478 if( xTestStatus == pdPASS )
\r
480 /* No errors have been reported so increment the loop counter so
\r
481 the check task knows this task is still running. */
\r
485 /*-----------------------------------------------------------*/
\r
487 static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
\r
489 /* Check the one shot timer only calls its callback once after it has been
\r
490 started, and that it reports its state correctly. */
\r
492 /* The one shot timer should not be active yet. */
\r
493 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
495 xTestStatus = pdFAIL;
\r
496 configASSERT( xTestStatus );
\r
499 if( ucOneShotTimerCounter != ( unsigned char ) 0 )
\r
501 xTestStatus = pdFAIL;
\r
502 configASSERT( xTestStatus );
\r
505 /* Start the one shot timer and check that it reports its state correctly. */
\r
506 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
507 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
509 xTestStatus = pdFAIL;
\r
510 configASSERT( xTestStatus );
\r
513 /* Delay for three times as long as the one shot timer period, then check
\r
514 to ensure it has only called its callback once, and is now not in the
\r
516 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( portTickType ) 3 );
\r
518 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
520 xTestStatus = pdFAIL;
\r
521 configASSERT( xTestStatus );
\r
524 if( ucOneShotTimerCounter != ( unsigned char ) 1 )
\r
526 xTestStatus = pdFAIL;
\r
527 configASSERT( xTestStatus );
\r
531 /* Reset the one shot timer callback count. */
\r
532 ucOneShotTimerCounter = ( unsigned char ) 0;
\r
535 if( xTestStatus == pdPASS )
\r
537 /* No errors have been reported so increment the loop counter so the
\r
538 check task knows this task is still running. */
\r
542 /*-----------------------------------------------------------*/
\r
544 static void prvTest6_CheckAutoReloadResetBehaviour( void )
\r
546 unsigned char ucTimer;
\r
548 /* Check timer reset behaviour. */
\r
550 /* Restart the one shot timer and check it reports its status correctly. */
\r
551 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
552 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
554 xTestStatus = pdFAIL;
\r
555 configASSERT( xTestStatus );
\r
558 /* Restart one of the auto reload timers and check that it reports its
\r
559 status correctly. */
\r
560 xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
561 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
563 xTestStatus = pdFAIL;
\r
564 configASSERT( xTestStatus );
\r
567 for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )
\r
569 /* Delay for half as long as the one shot timer period, then reset it.
\r
570 It should never expire while this is done, so its callback count should
\r
571 never increment. */
\r
572 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
\r
574 /* Check both running timers are still active, but have not called their
\r
575 callback functions. */
\r
576 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
578 xTestStatus = pdFAIL;
\r
579 configASSERT( xTestStatus );
\r
582 if( ucOneShotTimerCounter != ( unsigned char ) 0 )
\r
584 xTestStatus = pdFAIL;
\r
585 configASSERT( xTestStatus );
\r
588 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
590 xTestStatus = pdFAIL;
\r
591 configASSERT( xTestStatus );
\r
594 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( unsigned char ) 0 )
\r
596 xTestStatus = pdFAIL;
\r
597 configASSERT( xTestStatus );
\r
600 /* Reset both running timers. */
\r
601 xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
602 xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
604 if( xTestStatus == pdPASS )
\r
606 /* No errors have been reported so increment the loop counter so
\r
607 the check task knows this task is still running. */
\r
612 /* Finally delay long enough for both running timers to expire. */
\r
613 vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
\r
615 /* The timers were not reset during the above delay period so should now
\r
616 both have called their callback functions. */
\r
617 if( ucOneShotTimerCounter != ( unsigned char ) 1 )
\r
619 xTestStatus = pdFAIL;
\r
620 configASSERT( xTestStatus );
\r
623 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
\r
625 xTestStatus = pdFAIL;
\r
626 configASSERT( xTestStatus );
\r
629 /* The one shot timer should no longer be active, while the auto reload
\r
630 timer should still be active. */
\r
631 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
633 xTestStatus = pdFAIL;
\r
634 configASSERT( xTestStatus );
\r
637 if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
\r
639 xTestStatus = pdFAIL;
\r
640 configASSERT( xTestStatus );
\r
643 /* Stop the auto reload timer again. */
\r
644 xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
646 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
\r
648 xTestStatus = pdFAIL;
\r
649 configASSERT( xTestStatus );
\r
652 /* Clear the timer callback counts, ready for another iteration of these
\r
654 ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( unsigned char ) 0;
\r
655 ucOneShotTimerCounter = ( unsigned char ) 0;
\r
657 if( xTestStatus == pdPASS )
\r
659 /* No errors have been reported so increment the loop counter so the check
\r
660 task knows this task is still running. */
\r
664 /*-----------------------------------------------------------*/
\r
666 static void prvResetStartConditionsForNextIteration( void )
\r
668 unsigned char ucTimer;
\r
670 /* Start the timers again to start all the tests over again. */
\r
672 /* Start the timers again. */
\r
673 for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
675 /* The timer has not been started yet! */
\r
676 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
\r
678 xTestStatus = pdFAIL;
\r
679 configASSERT( xTestStatus );
\r
682 /* Now start the timer. This will appear to happen immediately to
\r
683 this task because this task is running at a priority below the timer
\r
685 xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
687 /* The timer should now be active. */
\r
688 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
690 xTestStatus = pdFAIL;
\r
691 configASSERT( xTestStatus );
\r
695 if( xTestStatus == pdPASS )
\r
697 /* No errors have been reported so increment the loop counter so the
\r
698 check task knows this task is still running. */
\r
702 /*-----------------------------------------------------------*/
\r
704 void vTimerPeriodicISRTests( void )
\r
706 static portTickType uxTick = ( portTickType ) -1;
\r
708 /* The xHigherPriorityTaskWoken parameter is not used in this case as this
\r
709 function is called from the tick hook anyway. However the API required it
\r
711 portBASE_TYPE xHigherPriorityTaskWoken = pdTRUE;
\r
712 portTickType xMargin;
\r
714 if( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
\r
716 /* The timer service task is not the highest priority task, so it cannot
\r
717 be assumed that timings will be exact. Timers should never call their
\r
718 callback before their expiry time, but a margin is permissible for calling
\r
719 their callback after their expiry time. If exact timing is required then
\r
720 configTIMER_TASK_PRIORITY must be set to ensure the timer service task
\r
721 is the highest priority task in the system. */
\r
729 /* This test is called from the tick ISR even when the scheduler is suspended.
\r
730 Therefore, it is possible for the xTickCount to be temporarily less than the
\r
731 uxTicks count maintained in this function. That can result in calculated
\r
732 unblock times being too short, as this function is not called as missed ticks
\r
733 (ticks that occur while the scheduler is suspended) are unwound to re-instate
\r
734 the real tick value. Therefore, if this happens, just abandon the test
\r
735 and start again. */
\r
736 if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
\r
738 uxTick = ( portTickType ) -1;
\r
747 /* The timers will have been created, but not started. Start them
\r
748 now by setting their period. */
\r
749 ucISRAutoReloadTimerCounter = 0;
\r
750 ucISROneShotTimerCounter = 0;
\r
751 xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, &xHigherPriorityTaskWoken );
\r
752 xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, &xHigherPriorityTaskWoken );
\r
754 else if( uxTick == xBasePeriod )
\r
756 /* Neither timer should have expired yet. */
\r
757 if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )
\r
759 xTestStatus = pdFAIL;
\r
760 configASSERT( xTestStatus );
\r
763 else if( uxTick == ( xBasePeriod + xMargin ) )
\r
765 /* Both timers should now have expired once. The auto reload timer will
\r
766 still be active, but the one shot timer should now have stopped. */
\r
767 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
\r
769 xTestStatus = pdFAIL;
\r
770 configASSERT( xTestStatus );
\r
773 else if( uxTick == ( 2 * xBasePeriod ) )
\r
775 /* The auto reload timer will still be active, but the one shot timer
\r
776 should now have stopped - however, at this time neither of the timers
\r
777 should have expired again since the last test. */
\r
778 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
\r
780 xTestStatus = pdFAIL;
\r
781 configASSERT( xTestStatus );
\r
784 else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
\r
786 /* The auto reload timer will still be active, but the one shot timer
\r
787 should now have stopped. At this time the auto reload timer should have
\r
788 expired again, but the one shot timer count should not have changed. */
\r
789 if( ucISRAutoReloadTimerCounter != 2 )
\r
791 xTestStatus = pdFAIL;
\r
792 configASSERT( xTestStatus );
\r
795 if( ucISROneShotTimerCounter != 1 )
\r
797 xTestStatus = pdFAIL;
\r
798 configASSERT( xTestStatus );
\r
801 else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( portTickType ) 2U ) ) )
\r
803 /* The auto reload timer will still be active, but the one shot timer
\r
804 should now have stopped. Again though, at this time, neither timer call
\r
805 back should have been called since the last test. */
\r
806 if( ucISRAutoReloadTimerCounter != 2 )
\r
808 xTestStatus = pdFAIL;
\r
809 configASSERT( xTestStatus );
\r
812 if( ucISROneShotTimerCounter != 1 )
\r
814 xTestStatus = pdFAIL;
\r
815 configASSERT( xTestStatus );
\r
818 else if( uxTick == ( 3 * xBasePeriod ) )
\r
820 /* Start the one shot timer again. */
\r
821 xTimerStartFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
\r
823 else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
\r
825 /* The auto reload timer and one shot timer will be active. At
\r
826 this time the auto reload timer should have expired again, but the one
\r
827 shot timer count should not have changed yet. */
\r
828 if( ucISRAutoReloadTimerCounter != 3 )
\r
830 xTestStatus = pdFAIL;
\r
831 configASSERT( xTestStatus );
\r
834 if( ucISROneShotTimerCounter != 1 )
\r
836 xTestStatus = pdFAIL;
\r
837 configASSERT( xTestStatus );
\r
840 /* Now stop the auto reload timer. The one shot timer was started
\r
841 a few ticks ago. */
\r
842 xTimerStopFromISR( xISRAutoReloadTimer, &xHigherPriorityTaskWoken );
\r
844 else if( uxTick == ( 4 * xBasePeriod ) )
\r
846 /* The auto reload timer is now stopped, and the one shot timer is
\r
847 active, but at this time neither timer should have expired since the
\r
849 if( ucISRAutoReloadTimerCounter != 3 )
\r
851 xTestStatus = pdFAIL;
\r
852 configASSERT( xTestStatus );
\r
855 if( ucISROneShotTimerCounter != 1 )
\r
857 xTestStatus = pdFAIL;
\r
858 configASSERT( xTestStatus );
\r
861 else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
\r
863 /* The auto reload timer is now stopped, and the one shot timer is
\r
864 active. The one shot timer should have expired again, but the auto
\r
865 reload timer should not have executed its callback. */
\r
866 if( ucISRAutoReloadTimerCounter != 3 )
\r
868 xTestStatus = pdFAIL;
\r
869 configASSERT( xTestStatus );
\r
872 if( ucISROneShotTimerCounter != 2 )
\r
874 xTestStatus = pdFAIL;
\r
875 configASSERT( xTestStatus );
\r
878 else if( uxTick == ( ( 8 * xBasePeriod ) + xMargin ) )
\r
880 /* The auto reload timer is now stopped, and the one shot timer has
\r
881 already expired and then stopped itself. Both callback counters should
\r
882 not have incremented since the last test. */
\r
883 if( ucISRAutoReloadTimerCounter != 3 )
\r
885 xTestStatus = pdFAIL;
\r
886 configASSERT( xTestStatus );
\r
889 if( ucISROneShotTimerCounter != 2 )
\r
891 xTestStatus = pdFAIL;
\r
892 configASSERT( xTestStatus );
\r
895 /* Now reset the one shot timer. */
\r
896 xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
\r
898 else if( uxTick == ( 9 * xBasePeriod ) )
\r
900 /* Only the one shot timer should be running, but it should not have
\r
901 expired since the last test. Check the callback counters have not
\r
902 incremented, then reset the one shot timer again. */
\r
903 if( ucISRAutoReloadTimerCounter != 3 )
\r
905 xTestStatus = pdFAIL;
\r
906 configASSERT( xTestStatus );
\r
909 if( ucISROneShotTimerCounter != 2 )
\r
911 xTestStatus = pdFAIL;
\r
912 configASSERT( xTestStatus );
\r
915 xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
\r
917 else if( uxTick == ( 10 * xBasePeriod ) )
\r
919 /* Only the one shot timer should be running, but it should not have
\r
920 expired since the last test. Check the callback counters have not
\r
921 incremented, then reset the one shot timer again. */
\r
922 if( ucISRAutoReloadTimerCounter != 3 )
\r
924 xTestStatus = pdFAIL;
\r
925 configASSERT( xTestStatus );
\r
928 if( ucISROneShotTimerCounter != 2 )
\r
930 xTestStatus = pdFAIL;
\r
931 configASSERT( xTestStatus );
\r
934 xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
\r
936 else if( uxTick == ( 11 * xBasePeriod ) )
\r
938 /* Only the one shot timer should be running, but it should not have
\r
939 expired since the last test. Check the callback counters have not
\r
940 incremented, then reset the one shot timer once again. */
\r
941 if( ucISRAutoReloadTimerCounter != 3 )
\r
943 xTestStatus = pdFAIL;
\r
944 configASSERT( xTestStatus );
\r
947 if( ucISROneShotTimerCounter != 2 )
\r
949 xTestStatus = pdFAIL;
\r
950 configASSERT( xTestStatus );
\r
953 xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
\r
955 else if( uxTick == ( ( 12 * xBasePeriod ) + xMargin ) )
\r
957 /* Only the one shot timer should have been running and this time it
\r
958 should have expired. Check its callback count has been incremented.
\r
959 The auto reload timer is still not running so should still have the same
\r
960 count value. This time the one shot timer is not reset so should not
\r
961 restart from its expiry period again. */
\r
962 if( ucISRAutoReloadTimerCounter != 3 )
\r
964 xTestStatus = pdFAIL;
\r
965 configASSERT( xTestStatus );
\r
968 if( ucISROneShotTimerCounter != 3 )
\r
970 xTestStatus = pdFAIL;
\r
971 configASSERT( xTestStatus );
\r
974 else if( uxTick == ( 15 * xBasePeriod ) )
\r
976 /* Neither timer should be running now. Check neither callback count
\r
977 has incremented, then go back to the start to run these tests all
\r
979 if( ucISRAutoReloadTimerCounter != 3 )
\r
981 xTestStatus = pdFAIL;
\r
982 configASSERT( xTestStatus );
\r
985 if( ucISROneShotTimerCounter != 3 )
\r
987 xTestStatus = pdFAIL;
\r
988 configASSERT( xTestStatus );
\r
991 uxTick = ( portTickType ) -1;
\r
994 /*-----------------------------------------------------------*/
\r
996 /*** Timer callback functions are defined below here. ***/
\r
998 static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )
\r
1000 portBASE_TYPE xTimerID;
\r
1002 xTimerID = ( portBASE_TYPE ) pvTimerGetTimerID( pxExpiredTimer );
\r
1003 if( xTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
\r
1005 ( ucAutoReloadTimerCounters[ xTimerID ] )++;
\r
1009 /* The timer ID appears to be unexpected (invalid). */
\r
1010 xTestStatus = pdFAIL;
\r
1011 configASSERT( xTestStatus );
\r
1014 /*-----------------------------------------------------------*/
\r
1016 static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer )
\r
1018 /* The parameter is not used in this case as only one timer uses this
\r
1019 callback function. */
\r
1020 ( void ) pxExpiredTimer;
\r
1022 ucOneShotTimerCounter++;
\r
1024 /*-----------------------------------------------------------*/
\r
1026 static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )
\r
1028 /* The parameter is not used in this case as only one timer uses this
\r
1029 callback function. */
\r
1030 ( void ) pxExpiredTimer;
\r
1032 ucISRAutoReloadTimerCounter++;
\r
1034 /*-----------------------------------------------------------*/
\r
1036 static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer )
\r
1038 /* The parameter is not used in this case as only one timer uses this
\r
1039 callback function. */
\r
1040 ( void ) pxExpiredTimer;
\r
1042 ucISROneShotTimerCounter++;
\r
1044 /*-----------------------------------------------------------*/
\r