How to Configure MPU on Cortex-M: Step-by-Step Guide
To configure the
MPU on a Cortex-M processor, you enable the MPU, define memory regions with base addresses, sizes, and access permissions, then enable the MPU with the desired settings. This involves writing to MPU registers like MPU->RNR, MPU->RBAR, and MPU->RASR to set each region's attributes.Syntax
Configuring the MPU involves these main steps:
- Enable MPU by setting the
MPU->CTRLregister. - Select region number with
MPU->RNR. - Set region base address in
MPU->RBAR. - Configure region attributes like size, access permissions, and enable bit in
MPU->RASR.
Each region must be configured separately, then the MPU enabled globally.
c
/* Example syntax to configure one MPU region */ MPU->CTRL = 0; // Disable MPU before configuration MPU->RNR = region_number; // Select region number MPU->RBAR = base_address; // Set base address MPU->RASR = (size << MPU_RASR_SIZE_Pos) | (access_permission << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk; // Set size, permissions, enable MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; // Enable MPU with default memory map for privileged access
Example
This example configures one MPU region at address 0x20000000 with size 32KB, full access, and enables the MPU.
c
#include "stm32f4xx.h" // or appropriate device header void MPU_Config(void) { // Disable MPU MPU->CTRL = 0; // Configure region 0 MPU->RNR = 0; // Select region 0 MPU->RBAR = 0x20000000; // Base address // Region size 32KB (size field = 14), full access (AP=3), enable region MPU->RASR = (14 << MPU_RASR_SIZE_Pos) | (3 << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk; // Enable MPU and default memory map for privileged access MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; // Memory barrier to ensure MPU settings take effect __DSB(); __ISB(); } int main(void) { MPU_Config(); while(1) {} }
Output
No visible output; MPU is configured to protect memory region 0x20000000-0x20007FFF with full access.
Common Pitfalls
- Forgetting to disable the MPU before configuration can cause unpredictable behavior.
- Incorrect region size encoding: size field is encoded as (region size in power of two) - 1, e.g., 32KB = 14.
- Not setting the enable bit in
MPU->RASRdisables the region. - Not using memory barriers (
__DSB()and__ISB()) after configuration can cause stale instruction or data fetches. - Overlapping regions without proper priority can cause access conflicts.
c
/* Wrong: Not disabling MPU before config */ MPU->RNR = 0; MPU->RBAR = 0x20000000; MPU->RASR = (14 << MPU_RASR_SIZE_Pos) | (3 << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk; MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; /* Right: Disable MPU first */ MPU->CTRL = 0; MPU->RNR = 0; MPU->RBAR = 0x20000000; MPU->RASR = (14 << MPU_RASR_SIZE_Pos) | (3 << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk; MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; __DSB(); __ISB();
Quick Reference
| Register | Purpose | Key Bits |
|---|---|---|
| MPU->CTRL | Enable/disable MPU | Bit 0: Enable, Bit 2: Privileged default memory map enable |
| MPU->RNR | Select MPU region number | Region number (0-7) |
| MPU->RBAR | Set base address of region | Bits [31:5]: Base address |
| MPU->RASR | Configure region attributes | Bits [5:1]: Size, Bits [28:24]: Access permission, Bit 0: Enable region |
Key Takeaways
Always disable the MPU before configuring regions to avoid conflicts.
Set each region's base address, size (encoded as power of two minus one), and access permissions carefully.
Enable the MPU globally after all regions are configured, and use memory barriers to apply settings.
Use the MPU->RNR register to select the region number before configuring it.
Check for overlapping regions and set priorities to prevent access errors.