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