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