The Cortex-M3 is an ARM processor core designed for microcontroller applications. It has a Von Neumann architecture with separate code and data memory regions. The memory regions are divided into different types with specific attributes defined in the Memory Protection Unit (MPU). Understanding the Cortex-M3 memory regions and their attributes is important for effective software development.
Code Memory Region
The code memory region contains the executable program code for the Cortex-M3 processor. It is read-only memory that cannot be written to at runtime. The MPU allows configuring the code region attributes:
- Executable – Code memory is executable
- Non-executable – Code memory is non-executable
- Read-only – Code memory is read-only
- Read/write – Code memory is readable and writable
Typically, the code memory region is configured as executable and read-only. Making the code region read/write allows self-modifying code capabilities. Setting the region as non-executable protects against malicious code execution.
Code Region Size
The Cortex-M3 supports up to 1MB of code memory. The exact size depends on the target microcontroller device. Code memory is implemented as internal flash, external flash, or ROM.
Executing Code from RAM
Although uncommon, it is possible to execute code from RAM instead of flash memory on the Cortex-M3. This requires configuring a RAM region as executable and copying code from flash to RAM at runtime. Executing code from RAM has the advantage of higher performance compared to flash.
SRAM Memory Region
The SRAM memory region contains volatile data used during program execution. It is readable and writable at runtime. The MPU allows configuring the SRAM region attributes:
- Executable – SRAM is executable
- Non-executable – SRAM is non-executable
- Read-only – SRAM is read-only
- Read/write – SRAM is readable and writable (default)
Typically, SRAM is configured as non-executable and read/write data memory. Setting the region as read-only prevents accidental writes and provides some data integrity protection.
SRAM Region Size
The Cortex-M3 supports up to 64KB of SRAM data memory. The actual size available is device-specific. SRAM provides fast access for frequently used data during program execution.
Executing Code from SRAM
SRAM can be configured as executable memory to allow executing code loaded into SRAM at runtime. This provides better performance compared to executing code directly from flash. However, SRAM is more limited in size than flash memory.
Peripheral Memory Region
The peripheral memory region provides access to on-chip peripherals such as timers, GPIO, communication interfaces, etc. The region is read/write by default. The MPU allows configuring the peripheral region attributes:
- Executable – Peripherals are executable (not applicable)
- Non-executable – Peripherals are non-executable (default)
- Read-only – Peripherals are read-only
- Read/write – Peripherals are readable and writable (default)
Typically, the peripheral region is configured as non-executable and read/write. Setting the region as read-only prevents accidental writes to peripherals registers.
Peripheral Region Size
The peripheral region size depends on the specific microcontroller device and number of on-chip peripherals. The region is mapped to provide access to all peripherals. Accesses are handled via memory-mapped I/O.
External Memory Region
The external memory region provides access to off-chip memories through the external bus interface. This includes external flash, SRAM, and other memories. The MPU allows configuring the external memory region attributes:
- Executable – External memory is executable
- Non-executable – External memory is non-executable
- Read-only – External memory is read-only
- Read/write – External memory is readable and writable
The configuration depends on the type of external memory. For example, external flash could be configured as executable and read-only. External SRAM could be configured as read/write data memory.
External Memory Region Size
The Cortex-M3 supports up to 64MB of external memory. The actual size depends on the microcontroller’s external bus interface and memory devices connected. External memory provides flexibility to extend code and data storage beyond internal memory capacity.
System Memory Region
The system memory region provides access to system control registers including NVIC, SysTick, MPU registers, etc. This region is read/write by default but can be configured as read-only by the MPU for write protection.
Since the system memory region covers critical system control registers, it should always be handled with care in software. Accidental writes can put the processor into unwanted states.
System Memory Region Size
The system memory region is a small fixed size, typically a few KB, to provide access to all system control registers. The exact size depends on the Cortex-M3 implementation in the specific microcontroller device.
Memory Access Permissions
The MPU allows configuring access permissions for each defined memory region. The permissions act as memory protection when accessing each region and include:
- No access – All accesses generate fault
- Read-only – Reads permitted, writes generate fault
- Write-only – Writes permitted, reads generate fault
- Read/Write – Reads and writes permitted
Typically, code memory is read-only, SRAM data memory is read/write. Peripherals and system memory are read/write by default but can be protected with read-only access.
Unprivileged vs Privileged Access
Another aspect of the MPU access permissions is unprivileged versus privileged access modes. The Cortex-M3 Handler mode is privileged while Thread mode is unprivileged. Memory regions can be configured to allow or block access based on privilege mode.
Memory Alignment and Size
The MPU allows configuring region size and alignment down to 1KB granularity. Size ranges from 1KB to 4GB. Alignment sets the start address granularity. Together, size and alignment allow carving the 4GB memory map into defined regions.
Setting size and alignment appropriately is important to maximize utilization of memory resources. Overly coarse alignment or size configuration can lead to unused gaps in the memory map.
Overlapping Memory Regions
It is possible to define overlapping memory regions with the MPU. In that case, the region with the highest numbered MPU register takes priority and overrides attributes of other overlapping regions. This provides a memory map override mechanism.
However, overlapping regions can also lead to unexpected behavior if not configured properly. It is best to keep regions non-overlapping whenever possible for simplicity.
Memory regions can be configured as cacheable or non-cacheable. Cacheability indicates whether memory accesses should be cached in the processor’s memory cache. Caching provides higher performance for memory reads.
However, cache coherency must also be handled appropriately especially for memory that can be accessed by multiple bus masters. Non-cacheable attribute disables caching for a memory region.
Memory Region Programming
The MPU memory regions are defined in software at runtime during system initialization. This allows full flexibility in configuring the memory map.
To program a memory region, the following steps are performed:
- Disable MPU (if enabled)
- Configure desired attributes in MPU register for region
- Set valid bit in MPU register to activate region
- Re-enable MPU
All active memory regions should be defined before enabling the MPU. The number of available MPU registers dictates how many regions can be active concurrently.
Default Memory Map
At reset, the MPU is disabled and the default memory map is active. This provides access to all memory regions with default attributes:
- Code region: Executable, Read-only
- SRAM region: Non-executable, Read/Write
- Peripheral region: Non-executable, Read/Write
- External memory: Varies based on memory devices
- System region: Read/Write
The default memory map provides full access functionality to all memory regions simultaneously. The MPU overrides this with user-defined regions.
MPU Region Priority
As mentioned earlier, higher numbered MPU registers have priority over lower numbered regions if there is overlap. This rule allows overriding attributes in a certain region of the memory map by defining a higher priority MPU region.
To avoid ambiguity, key memory regions like code and SRAM data should be defined in the higher priority MPU registers. Peripherals and external memory can use the lower registers.
MPU Programming Examples
Here are some examples of programming the MPU to define memory regions:
MPU->REG = 0x00000008; // 1MB code region size MPU->REG = 0x00000000; // Code region base address MPU->REG = 0x030C1437; // Executable, Read-only, Non-cacheable MPU->REG = 0x01000000; // Code region enable
SRAM Data Region
MPU->REG = 0x00000040; // 64KB SRAM size MPU->REG = 0x20000000; // SRAM base MPU->REG = 0x030C1417; // Non-executable, Read/Write, Non-cacheable MPU->REG = 0x01000000; // SRAM region enable
MPU->REG = 0x0007A120; // Peripheral region size (device specific) MPU->REG = 0x40000000; // Peripheral base address MPU->REG = 0x030C1417 // Non-executable, Read/Write, Non-cacheable MPU->REG = 0x01000000; // Peripheral region enable
The above examples show how code, SRAM, and peripheral regions can be configured with different attributes using the MPU registers. Once enabled, the MPU will enforce these attributes on memory accesses.
Debugging MPU Memory Faults
When the MPU is enabled, any memory access that violates the configured attributes or permissions will generate a memory fault exception. This results in the following:
- Exception entry into MemManage handler
- HALTED debug state
- Memory Management Fault Status Register (MMFSR) updated with violation details
Debugging MPU faults requires checking the MMFSR register to identify the violating region and memory access address. This information helps correct the MPU configuration or software memory access to eliminate the violation.
While the MPU provides memory protection, it has some limitations:
- Finite number of regions – Up to 16 on Cortex-M3
- 1KB minimum region size granularity
- Protection disabled during exception handling
- No guarantee against malware attacks
So the MPU does not provide complete memory safety. Additional mechanisms like Stack Overflow detection may be needed. Security-critical systems may utilize an MMU instead.
Using the MPU Effectively
Here are some tips for using the Cortex-M3 MPU effectively:
- Define all key memory regions – Code, SRAM, Peripherals
- Add read-only protection to immutable regions
- Keep regions non-overlapping if possible
- Set alignment and size appropriately to avoid gaps
- Use higher priority MPU registers for critical regions
- Enable MPU early during system startup
- Validate all memory access during development
Proper configuration and usage of the MPU can improve software reliability and provide protection against accidental memory corruption.
The Cortex-M3 MPU provides configurable memory regions with definable attributes including access permissions. This allows creating a customized memory map tailored to the application requirements. Appropriately configuring MPU regions helps improve system reliability and protect memory integrity during runtime. However, care must be taken to fully validate memory access to avoid MPU faults. Overall, the Cortex-M3 MPU is an invaluable tool for creating robust and secure embedded software.