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