When I first started tearing apart old electronics as a hobby, I assumed every circuit board was some unique mystery I had to decode from scratch. Over time I realized something reassuring: almost every embedded system, no matter how different they look on the outside, is built from the same handful of building blocks. Once you know what to look for, you can open up a smart thermostat, a drone flight controller, or an industrial sensor module and recognize the same fundamental pieces doing the same fundamental jobs.
In this article, I’m going to break down those building blocks one by one — the hardware, the firmware, and the internal wiring that connects them — so you can look at any embedded design and understand what role each component plays.
The Big Picture
Every embedded system, at minimum, needs a way to think (a processor), a way to remember (memory), a way to sense and act on the world (I/O and peripherals), a way to run (power), and a set of instructions to follow (firmware). Let’s look at how these fit together.
graph TB
PWR[Power Supply / Regulation] --> MCU
MCU[Processor Core - MCU/MPU] --> FLASH[Program Memory - Flash/ROM]
MCU --> RAM[Data Memory - RAM]
MCU --> GPIO[GPIO Pins]
MCU --> ADC[Analog to Digital Converter]
MCU --> TIMER[Timers / PWM]
MCU --> COMM[Communication Interfaces]
COMM --> UART[UART]
COMM --> SPI[SPI]
COMM --> I2C[I2C]
COMM --> WIFI[Wi-Fi / BLE]
GPIO --> SENSORS[Sensors]
GPIO --> ACTUATORS[Actuators]
MCU --> INT[Interrupt Controller]
MCU --> CLK[Clock / Oscillator]
1. The Processor (MCU or MPU)
The processor is the decision-making core of the system. In most embedded designs, this is a microcontroller unit (MCU) — a single chip combining a CPU core, memory, and peripherals. In more powerful embedded systems, it might be a microprocessor unit (MPU), which needs external memory and typically runs a full operating system like embedded Linux.
Common processor cores you’ll encounter:
- ARM Cortex-M series (M0, M3, M4, M7) — used in STM32, Nordic, NXP chips
- AVR 8-bit cores — used in classic Arduino boards
- Xtensa LX6/LX7 or RISC-V — used in Espressif’s ESP32 family
- ARM Cortex-A series — used in more powerful SoCs running embedded Linux
The processor fetches instructions from program memory, decodes them, executes them, and coordinates every other component in the system.
2. Memory
Memory in an embedded system is usually split into distinct categories, each with a different purpose:
- Flash memory (non-volatile): stores the compiled firmware. It survives power loss and is where your program code and constant data live.
- RAM / SRAM (volatile): stores variables, the stack, and the heap during runtime. It’s fast but loses its contents when power is removed.
- EEPROM (non-volatile, small): used for storing settings or calibration data that need to persist but change occasionally, without needing a full firmware reflash.
- External memory (in larger systems): SD cards, external Flash, or DRAM for systems that need to store large amounts of data, like logs or media files.
A typical memory map for a microcontroller might look like this:
graph LR
A[0x00000000<br/>Flash - Program Code] --> B[0x08000000<br/>Flash continued]
B --> C[0x20000000<br/>SRAM - Variables/Stack/Heap]
C --> D[0x40000000<br/>Peripheral Registers]
D --> E[0xE0000000<br/>Core Peripherals - NVIC, SysTick]
Understanding the memory map matters because firmware often accesses peripherals by writing directly to specific memory addresses — a concept I explore in depth in the article on memory-mapped I/O.
3. Input and Output (I/O) Interfaces
I/O is how the embedded system perceives and affects the physical world. This includes:
- GPIO (General Purpose Input/Output) pins: the most basic form of I/O, used to read digital signals (like a button press) or write digital signals (like turning on an LED).
- Analog-to-Digital Converters (ADC): convert continuous analog signals (like temperature or voltage) into digital values the processor can work with.
- Digital-to-Analog Converters (DAC): the reverse — converting digital values into analog output signals.
- PWM (Pulse Width Modulation): used to control motor speed, LED brightness, or generate analog-like output from digital pins.
4. Sensors
Sensors are the “eyes and ears” of an embedded system. Common examples include temperature sensors, accelerometers, gyroscopes, light sensors, humidity sensors, proximity sensors, and pressure sensors. Sensors typically communicate with the microcontroller over I2C or SPI, sending digital readings that represent a physical quantity.
5. Actuators
Actuators are the “hands” of the system — components that convert electrical signals into physical action. Examples include motors, relays, solenoids, buzzers, and LEDs. The processor commands actuators through GPIO, PWM signals, or dedicated motor driver ICs.
6. Communication Interfaces
Embedded systems rarely work in isolation. They need to talk to other chips, other devices, or the outside world. Common communication protocols include:
| Protocol | Typical Use | Speed |
|---|---|---|
| UART | Simple point-to-point serial communication, debugging | Low-Medium |
| SPI | Fast communication with sensors, displays, Flash chips | High |
| I2C | Multiple low-speed sensors on a shared bus | Low |
| CAN | Automotive and industrial networks | Medium |
| Wi-Fi / BLE | Wireless connectivity, IoT applications | High |
7. Power Supply and Power Management
Every embedded system needs a stable, correctly regulated power supply. This typically involves voltage regulators (linear or switching), battery management circuitry (for portable devices), and power sequencing logic to make sure components turn on in the right order. I go into much greater depth on this topic in the dedicated article on power management, but it’s worth noting here as a core structural component — poor power design causes more field failures than almost anything else in embedded hardware.
8. Timers and Clock Sources
Timers are hardware peripherals that count clock cycles, and they underpin almost everything time-related in an embedded system: generating PWM signals, triggering periodic interrupts, measuring elapsed time, and implementing communication protocol timing. The clock source itself — usually a crystal oscillator or an internal RC oscillator — determines how fast the processor and peripherals run.
9. Interrupt Controller
The interrupt controller (in ARM Cortex-M chips, this is the Nested Vectored Interrupt Controller, or NVIC) allows the processor to respond immediately to events — a button press, an incoming data packet, a timer expiring — without constantly polling for them in a loop. I dedicate a full article to interrupts elsewhere in this series, but structurally, it’s a core hardware block present in virtually every modern MCU.
10. Firmware
Firmware ties everything together. It’s the software, usually written in C or C++, that initializes the hardware at boot, configures peripherals, implements the application logic, and handles interrupts. Without firmware, all the hardware I’ve described above is just inert silicon.
Here’s a simplified example that shows several components working together — reading a sensor over ADC, and driving an actuator via PWM, based on the reading:
#include "stm32f4xx.h"
#define THRESHOLD 2048
void ADC_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->CR2 |= ADC_CR2_ADON;
}
uint16_t ADC_Read(void) {
ADC1->CR2 |= ADC_CR2_SWSTART;
while (!(ADC1->SR & ADC_SR_EOC));
return ADC1->DR;
}
void PWM_SetDuty(uint16_t duty) {
TIM3->CCR1 = duty;
}
int main(void) {
ADC_Init();
// (Timer/PWM init omitted for brevity)
while (1) {
uint16_t sensorValue = ADC_Read();
if (sensorValue > THRESHOLD) {
PWM_SetDuty(4095); // Full speed / brightness
} else {
PWM_SetDuty(sensorValue); // Proportional control
}
}
}
This small example touches five of the components discussed above: the processor core executing the loop, RAM holding the local variable, the ADC peripheral reading a sensor, the timer/PWM peripheral driving an actuator, and Flash memory storing the compiled program.
How These Components Interact: A Data Flow View
sequenceDiagram
participant S as Sensor
participant MCU as Microcontroller
participant MEM as RAM
participant A as Actuator
participant COM as Communication Module
S->>MCU: Analog/Digital signal
MCU->>MEM: Store reading
MCU->>MCU: Process (control logic)
MCU->>A: Drive output (PWM/GPIO)
MCU->>COM: Send status update
COM-->>MCU: Acknowledge / receive command
Optimization and Reliability Considerations
Choosing the right components isn’t just about function — it’s about fit. Engineers weigh:
- Cost: does the application need a $0.50 8-bit MCU, or a $5 32-bit SoC with Wi-Fi?
- Power budget: battery-powered devices need low-power sleep modes and efficient peripherals.
- Performance: does the control loop need to run at 1 kHz or 1 Hz?
- Reliability: industrial and automotive components often need extended temperature ranges and certified reliability ratings.
Real-World Example: A Smart Thermostat
Let’s ground this in a real device. A smart thermostat typically includes:
- A low-power 32-bit MCU (processor)
- Flash and RAM (built into the MCU)
- A temperature/humidity sensor over I2C
- A small display driven over SPI
- A relay or triac to control the HVAC system (actuator)
- A Wi-Fi module for connecting to a cloud app
- A battery or mains power supply with regulation circuitry
- Firmware implementing the control loop, Wi-Fi stack, and user interface logic
Every single component described in this article shows up in that one device.
Frequently Asked Questions
Do all embedded systems need all of these components? No. A very simple embedded system, like a digital kitchen timer, might only need a processor, memory, a couple of buttons, a display, and a buzzer — no wireless communication, no complex sensors.
What’s the difference between a sensor and a peripheral? A peripheral is a hardware block, often built into the microcontroller itself (like an ADC or a timer), that helps the processor interact with signals. A sensor is typically an external component that measures a physical quantity and communicates its reading to the microcontroller through a peripheral interface like I2C or SPI.
Why do some embedded systems use external memory instead of the built-in Flash/RAM? More powerful embedded systems, especially those running embedded Linux, often need more memory than can fit on-chip, so they use external DRAM and Flash or eMMC storage, connected via dedicated memory buses.
Summary
An embedded system is built from a consistent set of core components: a processor, memory, I/O interfaces, sensors, actuators, communication modules, power management circuitry, timers, an interrupt controller, and firmware that ties it all together. Once you can identify these pieces and understand how they interact, you can make sense of almost any embedded design, from the simplest microcontroller-based gadget to a sophisticated connected IoT device.
References and Further Reading
- ARM Cortex-M Technical Reference Manuals — https://developer.arm.com/documentation
- STM32 Reference Manuals — https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html
- Microchip AVR Datasheets — https://www.microchip.com/en-us/products/microcontrollers-and-microprocessors/8-bit-mcus/avr-mcus
- Espressif ESP32 Hardware Reference — https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/
- Arduino Hardware Documentation — https://docs.arduino.cc/hardware/
- FreeRTOS Documentation — https://www.freertos.org/Documentation/RTOS_book.html