Microcontrollers: The Heart of Embedded Systems
What is a microcontroller?
A microcontroller (MCU) is a single integrated circuit that combines a CPU, memory (Flash + RAM) and a set of peripherals on the same die. Unlike a general-purpose CPU, an MCU is designed to run a single dedicated program forever, talking to the physical world through its pins.
In short: MCU = tiny computer + I/O, built to control hardware in real-time with very little power.
Inside the chip
Every modern microcontroller is built from a few essential blocks:
- CPU core — typically ARM Cortex-M, RISC-V, AVR or Xtensa.
- Flash memory — non-volatile storage for your program (KB to MB).
- SRAM — fast volatile memory for variables and the stack.
- Peripherals — GPIO, timers, ADC, DAC, UART, SPI, I2C, USB, CAN.
- Clock + power — oscillators, PLLs, voltage regulators, sleep modes.
- Interrupt controller — lets hardware events preempt your code.
MCU families you should know
| Family | Vendor | Core | Best for |
|---|---|---|---|
| AVR (ATmega, ATtiny) | Microchip | 8-bit AVR | Learning, Arduino, low cost |
| STM32 | STMicroelectronics | ARM Cortex-M0/M3/M4/M7 | Industrial, motor control, general firmware |
| ESP32 / ESP32-S3 | Espressif | Xtensa / RISC-V + Wi-Fi/BT | IoT, wireless, edge AI |
| RP2040 | Raspberry Pi | Dual Cortex-M0+ | Hobby, education, PIO state machines |
| nRF52 / nRF53 | Nordic | Cortex-M4 + BLE | Wearables, low-power BLE |
Peripherals — talking to the real world
Digital I/O (GPIO)
Each pin can be configured as input or output, HIGH or LOW. Used for LEDs, buttons, relays, and bit-banged protocols.
Analog (ADC / DAC)
The ADC samples a continuous voltage into a digital value (e.g. 0–4095 on a 12-bit ADC). Used for sensors, audio, and measurements.
Communication buses
- UART — simple async serial, perfect for debug logs and modems.
- I2C — 2-wire bus for sensors, EEPROMs and small displays.
- SPI — fast 4-wire bus for flash, displays and ADCs.
- CAN — robust automotive / industrial bus.
- USB / Ethernet / Wi-Fi / BLE — connectivity to the outside world.
Choosing the right microcontroller
Ask these questions before you commit to a part:
- Power budget — battery life or always-on?
- Performance — clock speed, FPU, DSP, AI accelerators?
- Connectivity — Wi-Fi, BLE, Ethernet, LoRa, none?
- Memory — does your firmware fit? Plus 30% headroom.
- Toolchain — IDE, debugger, HAL quality, community.
- Availability + lifecycle — can you buy 10k of them in 5 years?
Pro tip: Always pick a part that has a sibling family. If the small one runs out of pins or RAM, you can move up without rewriting everything.
Your first bare-metal program
Here is the canonical "blink an LED on PA5 of an STM32" — written in plain register-level C:
#include <stdint.h>
#define RCC_AHB1ENR (*(volatile uint32_t *)0x40023830U)
#define GPIOA_MODER (*(volatile uint32_t *)0x40020000U)
#define GPIOA_ODR (*(volatile uint32_t *)0x40020014U)
int main(void) {
RCC_AHB1ENR |= (1U << 0); // enable GPIOA clock
GPIOA_MODER &= ~(3U << (5 * 2)); // clear mode bits for PA5
GPIOA_MODER |= (1U << (5 * 2)); // set PA5 as output
while (1) {
GPIOA_ODR ^= (1U << 5); // toggle PA5
for (volatile int i = 0; i < 400000; i++) { } // crude delay
}
}
If that LED blinks, you have officially written firmware. Welcome to embedded.
Where to go next
Now that you understand the chip, learn the language and the operating system that drive it:
- Embedded C — pointers, registers, drivers and bit manipulation.
- Embedded RTOS — multi-tasking firmware with FreeRTOS.
- Arduino Basics — the gentlest starting point.
- IoT Weather Station — put it all together.