2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /*-----------------------------------------------------------
\r
30 * Implementation of functions defined in portable.h for the ARM CM3 port.
\r
31 *----------------------------------------------------------*/
\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
38 /* Scheduler includes. */
\r
39 #include "FreeRTOS.h"
\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
46 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\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_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
\r
53 #define portNVIC_SYSPRI1_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
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 ( 8UL << 8UL ) /* 8 regions, unified. */
\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
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
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
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
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
99 /* Offsets in the stack to the parameters when inside the SVC handler. */
\r
100 #define portOFFSET_TO_PC ( 6 )
\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
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
112 * Setup the timer to generate the tick interrupts.
\r
114 static void prvSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION;
\r
117 * Configure a number of standard MPU regions that are used by all tasks.
\r
119 static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;
\r
122 * Start first task is a separate function so it can be tested in isolation.
\r
124 static void prvStartFirstTask( void ) PRIVILEGED_FUNCTION;
\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
131 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;
\r
134 * Checks to see if being called from the context of an unprivileged task, and
\r
135 * if so raises the privilege level and returns false - otherwise does nothing
\r
136 * other than return true.
\r
138 BaseType_t xPortRaisePrivilege( void );
\r
141 * Standard FreeRTOS exception handlers.
\r
143 void xPortPendSVHandler( void ) PRIVILEGED_FUNCTION;
\r
144 void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;
\r
145 void vPortSVCHandler( void ) PRIVILEGED_FUNCTION;
\r
148 * Starts the scheduler by restoring the context of the first task to run.
\r
150 static void prvRestoreContextOfFirstTask( void ) PRIVILEGED_FUNCTION;
\r
153 * C portion of the SVC handler. The SVC handler is split between an asm entry
\r
154 * and a C wrapper for simplicity of coding and maintenance.
\r
156 void prvSVCHandler( uint32_t *pulRegisters ) __attribute__((used)) PRIVILEGED_FUNCTION;
\r
159 * Function to enable the VFP.
\r
161 static void vPortEnableVFP( void );
\r
164 * Utility function.
\r
166 static uint32_t prvPortGetIPSR( void );
\r
169 * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
\r
170 * FreeRTOS API functions are not called from interrupts that have been assigned
\r
171 * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
\r
173 #if ( configASSERT_DEFINED == 1 )
\r
174 static uint8_t ucMaxSysCallPriority = 0;
\r
175 static uint32_t ulMaxPRIGROUPValue = 0;
\r
176 static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;
\r
177 #endif /* configASSERT_DEFINED */
\r
179 /*-----------------------------------------------------------*/
\r
182 * See header file for description.
\r
184 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged )
\r
186 /* Simulate the stack frame as it would be created by a context switch
\r
188 pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
\r
189 *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
\r
191 *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
\r
193 *pxTopOfStack = 0; /* LR */
\r
194 pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
\r
195 *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
\r
197 /* A save method is being used that requires each task to maintain its
\r
198 own exec return value. */
\r
200 *pxTopOfStack = portINITIAL_EXC_RETURN;
\r
202 pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
\r
204 if( xRunPrivileged == pdTRUE )
\r
206 *pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;
\r
210 *pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;
\r
213 return pxTopOfStack;
\r
215 /*-----------------------------------------------------------*/
\r
217 void prvSVCHandler( uint32_t *pulParam )
\r
219 uint8_t ucSVCNumber;
\r
222 /* The stack contains: r0, r1, r2, r3, r12, r14, the return address and
\r
223 xPSR. The first argument (r0) is pulParam[ 0 ]. */
\r
224 ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ];
\r
225 switch( ucSVCNumber )
\r
227 case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI;
\r
228 prvRestoreContextOfFirstTask();
\r
231 case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
\r
232 /* Barriers are normally not required
\r
233 but do ensure the code is completely
\r
234 within the specified behaviour for the
\r
236 __asm volatile( "dsb" );
\r
237 __asm volatile( "isb" );
\r
241 case portSVC_RAISE_PRIVILEGE : __asm
\r
243 mrs ulReg, control /* Obtain current control value. */
\r
244 bic ulReg, #1 /* Set privilege bit. */
\r
245 msr control, ulReg /* Write back new control value. */
\r
249 default : /* Unknown SVC call. */
\r
253 /*-----------------------------------------------------------*/
\r
255 __asm void vPortSVCHandler( void )
\r
257 extern prvSVCHandler
\r
261 /* Assumes psp was in use. */
\r
262 #ifndef USE_PROCESS_STACK /* Code should not be required if a main() is using the process stack. */
\r
272 /*-----------------------------------------------------------*/
\r
274 __asm void prvRestoreContextOfFirstTask( void )
\r
278 ldr r0, =0xE000ED08 /* Use the NVIC offset register to locate the stack. */
\r
281 msr msp, r0 /* Set the msp back to the start of the stack. */
\r
282 ldr r3, =pxCurrentTCB /* Restore the context. */
\r
284 ldr r0, [r1] /* The first item in the TCB is the task top of stack. */
\r
285 add r1, r1, #4 /* Move onto the second item in the TCB... */
\r
286 ldr r2, =0xe000ed9c /* Region Base Address register. */
\r
287 ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */
\r
288 stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */
\r
289 ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */
\r
291 msr psp, r0 /* Restore the task stack pointer. */
\r
297 /*-----------------------------------------------------------*/
\r
300 * See header file for description.
\r
302 BaseType_t xPortStartScheduler( void )
\r
304 /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See
\r
305 http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
\r
306 configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
\r
308 #if( configASSERT_DEFINED == 1 )
\r
310 volatile uint32_t ulOriginalPriority;
\r
311 volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
\r
312 volatile uint8_t ucMaxPriorityValue;
\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
319 Save the interrupt priority value that is about to be clobbered. */
\r
320 ulOriginalPriority = *pucFirstUserPriorityRegister;
\r
322 /* Determine the number of priority bits available. First write to all
\r
324 *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
\r
326 /* Read the value back to see how many bits stuck. */
\r
327 ucMaxPriorityValue = *pucFirstUserPriorityRegister;
\r
329 /* Use the same mask on the maximum system call priority. */
\r
330 ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
\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 while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
\r
337 ulMaxPRIGROUPValue--;
\r
338 ucMaxPriorityValue <<= ( uint8_t ) 0x01;
\r
341 #ifdef __NVIC_PRIO_BITS
\r
343 /* Check the CMSIS configuration that defines the number of
\r
344 priority bits matches the number of priority bits actually queried
\r
345 from the hardware. */
\r
346 configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
\r
350 #ifdef configPRIO_BITS
\r
352 /* Check the FreeRTOS configuration that defines the number of
\r
353 priority bits matches the number of priority bits actually queried
\r
354 from the hardware. */
\r
355 configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
\r
359 /* Shift the priority group value back to its position within the AIRCR
\r
361 ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
\r
362 ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
\r
364 /* Restore the clobbered interrupt priority register to its original
\r
366 *pucFirstUserPriorityRegister = ulOriginalPriority;
\r
368 #endif /* conifgASSERT_DEFINED */
\r
370 /* Make PendSV and SysTick the same priority as the kernel, and the SVC
\r
371 handler higher priority so it can be used to exit a critical section (where
\r
372 lower priorities are masked). */
\r
373 portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
\r
374 portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
\r
376 /* Configure the regions in the MPU that are common to all tasks. */
\r
379 /* Start the timer that generates the tick ISR. Interrupts are disabled
\r
381 prvSetupTimerInterrupt();
\r
383 /* Initialise the critical nesting count ready for the first task. */
\r
384 uxCriticalNesting = 0;
\r
386 /* Ensure the VFP is enabled - it should be anyway. */
\r
389 /* Lazy save always. */
\r
390 *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
\r
392 /* Start the first task. */
\r
393 prvStartFirstTask();
\r
395 /* Should not get here! */
\r
398 /*-----------------------------------------------------------*/
\r
400 __asm void prvStartFirstTask( void )
\r
404 /* Use the NVIC offset register to locate the stack. */
\r
405 ldr r0, =0xE000ED08
\r
408 /* Set the msp back to the start of the stack. */
\r
410 /* Clear the bit that indicates the FPU is in use in case the FPU was used
\r
411 before the scheduler was started - which would otherwise result in the
\r
412 unnecessary leaving of space in the SVC stack for lazy saving of FPU
\r
416 /* Globally enable interrupts. */
\r
421 svc portSVC_START_SCHEDULER /* System call to start first task. */
\r
426 void vPortEndScheduler( void )
\r
428 /* Not implemented in ports where there is nothing to return to.
\r
429 Artificially force an assert. */
\r
430 configASSERT( uxCriticalNesting == 1000UL );
\r
432 /*-----------------------------------------------------------*/
\r
434 void vPortEnterCritical( void )
\r
436 BaseType_t xRunningPrivileged = xPortRaisePrivilege();
\r
438 portDISABLE_INTERRUPTS();
\r
439 uxCriticalNesting++;
\r
441 vPortResetPrivilege( xRunningPrivileged );
\r
443 /*-----------------------------------------------------------*/
\r
445 void vPortExitCritical( void )
\r
447 BaseType_t xRunningPrivileged = xPortRaisePrivilege();
\r
449 configASSERT( uxCriticalNesting );
\r
450 uxCriticalNesting--;
\r
451 if( uxCriticalNesting == 0 )
\r
453 portENABLE_INTERRUPTS();
\r
455 vPortResetPrivilege( xRunningPrivileged );
\r
457 /*-----------------------------------------------------------*/
\r
459 __asm void xPortPendSVHandler( void )
\r
461 extern uxCriticalNesting;
\r
462 extern pxCurrentTCB;
\r
463 extern vTaskSwitchContext;
\r
469 ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
\r
472 tst r14, #0x10 /* Is the task using the FPU context? If so, push high vfp registers. */
\r
474 vstmdbeq r0!, {s16-s31}
\r
477 stmdb r0!, {r1, r4-r11, r14} /* Save the remaining registers. */
\r
478 str r0, [r2] /* Save the new top of stack into the first member of the TCB. */
\r
480 stmdb sp!, {r0, r3}
\r
481 mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
485 bl vTaskSwitchContext
\r
488 ldmia sp!, {r0, r3}
\r
489 /* Restore the context. */
\r
491 ldr r0, [r1] /* The first item in the TCB is the task top of stack. */
\r
492 add r1, r1, #4 /* Move onto the second item in the TCB... */
\r
493 ldr r2, =0xe000ed9c /* Region Base Address register. */
\r
494 ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */
\r
495 stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */
\r
496 ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */
\r
499 tst r14, #0x10 /* Is the task using the FPU context? If so, pop the high vfp registers too. */
\r
501 vldmiaeq r0!, {s16-s31}
\r
507 /*-----------------------------------------------------------*/
\r
509 void xPortSysTickHandler( void )
\r
513 ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
\r
515 /* Increment the RTOS tick. */
\r
516 if( xTaskIncrementTick() != pdFALSE )
\r
518 /* Pend a context switch. */
\r
519 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
\r
522 portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
\r
524 /*-----------------------------------------------------------*/
\r
527 * Setup the systick timer to generate the tick interrupts at the required
\r
530 static void prvSetupTimerInterrupt( void )
\r
532 /* Reset the SysTick. */
\r
533 portNVIC_SYSTICK_CTRL_REG = 0UL;
\r
534 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
\r
536 /* Configure SysTick to interrupt at the requested rate. */
\r
537 portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
\r
538 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
\r
540 /*-----------------------------------------------------------*/
\r
542 __asm void vPortSwitchToUserMode( void )
\r
551 /*-----------------------------------------------------------*/
\r
553 __asm void vPortEnableVFP( void )
\r
557 ldr.w r0, =0xE000ED88 /* The FPU enable bits are in the CPACR. */
\r
560 orr r1, r1, #( 0xf << 20 ) /* Enable CP10 and CP11 coprocessors, then save back. */
\r
566 /*-----------------------------------------------------------*/
\r
568 static void prvSetupMPU( void )
\r
570 extern uint32_t __privileged_functions_end__;
\r
571 extern uint32_t __FLASH_segment_start__;
\r
572 extern uint32_t __FLASH_segment_end__;
\r
573 extern uint32_t __privileged_data_start__;
\r
574 extern uint32_t __privileged_data_end__;
\r
576 /* Check the expected MPU is present. */
\r
577 if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
\r
579 /* First setup the entire flash for unprivileged read only access. */
\r
580 portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
\r
581 ( portMPU_REGION_VALID ) |
\r
582 ( portUNPRIVILEGED_FLASH_REGION );
\r
584 portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |
\r
585 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
586 ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
\r
587 ( portMPU_REGION_ENABLE );
\r
589 /* Setup the first 16K for privileged only access (even though less
\r
590 than 10K is actually being used). This is where the kernel code is
\r
592 portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
\r
593 ( portMPU_REGION_VALID ) |
\r
594 ( portPRIVILEGED_FLASH_REGION );
\r
596 portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
\r
597 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
598 ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
\r
599 ( portMPU_REGION_ENABLE );
\r
601 /* Setup the privileged data RAM region. This is where the kernel data
\r
603 portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
\r
604 ( portMPU_REGION_VALID ) |
\r
605 ( portPRIVILEGED_RAM_REGION );
\r
607 portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
\r
608 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
609 prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
\r
610 ( portMPU_REGION_ENABLE );
\r
612 /* By default allow everything to access the general peripherals. The
\r
613 system peripherals and registers are protected. */
\r
614 portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
\r
615 ( portMPU_REGION_VALID ) |
\r
616 ( portGENERAL_PERIPHERALS_REGION );
\r
618 portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |
\r
619 ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |
\r
620 ( portMPU_REGION_ENABLE );
\r
622 /* Enable the memory fault exception. */
\r
623 portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;
\r
625 /* Enable the MPU with the background region configured. */
\r
626 portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );
\r
629 /*-----------------------------------------------------------*/
\r
631 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
\r
633 uint32_t ulRegionSize, ulReturnValue = 4;
\r
635 /* 32 is the smallest region size, 31 is the largest valid value for
\r
637 for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
\r
639 if( ulActualSizeInBytes <= ulRegionSize )
\r
649 /* Shift the code by one before returning so it can be written directly
\r
650 into the the correct bit position of the attribute register. */
\r
651 return ( ulReturnValue << 1UL );
\r
653 /*-----------------------------------------------------------*/
\r
655 __asm BaseType_t xPortRaisePrivilege( void )
\r
658 tst r0, #1 /* Is the task running privileged? */
\r
660 movne r0, #0 /* CONTROL[0]!=0, return false. */
\r
661 svcne portSVC_RAISE_PRIVILEGE /* Switch to privileged. */
\r
662 moveq r0, #1 /* CONTROL[0]==0, return true. */
\r
665 /*-----------------------------------------------------------*/
\r
667 void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth )
\r
669 extern uint32_t __SRAM_segment_start__;
\r
670 extern uint32_t __SRAM_segment_end__;
\r
671 extern uint32_t __privileged_data_start__;
\r
672 extern uint32_t __privileged_data_end__;
\r
678 if( xRegions == NULL )
\r
680 /* No MPU regions are specified so allow access to all RAM. */
\r
681 xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
\r
682 ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
\r
683 ( portMPU_REGION_VALID ) |
\r
684 ( portSTACK_REGION );
\r
686 xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
\r
687 ( portMPU_REGION_READ_WRITE ) |
\r
688 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
689 ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
\r
690 ( portMPU_REGION_ENABLE );
\r
692 /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
\r
693 just removed the privileged only parameters. */
\r
694 xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
\r
695 ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
\r
696 ( portMPU_REGION_VALID ) |
\r
697 ( portSTACK_REGION + 1 );
\r
699 xMPUSettings->xRegion[ 1 ].ulRegionAttribute =
\r
700 ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
\r
701 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
702 prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
\r
703 ( portMPU_REGION_ENABLE );
\r
705 /* Invalidate all other regions. */
\r
706 for( ul = 2; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
\r
708 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
\r
709 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
\r
714 /* This function is called automatically when the task is created - in
\r
715 which case the stack region parameters will be valid. At all other
\r
716 times the stack parameters will not be valid and it is assumed that the
\r
717 stack region has already been configured. */
\r
718 if( ulStackDepth > 0 )
\r
720 /* Define the region that allows access to the stack. */
\r
721 xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
\r
722 ( ( uint32_t ) pxBottomOfStack ) |
\r
723 ( portMPU_REGION_VALID ) |
\r
724 ( portSTACK_REGION ); /* Region number. */
\r
726 xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
\r
727 ( portMPU_REGION_READ_WRITE ) | /* Read and write. */
\r
728 ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |
\r
729 ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
\r
730 ( portMPU_REGION_ENABLE );
\r
735 for( ul = 1; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
\r
737 if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
\r
739 /* Translate the generic region definition contained in
\r
740 xRegions into the CM3 specific MPU settings that are then
\r
741 stored in xMPUSettings. */
\r
742 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
\r
743 ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
\r
744 ( portMPU_REGION_VALID ) |
\r
745 ( portSTACK_REGION + ul ); /* Region number. */
\r
747 xMPUSettings->xRegion[ ul ].ulRegionAttribute =
\r
748 ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
\r
749 ( xRegions[ lIndex ].ulParameters ) |
\r
750 ( portMPU_REGION_ENABLE );
\r
754 /* Invalidate the region. */
\r
755 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
\r
756 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
\r
763 /*-----------------------------------------------------------*/
\r
765 __asm uint32_t prvPortGetIPSR( void )
\r
772 /*-----------------------------------------------------------*/
\r
774 #if( configASSERT_DEFINED == 1 )
\r
776 void vPortValidateInterruptPriority( void )
\r
778 uint32_t ulCurrentInterrupt;
\r
779 uint8_t ucCurrentPriority;
\r
781 /* Obtain the number of the currently executing interrupt. */
\r
782 ulCurrentInterrupt = prvPortGetIPSR();
\r
784 /* Is the interrupt number a user defined interrupt? */
\r
785 if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
\r
787 /* Look up the interrupt's priority. */
\r
788 ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
\r
790 /* The following assertion will fail if a service routine (ISR) for
\r
791 an interrupt that has been assigned a priority above
\r
792 configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
\r
793 function. ISR safe FreeRTOS API functions must *only* be called
\r
794 from interrupts that have been assigned a priority at or below
\r
795 configMAX_SYSCALL_INTERRUPT_PRIORITY.
\r
797 Numerically low interrupt priority numbers represent logically high
\r
798 interrupt priorities, therefore the priority of the interrupt must
\r
799 be set to a value equal to or numerically *higher* than
\r
800 configMAX_SYSCALL_INTERRUPT_PRIORITY.
\r
802 Interrupts that use the FreeRTOS API must not be left at their
\r
803 default priority of zero as that is the highest possible priority,
\r
804 which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
\r
805 and therefore also guaranteed to be invalid.
\r
807 FreeRTOS maintains separate thread and ISR API functions to ensure
\r
808 interrupt entry is as fast and simple as possible.
\r
810 The following links provide detailed information:
\r
811 http://www.freertos.org/RTOS-Cortex-M3-M4.html
\r
812 http://www.freertos.org/FAQHelp.html */
\r
813 configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
\r
816 /* Priority grouping: The interrupt controller (NVIC) allows the bits
\r
817 that define each interrupt's priority to be split between bits that
\r
818 define the interrupt's pre-emption priority bits and bits that define
\r
819 the interrupt's sub-priority. For simplicity all bits must be defined
\r
820 to be pre-emption priority bits. The following assertion will fail if
\r
821 this is not the case (if some bits represent a sub-priority).
\r
823 If the application only uses CMSIS libraries for interrupt
\r
824 configuration then the correct setting can be achieved on all Cortex-M
\r
825 devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
\r
826 scheduler. Note however that some vendor specific peripheral libraries
\r
827 assume a non-zero priority group setting, in which cases using a value
\r
828 of zero will result in unpredicable behaviour. */
\r
829 configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
\r
832 #endif /* configASSERT_DEFINED */
\r