2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
29 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the ARM CM0 port.
31 *----------------------------------------------------------*/
34 #include "intrinsics.h"
36 /* Scheduler includes. */
40 /* Constants required to manipulate the NVIC. */
41 #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
42 #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
43 #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
44 #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
45 #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
46 #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
47 #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
48 #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
49 #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
50 #define portNVIC_PEND_SYSTICK_SET_BIT ( 1UL << 26UL )
51 #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
52 #define portMIN_INTERRUPT_PRIORITY ( 255UL )
53 #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
54 #define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
56 /* Constants required to set up the initial stack. */
57 #define portINITIAL_XPSR ( 0x01000000 )
59 /* Each task maintains its own interrupt status in the critical nesting
61 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
63 /* The systick is a 24-bit counter. */
64 #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
66 /* A fiddle factor to estimate the number of SysTick counts that would have
67 * occurred while the SysTick counter is stopped during tickless idle
69 #ifndef portMISSED_COUNTS_FACTOR
70 #define portMISSED_COUNTS_FACTOR ( 94UL )
73 /* The number of SysTick increments that make up one tick period. */
74 #if ( configUSE_TICKLESS_IDLE == 1 )
75 static uint32_t ulTimerCountsForOneTick = 0;
76 #endif /* configUSE_TICKLESS_IDLE */
78 /* The maximum number of tick periods that can be suppressed is limited by the
79 * 24 bit resolution of the SysTick timer. */
80 #if ( configUSE_TICKLESS_IDLE == 1 )
81 static uint32_t xMaximumPossibleSuppressedTicks = 0;
82 #endif /* configUSE_TICKLESS_IDLE */
84 /* Compensate for the CPU cycles that pass while the SysTick is stopped (low
85 * power functionality only. */
86 #if ( configUSE_TICKLESS_IDLE == 1 )
87 static uint32_t ulStoppedTimerCompensation = 0;
88 #endif /* configUSE_TICKLESS_IDLE */
90 /* Let the user override the default SysTick clock rate. If defined by the
91 * user, this symbol must equal the SysTick clock rate when the CLK bit is 0 in the
92 * configuration register. */
93 #ifndef configSYSTICK_CLOCK_HZ
94 #define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ )
95 /* Ensure the SysTick is clocked at the same frequency as the core. */
96 #define portNVIC_SYSTICK_CLK_BIT_CONFIG ( portNVIC_SYSTICK_CLK_BIT )
98 /* Select the option to clock SysTick not at the same frequency as the core. */
99 #define portNVIC_SYSTICK_CLK_BIT_CONFIG ( 0 )
103 * Setup the timer to generate the tick interrupts. The implementation in this
104 * file is weak to allow application writers to change the timer used to
105 * generate the tick interrupt.
107 void vPortSetupTimerInterrupt( void );
110 * Exception handlers.
112 void xPortSysTickHandler( void );
115 * Start first task is a separate function so it can be tested in isolation.
117 extern void vPortStartFirstTask( void );
120 * Used to catch tasks that attempt to return from their implementing function.
122 static void prvTaskExitError( void );
124 /*-----------------------------------------------------------*/
127 * See header file for description.
129 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
130 TaskFunction_t pxCode,
131 void * pvParameters )
133 /* Simulate the stack frame as it would be created by a context switch
135 pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
136 *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
138 *pxTopOfStack = ( StackType_t ) pxCode; /* PC */
140 *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
141 pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
142 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
143 pxTopOfStack -= 8; /* R11..R4. */
147 /*-----------------------------------------------------------*/
149 static void prvTaskExitError( void )
151 /* A function that implements a task must not exit or attempt to return to
152 * its caller as there is nothing to return to. If a task wants to exit it
153 * should instead call vTaskDelete( NULL ).
155 * Artificially force an assert() to be triggered if configASSERT() is
156 * defined, then stop here so application writers can catch the error. */
157 configASSERT( uxCriticalNesting == ~0UL );
158 portDISABLE_INTERRUPTS();
164 /*-----------------------------------------------------------*/
167 * See header file for description.
169 BaseType_t xPortStartScheduler( void )
171 /* Make PendSV and SysTick the lowest priority interrupts. */
172 portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
173 portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
175 /* Start the timer that generates the tick ISR. Interrupts are disabled
177 vPortSetupTimerInterrupt();
179 /* Initialise the critical nesting count ready for the first task. */
180 uxCriticalNesting = 0;
182 /* Start the first task. */
183 vPortStartFirstTask();
185 /* Should not get here! */
188 /*-----------------------------------------------------------*/
190 void vPortEndScheduler( void )
192 /* Not implemented in ports where there is nothing to return to.
193 * Artificially force an assert. */
194 configASSERT( uxCriticalNesting == 1000UL );
196 /*-----------------------------------------------------------*/
198 void vPortYield( void )
200 /* Set a PendSV to request a context switch. */
201 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
203 /* Barriers are normally not required but do ensure the code is completely
204 * within the specified behaviour for the architecture. */
208 /*-----------------------------------------------------------*/
210 void vPortEnterCritical( void )
212 portDISABLE_INTERRUPTS();
217 /*-----------------------------------------------------------*/
219 void vPortExitCritical( void )
221 configASSERT( uxCriticalNesting );
224 if( uxCriticalNesting == 0 )
226 portENABLE_INTERRUPTS();
229 /*-----------------------------------------------------------*/
231 void xPortSysTickHandler( void )
233 uint32_t ulPreviousMask;
235 ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
237 /* Increment the RTOS tick. */
238 if( xTaskIncrementTick() != pdFALSE )
240 /* Pend a context switch. */
241 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
244 portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
246 /*-----------------------------------------------------------*/
249 * Setup the systick timer to generate the tick interrupts at the required
252 __weak void vPortSetupTimerInterrupt( void )
254 /* Calculate the constants required to configure the tick interrupt. */
255 #if ( configUSE_TICKLESS_IDLE == 1 )
257 ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
258 xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
259 ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
261 #endif /* configUSE_TICKLESS_IDLE */
263 /* Stop and reset the SysTick. */
264 portNVIC_SYSTICK_CTRL_REG = 0UL;
265 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
267 /* Configure SysTick to interrupt at the requested rate. */
268 portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
269 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
271 /*-----------------------------------------------------------*/
273 #if ( configUSE_TICKLESS_IDLE == 1 )
275 __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
277 uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickDecrementsLeft;
278 TickType_t xModifiableIdleTime;
280 /* Make sure the SysTick reload value does not overflow the counter. */
281 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
283 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
286 /* Enter a critical section but don't use the taskENTER_CRITICAL()
287 * method as that will mask interrupts that should exit sleep mode. */
288 __disable_interrupt();
292 /* If a context switch is pending or a task is waiting for the scheduler
293 * to be unsuspended then abandon the low power entry. */
294 if( eTaskConfirmSleepModeStatus() == eAbortSleep )
296 /* Re-enable interrupts - see comments above the __disable_interrupt()
298 __enable_interrupt();
302 /* Stop the SysTick momentarily. The time the SysTick is stopped for
303 * is accounted for as best it can be, but using the tickless mode will
304 * inevitably result in some tiny drift of the time maintained by the
305 * kernel with respect to calendar time. */
306 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
308 /* Use the SysTick current-value register to determine the number of
309 * SysTick decrements remaining until the next tick interrupt. If the
310 * current-value register is zero, then there are actually
311 * ulTimerCountsForOneTick decrements remaining, not zero, because the
312 * SysTick requests the interrupt when decrementing from 1 to 0. */
313 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
315 if( ulSysTickDecrementsLeft == 0 )
317 ulSysTickDecrementsLeft = ulTimerCountsForOneTick;
320 /* Calculate the reload value required to wait xExpectedIdleTime
321 * tick periods. -1 is used because this code normally executes part
322 * way through the first tick period. But if the SysTick IRQ is now
323 * pending, then clear the IRQ, suppressing the first tick, and correct
324 * the reload value to reflect that the second tick period is already
325 * underway. The expected idle time is always at least two ticks. */
326 ulReloadValue = ulSysTickDecrementsLeft + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
328 if( ( portNVIC_INT_CTRL_REG & portNVIC_PEND_SYSTICK_SET_BIT ) != 0 )
330 portNVIC_INT_CTRL_REG = portNVIC_PEND_SYSTICK_CLEAR_BIT;
331 ulReloadValue -= ulTimerCountsForOneTick;
334 if( ulReloadValue > ulStoppedTimerCompensation )
336 ulReloadValue -= ulStoppedTimerCompensation;
339 /* Set the new reload value. */
340 portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
342 /* Clear the SysTick count flag and set the count value back to
344 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
346 /* Restart SysTick. */
347 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
349 /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
350 * set its parameter to 0 to indicate that its implementation contains
351 * its own wait for interrupt or wait for event instruction, and so wfi
352 * should not be executed again. However, the original expected idle
353 * time variable must remain unmodified, so a copy is taken. */
354 xModifiableIdleTime = xExpectedIdleTime;
355 configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
357 if( xModifiableIdleTime > 0 )
364 configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
366 /* Re-enable interrupts to allow the interrupt that brought the MCU
367 * out of sleep mode to execute immediately. See comments above
368 * the __disable_interrupt() call above. */
369 __enable_interrupt();
373 /* Disable interrupts again because the clock is about to be stopped
374 * and interrupts that execute while the clock is stopped will increase
375 * any slippage between the time maintained by the RTOS and calendar
377 __disable_interrupt();
381 /* Disable the SysTick clock without reading the
382 * portNVIC_SYSTICK_CTRL_REG register to ensure the
383 * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
384 * the time the SysTick is stopped for is accounted for as best it can
385 * be, but using the tickless mode will inevitably result in some tiny
386 * drift of the time maintained by the kernel with respect to calendar
388 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
390 /* Determine whether the SysTick has already counted to zero. */
391 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
393 uint32_t ulCalculatedLoadValue;
395 /* The tick interrupt ended the sleep (or is now pending), and
396 * a new tick period has started. Reset portNVIC_SYSTICK_LOAD_REG
397 * with whatever remains of the new tick period. */
398 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
400 /* Don't allow a tiny value, or values that have somehow
401 * underflowed because the post sleep hook did something
402 * that took too long or because the SysTick current-value register
404 if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
406 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
409 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
411 /* As the pending tick will be processed as soon as this
412 * function exits, the tick value maintained by the tick is stepped
413 * forward by one less than the time spent waiting. */
414 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
418 /* Something other than the tick interrupt ended the sleep. */
420 /* Use the SysTick current-value register to determine the
421 * number of SysTick decrements remaining until the expected idle
422 * time would have ended. */
423 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
424 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG != portNVIC_SYSTICK_CLK_BIT )
426 /* If the SysTick is not using the core clock, the current-
427 * value register might still be zero here. In that case, the
428 * SysTick didn't load from the reload register, and there are
429 * ulReloadValue decrements remaining in the expected idle
431 if( ulSysTickDecrementsLeft == 0 )
433 ulSysTickDecrementsLeft = ulReloadValue;
436 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
438 /* Work out how long the sleep lasted rounded to complete tick
439 * periods (not the ulReload value which accounted for part
441 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - ulSysTickDecrementsLeft;
443 /* How many complete tick periods passed while the processor
445 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
447 /* The reload value is set to whatever fraction of a single tick
449 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
452 /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again,
453 * then set portNVIC_SYSTICK_LOAD_REG back to its standard value. If
454 * the SysTick is not using the core clock, temporarily configure it to
455 * use the core clock. This configuration forces the SysTick to load
456 * from portNVIC_SYSTICK_LOAD_REG immediately instead of at the next
457 * cycle of the other clock. Then portNVIC_SYSTICK_LOAD_REG is ready
458 * to receive the standard value immediately. */
459 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
460 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
461 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG == portNVIC_SYSTICK_CLK_BIT )
463 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
467 /* The temporary usage of the core clock has served its purpose,
468 * as described above. Resume usage of the other clock. */
469 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT;
471 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
473 /* The partial tick period already ended. Be sure the SysTick
474 * counts it only once. */
475 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0;
478 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
479 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
481 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
483 /* Step the tick to account for any tick periods that elapsed. */
484 vTaskStepTick( ulCompleteTickPeriods );
486 /* Exit with interrupts enabled. */
487 __enable_interrupt();
491 #endif /* configUSE_TICKLESS_IDLE */