2. Embedded System Architecture
Learning Objectives
- Explain the difference between Harvard and von Neumann architecture and why most MCUs use a Harvard-like design
- Compare MCU, ASIC, and FPGA as processing platforms and justify when each is chosen
- Describe how a memory map organizes flash, RAM, and peripheral registers in an MCU's address space
- Read and write to a memory-mapped peripheral register directly in C
- Identify the three system bus types (data, address, control) and their role in data movement
- Analyze a real MCU datasheet memory map and locate a peripheral's base address
Quick Answer
Embedded system architecture is the internal organization of the processor, memory, and buses that make up an embedded computing platform. At the center is usually a microcontroller (MCU) — a single chip combining a CPU core, flash memory, RAM, and peripherals (timers, ADC, UART) connected by internal buses. Architecture decisions matter because they set hard limits on speed, power, and cost: a Harvard architecture (separate instruction and data memory paths) lets an MCU fetch the next instruction while reading data in the same cycle, which is why almost every modern MCU (ARM Cortex-M, AVR, PIC) uses it instead of the single-bus von Neumann design found in early computers. Understanding architecture means understanding how the CPU actually talks to memory and peripherals, not just what components exist.
Harvard vs. Von Neumann: The Core Design Choice
Every processor architecture starts with one decision: does the CPU use one memory bus for both instructions and data (von Neumann), or two separate buses (Harvard)?
Von Neumann architecture — instructions and data share the same memory and the same bus. The CPU cannot fetch the next instruction and read/write data at the same time; they compete for the same bus. This is simpler to build and is how a laptop's x86 CPU is organized.
Harvard architecture — program memory (flash) and data memory (RAM) sit on separate buses with separate address spaces. The CPU can fetch an instruction and access data simultaneously, roughly doubling throughput for the same clock speed. Almost every microcontroller — ARM Cortex-M, AVR (Arduino), PIC, MSP430 — uses a Harvard or "modified Harvard" architecture for exactly this reason.
Why it matters practically: on an AVR (Arduino Uno), you cannot treat flash and RAM as one continuous array. That's why storing a large lookup table in flash instead of RAM requires special keywords:
#include <avr/pgmspace.h>
// Stored in flash (program memory), NOT copied into scarce 2KB RAM
const uint8_t sine_table[256] PROGMEM = {
128, 131, 134, 137, /* ... */ 128
};
uint8_t read_sine(uint8_t index) {
return pgm_read_byte(&sine_table[index]); // explicit flash read
}
A student who doesn't understand Harvard architecture will wonder why sine_table[index] alone doesn't work as expected on an 8-bit AVR — it's because flash and RAM are genuinely separate address spaces, not a programming inconvenience.
Processing Platforms: MCU vs. ASIC vs. FPGA
| Platform | What it is | Flexibility | Design time | Unit cost at volume | Typical use |
|---|---|---|---|---|---|
| MCU (microcontroller) | Fixed silicon; CPU + memory + peripherals on one chip, programmed in software | High (reprogram anytime) | Days | Low ($0.50-$10) | Thermostats, sensor nodes, motor controllers |
| ASIC (application-specific IC) | Custom-fabricated silicon for one exact function | None after fabrication | Months to years, $$$ | Very low at huge volume | Smartphone SoC, GPU |
| FPGA | Reconfigurable logic fabric; "hardware" you can rewrite | High (reconfigure logic itself) | Weeks | High per unit | Aerospace, prototyping ASICs, signal processing |
The rule of thumb: MCUs win when the task can run as software fast enough and volume is not astronomical. ASICs win when volume is enormous (millions of units) and the function never changes — the huge upfront design cost is amortized. FPGAs win when you need hardware-level parallelism (processing multiple signals every clock cycle) but can't justify an ASIC's cost, or need to be able to update the "hardware" logic later, as in a satellite that can't be physically serviced.
Memory Map: How the CPU Sees the Chip
Every MCU exposes flash, RAM, and every peripheral register through a single unified address space, called the memory map. Reading or writing a peripheral is done by reading or writing a specific memory address — there is no separate "I/O instruction" the way old x86 CPUs have.
A simplified STM32F103 memory map looks like this:
| Address range | Region |
|---|---|
| 0x0800 0000 – 0x0801 FFFF | Flash memory (program code) |
| 0x2000 0000 – 0x2000 4FFF | SRAM (data) |
| 0x4001 0800 – 0x4001 0BFF | GPIOA peripheral registers |
| 0x4001 3800 – 0x4001 3BFF | USART1 peripheral registers |
| 0xE000 E000 – 0xE000 EFFF | Cortex-M core peripherals (NVIC, SysTick) |
Because peripherals are just addresses, you can turn on an LED by writing directly to a register address, bypassing any library:
#include <stdint.h>
#define GPIOA_BASE 0x40010800UL
#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x0C)) // output data register
void toggle_pin5(void) {
GPIOA_ODR ^= (1 << 5); // XOR flips bit 5 (pin PA5) each call
}
The volatile keyword is not optional here — without it, the compiler may assume the value never changes between reads and optimize the access away, which would silently break the code on real hardware even though it "compiles fine."
System Buses: The Roads Data Travels On
Inside the chip, three logical bus types move information between the CPU core, memory, and peripherals:
- Address bus — carries the memory address the CPU wants to access (one-directional, CPU to memory/peripheral).
- Data bus — carries the actual value being read or written (bidirectional).
- Control bus — carries signals like read/write, clock, and interrupt requests that coordinate the transfer.
On ARM Cortex-M devices this is implemented through the AMBA bus (Advanced Microcontroller Bus Architecture): a fast AHB (Advanced High-performance Bus) connects the CPU core to flash and RAM, while a slower APB (Advanced Peripheral Bus) connects to peripherals like UART and timers that don't need full CPU-speed access. This tiered structure keeps the fast core from being slowed down by comparatively slow peripheral hardware.
Why It Matters
Architecture choices are not academic — they determine what your firmware can and cannot do. If you assume a von Neumann model on a Harvard MCU, your flash-based constant tables silently behave differently than RAM variables. If you don't understand the memory map, you cannot read a datasheet or write a bare-metal driver, because every peripheral operation reduces to "read this address, write that address." If you don't understand bus hierarchy, you won't understand why a peripheral read can stall the CPU for several cycles while a RAM read does not.
Key Terms
| Term | Definition | Related Concept |
|---|---|---|
| Harvard architecture | Separate instruction and data memory/buses, allowing simultaneous fetch and access | Von Neumann, pipelining |
| Von Neumann architecture | Single shared memory and bus for instructions and data | Harvard architecture |
| Memory map | The full address-space layout showing where flash, RAM, and each peripheral's registers live | Register-level programming |
| Memory-mapped I/O | Accessing peripheral hardware by reading/writing specific memory addresses | GPIO, register access |
| AMBA / AHB / APB | ARM's on-chip bus standard; AHB is fast (core/memory), APB is slower (peripherals) | System bus, Cortex-M |
| ASIC | Custom-fabricated chip designed for one specific function, not reprogrammable | SoC, FPGA |
| FPGA | Reconfigurable logic fabric that can be rewired after manufacturing | HDL, ASIC |
| volatile (C keyword) | Tells the compiler a variable/register may change outside program flow; prevents unsafe optimization | Register access, ISR |
Common Mistakes
Misconception: All computer architectures use one shared memory for both program and data, like a desktop CPU.
Why it's wrong: Most desktop CPUs present a von Neumann programming model even though they use Harvard-like caches internally, but almost every microcontroller uses genuine Harvard architecture with physically separate flash and RAM address spaces.
Correct understanding: On MCUs, flash (program) and RAM (data) are separate memories with separate access rules — which is why constants meant to stay in flash need special declarations like PROGMEM or const placement directives.
Misconception: An FPGA is just a slower, cheaper alternative to an ASIC. Why it's wrong: An FPGA is reconfigurable hardware — you can change its internal logic after deployment — while an ASIC is permanently fixed at fabrication. FPGAs are often more expensive per unit than ASICs at volume; their value is flexibility and fast turnaround, not low cost. Correct understanding: Choose FPGA for flexibility, hardware parallelism, or low-volume/prototype needs; choose ASIC for extreme volume where the function will never change and per-unit cost must be minimized.
Misconception: Accessing a peripheral register is fundamentally different from accessing a normal variable in C.
Why it's wrong: On memory-mapped architectures, a peripheral register is just a specific memory address. You read and write it with normal pointer dereferencing — the only special requirement is marking it volatile so the compiler doesn't optimize away accesses.
Correct understanding: *(volatile uint32_t *)0x40010800 behaves like any pointer dereference in C; the "peripheral" nature is purely about what hardware sits behind that address.
Comparison and Connections
| Aspect | MCU | ASIC | FPGA |
|---|---|---|---|
| Reconfigurable after manufacture | Yes (reprogram flash) | No | Yes (reload logic) |
| Best for | General embedded control tasks | Massive volume, fixed function | Parallel signal processing, prototyping, low volume |
| Design turnaround | Days | Months–years | Weeks |
| Example | STM32, ATmega328P | Apple A-series SoC | Xilinx Zynq |
| Typical language | C/C++ | Verilog/VHDL → silicon | Verilog/VHDL → bitstream |
Practice Questions
Recall
-
What are the three types of buses in a system architecture, and what does each carry? Answer guidance: Address bus (which location), data bus (the value), control bus (read/write, clock, interrupt signals).
-
Name the three chip-level platforms discussed and one example of each. Answer guidance: MCU (STM32/Arduino), ASIC (Apple A-series), FPGA (Xilinx Zynq).
Understanding
-
Explain why a Harvard architecture allows higher instruction throughput than a von Neumann architecture at the same clock speed. Answer guidance: Separate buses let instruction fetch and data access happen in the same clock cycle instead of competing for one shared bus, effectively pipelining fetch and execute stages.
-
Why does writing to a peripheral register in C require the
volatilekeyword? Answer guidance: Without it the compiler may cache the value in a register or eliminate "redundant" writes/reads during optimization, since it doesn't know the memory address can change due to hardware, not program flow.
Application
-
You are given a datasheet showing GPIOB's registers start at address 0x40010C00, and the output data register (ODR) is at offset 0x0C. Write the C code to set pin 3 of GPIOB high. Answer guidance:
#define GPIOB_ODR (*(volatile uint32_t*)(0x40010C00 + 0x0C)); GPIOB_ODR |= (1 << 3); -
You need a system that processes four sensor channels in true parallel, each requiring custom filtering logic, and the product will only ship 500 units. Which platform (MCU, ASIC, FPGA) fits best, and why? Answer guidance: FPGA — true parallel hardware processing is required (an MCU processes channels sequentially even if fast), and the low volume makes an ASIC's fabrication cost unjustifiable.
Analysis
-
Compare what happens on a von Neumann machine versus a Harvard machine when the CPU needs to fetch the next instruction while simultaneously loading a data value from memory. Answer guidance: Von Neumann: the two operations contend for the single shared bus, causing a stall or serialization ("von Neumann bottleneck"). Harvard: the fetch uses the instruction bus while the load uses the data bus, so both can proceed in the same cycle.
-
A junior engineer claims "APB peripherals should be made as fast as AHB so nothing ever stalls the CPU." Evaluate this claim. Answer guidance: Making all peripherals AHB-speed increases die area, power consumption, and design complexity for little benefit, since most peripherals (UART, timers) don't need core-speed bandwidth. The tiered AHB/APB split is a deliberate power/area/performance trade-off, not a limitation to be eliminated.
FAQ
Why do ARM Cortex-M chips call themselves "Harvard architecture" but still let me put constants in flash and access them like RAM?
Cortex-M uses a modified Harvard architecture: physically separate instruction and data buses for performance, but a unified address space that maps both flash and RAM into one address range so the compiler and linker can reference either uniformly. True 8-bit AVR chips use a stricter Harvard split, which is why PROGMEM is needed there but is largely unnecessary on Cortex-M.
How do I find a peripheral's base address without guessing? Read the microcontroller's reference manual (not just the datasheet) — it contains a full memory map table listing every peripheral's base address and register offsets. Vendor-provided header files (e.g., STM32 CMSIS headers) already define these as macros so you rarely hand-calculate them in real projects, but understanding where those macros come from matters for debugging.
Is FPGA programming the same as MCU programming? No. MCU programming writes sequential C/C++ instructions that execute one after another on a CPU core. FPGA "programming" (using Verilog or VHDL) describes parallel hardware circuits that all exist and operate simultaneously — you are literally configuring logic gates and flip-flops, not writing a sequential program.
Why does my code work in simulation but behave differently on real MCU hardware when I remove volatile?
The compiler optimizer, without volatile, may assume the peripheral register never changes outside the visible code and cache its value in a CPU register, skipping repeated hardware reads. Simulators sometimes don't model this optimization aggressively, masking the bug until it runs on real silicon.
Why do MCUs still dominate the embedded market when FPGAs and ASICs seem more powerful? For most embedded tasks, the CPU only needs to be "fast enough," and MCUs offer the best combination of low cost, short design time, easy reprogrammability, and mature toolchains. FPGAs and ASICs are reserved for cases with genuine parallel processing or extreme-volume requirements that justify their higher cost or design complexity.
Quick Revision
- Von Neumann = one shared bus for instructions and data; Harvard = separate buses, higher throughput
- Most MCUs (ARM Cortex-M, AVR, PIC) use Harvard or modified Harvard architecture
- MCU = flexible, cheap, fast to design; ASIC = fixed function, cheapest at huge volume; FPGA = reconfigurable parallel hardware
- The memory map assigns a unique address to flash, RAM, and every peripheral register
- Memory-mapped I/O means "accessing hardware" = "reading/writing a specific address"
volatilein C prevents the compiler from optimizing away hardware register accesses- Three bus types: address bus (location), data bus (value), control bus (coordination signals)
- ARM's AMBA architecture splits AHB (fast, core/memory) from APB (slower, peripherals)
- FPGAs use HDLs (VHDL/Verilog) to describe parallel hardware, not sequential software
- Reading a datasheet's memory map is a prerequisite for any bare-metal register-level driver
Related Topics
Prerequisites: Introduction to Embedded Systems, digital logic and number systems, basic C pointers
Related Topics: Embedded System Design, Embedded System Programming, Hardware-Software Co-Design
Next Topics: Real-Time Operating Systems, Embedded System Interfaces (communication buses and protocols)