Project 22: Memory Cartographer (SRAM Layout, Linker Script, Fragmentation, Wear)
Build a memory observability and policy framework that proves SRAM/flash safety margins and brownout-safe configuration persistence.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Level 5: Master |
| Time Estimate | 2-3 weeks |
| Main Programming Language | C (toolchain + runtime diagnostics) |
| Alternative Programming Languages | C++ |
| Coolness Level | Level 4: The “Whoa, You Built That?” |
| Business Potential | 1. The “Resume Gold” |
| Prerequisites | linker basics, stack/heap fundamentals, flash write behavior |
| Key Topics | linker script control, RAM profiling, fragmentation analysis, flash wear strategy |
1. Learning Objectives
By completing this project, you will:
- Build a precise SRAM ownership map for runtime subsystems.
- Configure linker memory regions for predictable placement.
- Measure stack high-water marks and heap fragmentation trends.
- Implement versioned, CRC-protected flash config records.
- Validate behavior under simulated power-loss during writes.
2. All Theory Needed (Project-Scoped)
2.1 Memory Ownership
Real-time firmware requires explicit ownership for static data, DMA buffers, queues, stack, and optional heap.
2.2 Linker Script as Architecture
Region definitions and section placement determine latency, safety margins, and fault behavior.
2.3 Fragmentation Dynamics
Heap failures can occur despite free bytes due to non-contiguous blocks.
2.4 Wear-Safe Persistence
Flash endurance requires append-style records and compaction policy, not repeated in-place writes.
2.5 Brownout-Safe Commit
Transactional writes with CRC and active-pointer switching prevent partial-write corruption.
3. Project Specification
3.1 What You Will Build
A memory audit subsystem with:
- static map extraction
- runtime high-water telemetry
- fragmentation indicator
- transactional config store
- power-fail recovery test mode
3.2 Functional Requirements
- Export flash/RAM section sizes from build artifacts.
- Track stack and heap peak utilization under stress.
- Detect and report fragmentation trend indicators.
- Persist versioned config records with CRC checks.
- Recover cleanly from interrupted commit simulation.
3.3 Non-Functional Requirements
- Performance: telemetry overhead remains low and bounded.
- Reliability: zero config corruption in repeated fault injection.
- Repeatability: same stress profile yields similar memory margins.
3.4 Real World Outcome
$ mem_audit --stress-profile performance_mode
[MAP] text=182KB rodata=31KB data=14KB bss=22KB
[RAM] stack_peak=18.2KB stack_budget=24KB margin=5.8KB
[RAM] heap_peak=6.3KB heap_frag_index=0.07
[DMA] audio_buffers=48KB alignment=PASS
[FLASH] config_records=1202 crc_fail=0
[POWER-FAIL SIM] interrupted_writes=200 recoveries=200 corruption=0
PASS: memory and persistence safety criteria met
4. Solution Architecture
4.1 High-Level Design
Build map parser --> static budget report
Runtime probes --> stack/heap/queue telemetry
Config store --> append record + CRC + activate pointer
Fault injector --> brownout simulation during commit
4.2 Key Components
| Component | Responsibility | Key Decision |
|---|---|---|
| Map analyzer | derive static section usage | integrate into CI artifact checks |
| Runtime monitor | stack/heap high-water metrics | low-overhead periodic sampling |
| Config journal | versioned append records | wear distribution policy |
| Recovery validator | replay after interrupted writes | deterministic boot-time selection |
4.3 Data Shapes (Pseudocode)
config_record = {magic, version, length, crc32, payload}
mem_stats = {stack_peak, heap_peak, frag_index, queue_peaks}
commit_state = {last_good_record_id, pending_record_id}
5. Implementation Guide
5.1 Phases
- Build static map extraction and baseline budget.
- Add runtime probes for stack/heap/queues.
- Add config journal with CRC verification.
- Run repeated power-fail commit tests.
5.2 The Core Question You’re Answering
“Can this firmware prove safe memory behavior over long-running, fault-prone operation?”
5.3 Questions to Guide Design
- What memory regions are hard-reserved for real-time paths?
- Which subsystems are forbidden from heap allocation?
- What exact boot rule picks valid config after interrupted writes?
5.4 Thinking Exercise
Design a memory budget table before coding and include safety margins for worst-case growth per subsystem.
5.5 Interview Questions They Will Ask
- How do you budget stack and heap on constrained MCU memory?
- Why does fragmentation matter even with free memory available?
- How do transactional flash writes prevent corruption?
- What runtime metrics indicate memory risk early?
- How does linker layout influence reliability?
5.6 Hints in Layers
- Hint 1: Start with explicit region ownership chart.
- Hint 2: Add lightweight probes before advanced policy.
- Hint 3: Use append-only config records first, compaction second.
- Hint 4: Automate power-fail simulation loops.
5.7 Common Pitfalls and Debugging
| Problem | Why | Fix | Quick Test |
|---|---|---|---|
| Unexpected hard faults | stack overflow under rare path | increase stack budget + depth probes | deep-call stress scenario |
| Heap allocation fails late | fragmentation growth | switch to pools/arenas | long churn run |
| Config invalid after reset | non-atomic commit | append+CRC+activate pattern | repeated interrupted write tests |
5.8 Definition of Done
- Static and runtime memory budgets are documented and measured.
- Stack high-water margins remain safe in stress mode.
- Fragmentation behavior is quantified and bounded.
- Brownout/interrupted commit recovery is deterministic.
6. References
- Microchip ATSAMD51J19 Product + Datasheet Entry
- ARM Cortex-M4 Technical Reference Manual
- “Embedded Systems Architecture” by Tammy Noergaard
- “Effective C” by Robert C. Seacord