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