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