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