]> begriffs open source - freertos/blob - portable/CCS/ARM_CM3/port.c
Add SPDX-License-Identifier: MIT to MIT licensed files.
[freertos] / portable / CCS / ARM_CM3 / port.c
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT
6  *
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 CM3 port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Scheduler includes. */\r
34 #include "FreeRTOS.h"\r
35 #include "task.h"\r
36 \r
37 #if ( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )\r
38     #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http: /*www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */\r
39 #endif\r
40 \r
41 #ifndef configSYSTICK_CLOCK_HZ\r
42     #define configSYSTICK_CLOCK_HZ      configCPU_CLOCK_HZ\r
43     /* Ensure the SysTick is clocked at the same frequency as the core. */\r
44     #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )\r
45 #else\r
46 \r
47 /* The way the SysTick is clocked is not modified in case it is not the same\r
48  * as the core. */\r
49     #define portNVIC_SYSTICK_CLK_BIT    ( 0 )\r
50 #endif\r
51 \r
52 /* Constants required to manipulate the core.  Registers first... */\r
53 #define portNVIC_SYSTICK_CTRL_REG             ( *( ( volatile uint32_t * ) 0xe000e010 ) )\r
54 #define portNVIC_SYSTICK_LOAD_REG             ( *( ( volatile uint32_t * ) 0xe000e014 ) )\r
55 #define portNVIC_SYSTICK_CURRENT_VALUE_REG    ( *( ( volatile uint32_t * ) 0xe000e018 ) )\r
56 #define portNVIC_SHPR3_REG                    ( *( ( volatile uint32_t * ) 0xe000ed20 ) )\r
57 /* ...then bits in the registers. */\r
58 #define portNVIC_SYSTICK_INT_BIT              ( 1UL << 1UL )\r
59 #define portNVIC_SYSTICK_ENABLE_BIT           ( 1UL << 0UL )\r
60 #define portNVIC_SYSTICK_COUNT_FLAG_BIT       ( 1UL << 16UL )\r
61 #define portNVIC_PENDSVCLEAR_BIT              ( 1UL << 27UL )\r
62 #define portNVIC_PEND_SYSTICK_CLEAR_BIT       ( 1UL << 25UL )\r
63 \r
64 #define portNVIC_PENDSV_PRI                   ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )\r
65 #define portNVIC_SYSTICK_PRI                  ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )\r
66 \r
67 /* Constants required to check the validity of an interrupt priority. */\r
68 #define portFIRST_USER_INTERRUPT_NUMBER       ( 16 )\r
69 #define portNVIC_IP_REGISTERS_OFFSET_16       ( 0xE000E3F0 )\r
70 #define portAIRCR_REG                         ( *( ( volatile uint32_t * ) 0xE000ED0C ) )\r
71 #define portMAX_8_BIT_VALUE                   ( ( uint8_t ) 0xff )\r
72 #define portTOP_BIT_OF_BYTE                   ( ( uint8_t ) 0x80 )\r
73 #define portMAX_PRIGROUP_BITS                 ( ( uint8_t ) 7 )\r
74 #define portPRIORITY_GROUP_MASK               ( 0x07UL << 8UL )\r
75 #define portPRIGROUP_SHIFT                    ( 8UL )\r
76 \r
77 /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */\r
78 #define portVECTACTIVE_MASK                   ( 0xFFUL )\r
79 \r
80 /* Constants required to set up the initial stack. */\r
81 #define portINITIAL_XPSR                      ( 0x01000000 )\r
82 \r
83 /* The systick is a 24-bit counter. */\r
84 #define portMAX_24_BIT_NUMBER                 ( 0xffffffUL )\r
85 \r
86 /* A fiddle factor to estimate the number of SysTick counts that would have\r
87  * occurred while the SysTick counter is stopped during tickless idle\r
88  * calculations. */\r
89 #define portMISSED_COUNTS_FACTOR              ( 45UL )\r
90 \r
91 /* For strict compliance with the Cortex-M spec the task start address should\r
92  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */\r
93 #define portSTART_ADDRESS_MASK                ( ( StackType_t ) 0xfffffffeUL )\r
94 \r
95 /*\r
96  * Setup the timer to generate the tick interrupts.  The implementation in this\r
97  * file is weak to allow application writers to change the timer used to\r
98  * generate the tick interrupt.\r
99  */\r
100 void vPortSetupTimerInterrupt( void );\r
101 \r
102 /*\r
103  * Exception handlers.\r
104  */\r
105 void xPortSysTickHandler( void );\r
106 \r
107 /*\r
108  * Start first task is a separate function so it can be tested in isolation.\r
109  */\r
110 extern void vPortStartFirstTask( void );\r
111 \r
112 /*\r
113  * Used to catch tasks that attempt to return from their implementing function.\r
114  */\r
115 static void prvTaskExitError( void );\r
116 \r
117 /*-----------------------------------------------------------*/\r
118 \r
119 /* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY\r
120  * setting. */\r
121 const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;\r
122 \r
123 /* Each task maintains its own interrupt status in the critical nesting\r
124  * variable. */\r
125 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;\r
126 \r
127 /*\r
128  * The number of SysTick increments that make up one tick period.\r
129  */\r
130 #if ( configUSE_TICKLESS_IDLE == 1 )\r
131     static uint32_t ulTimerCountsForOneTick = 0;\r
132 #endif /* configUSE_TICKLESS_IDLE */\r
133 \r
134 /*\r
135  * The maximum number of tick periods that can be suppressed is limited by the\r
136  * 24 bit resolution of the SysTick timer.\r
137  */\r
138 #if ( configUSE_TICKLESS_IDLE == 1 )\r
139     static uint32_t xMaximumPossibleSuppressedTicks = 0;\r
140 #endif /* configUSE_TICKLESS_IDLE */\r
141 \r
142 /*\r
143  * Compensate for the CPU cycles that pass while the SysTick is stopped (low\r
144  * power functionality only.\r
145  */\r
146 #if ( configUSE_TICKLESS_IDLE == 1 )\r
147     static uint32_t ulStoppedTimerCompensation = 0;\r
148 #endif /* configUSE_TICKLESS_IDLE */\r
149 \r
150 /*\r
151  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure\r
152  * FreeRTOS API functions are not called from interrupts that have been assigned\r
153  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
154  */\r
155 #if ( configASSERT_DEFINED == 1 )\r
156     static uint8_t ucMaxSysCallPriority = 0;\r
157     static uint32_t ulMaxPRIGROUPValue = 0;\r
158     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;\r
159 #endif /* configASSERT_DEFINED */\r
160 \r
161 /*-----------------------------------------------------------*/\r
162 \r
163 /*\r
164  * See header file for description.\r
165  */\r
166 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
167                                      TaskFunction_t pxCode,\r
168                                      void * pvParameters )\r
169 {\r
170     /* Simulate the stack frame as it would be created by a context switch\r
171      * interrupt. */\r
172 \r
173     /* Offset added to account for the way the MCU uses the stack on entry/exit\r
174      * of interrupts, and to ensure alignment. */\r
175     pxTopOfStack--;\r
176 \r
177     *pxTopOfStack = portINITIAL_XPSR;                                    /* xPSR */\r
178     pxTopOfStack--;\r
179     *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */\r
180     pxTopOfStack--;\r
181     *pxTopOfStack = ( StackType_t ) prvTaskExitError;                    /* LR */\r
182 \r
183     /* Save code space by skipping register initialisation. */\r
184     pxTopOfStack -= 5;                            /* R12, R3, R2 and R1. */\r
185     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
186 \r
187     pxTopOfStack -= 8;                            /* R11, R10, R9, R8, R7, R6, R5 and R4. */\r
188 \r
189     return pxTopOfStack;\r
190 }\r
191 /*-----------------------------------------------------------*/\r
192 \r
193 static void prvTaskExitError( void )\r
194 {\r
195     /* A function that implements a task must not exit or attempt to return to\r
196      * its caller as there is nothing to return to.  If a task wants to exit it\r
197      * should instead call vTaskDelete( NULL ).\r
198      *\r
199      * Artificially force an assert() to be triggered if configASSERT() is\r
200      * defined, then stop here so application writers can catch the error. */\r
201     configASSERT( uxCriticalNesting == ~0UL );\r
202     portDISABLE_INTERRUPTS();\r
203 \r
204     for( ; ; )\r
205     {\r
206     }\r
207 }\r
208 /*-----------------------------------------------------------*/\r
209 \r
210 /*\r
211  * See header file for description.\r
212  */\r
213 BaseType_t xPortStartScheduler( void )\r
214 {\r
215     #if ( configASSERT_DEFINED == 1 )\r
216         {\r
217             volatile uint32_t ulOriginalPriority;\r
218             volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );\r
219             volatile uint8_t ucMaxPriorityValue;\r
220 \r
221             /* Determine the maximum priority from which ISR safe FreeRTOS API\r
222              * functions can be called.  ISR safe functions are those that end in\r
223              * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to\r
224              * ensure interrupt entry is as fast and simple as possible.\r
225              *\r
226              * Save the interrupt priority value that is about to be clobbered. */\r
227             ulOriginalPriority = *pucFirstUserPriorityRegister;\r
228 \r
229             /* Determine the number of priority bits available.  First write to all\r
230              * possible bits. */\r
231             *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;\r
232 \r
233             /* Read the value back to see how many bits stuck. */\r
234             ucMaxPriorityValue = *pucFirstUserPriorityRegister;\r
235 \r
236             /* Use the same mask on the maximum system call priority. */\r
237             ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;\r
238 \r
239             /* Calculate the maximum acceptable priority group value for the number\r
240              * of bits read back. */\r
241             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;\r
242 \r
243             while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )\r
244             {\r
245                 ulMaxPRIGROUPValue--;\r
246                 ucMaxPriorityValue <<= ( uint8_t ) 0x01;\r
247             }\r
248 \r
249             #ifdef __NVIC_PRIO_BITS\r
250                 {\r
251                     /* Check the CMSIS configuration that defines the number of\r
252                      * priority bits matches the number of priority bits actually queried\r
253                      * from the hardware. */\r
254                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );\r
255                 }\r
256             #endif\r
257 \r
258             #ifdef configPRIO_BITS\r
259                 {\r
260                     /* Check the FreeRTOS configuration that defines the number of\r
261                      * priority bits matches the number of priority bits actually queried\r
262                      * from the hardware. */\r
263                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );\r
264                 }\r
265             #endif\r
266 \r
267             /* Shift the priority group value back to its position within the AIRCR\r
268              * register. */\r
269             ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;\r
270             ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;\r
271 \r
272             /* Restore the clobbered interrupt priority register to its original\r
273              * value. */\r
274             *pucFirstUserPriorityRegister = ulOriginalPriority;\r
275         }\r
276     #endif /* conifgASSERT_DEFINED */\r
277 \r
278     /* Make PendSV and SysTick the lowest priority interrupts. */\r
279     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;\r
280     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;\r
281 \r
282     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
283      * here already. */\r
284     vPortSetupTimerInterrupt();\r
285 \r
286     /* Initialise the critical nesting count ready for the first task. */\r
287     uxCriticalNesting = 0;\r
288 \r
289     /* Start the first task. */\r
290     vPortStartFirstTask();\r
291 \r
292     /* Should not get here! */\r
293     return 0;\r
294 }\r
295 /*-----------------------------------------------------------*/\r
296 \r
297 void vPortEndScheduler( void )\r
298 {\r
299     /* Not implemented in ports where there is nothing to return to.\r
300      * Artificially force an assert. */\r
301     configASSERT( uxCriticalNesting == 1000UL );\r
302 }\r
303 /*-----------------------------------------------------------*/\r
304 \r
305 void vPortEnterCritical( void )\r
306 {\r
307     portDISABLE_INTERRUPTS();\r
308     uxCriticalNesting++;\r
309 \r
310     /* This is not the interrupt safe version of the enter critical function so\r
311      * assert() if it is being called from an interrupt context.  Only API\r
312      * functions that end in "FromISR" can be used in an interrupt.  Only assert if\r
313      * the critical nesting count is 1 to protect against recursive calls if the\r
314      * assert function also uses a critical section. */\r
315     if( uxCriticalNesting == 1 )\r
316     {\r
317         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );\r
318     }\r
319 }\r
320 /*-----------------------------------------------------------*/\r
321 \r
322 void vPortExitCritical( void )\r
323 {\r
324     configASSERT( uxCriticalNesting );\r
325     uxCriticalNesting--;\r
326 \r
327     if( uxCriticalNesting == 0 )\r
328     {\r
329         portENABLE_INTERRUPTS();\r
330     }\r
331 }\r
332 /*-----------------------------------------------------------*/\r
333 \r
334 void xPortSysTickHandler( void )\r
335 {\r
336     /* The SysTick runs at the lowest interrupt priority, so when this interrupt\r
337      * executes all interrupts must be unmasked.  There is therefore no need to\r
338      * save and then restore the interrupt mask value as its value is already\r
339      * known. */\r
340     ( void ) portSET_INTERRUPT_MASK_FROM_ISR();\r
341     {\r
342         /* Increment the RTOS tick. */\r
343         if( xTaskIncrementTick() != pdFALSE )\r
344         {\r
345             /* A context switch is required.  Context switching is performed in\r
346              * the PendSV interrupt.  Pend the PendSV interrupt. */\r
347             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
348         }\r
349     }\r
350     portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );\r
351 }\r
352 /*-----------------------------------------------------------*/\r
353 \r
354 #if ( configUSE_TICKLESS_IDLE == 1 )\r
355 \r
356     #pragma WEAK( vPortSuppressTicksAndSleep )\r
357     void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )\r
358     {\r
359         uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;\r
360         TickType_t xModifiableIdleTime;\r
361 \r
362         /* Make sure the SysTick reload value does not overflow the counter. */\r
363         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )\r
364         {\r
365             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;\r
366         }\r
367 \r
368         /* Stop the SysTick momentarily.  The time the SysTick is stopped for\r
369          * is accounted for as best it can be, but using the tickless mode will\r
370          * inevitably result in some tiny drift of the time maintained by the\r
371          * kernel with respect to calendar time. */\r
372         portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;\r
373 \r
374         /* Calculate the reload value required to wait xExpectedIdleTime\r
375          * tick periods.  -1 is used because this code will execute part way\r
376          * through one of the tick periods. */\r
377         ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );\r
378 \r
379         if( ulReloadValue > ulStoppedTimerCompensation )\r
380         {\r
381             ulReloadValue -= ulStoppedTimerCompensation;\r
382         }\r
383 \r
384         /* Enter a critical section but don't use the taskENTER_CRITICAL()\r
385          * method as that will mask interrupts that should exit sleep mode. */\r
386         __asm( "        cpsid i");\r
387         __asm( "        dsb");\r
388         __asm( "        isb");\r
389 \r
390         /* If a context switch is pending or a task is waiting for the scheduler\r
391          * to be unsuspended then abandon the low power entry. */\r
392         if( eTaskConfirmSleepModeStatus() == eAbortSleep )\r
393         {\r
394             /* Restart from whatever is left in the count register to complete\r
395              * this tick period. */\r
396             portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
397 \r
398             /* Restart SysTick. */\r
399             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
400 \r
401             /* Reset the reload register to the value required for normal tick\r
402              * periods. */\r
403             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
404 \r
405             /* Re-enable interrupts - see comments above __disable_interrupt()\r
406              * call above. */\r
407             __asm( "    cpsie i");\r
408         }\r
409         else\r
410         {\r
411             /* Set the new reload value. */\r
412             portNVIC_SYSTICK_LOAD_REG = ulReloadValue;\r
413 \r
414             /* Clear the SysTick count flag and set the count value back to\r
415              * zero. */\r
416             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
417 \r
418             /* Restart SysTick. */\r
419             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
420 \r
421             /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can\r
422              * set its parameter to 0 to indicate that its implementation contains\r
423              * its own wait for interrupt or wait for event instruction, and so wfi\r
424              * should not be executed again.  However, the original expected idle\r
425              * time variable must remain unmodified, so a copy is taken. */\r
426             xModifiableIdleTime = xExpectedIdleTime;\r
427             configPRE_SLEEP_PROCESSING( xModifiableIdleTime );\r
428 \r
429             if( xModifiableIdleTime > 0 )\r
430             {\r
431                 __asm( "        dsb");\r
432                 __asm( "        wfi");\r
433                 __asm( "        isb");\r
434             }\r
435 \r
436             configPOST_SLEEP_PROCESSING( xExpectedIdleTime );\r
437 \r
438             /* Re-enable interrupts to allow the interrupt that brought the MCU\r
439              * out of sleep mode to execute immediately.  see comments above\r
440              * __disable_interrupt() call above. */\r
441             __asm( "    cpsie i");\r
442             __asm( "    dsb");\r
443             __asm( "    isb");\r
444 \r
445             /* Disable interrupts again because the clock is about to be stopped\r
446              * and interrupts that execute while the clock is stopped will increase\r
447              * any slippage between the time maintained by the RTOS and calendar\r
448              * time. */\r
449             __asm( "    cpsid i");\r
450             __asm( "    dsb");\r
451             __asm( "    isb");\r
452 \r
453             /* Disable the SysTick clock without reading the\r
454              * portNVIC_SYSTICK_CTRL_REG register to ensure the\r
455              * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set.  Again,\r
456              * the time the SysTick is stopped for is accounted for as best it can\r
457              * be, but using the tickless mode will inevitably result in some tiny\r
458              * drift of the time maintained by the kernel with respect to calendar\r
459              * time*/\r
460             portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );\r
461 \r
462             /* Determine if the SysTick clock has already counted to zero and\r
463              * been set back to the current reload value (the reload back being\r
464              * correct for the entire expected idle time) or if the SysTick is yet\r
465              * to count to zero (in which case an interrupt other than the SysTick\r
466              * must have brought the system out of sleep mode). */\r
467             if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )\r
468             {\r
469                 uint32_t ulCalculatedLoadValue;\r
470 \r
471                 /* The tick interrupt is already pending, and the SysTick count\r
472                  * reloaded with ulReloadValue.  Reset the\r
473                  * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick\r
474                  * period. */\r
475                 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );\r
476 \r
477                 /* Don't allow a tiny value, or values that have somehow\r
478                  * underflowed because the post sleep hook did something\r
479                  * that took too long. */\r
480                 if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )\r
481                 {\r
482                     ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );\r
483                 }\r
484 \r
485                 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;\r
486 \r
487                 /* As the pending tick will be processed as soon as this\r
488                  * function exits, the tick value maintained by the tick is stepped\r
489                  * forward by one less than the time spent waiting. */\r
490                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;\r
491             }\r
492             else\r
493             {\r
494                 /* Something other than the tick interrupt ended the sleep.\r
495                  * Work out how long the sleep lasted rounded to complete tick\r
496                  * periods (not the ulReload value which accounted for part\r
497                  * ticks). */\r
498                 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;\r
499 \r
500                 /* How many complete tick periods passed while the processor\r
501                  * was waiting? */\r
502                 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;\r
503 \r
504                 /* The reload value is set to whatever fraction of a single tick\r
505                  * period remains. */\r
506                 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;\r
507             }\r
508 \r
509             /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG\r
510              * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard\r
511              * value. */\r
512             portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
513             portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;\r
514             vTaskStepTick( ulCompleteTickPeriods );\r
515             portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;\r
516 \r
517             /* Exit with interrupts enabled. */\r
518             __asm( "    cpsie i");\r
519         }\r
520     }\r
521 \r
522 #endif /* configUSE_TICKLESS_IDLE */\r
523 /*-----------------------------------------------------------*/\r
524 \r
525 /*\r
526  * Setup the systick timer to generate the tick interrupts at the required\r
527  * frequency.\r
528  */\r
529 #pragma WEAK( vPortSetupTimerInterrupt )\r
530 void vPortSetupTimerInterrupt( void )\r
531 {\r
532     /* Calculate the constants required to configure the tick interrupt. */\r
533     #if ( configUSE_TICKLESS_IDLE == 1 )\r
534         {\r
535             ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );\r
536             xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;\r
537             ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );\r
538         }\r
539     #endif /* configUSE_TICKLESS_IDLE */\r
540 \r
541     /* Stop and clear the SysTick. */\r
542     portNVIC_SYSTICK_CTRL_REG = 0UL;\r
543     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
544 \r
545     /* Configure SysTick to interrupt at the requested rate. */\r
546     portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
547     portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );\r
548 }\r
549 /*-----------------------------------------------------------*/\r
550 \r
551 #if ( configASSERT_DEFINED == 1 )\r
552 \r
553     void vPortValidateInterruptPriority( void )\r
554     {\r
555         extern uint32_t ulPortGetIPSR( void );\r
556         uint32_t ulCurrentInterrupt;\r
557         uint8_t ucCurrentPriority;\r
558 \r
559         ulCurrentInterrupt = ulPortGetIPSR();\r
560 \r
561         /* Is the interrupt number a user defined interrupt? */\r
562         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )\r
563         {\r
564             /* Look up the interrupt's priority. */\r
565             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];\r
566 \r
567             /* The following assertion will fail if a service routine (ISR) for\r
568              * an interrupt that has been assigned a priority above\r
569              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
570              * function.  ISR safe FreeRTOS API functions must *only* be called\r
571              * from interrupts that have been assigned a priority at or below\r
572              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
573              *\r
574              * Numerically low interrupt priority numbers represent logically high\r
575              * interrupt priorities, therefore the priority of the interrupt must\r
576              * be set to a value equal to or numerically *higher* than\r
577              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
578              *\r
579              * Interrupts that  use the FreeRTOS API must not be left at their\r
580              * default priority of      zero as that is the highest possible priority,\r
581              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,\r
582              * and      therefore also guaranteed to be invalid.\r
583              *\r
584              * FreeRTOS maintains separate thread and ISR API functions to ensure\r
585              * interrupt entry is as fast and simple as possible.\r
586              *\r
587              * The following links provide detailed information:\r
588              * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html\r
589              * https://www.FreeRTOS.org/FAQHelp.html */\r
590             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );\r
591         }\r
592 \r
593         /* Priority grouping:  The interrupt controller (NVIC) allows the bits\r
594          * that define each interrupt's priority to be split between bits that\r
595          * define the interrupt's pre-emption priority bits and bits that define\r
596          * the interrupt's sub-priority.  For simplicity all bits must be defined\r
597          * to be pre-emption priority bits.  The following assertion will fail if\r
598          * this is not the case (if some bits represent a sub-priority).\r
599          *\r
600          * If the application only uses CMSIS libraries for interrupt\r
601          * configuration then the correct setting can be achieved on all Cortex-M\r
602          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the\r
603          * scheduler.  Note however that some vendor specific peripheral libraries\r
604          * assume a non-zero priority group setting, in which cases using a value\r
605          * of zero will result in unpredictable behaviour. */\r
606         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );\r
607     }\r
608 \r
609 #endif /* configASSERT_DEFINED */\r