0
0
Cnc-programmingHow-ToBeginner · 4 min read

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->CTRL register.
  • 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->RASR disables 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

RegisterPurposeKey Bits
MPU->CTRLEnable/disable MPUBit 0: Enable, Bit 2: Privileged default memory map enable
MPU->RNRSelect MPU region numberRegion number (0-7)
MPU->RBARSet base address of regionBits [31:5]: Base address
MPU->RASRConfigure region attributesBits [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.