Embedded Software Foundations
A structured introduction to embedded systems, software architecture, toolchains, memory, hardware interfaces, debugging, and core data structures.
Level: beginner
Tags: embedded, firmware, gcc, hal, memory, debugging
Lesson
At a glance
This lesson introduces the core building blocks of embedded software development: platform structure, host-target workflow, hardware abstraction, build tooling, memory organization, hardware interfaces, debugging, and data structures.
1. What an embedded system is
An embedded system is a computerized system designed to perform a specific function under constraints such as cost, size, power consumption, memory, performance, and sometimes real-time behavior.
Software is not isolated: it is part of a hardware-software product that must be built, installed, tested, and maintained over time.
2. Host, target, and workflow
- Host machine — where source code is written, compiled, versioned, and debugged
- Target — the embedded board or microcontroller that runs the program
- Programmer/debugger — loads firmware and allows inspection of registers, memory, and control flow
- Build artifacts — ELF, HEX, BIN, map files, objects, and libraries
This separation explains why cross-compilation is central in embedded development.
3. Microprocessor vs microcontroller
A microprocessor mainly contains the CPU and needs external memory and peripherals. A microcontroller integrates CPU, memory, and peripherals on the same chip.
- CPU — executes instructions, depends on ISA and ABI
- Flash — non-volatile memory for code and constants
- SRAM — runtime memory for stack, heap, globals, and buffers
- Peripherals — GPIO, UART, SPI, I2C, ADC, timers, DMA, watchdog
- Clock and power — affect timing, delays, baud rates, and low-power modes
- Interrupt controller — manages asynchronous events and priorities
4. Software architecture layers
- Bare-metal firmware — direct interaction with registers and peripherals
- Driver — module that controls a specific peripheral
- HAL — stable interface hiding MCU or board differences
- Application layer — product logic, algorithms, states, and protocols
A good architecture separates application logic from hardware-specific details.
5. Essential tools
- Simulator
- Emulator
- Compiler / cross-compiler
- Installer / loader
- Debugger
Vendor IDEs can accelerate setup, but command-line builds are often more reproducible and better suited for automation and CI.
6. Embedded C and code quality
Embedded C requires more than syntax knowledge. It also requires understanding:
- memory layout
- volatility
- type sizes
- alignment
- ABI rules
- timing constraints
- hardware side effects
Prefer explicit-width integer types such as uint8_t, uint16_t,
and uint32_t.
7. volatile, const, and register access
volatile is essential for hardware registers, interrupt-shared variables,
and DMA-shared data.
- Use
volatilewhen a value can change outside normal compiler control flow - Do not use
volatileas a generic concurrency fix - Use
constfor lookup tables, strings, and configuration data - Combine
constandvolatilefor read-only hardware registers
8. Toolchain, compilation, linker, and Make
- Preprocessing
- Compilation
- Assembly
- Linking
- Locating
- Conversion / installation
The linker script is what maps the program to real platform memory.
GNU Make makes compiler flags, source lists, targets, clean rules, and platform variants explicit.
9. Memory model and sections
- Flash / ROM — code, constants, vectors
- SRAM — runtime writable data
- .text — code
- .rodata — read-only constants
- .data — initialized writable globals/statics
- .bss — zero-initialized or uninitialized globals/statics
- stack — automatic locals and call frames
- heap — dynamic allocation
Memory must be sized, measured, and monitored carefully in embedded systems.
10. ABI, pointers, alignment, and endianness
The ABI/EABI defines binary compatibility rules between compiler, object code, libraries, and runtime.
- register usage and calling convention
- parameter passing
- stack alignment
- object layout and symbols
- CPU/FPU/instruction-set compatibility
In embedded systems, pointers often represent hardware addresses, not only variables.
11. Memory-mapped I/O and bit manipulation
In memory-mapped I/O, reading or writing an address can mean interacting with a peripheral.
- read-modify-write carefully
- respect write-one-to-clear semantics
- avoid writing reserved bits
- use masks and field helpers
Good hardware-facing software should hide register details behind small, reusable interfaces.
12. Debugging and validation
Embedded debugging combines software and hardware observation.
- breakpoints
- watchpoints
- step into / over
- memory view
- register view
- disassembly
Typical bug causes include wrong vector tables, invalid stack pointers, missing volatile, disabled peripheral clocks, stack corruption, and platform mismatches.
13. Data structures in embedded systems
Data structures must be chosen with memory footprint, determinism, and concurrency in mind.
- enum — readable states and modes
- struct — grouped related data
- union — multiple views of the same memory
- LIFO — predictable push/pop operations
- circular buffer — excellent for producer/consumer streams
- linked list — flexible but often expensive in embedded systems
14. Practical rule
Embedded software is not just writing C code.
You need to understand the full chain:
- hardware constraints
- architecture layers
- toolchain and build system
- memory and ABI
- hardware interfaces
- debugging discipline
- data structure trade-offs
Map
Interactive map
Embedded Software Foundations
Click a node to inspect its meaning.