]> begriffs open source - freertos/blob - portable/RVDS/ARM_CM4_MPU/port.c
[AUTO][RELEASE]: Bump file header version to "10.4.4"
[freertos] / portable / RVDS / ARM_CM4_MPU / port.c
1 /*\r
2  * FreeRTOS Kernel V10.4.4\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 CM4 MPU port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
34  * all the API functions to use the MPU wrappers.  That should only be done when\r
35  * task.h is included from an application file. */\r
36 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
37 \r
38 /* Scheduler includes. */\r
39 #include "FreeRTOS.h"\r
40 #include "task.h"\r
41 \r
42 #ifndef __TARGET_FPU_VFP\r
43     #error This port can only be used when the project options are configured to enable hardware floating point support.\r
44 #endif\r
45 \r
46 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
47 \r
48 /* Constants required to access and manipulate the NVIC. */\r
49 #define portNVIC_SYSTICK_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000e010 ) )\r
50 #define portNVIC_SYSTICK_LOAD_REG                 ( *( ( volatile uint32_t * ) 0xe000e014 ) )\r
51 #define portNVIC_SYSTICK_CURRENT_VALUE_REG        ( *( ( volatile uint32_t * ) 0xe000e018 ) )\r
52 #define portNVIC_SHPR3_REG                        ( *( ( volatile uint32_t * ) 0xe000ed20 ) )\r
53 #define portNVIC_SHPR2_REG                        ( *( ( volatile uint32_t * ) 0xe000ed1c ) )\r
54 #define portNVIC_SYS_CTRL_STATE_REG               ( *( ( volatile uint32_t * ) 0xe000ed24 ) )\r
55 #define portNVIC_MEM_FAULT_ENABLE                 ( 1UL << 16UL )\r
56 \r
57 /* Constants required to access and manipulate the MPU. */\r
58 #define portMPU_TYPE_REG                          ( *( ( volatile uint32_t * ) 0xe000ed90 ) )\r
59 #define portMPU_REGION_BASE_ADDRESS_REG           ( *( ( volatile uint32_t * ) 0xe000ed9C ) )\r
60 #define portMPU_REGION_ATTRIBUTE_REG              ( *( ( volatile uint32_t * ) 0xe000edA0 ) )\r
61 #define portMPU_CTRL_REG                          ( *( ( volatile uint32_t * ) 0xe000ed94 ) )\r
62 #define portEXPECTED_MPU_TYPE_VALUE               ( portTOTAL_NUM_REGIONS << 8UL )\r
63 #define portMPU_ENABLE                            ( 0x01UL )\r
64 #define portMPU_BACKGROUND_ENABLE                 ( 1UL << 2UL )\r
65 #define portPRIVILEGED_EXECUTION_START_ADDRESS    ( 0UL )\r
66 #define portMPU_REGION_VALID                      ( 0x10UL )\r
67 #define portMPU_REGION_ENABLE                     ( 0x01UL )\r
68 #define portPERIPHERALS_START_ADDRESS             0x40000000UL\r
69 #define portPERIPHERALS_END_ADDRESS               0x5FFFFFFFUL\r
70 \r
71 /* Constants required to access and manipulate the SysTick. */\r
72 #define portNVIC_SYSTICK_CLK                      ( 0x00000004UL )\r
73 #define portNVIC_SYSTICK_INT                      ( 0x00000002UL )\r
74 #define portNVIC_SYSTICK_ENABLE                   ( 0x00000001UL )\r
75 #define portNVIC_PENDSV_PRI                       ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )\r
76 #define portNVIC_SYSTICK_PRI                      ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )\r
77 #define portNVIC_SVC_PRI                          ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )\r
78 \r
79 /* Constants required to manipulate the VFP. */\r
80 #define portFPCCR                                 ( ( volatile uint32_t * ) 0xe000ef34UL ) /* Floating point context control register. */\r
81 #define portASPEN_AND_LSPEN_BITS                  ( 0x3UL << 30UL )\r
82 \r
83 /* Constants required to set up the initial stack. */\r
84 #define portINITIAL_XPSR                          ( 0x01000000UL )\r
85 #define portINITIAL_EXC_RETURN                    ( 0xfffffffdUL )\r
86 #define portINITIAL_CONTROL_IF_UNPRIVILEGED       ( 0x03 )\r
87 #define portINITIAL_CONTROL_IF_PRIVILEGED         ( 0x02 )\r
88 \r
89 /* Constants required to check the validity of an interrupt priority. */\r
90 #define portFIRST_USER_INTERRUPT_NUMBER           ( 16 )\r
91 #define portNVIC_IP_REGISTERS_OFFSET_16           ( 0xE000E3F0 )\r
92 #define portAIRCR_REG                             ( *( ( volatile uint32_t * ) 0xE000ED0C ) )\r
93 #define portMAX_8_BIT_VALUE                       ( ( uint8_t ) 0xff )\r
94 #define portTOP_BIT_OF_BYTE                       ( ( uint8_t ) 0x80 )\r
95 #define portMAX_PRIGROUP_BITS                     ( ( uint8_t ) 7 )\r
96 #define portPRIORITY_GROUP_MASK                   ( 0x07UL << 8UL )\r
97 #define portPRIGROUP_SHIFT                        ( 8UL )\r
98 \r
99 /* Offsets in the stack to the parameters when inside the SVC handler. */\r
100 #define portOFFSET_TO_PC                          ( 6 )\r
101 \r
102 /* For strict compliance with the Cortex-M spec the task start address should\r
103  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */\r
104 #define portSTART_ADDRESS_MASK                    ( ( StackType_t ) 0xfffffffeUL )\r
105 \r
106 /* Each task maintains its own interrupt status in the critical nesting\r
107  * variable.  Note this is not saved as part of the task context as context\r
108  * switches can only occur when uxCriticalNesting is zero. */\r
109 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;\r
110 \r
111 /*\r
112  * Setup the timer to generate the tick interrupts.\r
113  */\r
114 void vSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION;\r
115 \r
116 /*\r
117  * Configure a number of standard MPU regions that are used by all tasks.\r
118  */\r
119 static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;\r
120 \r
121 /*\r
122  * Start first task is a separate function so it can be tested in isolation.\r
123  */\r
124 static void prvStartFirstTask( void ) PRIVILEGED_FUNCTION;\r
125 \r
126 /*\r
127  * Return the smallest MPU region size that a given number of bytes will fit\r
128  * into.  The region size is returned as the value that should be programmed\r
129  * into the region attribute register for that region.\r
130  */\r
131 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;\r
132 \r
133 /*\r
134  * Standard FreeRTOS exception handlers.\r
135  */\r
136 void xPortPendSVHandler( void ) PRIVILEGED_FUNCTION;\r
137 void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;\r
138 void vPortSVCHandler( void ) PRIVILEGED_FUNCTION;\r
139 \r
140 /*\r
141  * Starts the scheduler by restoring the context of the first task to run.\r
142  */\r
143 static void prvRestoreContextOfFirstTask( void ) PRIVILEGED_FUNCTION;\r
144 \r
145 /*\r
146  * C portion of the SVC handler.  The SVC handler is split between an asm entry\r
147  * and a C wrapper for simplicity of coding and maintenance.\r
148  */\r
149 void prvSVCHandler( uint32_t * pulRegisters ) __attribute__( ( used ) ) PRIVILEGED_FUNCTION;\r
150 \r
151 /*\r
152  * Function to enable the VFP.\r
153  */\r
154 static void vPortEnableVFP( void );\r
155 \r
156 /*\r
157  * Utility function.\r
158  */\r
159 static uint32_t prvPortGetIPSR( void );\r
160 \r
161 /*\r
162  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure\r
163  * FreeRTOS API functions are not called from interrupts that have been assigned\r
164  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
165  */\r
166 #if ( configASSERT_DEFINED == 1 )\r
167     static uint8_t ucMaxSysCallPriority = 0;\r
168     static uint32_t ulMaxPRIGROUPValue = 0;\r
169     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;\r
170 #endif /* configASSERT_DEFINED */\r
171 \r
172 /**\r
173  * @brief Checks whether or not the processor is privileged.\r
174  *\r
175  * @return 1 if the processor is already privileged, 0 otherwise.\r
176  */\r
177 BaseType_t xIsPrivileged( void );\r
178 \r
179 /**\r
180  * @brief Lowers the privilege level by setting the bit 0 of the CONTROL\r
181  * register.\r
182  *\r
183  * Bit 0 of the CONTROL register defines the privilege level of Thread Mode.\r
184  *  Bit[0] = 0 --> The processor is running privileged\r
185  *  Bit[0] = 1 --> The processor is running unprivileged.\r
186  */\r
187 void vResetPrivilege( void );\r
188 \r
189 /**\r
190  * @brief Calls the port specific code to raise the privilege.\r
191  *\r
192  * @return pdFALSE if privilege was raised, pdTRUE otherwise.\r
193  */\r
194 extern BaseType_t xPortRaisePrivilege( void );\r
195 \r
196 /**\r
197  * @brief If xRunningPrivileged is not pdTRUE, calls the port specific\r
198  * code to reset the privilege, otherwise does nothing.\r
199  */\r
200 extern void vPortResetPrivilege( BaseType_t xRunningPrivileged );\r
201 /*-----------------------------------------------------------*/\r
202 \r
203 /*\r
204  * See header file for description.\r
205  */\r
206 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
207                                      TaskFunction_t pxCode,\r
208                                      void * pvParameters,\r
209                                      BaseType_t xRunPrivileged )\r
210 {\r
211     /* Simulate the stack frame as it would be created by a context switch\r
212      * interrupt. */\r
213     pxTopOfStack--;                                                      /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */\r
214     *pxTopOfStack = portINITIAL_XPSR;                                    /* xPSR */\r
215     pxTopOfStack--;\r
216     *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */\r
217     pxTopOfStack--;\r
218     *pxTopOfStack = 0;                                                   /* LR */\r
219     pxTopOfStack -= 5;                                                   /* R12, R3, R2 and R1. */\r
220     *pxTopOfStack = ( StackType_t ) pvParameters;                        /* R0 */\r
221 \r
222     /* A save method is being used that requires each task to maintain its\r
223      * own exec return value. */\r
224     pxTopOfStack--;\r
225     *pxTopOfStack = portINITIAL_EXC_RETURN;\r
226 \r
227     pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */\r
228 \r
229     if( xRunPrivileged == pdTRUE )\r
230     {\r
231         *pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;\r
232     }\r
233     else\r
234     {\r
235         *pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;\r
236     }\r
237 \r
238     return pxTopOfStack;\r
239 }\r
240 /*-----------------------------------------------------------*/\r
241 \r
242 void prvSVCHandler( uint32_t * pulParam )\r
243 {\r
244     uint8_t ucSVCNumber;\r
245     uint32_t ulReg, ulPC;\r
246 \r
247     #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
248         extern uint32_t __syscalls_flash_start__;\r
249         extern uint32_t __syscalls_flash_end__;\r
250     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
251 \r
252     /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first\r
253      * argument (r0) is pulParam[ 0 ]. */\r
254     ulPC = pulParam[ portOFFSET_TO_PC ];\r
255     ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];\r
256 \r
257     switch( ucSVCNumber )\r
258     {\r
259         case portSVC_START_SCHEDULER:\r
260             portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;\r
261             prvRestoreContextOfFirstTask();\r
262             break;\r
263 \r
264         case portSVC_YIELD:\r
265             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
266 \r
267             /* Barriers are normally not required\r
268              * but do ensure the code is completely\r
269              * within the specified behaviour for the\r
270              * architecture. */\r
271             __asm volatile ( "dsb" );\r
272             __asm volatile ( "isb" );\r
273 \r
274             break;\r
275 \r
276             #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
277                 case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the\r
278                                                * svc was raised from any of the\r
279                                                * system calls. */\r
280 \r
281                     if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&\r
282                         ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )\r
283                     {\r
284                         __asm\r
285                         {\r
286 /* *INDENT-OFF* */\r
287                             mrs ulReg, control /* Obtain current control value. */\r
288                             bic ulReg, # 1     /* Set privilege bit. */\r
289                             msr control, ulReg /* Write back new control value. */\r
290 /* *INDENT-ON* */\r
291                         }\r
292                     }\r
293 \r
294                     break;\r
295             #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
296                 case portSVC_RAISE_PRIVILEGE:\r
297                     __asm\r
298                     {\r
299 /* *INDENT-OFF* */\r
300                         mrs ulReg, control /* Obtain current control value. */\r
301                         bic ulReg, # 1     /* Set privilege bit. */\r
302                         msr control, ulReg /* Write back new control value. */\r
303 /* *INDENT-ON* */\r
304                     }\r
305                     break;\r
306                     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
307 \r
308                 default: /* Unknown SVC call. */\r
309                     break;\r
310     }\r
311 }\r
312 /*-----------------------------------------------------------*/\r
313 \r
314 __asm void vPortSVCHandler( void )\r
315 {\r
316     extern prvSVCHandler\r
317 \r
318 /* *INDENT-OFF* */\r
319         PRESERVE8\r
320 \r
321     /* Assumes psp was in use. */\r
322     #ifndef USE_PROCESS_STACK   /* Code should not be required if a main() is using the process stack. */\r
323         tst lr, # 4\r
324         ite eq\r
325         mrseq r0, msp\r
326         mrsne r0, psp\r
327     #else\r
328         mrs r0, psp\r
329     #endif\r
330 \r
331     b prvSVCHandler\r
332 /* *INDENT-ON* */\r
333 }\r
334 /*-----------------------------------------------------------*/\r
335 \r
336 __asm void prvRestoreContextOfFirstTask( void )\r
337 {\r
338 /* *INDENT-OFF* */\r
339     PRESERVE8\r
340 \r
341     ldr r0, =0xE000ED08 /* Use the NVIC offset register to locate the stack. */\r
342     ldr r0, [ r0 ]\r
343     ldr r0, [ r0 ]\r
344     msr msp, r0              /* Set the msp back to the start of the stack. */\r
345     ldr r3, =pxCurrentTCB   /* Restore the context. */\r
346     ldr r1, [ r3 ]\r
347     ldr r0, [ r1 ]    /* The first item in the TCB is the task top of stack. */\r
348     add r1, r1, #4          /* Move onto the second item in the TCB... */\r
349 \r
350     dmb               /* Complete outstanding transfers before disabling MPU. */\r
351     ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
352     ldr r3, [ r2 ] /* Read the value of MPU_CTRL. */\r
353     bic r3, r3, # 1          /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
354     str r3, [ r2 ]           /* Disable MPU. */\r
355 \r
356     ldr r2, =0xe000ed9c     /* Region Base Address register. */\r
357     ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
358     stmia r2, { r4 - r11 }  /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
359 \r
360     #if ( portTOTAL_NUM_REGIONS == 16 )\r
361         ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
362         stmia r2, { r4 - r11 } /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
363         ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
364         stmia r2, { r4 - r11 }  /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
365     #endif /* portTOTAL_NUM_REGIONS == 16. */\r
366 \r
367     ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
368     ldr r3, [ r2 ] /* Read the value of MPU_CTRL. */\r
369     orr r3, r3, #1          /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
370     str r3, [ r2 ]           /* Enable MPU. */\r
371     dsb                      /* Force memory writes before continuing. */\r
372 \r
373     ldmia r0 !, { r3 - r11, r14 } /* Pop the registers that are not automatically saved on exception entry. */\r
374     msr control, r3\r
375     msr psp, r0 /* Restore the task stack pointer. */\r
376     mov r0, #0\r
377     msr basepri, r0\r
378     bx r14\r
379     nop\r
380 /* *INDENT-ON* */\r
381 }\r
382 /*-----------------------------------------------------------*/\r
383 \r
384 /*\r
385  * See header file for description.\r
386  */\r
387 BaseType_t xPortStartScheduler( void )\r
388 {\r
389     /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.\r
390      * See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */\r
391     configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );\r
392 \r
393     #if ( configASSERT_DEFINED == 1 )\r
394         {\r
395             volatile uint32_t ulOriginalPriority;\r
396             volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );\r
397             volatile uint8_t ucMaxPriorityValue;\r
398 \r
399             /* Determine the maximum priority from which ISR safe FreeRTOS API\r
400              * functions can be called.  ISR safe functions are those that end in\r
401              * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to\r
402              * ensure interrupt entry is as fast and simple as possible.\r
403              *\r
404              * Save the interrupt priority value that is about to be clobbered. */\r
405             ulOriginalPriority = *pucFirstUserPriorityRegister;\r
406 \r
407             /* Determine the number of priority bits available.  First write to all\r
408              * possible bits. */\r
409             *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;\r
410 \r
411             /* Read the value back to see how many bits stuck. */\r
412             ucMaxPriorityValue = *pucFirstUserPriorityRegister;\r
413 \r
414             /* Use the same mask on the maximum system call priority. */\r
415             ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;\r
416 \r
417             /* Calculate the maximum acceptable priority group value for the number\r
418              * of bits read back. */\r
419             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;\r
420 \r
421             while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )\r
422             {\r
423                 ulMaxPRIGROUPValue--;\r
424                 ucMaxPriorityValue <<= ( uint8_t ) 0x01;\r
425             }\r
426 \r
427             #ifdef __NVIC_PRIO_BITS\r
428                 {\r
429                     /* Check the CMSIS configuration that defines the number of\r
430                      * priority bits matches the number of priority bits actually queried\r
431                      * from the hardware. */\r
432                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );\r
433                 }\r
434             #endif\r
435 \r
436             #ifdef configPRIO_BITS\r
437                 {\r
438                     /* Check the FreeRTOS configuration that defines the number of\r
439                      * priority bits matches the number of priority bits actually queried\r
440                      * from the hardware. */\r
441                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );\r
442                 }\r
443             #endif\r
444 \r
445             /* Shift the priority group value back to its position within the AIRCR\r
446              * register. */\r
447             ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;\r
448             ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;\r
449 \r
450             /* Restore the clobbered interrupt priority register to its original\r
451              * value. */\r
452             *pucFirstUserPriorityRegister = ulOriginalPriority;\r
453         }\r
454     #endif /* conifgASSERT_DEFINED */\r
455 \r
456     /* Make PendSV and SysTick the same priority as the kernel, and the SVC\r
457      * handler higher priority so it can be used to exit a critical section (where\r
458      * lower priorities are masked). */\r
459     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;\r
460     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;\r
461 \r
462     /* Configure the regions in the MPU that are common to all tasks. */\r
463     prvSetupMPU();\r
464 \r
465     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
466      * here already. */\r
467     vSetupTimerInterrupt();\r
468 \r
469     /* Initialise the critical nesting count ready for the first task. */\r
470     uxCriticalNesting = 0;\r
471 \r
472     /* Ensure the VFP is enabled - it should be anyway. */\r
473     vPortEnableVFP();\r
474 \r
475     /* Lazy save always. */\r
476     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;\r
477 \r
478     /* Start the first task. */\r
479     prvStartFirstTask();\r
480 \r
481     /* Should not get here! */\r
482     return 0;\r
483 }\r
484 /*-----------------------------------------------------------*/\r
485 \r
486 __asm void prvStartFirstTask( void )\r
487 {\r
488 /* *INDENT-OFF* */\r
489     PRESERVE8\r
490 \r
491     /* Use the NVIC offset register to locate the stack. */\r
492     ldr r0, =0xE000ED08\r
493     ldr r0, [ r0 ]\r
494     ldr r0, [ r0 ]\r
495     /* Set the msp back to the start of the stack. */\r
496     msr msp, r0\r
497 \r
498     /* Clear the bit that indicates the FPU is in use in case the FPU was used\r
499      * before the scheduler was started - which would otherwise result in the\r
500      * unnecessary leaving of space in the SVC stack for lazy saving of FPU\r
501      * registers. */\r
502     mov r0, #0\r
503     msr control, r0\r
504     /* Globally enable interrupts. */\r
505     cpsie i\r
506     cpsie f\r
507     dsb\r
508     isb\r
509     svc portSVC_START_SCHEDULER /* System call to start first task. */\r
510     nop\r
511     nop\r
512 /* *INDENT-ON* */\r
513 }\r
514 \r
515 void vPortEndScheduler( void )\r
516 {\r
517     /* Not implemented in ports where there is nothing to return to.\r
518      * Artificially force an assert. */\r
519     configASSERT( uxCriticalNesting == 1000UL );\r
520 }\r
521 /*-----------------------------------------------------------*/\r
522 \r
523 void vPortEnterCritical( void )\r
524 {\r
525     BaseType_t xRunningPrivileged = xPortRaisePrivilege();\r
526 \r
527     portDISABLE_INTERRUPTS();\r
528     uxCriticalNesting++;\r
529 \r
530     vPortResetPrivilege( xRunningPrivileged );\r
531 }\r
532 /*-----------------------------------------------------------*/\r
533 \r
534 void vPortExitCritical( void )\r
535 {\r
536     BaseType_t xRunningPrivileged = xPortRaisePrivilege();\r
537 \r
538     configASSERT( uxCriticalNesting );\r
539     uxCriticalNesting--;\r
540 \r
541     if( uxCriticalNesting == 0 )\r
542     {\r
543         portENABLE_INTERRUPTS();\r
544     }\r
545 \r
546     vPortResetPrivilege( xRunningPrivileged );\r
547 }\r
548 /*-----------------------------------------------------------*/\r
549 \r
550 __asm void xPortPendSVHandler( void )\r
551 {\r
552     extern uxCriticalNesting;\r
553     extern pxCurrentTCB;\r
554     extern vTaskSwitchContext;\r
555 \r
556 /* *INDENT-OFF* */\r
557     PRESERVE8\r
558 \r
559     mrs r0, psp\r
560 \r
561     ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */\r
562     ldr r2, [ r3 ]\r
563 \r
564     tst r14, #0x10 /* Is the task using the FPU context?  If so, push high vfp registers. */\r
565     it eq\r
566     vstmdbeq r0 !, { s16 - s31 }\r
567 \r
568     mrs r1, control\r
569     stmdb r0 !, { r1, r4 - r11, r14 }   /* Save the remaining registers. */\r
570     str r0, [ r2 ] /* Save the new top of stack into the first member of the TCB. */\r
571 \r
572     stmdb sp !, { r0, r3 }\r
573     mov r0, # configMAX_SYSCALL_INTERRUPT_PRIORITY\r
574     msr basepri, r0\r
575     dsb\r
576     isb\r
577     bl vTaskSwitchContext\r
578     mov r0, #0\r
579     msr basepri, r0\r
580     ldmia sp !, { r0, r3 }\r
581     /* Restore the context. */\r
582     ldr r1, [ r3 ]\r
583     ldr r0, [ r1 ]           /* The first item in the TCB is the task top of stack. */\r
584     add r1, r1, #4          /* Move onto the second item in the TCB... */\r
585 \r
586     dmb                      /* Complete outstanding transfers before disabling MPU. */\r
587     ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
588     ldr r3, [ r2 ] /* Read the value of MPU_CTRL. */\r
589     bic r3, r3, #1          /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
590     str r3, [ r2 ]           /* Disable MPU. */\r
591 \r
592     ldr r2, =0xe000ed9c     /* Region Base Address register. */\r
593     ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
594     stmia r2, { r4 - r11 }   /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
595 \r
596     #if ( portTOTAL_NUM_REGIONS == 16 )\r
597         ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
598         stmia r2, { r4 - r11 }  /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
599         ldmia r1 !, { r4 - r11 } /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
600         stmia r2, { r4 - r11 } /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
601     #endif /* portTOTAL_NUM_REGIONS == 16. */\r
602 \r
603     ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
604     ldr r3, [ r2 ] /* Read the value of MPU_CTRL. */\r
605     orr r3, r3, #1          /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
606     str r3, [ r2 ]           /* Enable MPU. */\r
607     dsb                      /* Force memory writes before continuing. */\r
608 \r
609     ldmia r0 !, { r3 - r11, r14 }                               /* Pop the registers that are not automatically saved on exception entry. */\r
610     msr control, r3\r
611 \r
612     tst r14, #0x10 /* Is the task using the FPU context?  If so, pop the high vfp registers too. */\r
613     it eq\r
614     vldmiaeq r0 !, { s16 - s31 }\r
615 \r
616     msr psp, r0\r
617     bx r14\r
618     nop\r
619 /* *INDENT-ON* */\r
620 }\r
621 /*-----------------------------------------------------------*/\r
622 \r
623 void xPortSysTickHandler( void )\r
624 {\r
625     uint32_t ulDummy;\r
626 \r
627     ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();\r
628     {\r
629         /* Increment the RTOS tick. */\r
630         if( xTaskIncrementTick() != pdFALSE )\r
631         {\r
632             /* Pend a context switch. */\r
633             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
634         }\r
635     }\r
636     portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );\r
637 }\r
638 /*-----------------------------------------------------------*/\r
639 \r
640 /*\r
641  * Setup the systick timer to generate the tick interrupts at the required\r
642  * frequency.\r
643  */\r
644 __weak void vSetupTimerInterrupt( void )\r
645 {\r
646     /* Reset the SysTick. */\r
647     portNVIC_SYSTICK_CTRL_REG = 0UL;\r
648     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
649 \r
650     /* Configure SysTick to interrupt at the requested rate. */\r
651     portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
652     portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;\r
653 }\r
654 /*-----------------------------------------------------------*/\r
655 \r
656 __asm void vPortSwitchToUserMode( void )\r
657 {\r
658 /* *INDENT-OFF* */\r
659     PRESERVE8\r
660 \r
661     mrs r0, control\r
662     orr r0, #1\r
663     msr control, r0\r
664     bx r14\r
665 /* *INDENT-ON* */\r
666 }\r
667 /*-----------------------------------------------------------*/\r
668 \r
669 __asm void vPortEnableVFP( void )\r
670 {\r
671 /* *INDENT-OFF* */\r
672     PRESERVE8\r
673 \r
674     ldr.w r0, =0xE000ED88 /* The FPU enable bits are in the CPACR. */\r
675     ldr r1, [ r0 ]\r
676 \r
677     orr r1, r1, #( 0xf << 20 ) /* Enable CP10 and CP11 coprocessors, then save back. */\r
678     str r1, [ r0 ]\r
679     bx r14\r
680     nop\r
681     nop\r
682 /* *INDENT-ON* */\r
683 }\r
684 /*-----------------------------------------------------------*/\r
685 \r
686 static void prvSetupMPU( void )\r
687 {\r
688     extern uint32_t __privileged_functions_start__;\r
689     extern uint32_t __privileged_functions_end__;\r
690     extern uint32_t __FLASH_segment_start__;\r
691     extern uint32_t __FLASH_segment_end__;\r
692     extern uint32_t __privileged_data_start__;\r
693     extern uint32_t __privileged_data_end__;\r
694 \r
695     /* The only permitted number of regions are 8 or 16. */\r
696     configASSERT( ( portTOTAL_NUM_REGIONS == 8 ) || ( portTOTAL_NUM_REGIONS == 16 ) );\r
697 \r
698     /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */\r
699     configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );\r
700 \r
701     /* Check the expected MPU is present. */\r
702     if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )\r
703     {\r
704         /* First setup the unprivileged flash for unprivileged read only access. */\r
705         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */\r
706                                           ( portMPU_REGION_VALID ) |\r
707                                           ( portUNPRIVILEGED_FLASH_REGION );\r
708 \r
709         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |\r
710                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
711                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |\r
712                                        ( portMPU_REGION_ENABLE );\r
713 \r
714         /* Setup the privileged flash for privileged only access.  This is where\r
715          * the kernel code is placed. */\r
716         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */\r
717                                           ( portMPU_REGION_VALID ) |\r
718                                           ( portPRIVILEGED_FLASH_REGION );\r
719 \r
720         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |\r
721                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
722                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |\r
723                                        ( portMPU_REGION_ENABLE );\r
724 \r
725         /* Setup the privileged data RAM region.  This is where the kernel data\r
726          * is placed. */\r
727         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */\r
728                                           ( portMPU_REGION_VALID ) |\r
729                                           ( portPRIVILEGED_RAM_REGION );\r
730 \r
731         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |\r
732                                        ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
733                                        prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |\r
734                                        ( portMPU_REGION_ENABLE );\r
735 \r
736         /* By default allow everything to access the general peripherals.  The\r
737          * system peripherals and registers are protected. */\r
738         portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |\r
739                                           ( portMPU_REGION_VALID ) |\r
740                                           ( portGENERAL_PERIPHERALS_REGION );\r
741 \r
742         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |\r
743                                        ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |\r
744                                        ( portMPU_REGION_ENABLE );\r
745 \r
746         /* Enable the memory fault exception. */\r
747         portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;\r
748 \r
749         /* Enable the MPU with the background region configured. */\r
750         portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );\r
751     }\r
752 }\r
753 /*-----------------------------------------------------------*/\r
754 \r
755 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )\r
756 {\r
757     uint32_t ulRegionSize, ulReturnValue = 4;\r
758 \r
759     /* 32 is the smallest region size, 31 is the largest valid value for\r
760      * ulReturnValue. */\r
761     for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )\r
762     {\r
763         if( ulActualSizeInBytes <= ulRegionSize )\r
764         {\r
765             break;\r
766         }\r
767         else\r
768         {\r
769             ulReturnValue++;\r
770         }\r
771     }\r
772 \r
773     /* Shift the code by one before returning so it can be written directly\r
774      * into the the correct bit position of the attribute register. */\r
775     return( ulReturnValue << 1UL );\r
776 }\r
777 /*-----------------------------------------------------------*/\r
778 \r
779 __asm BaseType_t xIsPrivileged( void )\r
780 {\r
781 /* *INDENT-OFF* */\r
782     PRESERVE8\r
783 \r
784     mrs r0, control /* r0 = CONTROL. */\r
785     tst r0, #1     /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */\r
786     ite ne\r
787     movne r0, #0   /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */\r
788     moveq r0, #1   /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */\r
789     bx lr           /* Return. */\r
790 /* *INDENT-ON* */\r
791 }\r
792 /*-----------------------------------------------------------*/\r
793 \r
794 __asm void vResetPrivilege( void )\r
795 {\r
796 /* *INDENT-OFF* */\r
797     PRESERVE8\r
798 \r
799     mrs r0, control /* r0 = CONTROL. */\r
800     orrs r0, #1    /* r0 = r0 | 1. */\r
801     msr control, r0 /* CONTROL = r0. */\r
802     bx lr           /* Return. */\r
803 /* *INDENT-ON* */\r
804 }\r
805 /*-----------------------------------------------------------*/\r
806 \r
807 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,\r
808                                 const struct xMEMORY_REGION * const xRegions,\r
809                                 StackType_t * pxBottomOfStack,\r
810                                 uint32_t ulStackDepth )\r
811 {\r
812     extern uint32_t __SRAM_segment_start__;\r
813     extern uint32_t __SRAM_segment_end__;\r
814     extern uint32_t __privileged_data_start__;\r
815     extern uint32_t __privileged_data_end__;\r
816 \r
817 \r
818     int32_t lIndex;\r
819     uint32_t ul;\r
820 \r
821     if( xRegions == NULL )\r
822     {\r
823         /* No MPU regions are specified so allow access to all RAM. */\r
824         xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =\r
825             ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */\r
826             ( portMPU_REGION_VALID ) |\r
827             ( portSTACK_REGION );\r
828 \r
829         xMPUSettings->xRegion[ 0 ].ulRegionAttribute =\r
830             ( portMPU_REGION_READ_WRITE ) |\r
831             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
832             ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |\r
833             ( portMPU_REGION_ENABLE );\r
834 \r
835         /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have\r
836          * just removed the privileged only parameters. */\r
837         xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =\r
838             ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */\r
839             ( portMPU_REGION_VALID ) |\r
840             ( portSTACK_REGION + 1 );\r
841 \r
842         xMPUSettings->xRegion[ 1 ].ulRegionAttribute =\r
843             ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |\r
844             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
845             prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |\r
846             ( portMPU_REGION_ENABLE );\r
847 \r
848         /* Invalidate all other regions. */\r
849         for( ul = 2; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )\r
850         {\r
851             xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;\r
852             xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;\r
853         }\r
854     }\r
855     else\r
856     {\r
857         /* This function is called automatically when the task is created - in\r
858          * which case the stack region parameters will be valid.  At all other\r
859          * times the stack parameters will not be valid and it is assumed that the\r
860          * stack region has already been configured. */\r
861         if( ulStackDepth > 0 )\r
862         {\r
863             /* Define the region that allows access to the stack. */\r
864             xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =\r
865                 ( ( uint32_t ) pxBottomOfStack ) |\r
866                 ( portMPU_REGION_VALID ) |\r
867                 ( portSTACK_REGION ); /* Region number. */\r
868 \r
869             xMPUSettings->xRegion[ 0 ].ulRegionAttribute =\r
870                 ( portMPU_REGION_READ_WRITE ) | /* Read and write. */\r
871                 ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |\r
872                 ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
873                 ( portMPU_REGION_ENABLE );\r
874         }\r
875 \r
876         lIndex = 0;\r
877 \r
878         for( ul = 1; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )\r
879         {\r
880             if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )\r
881             {\r
882                 /* Translate the generic region definition contained in\r
883                  * xRegions into the CM4 specific MPU settings that are then\r
884                  * stored in xMPUSettings. */\r
885                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =\r
886                     ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |\r
887                     ( portMPU_REGION_VALID ) |\r
888                     ( portSTACK_REGION + ul ); /* Region number. */\r
889 \r
890                 xMPUSettings->xRegion[ ul ].ulRegionAttribute =\r
891                     ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |\r
892                     ( xRegions[ lIndex ].ulParameters ) |\r
893                     ( portMPU_REGION_ENABLE );\r
894             }\r
895             else\r
896             {\r
897                 /* Invalidate the region. */\r
898                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;\r
899                 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;\r
900             }\r
901 \r
902             lIndex++;\r
903         }\r
904     }\r
905 }\r
906 /*-----------------------------------------------------------*/\r
907 \r
908 __asm uint32_t prvPortGetIPSR( void )\r
909 {\r
910 /* *INDENT-OFF* */\r
911     PRESERVE8\r
912 \r
913     mrs r0, ipsr\r
914     bx r14\r
915 /* *INDENT-ON* */\r
916 }\r
917 /*-----------------------------------------------------------*/\r
918 \r
919 #if ( configASSERT_DEFINED == 1 )\r
920 \r
921     void vPortValidateInterruptPriority( void )\r
922     {\r
923         uint32_t ulCurrentInterrupt;\r
924         uint8_t ucCurrentPriority;\r
925 \r
926         /* Obtain the number of the currently executing interrupt. */\r
927         ulCurrentInterrupt = prvPortGetIPSR();\r
928 \r
929         /* Is the interrupt number a user defined interrupt? */\r
930         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )\r
931         {\r
932             /* Look up the interrupt's priority. */\r
933             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];\r
934 \r
935             /* The following assertion will fail if a service routine (ISR) for\r
936              * an interrupt that has been assigned a priority above\r
937              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
938              * function.  ISR safe FreeRTOS API functions must *only* be called\r
939              * from interrupts that have been assigned a priority at or below\r
940              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
941              *\r
942              * Numerically low interrupt priority numbers represent logically high\r
943              * interrupt priorities, therefore the priority of the interrupt must\r
944              * be set to a value equal to or numerically *higher* than\r
945              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
946              *\r
947              * Interrupts that use the FreeRTOS API must not be left at their\r
948              * default priority of zero as that is the highest possible priority,\r
949              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,\r
950              * and therefore also guaranteed to be invalid.\r
951              *\r
952              * FreeRTOS maintains separate thread and ISR API functions to ensure\r
953              * interrupt entry is as fast and simple as possible.\r
954              *\r
955              * The following links provide detailed information:\r
956              * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html\r
957              * https://www.FreeRTOS.org/FAQHelp.html */\r
958             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );\r
959         }\r
960 \r
961         /* Priority grouping:  The interrupt controller (NVIC) allows the bits\r
962          * that define each interrupt's priority to be split between bits that\r
963          * define the interrupt's pre-emption priority bits and bits that define\r
964          * the interrupt's sub-priority.  For simplicity all bits must be defined\r
965          * to be pre-emption priority bits.  The following assertion will fail if\r
966          * this is not the case (if some bits represent a sub-priority).\r
967          *\r
968          * If the application only uses CMSIS libraries for interrupt\r
969          * configuration then the correct setting can be achieved on all Cortex-M\r
970          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the\r
971          * scheduler.  Note however that some vendor specific peripheral libraries\r
972          * assume a non-zero priority group setting, in which cases using a value\r
973          * of zero will result in unpredictable behaviour. */\r
974         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );\r
975     }\r
976 \r
977 #endif /* configASSERT_DEFINED */\r