]> begriffs open source - freertos/blob - portable/RVDS/ARM_CM0/port.c
[AUTO][RELEASE]: Bump file header version to "10.5.0"
[freertos] / portable / RVDS / ARM_CM0 / port.c
1 /*\r
2  * FreeRTOS Kernel V10.5.0\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT\r
6  *\r
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
8  * this software and associated documentation files (the "Software"), to deal in\r
9  * the Software without restriction, including without limitation the rights to\r
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
11  * the Software, and to permit persons to whom the Software is furnished to do so,\r
12  * subject to the following conditions:\r
13  *\r
14  * The above copyright notice and this permission notice shall be included in all\r
15  * copies or substantial portions of the Software.\r
16  *\r
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
23  *\r
24  * https://www.FreeRTOS.org\r
25  * https://github.com/FreeRTOS\r
26  *\r
27  */\r
28 \r
29 /*-----------------------------------------------------------\r
30 * Implementation of functions defined in portable.h for the ARM CM0 port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Scheduler includes. */\r
34 #include "FreeRTOS.h"\r
35 #include "task.h"\r
36 \r
37 /* Constants required to manipulate the NVIC. */\r
38 #define portNVIC_SYSTICK_CTRL_REG             ( *( ( volatile uint32_t * ) 0xe000e010 ) )\r
39 #define portNVIC_SYSTICK_LOAD_REG             ( *( ( volatile uint32_t * ) 0xe000e014 ) )\r
40 #define portNVIC_SYSTICK_CURRENT_VALUE_REG    ( *( ( volatile uint32_t * ) 0xe000e018 ) )\r
41 #define portNVIC_INT_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000ed04 ) )\r
42 #define portNVIC_SHPR3_REG                    ( *( ( volatile uint32_t * ) 0xe000ed20 ) )\r
43 #define portNVIC_SYSTICK_CLK_BIT              ( 1UL << 2UL )\r
44 #define portNVIC_SYSTICK_INT_BIT              ( 1UL << 1UL )\r
45 #define portNVIC_SYSTICK_ENABLE_BIT           ( 1UL << 0UL )\r
46 #define portNVIC_SYSTICK_COUNT_FLAG_BIT       ( 1UL << 16UL )\r
47 #define portNVIC_PENDSVSET_BIT                ( 1UL << 28UL )\r
48 #define portMIN_INTERRUPT_PRIORITY            ( 255UL )\r
49 #define portNVIC_PENDSV_PRI                   ( portMIN_INTERRUPT_PRIORITY << 16UL )\r
50 #define portNVIC_SYSTICK_PRI                  ( portMIN_INTERRUPT_PRIORITY << 24UL )\r
51 \r
52 /* Constants required to set up the initial stack. */\r
53 #define portINITIAL_XPSR                      ( 0x01000000 )\r
54 \r
55 /* The systick is a 24-bit counter. */\r
56 #define portMAX_24_BIT_NUMBER                 ( 0xffffffUL )\r
57 \r
58 /* A fiddle factor to estimate the number of SysTick counts that would have\r
59  * occurred while the SysTick counter is stopped during tickless idle\r
60  * calculations. */\r
61 #ifndef portMISSED_COUNTS_FACTOR\r
62     #define portMISSED_COUNTS_FACTOR    ( 45UL )\r
63 #endif\r
64 \r
65 /* Constants used with memory barrier intrinsics. */\r
66 #define portSY_FULL_READ_WRITE    ( 15 )\r
67 \r
68 /* Legacy macro for backward compatibility only.  This macro used to be used to\r
69  * replace the function that configures the clock used to generate the tick\r
70  * interrupt (prvSetupTimerInterrupt()), but now the function is declared weak so\r
71  * the application writer can override it by simply defining a function of the\r
72  * same name (vApplicationSetupTickInterrupt()). */\r
73 #ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION\r
74     #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION    0\r
75 #endif\r
76 \r
77 /* Each task maintains its own interrupt status in the critical nesting\r
78  * variable. */\r
79 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;\r
80 \r
81 /* The number of SysTick increments that make up one tick period. */\r
82 #if ( configUSE_TICKLESS_IDLE == 1 )\r
83     static uint32_t ulTimerCountsForOneTick = 0;\r
84 #endif /* configUSE_TICKLESS_IDLE */\r
85 \r
86 /* The maximum number of tick periods that can be suppressed is limited by the\r
87  * 24 bit resolution of the SysTick timer. */\r
88 #if ( configUSE_TICKLESS_IDLE == 1 )\r
89     static uint32_t xMaximumPossibleSuppressedTicks = 0;\r
90 #endif /* configUSE_TICKLESS_IDLE */\r
91 \r
92 /* Compensate for the CPU cycles that pass while the SysTick is stopped (low\r
93  * power functionality only.\r
94  */\r
95 #if ( configUSE_TICKLESS_IDLE == 1 )\r
96     static uint32_t ulStoppedTimerCompensation = 0;\r
97 #endif /* configUSE_TICKLESS_IDLE */\r
98 \r
99 /*\r
100  * Setup the timer to generate the tick interrupts.  The implementation in this\r
101  * file is weak to allow application writers to change the timer used to\r
102  * generate the tick interrupt.\r
103  */\r
104 void vPortSetupTimerInterrupt( void );\r
105 \r
106 /*\r
107  * Exception handlers.\r
108  */\r
109 void xPortPendSVHandler( void );\r
110 void xPortSysTickHandler( void );\r
111 void vPortSVCHandler( void );\r
112 \r
113 /*\r
114  * Start first task is a separate function so it can be tested in isolation.\r
115  */\r
116 static void prvPortStartFirstTask( void );\r
117 \r
118 /*\r
119  * Used to catch tasks that attempt to return from their implementing function.\r
120  */\r
121 static void prvTaskExitError( void );\r
122 \r
123 /*-----------------------------------------------------------*/\r
124 \r
125 /*\r
126  * See header file for description.\r
127  */\r
128 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
129                                      TaskFunction_t pxCode,\r
130                                      void * pvParameters )\r
131 {\r
132     /* Simulate the stack frame as it would be created by a context switch\r
133      * interrupt. */\r
134     pxTopOfStack--;                                   /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */\r
135     *pxTopOfStack = portINITIAL_XPSR;                 /* xPSR */\r
136     pxTopOfStack--;\r
137     *pxTopOfStack = ( StackType_t ) pxCode;           /* PC */\r
138     pxTopOfStack--;\r
139     *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */\r
140     pxTopOfStack -= 5;                                /* R12, R3, R2 and R1. */\r
141     *pxTopOfStack = ( StackType_t ) pvParameters;     /* R0 */\r
142     pxTopOfStack -= 8;                                /* R11..R4. */\r
143 \r
144     return pxTopOfStack;\r
145 }\r
146 /*-----------------------------------------------------------*/\r
147 \r
148 static void prvTaskExitError( void )\r
149 {\r
150     /* A function that implements a task must not exit or attempt to return to\r
151      * its caller as there is nothing to return to.  If a task wants to exit it\r
152      * should instead call vTaskDelete( NULL ).\r
153      *\r
154      * Artificially force an assert() to be triggered if configASSERT() is\r
155      * defined, then stop here so application writers can catch the error. */\r
156     configASSERT( uxCriticalNesting == ~0UL );\r
157     portDISABLE_INTERRUPTS();\r
158 \r
159     for( ; ; )\r
160     {\r
161     }\r
162 }\r
163 /*-----------------------------------------------------------*/\r
164 \r
165 void vPortSVCHandler( void )\r
166 {\r
167     /* This function is no longer used, but retained for backward\r
168      * compatibility. */\r
169 }\r
170 /*-----------------------------------------------------------*/\r
171 \r
172 __asm void prvPortStartFirstTask( void )\r
173 {\r
174     extern pxCurrentTCB;\r
175 \r
176     PRESERVE8\r
177 \r
178     /* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector\r
179      * table offset register that can be used to locate the initial stack value.\r
180      * Not all M0 parts have the application vector table at address 0. */\r
181 /* *INDENT-OFF* */\r
182 \r
183     ldr r3, = pxCurrentTCB /* Obtain location of pxCurrentTCB. */\r
184     ldr r1, [ r3 ]\r
185     ldr r0, [ r1 ]         /* The first item in pxCurrentTCB is the task top of stack. */\r
186     adds r0, # 32          /* Discard everything up to r0. */\r
187     msr psp, r0            /* This is now the new top of stack to use in the task. */\r
188     movs r0, # 2           /* Switch to the psp stack. */\r
189     msr CONTROL, r0\r
190     isb\r
191     pop { r0 - r5 } /* Pop the registers that are saved automatically. */\r
192     mov lr, r5 /* lr is now in r5. */\r
193     pop { r3 } /* The return address is now in r3. */\r
194     pop { r2 } /* Pop and discard the XPSR. */\r
195     cpsie i /* The first task has its context and interrupts can be enabled. */\r
196     bx r3 /* Finally, jump to the user defined task code. */\r
197 \r
198     ALIGN\r
199 /* *INDENT-ON* */\r
200 }\r
201 /*-----------------------------------------------------------*/\r
202 \r
203 /*\r
204  * See header file for description.\r
205  */\r
206 BaseType_t xPortStartScheduler( void )\r
207 {\r
208     /* Make PendSV, CallSV and SysTick the same priority as the kernel. */\r
209     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;\r
210 \r
211     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;\r
212 \r
213     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
214      * here already. */\r
215     vPortSetupTimerInterrupt();\r
216 \r
217     /* Initialise the critical nesting count ready for the first task. */\r
218     uxCriticalNesting = 0;\r
219 \r
220     /* Start the first task. */\r
221     prvPortStartFirstTask();\r
222 \r
223     /* Should not get here! */\r
224     return 0;\r
225 }\r
226 /*-----------------------------------------------------------*/\r
227 \r
228 void vPortEndScheduler( void )\r
229 {\r
230     /* Not implemented in ports where there is nothing to return to.\r
231      * Artificially force an assert. */\r
232     configASSERT( uxCriticalNesting == 1000UL );\r
233 }\r
234 /*-----------------------------------------------------------*/\r
235 \r
236 void vPortYield( void )\r
237 {\r
238     /* Set a PendSV to request a context switch. */\r
239     portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
240 \r
241     /* Barriers are normally not required but do ensure the code is completely\r
242      * within the specified behaviour for the architecture. */\r
243     __dsb( portSY_FULL_READ_WRITE );\r
244     __isb( portSY_FULL_READ_WRITE );\r
245 }\r
246 /*-----------------------------------------------------------*/\r
247 \r
248 void vPortEnterCritical( void )\r
249 {\r
250     portDISABLE_INTERRUPTS();\r
251     uxCriticalNesting++;\r
252     __dsb( portSY_FULL_READ_WRITE );\r
253     __isb( portSY_FULL_READ_WRITE );\r
254 }\r
255 /*-----------------------------------------------------------*/\r
256 \r
257 void vPortExitCritical( void )\r
258 {\r
259     configASSERT( uxCriticalNesting );\r
260     uxCriticalNesting--;\r
261 \r
262     if( uxCriticalNesting == 0 )\r
263     {\r
264         portENABLE_INTERRUPTS();\r
265     }\r
266 }\r
267 /*-----------------------------------------------------------*/\r
268 \r
269 __asm uint32_t ulSetInterruptMaskFromISR( void )\r
270 {\r
271 /* *INDENT-OFF* */\r
272     mrs r0, PRIMASK\r
273     cpsid i\r
274     bx lr\r
275 /* *INDENT-ON* */\r
276 }\r
277 /*-----------------------------------------------------------*/\r
278 \r
279 __asm void vClearInterruptMaskFromISR( uint32_t ulMask )\r
280 {\r
281 /* *INDENT-OFF* */\r
282     msr PRIMASK, r0\r
283     bx lr\r
284 /* *INDENT-ON* */\r
285 }\r
286 /*-----------------------------------------------------------*/\r
287 \r
288 __asm void xPortPendSVHandler( void )\r
289 {\r
290     extern vTaskSwitchContext\r
291     extern pxCurrentTCB\r
292 \r
293 /* *INDENT-OFF* */\r
294     PRESERVE8\r
295 \r
296     mrs r0, psp\r
297 \r
298     ldr r3, = pxCurrentTCB /* Get the location of the current TCB. */\r
299     ldr r2, [ r3 ]\r
300 \r
301     subs r0, # 32  /* Make space for the remaining low registers. */\r
302     str r0, [ r2 ] /* Save the new top of stack. */\r
303     stmia r0 !, { r4 - r7 } /* Store the low registers that are not saved automatically. */\r
304     mov r4, r8 /* Store the high registers. */\r
305     mov r5, r9\r
306     mov r6, r10\r
307     mov r7, r11\r
308     stmia r0 !, { r4 - r7 }\r
309 \r
310     push { r3, r14 }\r
311     cpsid i\r
312     bl vTaskSwitchContext\r
313     cpsie i\r
314     pop { r2, r3 } /* lr goes in r3. r2 now holds tcb pointer. */\r
315 \r
316     ldr r1, [ r2 ]\r
317     ldr r0, [ r1 ] /* The first item in pxCurrentTCB is the task top of stack. */\r
318     adds r0, # 16  /* Move to the high registers. */\r
319     ldmia r0 !, { r4 - r7 } /* Pop the high registers. */\r
320     mov r8, r4\r
321     mov r9, r5\r
322     mov r10, r6\r
323     mov r11, r7\r
324 \r
325     msr psp, r0   /* Remember the new top of stack for the task. */\r
326 \r
327     subs r0, # 32 /* Go back for the low registers that are not automatically restored. */\r
328     ldmia r0 !, { r4 - r7 } /* Pop low registers.  */\r
329 \r
330     bx r3\r
331     ALIGN\r
332 /* *INDENT-ON* */\r
333 }\r
334 /*-----------------------------------------------------------*/\r
335 \r
336 void xPortSysTickHandler( void )\r
337 {\r
338     uint32_t ulPreviousMask;\r
339 \r
340     ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();\r
341     {\r
342         /* Increment the RTOS tick. */\r
343         if( xTaskIncrementTick() != pdFALSE )\r
344         {\r
345             /* Pend a context switch. */\r
346             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
347         }\r
348     }\r
349     portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );\r
350 }\r
351 /*-----------------------------------------------------------*/\r
352 \r
353 /*\r
354  * Setup the systick timer to generate the tick interrupts at the required\r
355  * frequency.\r
356  */\r
357 #if ( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )\r
358 \r
359     __weak void vPortSetupTimerInterrupt( void )\r
360     {\r
361         /* Calculate the constants required to configure the tick interrupt. */\r
362         #if ( configUSE_TICKLESS_IDLE == 1 )\r
363             ulTimerCountsForOneTick = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );\r
364             xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;\r
365             ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR;\r
366         #endif /* configUSE_TICKLESS_IDLE */\r
367 \r
368         /* Stop and reset the SysTick. */\r
369         portNVIC_SYSTICK_CTRL_REG = 0UL;\r
370         portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
371 \r
372         /* Configure SysTick to interrupt at the requested rate. */\r
373         portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
374         portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;\r
375     }\r
376 \r
377 #endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */\r
378 /*-----------------------------------------------------------*/\r
379 \r
380 #if ( configUSE_TICKLESS_IDLE == 1 )\r
381 \r
382     __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )\r
383     {\r
384         uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;\r
385         TickType_t xModifiableIdleTime;\r
386 \r
387         /* Make sure the SysTick reload value does not overflow the counter. */\r
388         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )\r
389         {\r
390             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;\r
391         }\r
392 \r
393         /* Stop the SysTick momentarily. The time the SysTick is stopped for\r
394          * is accounted for as best it can be, but using the tickless mode will\r
395          * inevitably result in some tiny drift of the time maintained by the\r
396          * kernel with respect to calendar time. */\r
397         portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;\r
398 \r
399         /* Calculate the reload value required to wait xExpectedIdleTime\r
400          * tick periods.  -1 is used because this code will execute part way\r
401          * through one of the tick periods. */\r
402         ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );\r
403 \r
404         if( ulReloadValue > ulStoppedTimerCompensation )\r
405         {\r
406             ulReloadValue -= ulStoppedTimerCompensation;\r
407         }\r
408 \r
409         /* Enter a critical section but don't use the taskENTER_CRITICAL()\r
410          * method as that will mask interrupts that should exit sleep mode. */\r
411         __disable_irq();\r
412         __dsb( portSY_FULL_READ_WRITE );\r
413         __isb( portSY_FULL_READ_WRITE );\r
414 \r
415         /* If a context switch is pending or a task is waiting for the scheduler\r
416          * to be unsuspended then abandon the low power entry. */\r
417         if( eTaskConfirmSleepModeStatus() == eAbortSleep )\r
418         {\r
419             /* Restart from whatever is left in the count register to complete\r
420              * this tick period. */\r
421             portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
422 \r
423             /* Restart SysTick. */\r
424             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
425 \r
426             /* Reset the reload register to the value required for normal tick\r
427              * periods. */\r
428             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
429 \r
430             /* Re-enable interrupts - see comments above __disable_irq() call\r
431              * above. */\r
432             __enable_irq();\r
433         }\r
434         else\r
435         {\r
436             /* Set the new reload value. */\r
437             portNVIC_SYSTICK_LOAD_REG = ulReloadValue;\r
438 \r
439             /* Clear the SysTick count flag and set the count value back to\r
440              * zero. */\r
441             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
442 \r
443             /* Restart SysTick. */\r
444             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
445 \r
446             /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can\r
447              * set its parameter to 0 to indicate that its implementation contains\r
448              * its own wait for interrupt or wait for event instruction, and so wfi\r
449              * should not be executed again. However, the original expected idle\r
450              * time variable must remain unmodified, so a copy is taken. */\r
451             xModifiableIdleTime = xExpectedIdleTime;\r
452             configPRE_SLEEP_PROCESSING( xModifiableIdleTime );\r
453 \r
454             if( xModifiableIdleTime > 0 )\r
455             {\r
456                 __dsb( portSY_FULL_READ_WRITE );\r
457                 __wfi();\r
458                 __isb( portSY_FULL_READ_WRITE );\r
459             }\r
460 \r
461             configPOST_SLEEP_PROCESSING( xExpectedIdleTime );\r
462 \r
463             /* Re-enable interrupts to allow the interrupt that brought the MCU\r
464              * out of sleep mode to execute immediately. see comments above\r
465              * __disable_interrupt() call above. */\r
466             __enable_irq();\r
467             __dsb( portSY_FULL_READ_WRITE );\r
468             __isb( portSY_FULL_READ_WRITE );\r
469 \r
470             /* Disable interrupts again because the clock is about to be stopped\r
471              * and interrupts that execute while the clock is stopped will increase\r
472              * any slippage between the time maintained by the RTOS and calendar\r
473              * time. */\r
474             __disable_irq();\r
475             __dsb( portSY_FULL_READ_WRITE );\r
476             __isb( portSY_FULL_READ_WRITE );\r
477 \r
478             /* Disable the SysTick clock without reading the\r
479              * portNVIC_SYSTICK_CTRL_REG register to ensure the\r
480              * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set.  Again,\r
481              * the time the SysTick is stopped for is accounted for as best it can\r
482              * be, but using the tickless mode will inevitably result in some tiny\r
483              * drift of the time maintained by the kernel with respect to calendar\r
484              * time*/\r
485             portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );\r
486 \r
487             /* Determine if the SysTick clock has already counted to zero and\r
488              * been set back to the current reload value (the reload back being\r
489              * correct for the entire expected idle time) or if the SysTick is yet\r
490              * to count to zero (in which case an interrupt other than the SysTick\r
491              * must have brought the system out of sleep mode). */\r
492             if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )\r
493             {\r
494                 uint32_t ulCalculatedLoadValue;\r
495 \r
496                 /* The tick interrupt is already pending, and the SysTick count\r
497                  * reloaded with ulReloadValue.  Reset the\r
498                  * portNVIC_SYSTICK_LOAD with whatever remains of this tick\r
499                  * period. */\r
500                 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );\r
501 \r
502                 /* Don't allow a tiny value, or values that have somehow\r
503                  * underflowed because the post sleep hook did something\r
504                  * that took too long. */\r
505                 if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )\r
506                 {\r
507                     ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );\r
508                 }\r
509 \r
510                 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;\r
511 \r
512                 /* As the pending tick will be processed as soon as this\r
513                  * function exits, the tick value maintained by the tick is stepped\r
514                  * forward by one less than the time spent waiting. */\r
515                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;\r
516             }\r
517             else\r
518             {\r
519                 /* Something other than the tick interrupt ended the sleep.\r
520                  * Work out how long the sleep lasted rounded to complete tick\r
521                  * periods (not the ulReload value which accounted for part\r
522                  * ticks). */\r
523                 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
524 \r
525                 /* How many complete tick periods passed while the processor\r
526                  * was waiting? */\r
527                 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;\r
528 \r
529                 /* The reload value is set to whatever fraction of a single tick\r
530                  * period remains. */\r
531                 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;\r
532             }\r
533 \r
534             /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD\r
535              * again, then set portNVIC_SYSTICK_LOAD back to its standard\r
536              * value. */\r
537             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
538             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
539             vTaskStepTick( ulCompleteTickPeriods );\r
540             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
541 \r
542             /* Exit with interrpts enabled. */\r
543             __enable_irq();\r
544         }\r
545     }\r
546 \r
547 #endif /* #if configUSE_TICKLESS_IDLE */\r
548 \r
549 /*-----------------------------------------------------------*/\r