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 *----------------------------------------------------------*/
33 /* Scheduler includes. */
37 /* Constants required to manipulate the NVIC. */
38 #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
39 #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
40 #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
41 #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
42 #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
43 #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
44 #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
45 #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
46 #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
47 #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
48 #define portNVIC_PEND_SYSTICK_SET_BIT ( 1UL << 26UL )
49 #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
50 #define portMIN_INTERRUPT_PRIORITY ( 255UL )
51 #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
52 #define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
54 /* Constants required to set up the initial stack. */
55 #define portINITIAL_XPSR ( 0x01000000 )
57 /* The systick is a 24-bit counter. */
58 #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
60 /* A fiddle factor to estimate the number of SysTick counts that would have
61 * occurred while the SysTick counter is stopped during tickless idle
63 #ifndef portMISSED_COUNTS_FACTOR
64 #define portMISSED_COUNTS_FACTOR ( 94UL )
67 /* Let the user override the default SysTick clock rate. If defined by the
68 * user, this symbol must equal the SysTick clock rate when the CLK bit is 0 in the
69 * configuration register. */
70 #ifndef configSYSTICK_CLOCK_HZ
71 #define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ )
72 /* Ensure the SysTick is clocked at the same frequency as the core. */
73 #define portNVIC_SYSTICK_CLK_BIT_CONFIG ( portNVIC_SYSTICK_CLK_BIT )
75 /* Select the option to clock SysTick not at the same frequency as the core. */
76 #define portNVIC_SYSTICK_CLK_BIT_CONFIG ( 0 )
79 /* Let the user override the pre-loading of the initial LR with the address of
80 * prvTaskExitError() in case it messes up unwinding of the stack in the
82 #ifdef configTASK_RETURN_ADDRESS
83 #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
85 #define portTASK_RETURN_ADDRESS prvTaskExitError
89 * Setup the timer to generate the tick interrupts. The implementation in this
90 * file is weak to allow application writers to change the timer used to
91 * generate the tick interrupt.
93 void vPortSetupTimerInterrupt( void );
98 void xPortPendSVHandler( void ) __attribute__( ( naked ) );
99 void xPortSysTickHandler( void );
100 void vPortSVCHandler( void );
103 * Start first task is a separate function so it can be tested in isolation.
105 static void vPortStartFirstTask( void ) __attribute__( ( naked ) );
108 * Used to catch tasks that attempt to return from their implementing function.
110 static void prvTaskExitError( void );
112 /*-----------------------------------------------------------*/
114 /* Each task maintains its own interrupt status in the critical nesting
116 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
118 /*-----------------------------------------------------------*/
121 * The number of SysTick increments that make up one tick period.
123 #if ( configUSE_TICKLESS_IDLE == 1 )
124 static uint32_t ulTimerCountsForOneTick = 0;
125 #endif /* configUSE_TICKLESS_IDLE */
128 * The maximum number of tick periods that can be suppressed is limited by the
129 * 24 bit resolution of the SysTick timer.
131 #if ( configUSE_TICKLESS_IDLE == 1 )
132 static uint32_t xMaximumPossibleSuppressedTicks = 0;
133 #endif /* configUSE_TICKLESS_IDLE */
136 * Compensate for the CPU cycles that pass while the SysTick is stopped (low
137 * power functionality only.
139 #if ( configUSE_TICKLESS_IDLE == 1 )
140 static uint32_t ulStoppedTimerCompensation = 0;
141 #endif /* configUSE_TICKLESS_IDLE */
143 /*-----------------------------------------------------------*/
146 * See header file for description.
148 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
149 TaskFunction_t pxCode,
150 void * pvParameters )
152 /* Simulate the stack frame as it would be created by a context switch
154 pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
155 *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
157 *pxTopOfStack = ( StackType_t ) pxCode; /* PC */
159 *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
160 pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
161 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
162 pxTopOfStack -= 8; /* R11..R4. */
166 /*-----------------------------------------------------------*/
168 static void prvTaskExitError( void )
170 volatile uint32_t ulDummy = 0UL;
172 /* A function that implements a task must not exit or attempt to return to
173 * its caller as there is nothing to return to. If a task wants to exit it
174 * should instead call vTaskDelete( NULL ).
176 * Artificially force an assert() to be triggered if configASSERT() is
177 * defined, then stop here so application writers can catch the error. */
178 configASSERT( uxCriticalNesting == ~0UL );
179 portDISABLE_INTERRUPTS();
181 while( ulDummy == 0 )
183 /* This file calls prvTaskExitError() after the scheduler has been
184 * started to remove a compiler warning about the function being defined
185 * but never called. ulDummy is used purely to quieten other warnings
186 * about code appearing after this function is called - making ulDummy
187 * volatile makes the compiler think the function could return and
188 * therefore not output an 'unreachable code' warning for code that appears
192 /*-----------------------------------------------------------*/
194 void vPortSVCHandler( void )
196 /* This function is no longer used, but retained for backward
199 /*-----------------------------------------------------------*/
201 void vPortStartFirstTask( void )
203 /* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector
204 * table offset register that can be used to locate the initial stack value.
205 * Not all M0 parts have the application vector table at address 0. */
207 " .syntax unified \n"
208 " ldr r2, pxCurrentTCBConst2 \n"/* Obtain location of pxCurrentTCB. */
210 " ldr r0, [r3] \n"/* The first item in pxCurrentTCB is the task top of stack. */
211 " adds r0, #32 \n"/* Discard everything up to r0. */
212 " msr psp, r0 \n"/* This is now the new top of stack to use in the task. */
213 " movs r0, #2 \n"/* Switch to the psp stack. */
214 " msr CONTROL, r0 \n"
216 " pop {r0-r5} \n"/* Pop the registers that are saved automatically. */
217 " mov lr, r5 \n"/* lr is now in r5. */
218 " pop {r3} \n"/* Return address is now in r3. */
219 " pop {r2} \n"/* Pop and discard XPSR. */
220 " cpsie i \n"/* The first task has its context and interrupts can be enabled. */
221 " bx r3 \n"/* Finally, jump to the user defined task code. */
224 "pxCurrentTCBConst2: .word pxCurrentTCB "
227 /*-----------------------------------------------------------*/
230 * See header file for description.
232 BaseType_t xPortStartScheduler( void )
234 /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
235 portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
236 portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
238 /* Start the timer that generates the tick ISR. Interrupts are disabled
240 vPortSetupTimerInterrupt();
242 /* Initialise the critical nesting count ready for the first task. */
243 uxCriticalNesting = 0;
245 /* Start the first task. */
246 vPortStartFirstTask();
248 /* Should never get here as the tasks will now be executing! Call the task
249 * exit error function to prevent compiler warnings about a static function
250 * not being called in the case that the application writer overrides this
251 * functionality by defining configTASK_RETURN_ADDRESS. Call
252 * vTaskSwitchContext() so link time optimisation does not remove the
254 vTaskSwitchContext();
257 /* Should not get here! */
260 /*-----------------------------------------------------------*/
262 void vPortEndScheduler( void )
264 /* Not implemented in ports where there is nothing to return to.
265 * Artificially force an assert. */
266 configASSERT( uxCriticalNesting == 1000UL );
268 /*-----------------------------------------------------------*/
270 void vPortYield( void )
272 /* Set a PendSV to request a context switch. */
273 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
275 /* Barriers are normally not required but do ensure the code is completely
276 * within the specified behaviour for the architecture. */
277 __asm volatile ( "dsb" ::: "memory" );
278 __asm volatile ( "isb" );
280 /*-----------------------------------------------------------*/
282 void vPortEnterCritical( void )
284 portDISABLE_INTERRUPTS();
286 __asm volatile ( "dsb" ::: "memory" );
287 __asm volatile ( "isb" );
289 /*-----------------------------------------------------------*/
291 void vPortExitCritical( void )
293 configASSERT( uxCriticalNesting );
296 if( uxCriticalNesting == 0 )
298 portENABLE_INTERRUPTS();
301 /*-----------------------------------------------------------*/
303 uint32_t ulSetInterruptMaskFromISR( void )
306 " mrs r0, PRIMASK \n"
312 /*-----------------------------------------------------------*/
314 void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask )
317 " msr PRIMASK, r0 \n"
322 /*-----------------------------------------------------------*/
324 void xPortPendSVHandler( void )
326 /* This is a naked function. */
330 " .syntax unified \n"
333 " ldr r3, pxCurrentTCBConst \n"/* Get the location of the current TCB. */
336 " subs r0, r0, #32 \n"/* Make space for the remaining low registers. */
337 " str r0, [r2] \n"/* Save the new top of stack. */
338 " stmia r0!, {r4-r7} \n"/* Store the low registers that are not saved automatically. */
339 " mov r4, r8 \n"/* Store the high registers. */
343 " stmia r0!, {r4-r7} \n"
347 " bl vTaskSwitchContext \n"
349 " pop {r2, r3} \n"/* lr goes in r3. r2 now holds tcb pointer. */
352 " ldr r0, [r1] \n"/* The first item in pxCurrentTCB is the task top of stack. */
353 " adds r0, r0, #16 \n"/* Move to the high registers. */
354 " ldmia r0!, {r4-r7} \n"/* Pop the high registers. */
360 " msr psp, r0 \n"/* Remember the new top of stack for the task. */
362 " subs r0, r0, #32 \n"/* Go back for the low registers that are not automatically restored. */
363 " ldmia r0!, {r4-r7} \n"/* Pop low registers. */
368 "pxCurrentTCBConst: .word pxCurrentTCB "
371 /*-----------------------------------------------------------*/
373 void xPortSysTickHandler( void )
375 uint32_t ulPreviousMask;
377 ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
379 /* Increment the RTOS tick. */
380 if( xTaskIncrementTick() != pdFALSE )
382 /* Pend a context switch. */
383 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
386 portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
388 /*-----------------------------------------------------------*/
391 * Setup the systick timer to generate the tick interrupts at the required
394 __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void )
396 /* Calculate the constants required to configure the tick interrupt. */
397 #if ( configUSE_TICKLESS_IDLE == 1 )
399 ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
400 xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
401 ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
403 #endif /* configUSE_TICKLESS_IDLE */
405 /* Stop and reset the SysTick. */
406 portNVIC_SYSTICK_CTRL_REG = 0UL;
407 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
409 /* Configure SysTick to interrupt at the requested rate. */
410 portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
411 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
413 /*-----------------------------------------------------------*/
415 #if ( configUSE_TICKLESS_IDLE == 1 )
417 __attribute__( ( weak ) ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
419 uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickDecrementsLeft;
420 TickType_t xModifiableIdleTime;
422 /* Make sure the SysTick reload value does not overflow the counter. */
423 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
425 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
428 /* Enter a critical section but don't use the taskENTER_CRITICAL()
429 * method as that will mask interrupts that should exit sleep mode. */
430 __asm volatile ( "cpsid i" ::: "memory" );
431 __asm volatile ( "dsb" );
432 __asm volatile ( "isb" );
434 /* If a context switch is pending or a task is waiting for the scheduler
435 * to be unsuspended then abandon the low power entry. */
436 if( eTaskConfirmSleepModeStatus() == eAbortSleep )
438 /* Re-enable interrupts - see comments above the cpsid instruction
440 __asm volatile ( "cpsie i" ::: "memory" );
444 /* Stop the SysTick momentarily. The time the SysTick is stopped for
445 * is accounted for as best it can be, but using the tickless mode will
446 * inevitably result in some tiny drift of the time maintained by the
447 * kernel with respect to calendar time. */
448 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
450 /* Use the SysTick current-value register to determine the number of
451 * SysTick decrements remaining until the next tick interrupt. If the
452 * current-value register is zero, then there are actually
453 * ulTimerCountsForOneTick decrements remaining, not zero, because the
454 * SysTick requests the interrupt when decrementing from 1 to 0. */
455 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
457 if( ulSysTickDecrementsLeft == 0 )
459 ulSysTickDecrementsLeft = ulTimerCountsForOneTick;
462 /* Calculate the reload value required to wait xExpectedIdleTime
463 * tick periods. -1 is used because this code normally executes part
464 * way through the first tick period. But if the SysTick IRQ is now
465 * pending, then clear the IRQ, suppressing the first tick, and correct
466 * the reload value to reflect that the second tick period is already
467 * underway. The expected idle time is always at least two ticks. */
468 ulReloadValue = ulSysTickDecrementsLeft + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
470 if( ( portNVIC_INT_CTRL_REG & portNVIC_PEND_SYSTICK_SET_BIT ) != 0 )
472 portNVIC_INT_CTRL_REG = portNVIC_PEND_SYSTICK_CLEAR_BIT;
473 ulReloadValue -= ulTimerCountsForOneTick;
476 if( ulReloadValue > ulStoppedTimerCompensation )
478 ulReloadValue -= ulStoppedTimerCompensation;
481 /* Set the new reload value. */
482 portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
484 /* Clear the SysTick count flag and set the count value back to
486 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
488 /* Restart SysTick. */
489 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
491 /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
492 * set its parameter to 0 to indicate that its implementation contains
493 * its own wait for interrupt or wait for event instruction, and so wfi
494 * should not be executed again. However, the original expected idle
495 * time variable must remain unmodified, so a copy is taken. */
496 xModifiableIdleTime = xExpectedIdleTime;
497 configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
499 if( xModifiableIdleTime > 0 )
501 __asm volatile ( "dsb" ::: "memory" );
502 __asm volatile ( "wfi" );
503 __asm volatile ( "isb" );
506 configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
508 /* Re-enable interrupts to allow the interrupt that brought the MCU
509 * out of sleep mode to execute immediately. See comments above
510 * the cpsid instruction above. */
511 __asm volatile ( "cpsie i" ::: "memory" );
512 __asm volatile ( "dsb" );
513 __asm volatile ( "isb" );
515 /* Disable interrupts again because the clock is about to be stopped
516 * and interrupts that execute while the clock is stopped will increase
517 * any slippage between the time maintained by the RTOS and calendar
519 __asm volatile ( "cpsid i" ::: "memory" );
520 __asm volatile ( "dsb" );
521 __asm volatile ( "isb" );
523 /* Disable the SysTick clock without reading the
524 * portNVIC_SYSTICK_CTRL_REG register to ensure the
525 * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
526 * the time the SysTick is stopped for is accounted for as best it can
527 * be, but using the tickless mode will inevitably result in some tiny
528 * drift of the time maintained by the kernel with respect to calendar
530 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
532 /* Determine whether the SysTick has already counted to zero. */
533 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
535 uint32_t ulCalculatedLoadValue;
537 /* The tick interrupt ended the sleep (or is now pending), and
538 * a new tick period has started. Reset portNVIC_SYSTICK_LOAD_REG
539 * with whatever remains of the new tick period. */
540 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
542 /* Don't allow a tiny value, or values that have somehow
543 * underflowed because the post sleep hook did something
544 * that took too long or because the SysTick current-value register
546 if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
548 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
551 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
553 /* As the pending tick will be processed as soon as this
554 * function exits, the tick value maintained by the tick is stepped
555 * forward by one less than the time spent waiting. */
556 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
560 /* Something other than the tick interrupt ended the sleep. */
562 /* Use the SysTick current-value register to determine the
563 * number of SysTick decrements remaining until the expected idle
564 * time would have ended. */
565 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
566 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG != portNVIC_SYSTICK_CLK_BIT )
568 /* If the SysTick is not using the core clock, the current-
569 * value register might still be zero here. In that case, the
570 * SysTick didn't load from the reload register, and there are
571 * ulReloadValue decrements remaining in the expected idle
573 if( ulSysTickDecrementsLeft == 0 )
575 ulSysTickDecrementsLeft = ulReloadValue;
578 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
580 /* Work out how long the sleep lasted rounded to complete tick
581 * periods (not the ulReload value which accounted for part
583 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - ulSysTickDecrementsLeft;
585 /* How many complete tick periods passed while the processor
587 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
589 /* The reload value is set to whatever fraction of a single tick
591 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
594 /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again,
595 * then set portNVIC_SYSTICK_LOAD_REG back to its standard value. If
596 * the SysTick is not using the core clock, temporarily configure it to
597 * use the core clock. This configuration forces the SysTick to load
598 * from portNVIC_SYSTICK_LOAD_REG immediately instead of at the next
599 * cycle of the other clock. Then portNVIC_SYSTICK_LOAD_REG is ready
600 * to receive the standard value immediately. */
601 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
602 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
603 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG == portNVIC_SYSTICK_CLK_BIT )
605 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
609 /* The temporary usage of the core clock has served its purpose,
610 * as described above. Resume usage of the other clock. */
611 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT;
613 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
615 /* The partial tick period already ended. Be sure the SysTick
616 * counts it only once. */
617 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0;
620 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
621 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
623 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
625 /* Step the tick to account for any tick periods that elapsed. */
626 vTaskStepTick( ulCompleteTickPeriods );
628 /* Exit with interrupts enabled. */
629 __asm volatile ( "cpsie i" ::: "memory" );
633 #endif /* configUSE_TICKLESS_IDLE */