1 /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
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.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the ARM CM0 port.
31 *----------------------------------------------------------*/
32 
33 /* IAR includes. */
34 #include "intrinsics.h"
35 
36 /* Scheduler includes. */
37 #include "FreeRTOS.h"
38 #include "task.h"
39 
40 /* Prototype of all Interrupt Service Routines (ISRs). */
41 typedef void ( * portISR_t )( void );
42 
43 /* Constants required to manipulate the NVIC. */
44 #define portNVIC_SYSTICK_CTRL_REG             ( *( ( volatile uint32_t * ) 0xe000e010 ) )
45 #define portNVIC_SYSTICK_LOAD_REG             ( *( ( volatile uint32_t * ) 0xe000e014 ) )
46 #define portNVIC_SYSTICK_CURRENT_VALUE_REG    ( *( ( volatile uint32_t * ) 0xe000e018 ) )
47 #define portNVIC_INT_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
48 #define portNVIC_SHPR3_REG                    ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
49 #define portNVIC_SYSTICK_CLK_BIT              ( 1UL << 2UL )
50 #define portNVIC_SYSTICK_INT_BIT              ( 1UL << 1UL )
51 #define portNVIC_SYSTICK_ENABLE_BIT           ( 1UL << 0UL )
52 #define portNVIC_SYSTICK_COUNT_FLAG_BIT       ( 1UL << 16UL )
53 #define portNVIC_PEND_SYSTICK_SET_BIT         ( 1UL << 26UL )
54 #define portNVIC_PEND_SYSTICK_CLEAR_BIT       ( 1UL << 25UL )
55 #define portMIN_INTERRUPT_PRIORITY            ( 255UL )
56 #define portNVIC_PENDSV_PRI                   ( portMIN_INTERRUPT_PRIORITY << 16UL )
57 #define portNVIC_SYSTICK_PRI                  ( portMIN_INTERRUPT_PRIORITY << 24UL )
58 
59 /* Constants used to check the installation of the FreeRTOS interrupt handlers. */
60 #define portSCB_VTOR_REG                      ( *( ( portISR_t ** ) 0xe000ed08 ) )
61 #define portVECTOR_INDEX_PENDSV               ( 14 )
62 
63 /* Constants required to set up the initial stack. */
64 #define portINITIAL_XPSR                      ( 0x01000000 )
65 
66 /* Each task maintains its own interrupt status in the critical nesting
67  * variable. */
68 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
69 
70 /* The systick is a 24-bit counter. */
71 #define portMAX_24_BIT_NUMBER    ( 0xffffffUL )
72 
73 /* A fiddle factor to estimate the number of SysTick counts that would have
74  * occurred while the SysTick counter is stopped during tickless idle
75  * calculations. */
76 #ifndef portMISSED_COUNTS_FACTOR
77     #define portMISSED_COUNTS_FACTOR    ( 94UL )
78 #endif
79 
80 /* The number of SysTick increments that make up one tick period. */
81 #if ( configUSE_TICKLESS_IDLE == 1 )
82     static uint32_t ulTimerCountsForOneTick = 0;
83 #endif /* configUSE_TICKLESS_IDLE */
84 
85 /* The maximum number of tick periods that can be suppressed is limited by the
86  * 24 bit resolution of the SysTick timer. */
87 #if ( configUSE_TICKLESS_IDLE == 1 )
88     static uint32_t xMaximumPossibleSuppressedTicks = 0;
89 #endif /* configUSE_TICKLESS_IDLE */
90 
91 /* Compensate for the CPU cycles that pass while the SysTick is stopped (low
92  * power functionality only. */
93 #if ( configUSE_TICKLESS_IDLE == 1 )
94     static uint32_t ulStoppedTimerCompensation = 0;
95 #endif /* configUSE_TICKLESS_IDLE */
96 
97 /* Let the user override the default SysTick clock rate.  If defined by the
98  * user, this symbol must equal the SysTick clock rate when the CLK bit is 0 in the
99  * configuration register. */
100 #ifndef configSYSTICK_CLOCK_HZ
101     #define configSYSTICK_CLOCK_HZ             ( configCPU_CLOCK_HZ )
102     /* Ensure the SysTick is clocked at the same frequency as the core. */
103     #define portNVIC_SYSTICK_CLK_BIT_CONFIG    ( portNVIC_SYSTICK_CLK_BIT )
104 #else
105     /* Select the option to clock SysTick not at the same frequency as the core. */
106     #define portNVIC_SYSTICK_CLK_BIT_CONFIG    ( 0 )
107 #endif
108 
109 /*
110  * Setup the timer to generate the tick interrupts.  The implementation in this
111  * file is weak to allow application writers to change the timer used to
112  * generate the tick interrupt.
113  */
114 void vPortSetupTimerInterrupt( void );
115 
116 /*
117  * Exception handlers.
118  */
119 void xPortSysTickHandler( void );
120 
121 /*
122  * Start first task is a separate function so it can be tested in isolation.
123  */
124 extern void vPortStartFirstTask( void );
125 
126 /*
127  * Used to catch tasks that attempt to return from their implementing function.
128  */
129 static void prvTaskExitError( void );
130 
131 /*
132  * FreeRTOS handlers implemented in assembly.
133  */
134 extern void xPortPendSVHandler( void );
135 /*-----------------------------------------------------------*/
136 
137 /*
138  * See header file for description.
139  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)140 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
141                                      TaskFunction_t pxCode,
142                                      void * pvParameters )
143 {
144     /* Simulate the stack frame as it would be created by a context switch
145      * interrupt. */
146     pxTopOfStack--;                                   /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
147     *pxTopOfStack = portINITIAL_XPSR;                 /* xPSR */
148     pxTopOfStack--;
149     *pxTopOfStack = ( StackType_t ) pxCode;           /* PC */
150     pxTopOfStack--;
151     *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
152     pxTopOfStack -= 5;                                /* R12, R3, R2 and R1. */
153     *pxTopOfStack = ( StackType_t ) pvParameters;     /* R0 */
154     pxTopOfStack -= 8;                                /* R11..R4. */
155 
156     return pxTopOfStack;
157 }
158 /*-----------------------------------------------------------*/
159 
prvTaskExitError(void)160 static void prvTaskExitError( void )
161 {
162     /* A function that implements a task must not exit or attempt to return to
163      * its caller as there is nothing to return to.  If a task wants to exit it
164      * should instead call vTaskDelete( NULL ).
165      *
166      * Artificially force an assert() to be triggered if configASSERT() is
167      * defined, then stop here so application writers can catch the error. */
168     configASSERT( uxCriticalNesting == ~0UL );
169     portDISABLE_INTERRUPTS();
170 
171     for( ; ; )
172     {
173     }
174 }
175 /*-----------------------------------------------------------*/
176 
177 /*
178  * See header file for description.
179  */
xPortStartScheduler(void)180 BaseType_t xPortStartScheduler( void )
181 {
182     /* An application can install FreeRTOS interrupt handlers in one of the
183      * following ways:
184      * 1. Direct Routing - Install the function xPortPendSVHandler for PendSV
185      *    interrupt.
186      * 2. Indirect Routing - Install separate handler for PendSV interrupt and
187      *    route program control from that handler to xPortPendSVHandler function.
188      *
189      * Applications that use Indirect Routing must set
190      * configCHECK_HANDLER_INSTALLATION to 0 in their FreeRTOSConfig.h. Direct
191      * routing, which is validated here when configCHECK_HANDLER_INSTALLATION
192      * is 1, should be preferred when possible. */
193     #if ( configCHECK_HANDLER_INSTALLATION == 1 )
194     {
195         /* Point pxVectorTable to the interrupt vector table. Systems without
196          * a VTOR register provide the value zero in the VTOR register and
197          * the vector table itself is located at the address 0x00000000. */
198         const portISR_t * const pxVectorTable = portSCB_VTOR_REG;
199 
200         /* Validate that the application has correctly installed the FreeRTOS
201          * handler for PendSV interrupt. We do not check the installation of the
202          * SysTick handler because the application may choose to drive the RTOS
203          * tick using a timer other than the SysTick timer by overriding the
204          * weak function vPortSetupTimerInterrupt().
205          *
206          * Assertion failures here indicate incorrect installation of the
207          * FreeRTOS handler. For help installing the FreeRTOS handler, see
208          * https://www.FreeRTOS.org/FAQHelp.html.
209          *
210          * Systems with a configurable address for the interrupt vector table
211          * can also encounter assertion failures or even system faults here if
212          * VTOR is not set correctly to point to the application's vector table. */
213         configASSERT( pxVectorTable[ portVECTOR_INDEX_PENDSV ] == xPortPendSVHandler );
214     }
215     #endif /* configCHECK_HANDLER_INSTALLATION */
216 
217     /* Make PendSV and SysTick the lowest priority interrupts. */
218     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
219     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
220 
221     /* Start the timer that generates the tick ISR.  Interrupts are disabled
222      * here already. */
223     vPortSetupTimerInterrupt();
224 
225     /* Initialise the critical nesting count ready for the first task. */
226     uxCriticalNesting = 0;
227 
228     /* Start the first task. */
229     vPortStartFirstTask();
230 
231     /* Should not get here! */
232     return 0;
233 }
234 /*-----------------------------------------------------------*/
235 
vPortEndScheduler(void)236 void vPortEndScheduler( void )
237 {
238     /* Not implemented in ports where there is nothing to return to.
239      * Artificially force an assert. */
240     configASSERT( uxCriticalNesting == 1000UL );
241 }
242 /*-----------------------------------------------------------*/
243 
vPortYield(void)244 void vPortYield( void )
245 {
246     /* Set a PendSV to request a context switch. */
247     portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
248 
249     /* Barriers are normally not required but do ensure the code is completely
250      * within the specified behaviour for the architecture. */
251     __DSB();
252     __ISB();
253 }
254 /*-----------------------------------------------------------*/
255 
vPortEnterCritical(void)256 void vPortEnterCritical( void )
257 {
258     portDISABLE_INTERRUPTS();
259     uxCriticalNesting++;
260     __DSB();
261     __ISB();
262 }
263 /*-----------------------------------------------------------*/
264 
vPortExitCritical(void)265 void vPortExitCritical( void )
266 {
267     configASSERT( uxCriticalNesting );
268     uxCriticalNesting--;
269 
270     if( uxCriticalNesting == 0 )
271     {
272         portENABLE_INTERRUPTS();
273     }
274 }
275 /*-----------------------------------------------------------*/
276 
xPortSysTickHandler(void)277 void xPortSysTickHandler( void )
278 {
279     uint32_t ulPreviousMask;
280 
281     ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
282     traceISR_ENTER();
283     {
284         /* Increment the RTOS tick. */
285         if( xTaskIncrementTick() != pdFALSE )
286         {
287             traceISR_EXIT_TO_SCHEDULER();
288             /* Pend a context switch. */
289             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
290         }
291         else
292         {
293             traceISR_EXIT();
294         }
295     }
296     portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
297 }
298 /*-----------------------------------------------------------*/
299 
300 /*
301  * Setup the systick timer to generate the tick interrupts at the required
302  * frequency.
303  */
vPortSetupTimerInterrupt(void)304 __weak void vPortSetupTimerInterrupt( void )
305 {
306     /* Calculate the constants required to configure the tick interrupt. */
307     #if ( configUSE_TICKLESS_IDLE == 1 )
308     {
309         ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
310         xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
311         ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
312     }
313     #endif /* configUSE_TICKLESS_IDLE */
314 
315     /* Stop and reset the SysTick. */
316     portNVIC_SYSTICK_CTRL_REG = 0UL;
317     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
318 
319     /* Configure SysTick to interrupt at the requested rate. */
320     portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
321     portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
322 }
323 /*-----------------------------------------------------------*/
324 
325 #if ( configUSE_TICKLESS_IDLE == 1 )
326 
vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)327     __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
328     {
329         uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickDecrementsLeft;
330         TickType_t xModifiableIdleTime;
331 
332         /* Make sure the SysTick reload value does not overflow the counter. */
333         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
334         {
335             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
336         }
337 
338         /* Enter a critical section but don't use the taskENTER_CRITICAL()
339          * method as that will mask interrupts that should exit sleep mode. */
340         __disable_interrupt();
341         __DSB();
342         __ISB();
343 
344         /* If a context switch is pending or a task is waiting for the scheduler
345          * to be unsuspended then abandon the low power entry. */
346         if( eTaskConfirmSleepModeStatus() == eAbortSleep )
347         {
348             /* Re-enable interrupts - see comments above the __disable_interrupt()
349              * call above. */
350             __enable_interrupt();
351         }
352         else
353         {
354             /* Stop the SysTick momentarily.  The time the SysTick is stopped for
355              * is accounted for as best it can be, but using the tickless mode will
356              * inevitably result in some tiny drift of the time maintained by the
357              * kernel with respect to calendar time. */
358             portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
359 
360             /* Use the SysTick current-value register to determine the number of
361              * SysTick decrements remaining until the next tick interrupt.  If the
362              * current-value register is zero, then there are actually
363              * ulTimerCountsForOneTick decrements remaining, not zero, because the
364              * SysTick requests the interrupt when decrementing from 1 to 0. */
365             ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
366 
367             if( ulSysTickDecrementsLeft == 0 )
368             {
369                 ulSysTickDecrementsLeft = ulTimerCountsForOneTick;
370             }
371 
372             /* Calculate the reload value required to wait xExpectedIdleTime
373              * tick periods.  -1 is used because this code normally executes part
374              * way through the first tick period.  But if the SysTick IRQ is now
375              * pending, then clear the IRQ, suppressing the first tick, and correct
376              * the reload value to reflect that the second tick period is already
377              * underway.  The expected idle time is always at least two ticks. */
378             ulReloadValue = ulSysTickDecrementsLeft + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
379 
380             if( ( portNVIC_INT_CTRL_REG & portNVIC_PEND_SYSTICK_SET_BIT ) != 0 )
381             {
382                 portNVIC_INT_CTRL_REG = portNVIC_PEND_SYSTICK_CLEAR_BIT;
383                 ulReloadValue -= ulTimerCountsForOneTick;
384             }
385 
386             if( ulReloadValue > ulStoppedTimerCompensation )
387             {
388                 ulReloadValue -= ulStoppedTimerCompensation;
389             }
390 
391             /* Set the new reload value. */
392             portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
393 
394             /* Clear the SysTick count flag and set the count value back to
395              * zero. */
396             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
397 
398             /* Restart SysTick. */
399             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
400 
401             /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
402              * set its parameter to 0 to indicate that its implementation contains
403              * its own wait for interrupt or wait for event instruction, and so wfi
404              * should not be executed again.  However, the original expected idle
405              * time variable must remain unmodified, so a copy is taken. */
406             xModifiableIdleTime = xExpectedIdleTime;
407             configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
408 
409             if( xModifiableIdleTime > 0 )
410             {
411                 __DSB();
412                 __WFI();
413                 __ISB();
414             }
415 
416             configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
417 
418             /* Re-enable interrupts to allow the interrupt that brought the MCU
419              * out of sleep mode to execute immediately.  See comments above
420              * the __disable_interrupt() call above. */
421             __enable_interrupt();
422             __DSB();
423             __ISB();
424 
425             /* Disable interrupts again because the clock is about to be stopped
426              * and interrupts that execute while the clock is stopped will increase
427              * any slippage between the time maintained by the RTOS and calendar
428              * time. */
429             __disable_interrupt();
430             __DSB();
431             __ISB();
432 
433             /* Disable the SysTick clock without reading the
434              * portNVIC_SYSTICK_CTRL_REG register to ensure the
435              * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set.  Again,
436              * the time the SysTick is stopped for is accounted for as best it can
437              * be, but using the tickless mode will inevitably result in some tiny
438              * drift of the time maintained by the kernel with respect to calendar
439              * time*/
440             portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );
441 
442             /* Determine whether the SysTick has already counted to zero. */
443             if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
444             {
445                 uint32_t ulCalculatedLoadValue;
446 
447                 /* The tick interrupt ended the sleep (or is now pending), and
448                  * a new tick period has started.  Reset portNVIC_SYSTICK_LOAD_REG
449                  * with whatever remains of the new tick period. */
450                 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
451 
452                 /* Don't allow a tiny value, or values that have somehow
453                  * underflowed because the post sleep hook did something
454                  * that took too long or because the SysTick current-value register
455                  * is zero. */
456                 if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
457                 {
458                     ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
459                 }
460 
461                 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
462 
463                 /* As the pending tick will be processed as soon as this
464                  * function exits, the tick value maintained by the tick is stepped
465                  * forward by one less than the time spent waiting. */
466                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
467             }
468             else
469             {
470                 /* Something other than the tick interrupt ended the sleep. */
471 
472                 /* Use the SysTick current-value register to determine the
473                  * number of SysTick decrements remaining until the expected idle
474                  * time would have ended. */
475                 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;
476                 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG != portNVIC_SYSTICK_CLK_BIT )
477                 {
478                     /* If the SysTick is not using the core clock, the current-
479                      * value register might still be zero here.  In that case, the
480                      * SysTick didn't load from the reload register, and there are
481                      * ulReloadValue decrements remaining in the expected idle
482                      * time, not zero. */
483                     if( ulSysTickDecrementsLeft == 0 )
484                     {
485                         ulSysTickDecrementsLeft = ulReloadValue;
486                     }
487                 }
488                 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
489 
490                 /* Work out how long the sleep lasted rounded to complete tick
491                  * periods (not the ulReload value which accounted for part
492                  * ticks). */
493                 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - ulSysTickDecrementsLeft;
494 
495                 /* How many complete tick periods passed while the processor
496                  * was waiting? */
497                 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
498 
499                 /* The reload value is set to whatever fraction of a single tick
500                  * period remains. */
501                 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
502             }
503 
504             /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again,
505              * then set portNVIC_SYSTICK_LOAD_REG back to its standard value.  If
506              * the SysTick is not using the core clock, temporarily configure it to
507              * use the core clock.  This configuration forces the SysTick to load
508              * from portNVIC_SYSTICK_LOAD_REG immediately instead of at the next
509              * cycle of the other clock.  Then portNVIC_SYSTICK_LOAD_REG is ready
510              * to receive the standard value immediately. */
511             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
512             portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
513             #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG == portNVIC_SYSTICK_CLK_BIT )
514             {
515                 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
516             }
517             #else
518             {
519                 /* The temporary usage of the core clock has served its purpose,
520                  * as described above.  Resume usage of the other clock. */
521                 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT;
522 
523                 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
524                 {
525                     /* The partial tick period already ended.  Be sure the SysTick
526                      * counts it only once. */
527                     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0;
528                 }
529 
530                 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
531                 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
532             }
533             #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */
534 
535             /* Step the tick to account for any tick periods that elapsed. */
536             vTaskStepTick( ulCompleteTickPeriods );
537 
538             /* Exit with interrupts enabled. */
539             __enable_interrupt();
540         }
541     }
542 
543 #endif /* configUSE_TICKLESS_IDLE */
544