2 FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
75 /* Standard includes. */
\r
78 /* FreeRTOS includes. */
\r
79 #include "FreeRTOS.h"
\r
82 /* Library includes. */
\r
87 * When configCREATE_LOW_POWER_DEMO is set to 1 then the tick interrupt
\r
88 * is generated by the AST. The AST configuration and handling functions are
\r
89 * defined in this file.
\r
91 * When configCREATE_LOW_POWER_DEMO is set to 0 the tick interrupt is
\r
92 * generated by the standard FreeRTOS Cortex-M port layer, which uses the
\r
95 #if configCREATE_LOW_POWER_DEMO == 1
\r
97 /* Constants required to pend a PendSV interrupt from the tick ISR if the
\r
98 preemptive scheduler is being used. These are just standard bits and registers
\r
99 within the Cortex-M core itself. */
\r
100 #define portNVIC_INT_CTRL_REG ( * ( ( volatile unsigned long * ) 0xe000ed04 ) )
\r
101 #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
\r
103 /* The alarm used to generate interrupts in the asynchronous timer. */
\r
104 #define portAST_ALARM_CHANNEL 0
\r
106 /*-----------------------------------------------------------*/
\r
109 * The tick interrupt is generated by the asynchronous timer. The default tick
\r
110 * interrupt handler cannot be used (even with the AST being handled from the
\r
111 * tick hook function) because the default tick interrupt accesses the SysTick
\r
112 * registers when configUSE_TICKLESS_IDLE set to 1. AST_ALARM_Handler() is the
\r
113 * default name for the AST alarm interrupt. This definition overrides the
\r
114 * default implementation that is weakly defined in the interrupt vector table
\r
117 void AST_ALARM_Handler(void);
\r
119 /*-----------------------------------------------------------*/
\r
121 /* Calculate how many clock increments make up a single tick period. */
\r
122 static const uint32_t ulAlarmValueForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
\r
124 /* Holds the maximum number of ticks that can be suppressed - which is
\r
125 basically how far into the future an interrupt can be generated. Set
\r
126 during initialisation. */
\r
127 static portTickType xMaximumPossibleSuppressedTicks = 0;
\r
129 /* Flag set from the tick interrupt to allow the sleep processing to know if
\r
130 sleep mode was exited because of an AST interrupt or a different interrupt. */
\r
131 static volatile uint32_t ulTickFlag = pdFALSE;
\r
133 /* The AST counter is stopped temporarily each time it is re-programmed. The
\r
134 following variable offsets the AST counter alarm value by the number of AST
\r
135 counts that would typically be missed while the counter was stopped to compensate
\r
136 for the lost time. _RB_ Value needs calculating correctly. */
\r
137 static uint32_t ulStoppedTimerCompensation = 10 / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
\r
139 /*-----------------------------------------------------------*/
\r
141 /* The tick interrupt handler. This is always the same other than the part that
\r
142 clears the interrupt, which is specific to the clock being used to generate the
\r
144 void AST_ALARM_Handler(void)
\r
146 /* If using preemption, also force a context switch by pending the PendSV
\r
148 #if configUSE_PREEMPTION == 1
\r
150 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
\r
154 /* Protect incrementing the tick with an interrupt safe critical section. */
\r
155 ( void ) portSET_INTERRUPT_MASK_FROM_ISR();
\r
157 vTaskIncrementTick();
\r
159 /* Just completely clear the interrupt mask on exit by passing 0 because
\r
160 it is known that this interrupt will only ever execute with the lowest
\r
161 possible interrupt priority. */
\r
163 portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
\r
165 /* The CPU woke because of a tick. */
\r
166 ulTickFlag = pdTRUE;
\r
168 /* If this is the first tick since exiting tickless mode then the AST needs
\r
169 to be reconfigured to generate interrupts at the defined tick frequency. */
\r
170 ast_write_alarm0_value( AST, ulAlarmValueForOneTick );
\r
172 /* Ensure the interrupt is clear before exiting. */
\r
173 ast_clear_interrupt_flag( AST, AST_INTERRUPT_ALARM );
\r
175 /*-----------------------------------------------------------*/
\r
177 /* Override the default definition of vPortSetupTimerInterrupt() that is weakly
\r
178 defined in the FreeRTOS Cortex-M3 port layer layer with a version that
\r
179 configures the asynchronous timer (AST) to generate the tick interrupt. */
\r
180 void vPortSetupTimerInterrupt( void )
\r
182 struct ast_config ast_conf;
\r
184 /* Ensure the AST can bring the CPU out of sleep mode. */
\r
185 sleepmgr_lock_mode( SLEEPMGR_RET );
\r
187 /* Ensure the 32KHz oscillator is enabled. */
\r
188 if( osc_is_ready( OSC_ID_OSC32 ) == pdFALSE )
\r
190 osc_enable( OSC_ID_OSC32 );
\r
191 osc_wait_ready( OSC_ID_OSC32 );
\r
194 /* Enable the AST itself. */
\r
197 ast_conf.mode = AST_COUNTER_MODE; /* Simple up counter. */
\r
198 ast_conf.osc_type = AST_OSC_32KHZ;
\r
199 ast_conf.psel = 0; /* No prescale so the actual frequency is 32KHz/2. */
\r
200 ast_conf.counter = 0;
\r
201 ast_set_config( AST, &ast_conf );
\r
203 /* The AST alarm interrupt is used as the tick interrupt. Ensure the alarm
\r
204 status starts clear. */
\r
205 ast_clear_interrupt_flag( AST, AST_INTERRUPT_ALARM );
\r
207 /* Enable wakeup from alarm 0 in the AST and power manager. */
\r
208 ast_enable_wakeup( AST, AST_WAKEUP_ALARM );
\r
209 bpm_enable_wakeup_source( BPM, ( 1 << BPM_BKUPWEN_AST ) );
\r
211 /* Tick interrupt MUST execute at the lowest interrupt priority. */
\r
212 NVIC_SetPriority( AST_ALARM_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
\r
213 ast_enable_interrupt( AST, AST_INTERRUPT_ALARM );
\r
214 NVIC_ClearPendingIRQ( AST_ALARM_IRQn );
\r
215 NVIC_EnableIRQ( AST_ALARM_IRQn );
\r
217 /* Automatically clear the counter on interrupt. */
\r
218 ast_enable_counter_clear_on_alarm( AST, portAST_ALARM_CHANNEL );
\r
220 /* Start with the tick active and generating a tick with regular period. */
\r
221 ast_write_alarm0_value( AST, ulAlarmValueForOneTick );
\r
222 ast_write_counter_value( AST, 0 );
\r
224 /* See the comments where xMaximumPossibleSuppressedTicks is declared. */
\r
225 xMaximumPossibleSuppressedTicks = ULONG_MAX / ulAlarmValueForOneTick;
\r
227 /*-----------------------------------------------------------*/
\r
229 void prvDisableAST( void )
\r
231 while( ast_is_busy( AST ) )
\r
233 /* Nothing to do here, just waiting. */
\r
235 AST->AST_CR &= ~( AST_CR_EN );
\r
236 while( ast_is_busy( AST ) )
\r
238 /* Nothing to do here, just waiting. */
\r
241 /*-----------------------------------------------------------*/
\r
243 void prvEnableAST( void )
\r
245 while( ast_is_busy( AST ) )
\r
247 /* Nothing to do here, just waiting. */
\r
249 AST->AST_CR |= AST_CR_EN;
\r
250 while( ast_is_busy( AST ) )
\r
252 /* Nothing to do here, just waiting. */
\r
255 /*-----------------------------------------------------------*/
\r
257 /* Override the default definition of vPortSuppressTicksAndSleep() that is weakly
\r
258 defined in the FreeRTOS Cortex-M3 port layer layer with a version that manages
\r
259 the asynchronous timer (AST), as the tick is generated from the low power AST
\r
260 and not the SysTick as would normally be the case on a Cortex-M. */
\r
261 void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime )
\r
263 uint32_t ulAlarmValue, ulCompleteTickPeriods;
\r
264 eSleepModeStatus eSleepAction;
\r
265 portTickType xModifiableIdleTime;
\r
266 enum sleepmgr_mode xSleepMode;
\r
268 /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */
\r
270 /* Make sure the AST reload value does not overflow the counter. */
\r
271 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
\r
273 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
\r
276 /* Calculate the reload value required to wait xExpectedIdleTime tick
\r
277 periods. -1 is used because this code will execute part way through one of
\r
278 the tick periods, and the fraction of a tick period is accounted for
\r
280 ulAlarmValue = ( ulAlarmValueForOneTick * ( xExpectedIdleTime - 1UL ) );
\r
281 if( ulAlarmValue > ulStoppedTimerCompensation )
\r
283 /* Compensate for the fact that the AST is going to be stopped
\r
285 ulAlarmValue -= ulStoppedTimerCompensation;
\r
288 /* Stop the AST momentarily. The time the AST is stopped for is accounted
\r
289 for as best it can be, but using the tickless mode will inevitably result in
\r
290 some tiny drift of the time maintained by the kernel with respect to
\r
294 /* Enter a critical section but don't use the taskENTER_CRITICAL() method as
\r
295 that will mask interrupts that should exit sleep mode. */
\r
296 __asm volatile( "cpsid i \n\t"
\r
299 /* The tick flag is set to false before sleeping. If it is true when sleep
\r
300 mode is exited then sleep mode was probably exited because the tick was
\r
301 suppressed for the entire xExpectedIdleTime period. */
\r
302 ulTickFlag = pdFALSE;
\r
304 /* If a context switch is pending then abandon the low power entry as
\r
305 the context switch might have been pended by an external interrupt that
\r
306 requires processing. */
\r
307 eSleepAction = eTaskConfirmSleepModeStatus();
\r
308 if( eSleepAction == eAbortSleep )
\r
310 /* Restart tick. */
\r
313 /* Re-enable interrupts - see comments above the cpsid instruction()
\r
315 __asm volatile( "cpsie i" );
\r
319 /* Adjust the alarm value to take into account that the current time
\r
320 slice is already partially complete. */
\r
321 ulAlarmValue -= ast_read_counter_value( AST );
\r
322 ast_write_alarm0_value( AST, ulAlarmValue );
\r
324 /* Restart the AST. */
\r
327 /* Allow the application to define some pre-sleep processing. */
\r
328 xModifiableIdleTime = xExpectedIdleTime;
\r
329 configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
\r
331 /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()
\r
332 means the application defined code has already executed the WAIT
\r
334 if( xModifiableIdleTime > 0 )
\r
336 /* Find the deepest allowable sleep mode. */
\r
337 xSleepMode = sleepmgr_get_sleep_mode();
\r
339 if( xSleepMode != SLEEPMGR_ACTIVE )
\r
341 /* Sleep until something happens. */
\r
342 bpm_sleep( BPM, xSleepMode );
\r
346 /* Allow the application to define some post sleep processing. */
\r
347 configPOST_SLEEP_PROCESSING( xModifiableIdleTime );
\r
349 /* Stop AST. Again, the time the SysTick is stopped for is accounted
\r
350 for as best it can be, but using the tickless mode will inevitably
\r
351 result in some tiny drift of the time maintained by the kernel with
\r
352 respect to calendar time. */
\r
355 /* Re-enable interrupts - see comments above the cpsid instruction()
\r
357 __asm volatile( "cpsie i" );
\r
359 if( ulTickFlag != pdFALSE )
\r
361 /* The tick interrupt has already executed, although because this
\r
362 function is called with the scheduler suspended the actual tick
\r
363 processing will not occur until after this function has exited.
\r
364 Reset the alarm value with whatever remains of this tick period. */
\r
365 ulAlarmValue = ulAlarmValueForOneTick - ast_read_counter_value( AST );
\r
366 ast_write_alarm0_value( AST, ulAlarmValue );
\r
368 /* The tick interrupt handler will already have pended the tick
\r
369 processing in the kernel. As the pending tick will be processed as
\r
370 soon as this function exits, the tick value maintained by the tick
\r
371 is stepped forward by one less than the time spent sleeping. The
\r
372 actual stepping of the tick appears later in this function. */
\r
373 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
\r
377 /* Something other than the tick interrupt ended the sleep. How
\r
378 many complete tick periods passed while the processor was
\r
380 ulCompleteTickPeriods = ast_read_counter_value( AST ) / ulAlarmValueForOneTick;
\r
382 /* The alarm value is set to whatever fraction of a single tick
\r
384 ulAlarmValue = ast_read_counter_value( AST ) - ( ulCompleteTickPeriods * ulAlarmValueForOneTick );
\r
385 ast_write_alarm0_value( AST, ulAlarmValue );
\r
388 /* Restart the AST so it runs up to the alarm value. The alarm value
\r
389 will get set to the value required to generate exactly one tick period
\r
390 the next time the AST interrupt executes. */
\r
393 /* Wind the tick forward by the number of tick periods that the CPU
\r
394 remained in a low power state. */
\r
395 vTaskStepTick( ulCompleteTickPeriods );
\r
400 #endif /* configCREATE_LOW_POWER_DEMO == 1 */
\r