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