No description
- C 65%
- CMake 35%
| CMakeLists.txt | ||
| launch_in_renode.resc | ||
| main.c | ||
| pico_sdk_import.cmake | ||
| README.md | ||
RP2040 MPU demo (Raspberry Pi Pico, Cortex-M0+)
Build & flash
export PICO_SDK_PATH=/path/to/pico-sdk
mkdir build && cd build
cmake -DPICO_BOARD=pico ..
make
# copy mpu_demo.uf2 to the RPI-RP2 drive (BOOTSEL), open the console (USB CDC or UART0 115200)
What the M0+ MPU offers (ARMv6-M PMSA)
| Item | RP2040 |
|---|---|
| Regions | 8 (MPU_TYPE.DREGION) |
| Region size | power of 2, 256 B … 4 GB, base aligned on size |
| Sub-regions | 8 per region (if size ≥ 256 B), disabled with SRD |
| Attributes | AP (priv/unpriv RW/RO/none), XN, C/B/S |
| Overlap | the highest region number wins |
| Fault | HardFault only (no MemManage, no MMFAR/CFSR) |
PRIVDEFENA |
privileged code uses the default map outside the regions |
Registers: MPU_TYPE 0xE000ED90, CTRL ED94, RNR ED98, RBAR ED9C, RASR EDA0.
Experiments and expected output
| # | Shows | Result |
|---|---|---|
| 0 | MPU off | everything is allowed, ram_fn() returns 42 |
| 1 | AP=RO on a RAM table |
read ok, write → FAULT, value unchanged |
| 2 | XN bit |
RAM code runs with XN=0 and faults with XN=1; data writes are still fine |
| 3 | SRD=0xFE |
guarded[0..127] → FAULT, guarded[128..] ok |
| 4 | CONTROL.nPRIV + PSP |
the task computes in its sandbox; 2 faults when it touches kernel_data |
The HardFault handler records the fault and then resumes execution. On the M0+, every LDR/STR is 16-bit, so it skips the faulting instruction with PC += 2. If the fault was an instruction fetch from an XN region, it returns to the caller through the stacked LR instead. A real system would not resume like this. It would kill the task or reset.
Exercises for students
- Set
MPU_CTRL_HFNMIENAand explain what happens on a fault, and why. - Remove
PRIVDEFENA: which regions must you add so thatmain()keeps working (SRAM, peripherals, ROM, PPB…)? - Build a stack guard: place a 256 B no-access region at the bottom of the main stack (see
__StackLimitin the linker script), then trigger it with deep recursion. Compare withPICO_USE_STACK_GUARDS=1in the SDK. - Use
AP_PRIV_RW_USER_ROto let the unprivileged task readkernel_databut not write it. - Add a
printftosandboxed_task(): why does it fault, and how could an SVC-based "syscall" solve this? - Write a minimal two-task round-robin scheduler (SysTick + PendSV) that reprograms region 4 on every context switch.