SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: How to Find Valid vs Invalid Addresses for Your Cortex-M3 Microcontroller?
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

How to Find Valid vs Invalid Addresses for Your Cortex-M3 Microcontroller?

Eileen David
Last updated: October 5, 2023 9:55 am
Eileen David 10 Min Read
Share
SHARE

When working with a Cortex-M3 microcontroller, it is crucial to understand how to differentiate between valid and invalid addresses. This will allow you to properly utilize the address space and avoid accessing restricted or non-existent memory locations which could lead to crashes or undefined behavior. Generally, valid addresses fall within mapped regions of memory while invalid ones do not.

Contents
Understanding the Cortex-M3 Memory MapUsing Section AttributesWatching Out For Stack and HeapUtilizing MPU and MMU for Memory ProtectionUsing Assertion Library to Check AddressesPerforming Manual Address CheckingSticking to Aligned AccessAvoiding Common Addressing PitfallsConfiguring Debugger Memory Access WarningsSummaryAdditional QuestionsHow do I know where to locate my Cortex-M3 code and data?What causes stack overflow errors on Cortex-M3?How do I determine valid peripheral addresses?What issues can unaligned memory access cause?How can I best leverage the MPU on my Cortex-M3?What compiler options help detect invalid addresses?Conclusion

Understanding the Cortex-M3 Memory Map

The Cortex-M3 has a complex memory map with different regions mapped for different purposes. At a high level, the main memory areas are:

  • Code region for program code (flash memory)
  • SRAM region for data
  • Peripheral region for registers of on-chip peripherals
  • System region for registers like the SysTick timer

Each region has specific base and size values that determine the valid address range. Trying to access an address outside these ranges results in a fault. It’s important to check your microcontroller’s reference manual for the exact memory map.

For example, on a sample Cortex-M3 the code region may be at 0x00000000-0x0007FFFF (512KB), SRAM at 0x20000000-0x2000FFFF (64KB), peripherals 0x40000000-0x5FFFFFFF (1GB) and system region 0xE0000000-0xE00FFFFF (1MB).

Using Section Attributes

One way the compiler helps differentiate valid/invalid addresses is by using section attributes. Sections attributes are used to annotate code and data so the linker can place them appropriately.

Some common section attributes on Cortex-M3 are:

  • @”.text” – for code memory region
  • @”.data” – for initialized SRAM variables
  • @”.bss” – uninitialized SRAM variables
  • @”.rodata” – const qualified read only data

By using the correct section attributes, the linker will only allocate those variables/code in valid memory regions for those types. Trying to place data in code memory or code in SRAM will raise errors during link time if section attributes are used properly.

Watching Out For Stack and Heap

The stack and heap are two memory constructs that dynamically grow and shrink during runtime. The stack holds local variables, function parameters, return addresses while the heap is used for dynamic memory allocation.

Both the stack and heap can encounter invalid memory accesses if they grow too large. For stack, local arrays or deep recursion can cause it to exceed its allocated memory and corrupt other data. For heap, allocating more memory than available space will lead to overflow.

So for both stack and heap, it’s important to:

  • Properly size their memory during initialization
  • Use stack/heap overflow protection if available
  • Carefully check for large stack variables or memory allocations

This will help prevent accidental corruption from exceeding valid memory boundaries.

Utilizing MPU and MMU for Memory Protection

The Memory Protection Unit (MPU) and Memory Management Unit (MMU) are hardware features on Cortex-M3 that can be used to enforce valid memory access. The MPU sets configurable rules for which memory regions can be accessed and which mode (privilege level) is needed. This prevents accidental writes or corruption.

The MMU maps virtual addresses to physical and provides an additional layer of access control. Properly configuring MPU/MMU regions can detect invalid accesses which generate faults. Handling these faults allows recovery versus crashes from invalid access. Some ways to leverage MPU/MMU protections:

  • Make code and read-only data unwriteable
  • Make peripheral memory privileged execution only
  • Use multiple MPU regions to protect each memory area appropriately
  • Map SRAM into virtual address space with MMU

Using Assertion Library to Check Addresses

Incorporating assertion checks for addresses being within expected ranges can help detect invalid accesses during debugging and testing. An assertion library like CMSIS-CORE’s arm_assert.h provides useful macros for address range checks:

  • ARM_ASSERT_WITHIN_RANGE – Checks single address against min/max bounds
  • ARM_ASSERT_ALIGNED – Checks for aligned address
  • ARM_ASSERT_FITS_WITHIN – Checks full address range fits within min/max

Adding assertions to validate passed pointers, array accesses, and other address computations provides runtime checking to complement static analysis. Failed assertions immediately highlight issues vs subtle memory corruption.

Performing Manual Address Checking

There are times when manually checking for valid addresses is needed, especially when interacting with memory-mapped peripherals. Some common approaches are:

  • Compare address against base/bounds of peripheral
  • Mask address then compare expected bits
  • Check aligned address for 32-bit or 16-bit accesses
  • Sanitize user input addresses before usage

Manual validation requires knowing the memory map details but gives the most flexibility. Often addresses are stored in variables so combining manual checks with assertions can provide robust address validation.

Sticking to Aligned Access

Unaligned memory access to peripherals or data arrays can result in faults or incorrect behavior on Cortex-M3. Aligning accesses to match data size is safer:

  • 32-bit variables on 4-byte boundaries
  • 16-bit variables on 2-byte boundaries
  • 8-bit variables on any byte

The compiler aligns global/static data properly but stack variables may need explicit alignment. Unaligned access is usually not an issue for SRAM but is vital when accessing registers and hardware.

Avoiding Common Addressing Pitfalls

Some other ways invalid addresses can sneak into Cortex-M3 code include:

  • Pointer arithmetic going past arrays
  • Mismatched pointer types
  • Off-by-one errors with for loop boundaries
  • Uninitialized pointers
  • Race conditions from tasks/interrupts

Carefully reviewing pointer arithmetic and loop iterators can reveal these issues. Static analysis tools like Polyspace or Astrée can also detect many invalid memory access patterns.

Configuring Debugger Memory Access Warnings

Development tools like debuggers can be configured to halt or warn on invalid memory accesses:

  • Halt on unaligned access options
  • Halt on access to reserved addresses
  • Flash error on write to flash memory
  • Break on memory access errors

Slowing execution and diagnosing invalid accesses during debug sessions complements static checking and hardware protections to reinforce address validation.

Summary

Validating addresses is a crucial aspect of Cortex-M3 development. Leveraging the compiler, hardware protections like MPU/MMU, debuggers, assertions, and manual checks provides layers of defense against invalid accesses. Rules for aligned access, careful use of stack/heap, and avoiding common pitfalls also helps eliminate many address-related bugs.

With robust address validation, Cortex-M3 software can confidently access memory without crashes, corruption, or undefined behavior. This builds more stable and secure embedded systems.

Understanding the valid memory map, using appropriate attributes, checking alignments, assertions for runtime debugging, and proper configuration of hardware protections/debug tools provides a comprehensive approach. As Cortex-M3 applications become more complex, these techniques enable proper utilization of the address space during development and in deployed systems.

Additional Questions

Here are some additional questions readers may have about finding valid vs invalid addresses on a Cortex-M3:

How do I know where to locate my Cortex-M3 code and data?

Check the microcontroller reference manual for the memory map, which shows valid regions for code and data. Usually code goes in flash memory while initialized and zero init data go in SRAM. Also utilize linker section attributes like .text, .data, and .bss to allocate properly.

What causes stack overflow errors on Cortex-M3?

Deep function call recursion, large stack arrays, and interrupt usage can grow the stack beyond its allocated memory range. Set a stack overflow threshold via the Stack Overflow Checking register if available. Also be wary of large stack variables.

How do I determine valid peripheral addresses?

The peripheral memory map defines the base address and address block size for each peripheral. Make sure to access registers only within those ranges. The SVD files describe valid registers for each peripheral.

What issues can unaligned memory access cause?

Unaligned access to variables and peripherals may be unsupported and cause faults or read incorrect data. Align variables and accesses to match the size, i.e. 32-bit variables on 4 byte boundaries. Use compiler directives if needed.

How can I best leverage the MPU on my Cortex-M3?

Configure MPU regions to separate memory areas for code, SRAM, peripherals, etc. Make flash read-only and SRAM non-executable. Use privileged mode for peripherals. Violations generate faults to detect invalid access.

What compiler options help detect invalid addresses?

Compile with pointer safety (-fno-strict-aliasing), bounds checking (-fbounds-check), and stack protection (-fstack-protector) enabled. Make sure to validate compiler placed checks don’t impact performance.

Conclusion

This covers the key techniques for differentiating between valid and invalid addresses on a Cortex-M3 microcontroller. Proper memory maps, alignment, hardware protections, assertions, and access patterns all contribute to robust address validation. Always refer to the reference manual and utilize available tools/libraries to reinforce addressing within your software.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Tips on Cortex-M3 Memory Mapping
Next Article How to check if a Cortex-M3 Address is in Flash or SRAM Memory?
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

What is bare metal embedded programming?

Bare metal embedded programming refers to developing firmware directly on…

9 Min Read

basepri register

The basepri register is one of the system control registers…

6 Min Read

ARM Program Status Registers

The ARM Program Status Registers (PSRs) are special purpose 32-bit…

15 Min Read

What is Common Microcontroller Software Interface Standard (CMSIS)?

The Common Microcontroller Software Interface Standard (CMSIS) is a vendor-independent…

7 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account