Microcontroller programming

2026-02-09

Nicolas De Coster & Henk Buursen

Choose microcontroller

Better "fit for purpose"

Consider:

  • processing power
  • memory
  • I/O capabilities (+pins number)
  • power consumption
  • existing libraries / support

From blinking led to linux OS (5G chips) and beyond.

AtTiny

8 bits

1–20 MHz

Single pin UPDI

SAMD

32 bits

48 MHz ARM M0+

Native USB

RP2040

32 bits

133 MHz Dual M0+

Programmable I/O

ESP32-C3/S3

RISC-V

160 MHz

WiFi + Bluetooth

AtTiny (412 / 1614 / 3216 / ...)

  • 8 bits - 1MHz-20Mhz (→ 32MHz overclock)
  • Versatile I/O (analog, PWM, I²C, UART, SPI, ...)
  • Single pin programming (UPDI) = half-duplex serial
  • Sandbox board : Adrianino

SAMD (11C, 11D, 21E, D51)

  • 32 bits - 48MHz - Single ARM Cortex-M0+
  • Native USB support (+CDC +HID)
  • Versatile I/O (analog, PWM, I²C, UART, SPI, ...)
  • Programming : SWD / JTAG (then bootloader?)
  • Sandbox board : Samdino or QPAD21

RP2040 / RP2350 (Xiao or Rpi Pico)

  • 32 bits - 48MHz - 133MHz (→ >250MHz overclk)
  • Dual ARM Cortex-M0+ / CortexM33 & Hazard3 RISC-V
  • Programmable I/O (PIO)
  • Hardcoded bootloader (UF2)
  • Sandbox board : FabXIAO or QPAD-Xiao

ESP32-C3/S3

  • RISC-V - 160MHz
  • Wifi - BlueTooth
  • Versatile I/O
  • Sandbox board : FabXIAO

Others

nRF52840 (Xiao BLE)
STM32 ("Blue Pill"), FabSat (instr. bootcamp 2026)
PIC (Microchip), Pinguino
MSP/TI
...

General rule : RTFM / RTFDatasheet

Always refer to the microcontroller's datasheet and reference manual for detailed specifications and usage instructions. These documents provide essential information for programming and configuring the microcontroller.

Choose language

We recommend
You might want to test

Assembly / PIO / VHDL / Verilog

  • Direct hardware control
  • Efficient but complex to write
  • Programmable I/O (PIO) offloads I/O from CPU
  • Learn binary/logic basics! (worth it!)
  • Efficient & low-level hardware access
  • Compiled language (machine code)
  • Arduino is C++ based
  • Industry standard for embedded systems
  • Higher level of abstraction
  • Interpreted or precompiled to bytecode
  • Easier to learn & fast prototyping
  • MicroPython & CircuitPython variants
  • Strong safety guarantees
  • Modern language features
  • Compiled language (like C/C++)
  • Growing ecosystem for embedded systems
  • Familiar syntax for web developers
  • Can run on microcontrollers (Kaluma, Espruino)
  • Requires more resources than C
  • Good for rapid prototyping
  • TinyGo brings Go to microcontrollers
  • Supports various MCUs (SAMD, RP2040, ESP32, ...)
  • Optimized garbage collector
  • Built-in GPIO, I2C, SPI libraries
  • Cross-compilation support
  • Real-time OS kernel for embedded systems
  • FreeRTOS is the most popular open-source RTOS
  • Provides task scheduling, synchronization, and memory management
  • Supports multi-threading and priority-based scheduling
  • Available for most popular MCU platforms

Mixed languages

Mixing languages might give you the best of each world :

  • ASM → C → C++
  • Micropython + PIO

Mixing microPython and PIO "assembly" on RP2040


AI Programming Assistants

  • Makes you faster, not smarter
  • Learning : different approaches and patterns
  • Never use/execute code you don't fully understand
  • Always review and test generated code thoroughly
  • Tool to accelerate, not to replace your thinking

Programming basics

Ada Lovelace

Very first algorithm (1843!): conditionnal branching and loop.

Loop : "Infinite" while


Make your code run "forever".

Loop : "conditional" while


Make your code run "as long as"...

Loop : for


Make your code run a specific number of times.

Function Call


Make your code modular by using functions.

Branching : if then else


Code execution based on a condition.

Programming

UPDI

Single pin (reset), half-duplex serial

Used for AtTiny/AVR

ISP

In-System Programming (~3 wires)

Classic AVR, PIC, etc.

SWD/JTAG

Serial Wire Debug & Joint Test Action Gropu

ARM Cortex-M, SAMD, RP2040, ...

UF2

USB Flashing Format

RP2040, RP2350

Bootloader : small program stored memory that initialize the µC and load/rewrite code from a secondary storage device such as serial port (USB/UART), flash memory or EEPROM.

Hardcoded bootloader (UF2)

  • Hardcoded bootloader : you "can't" brick it
  • Appears as a USB mass storage device
  • Drag and drop firmware files (UF2 format)

One programmer to rule them all

Quentorres (Instr. bootcamp 2024)

Basic board for using Alex Tardov's Free DAP

Arduino (C/C++)

Know the differences:

  • Arduino board = hardware platform
  • Arduino libraries = set of functions
  • Arduino IDE = development environment

All three are distinct but commonly used together

Arduino Uno = board = hardware

  • Specific hardware board with ATmega328P (outdated!) microcontroller
  • One of the most commonly used Arduino boards
  • Popular for prototyping and educational purposes
Arduino Uno R3 board ("quite" outdated)

Arduino is a set of libraries

  • Simplifies common tasks: analog inputs, digital outputs, peripherals
  • Abstracts register details for easier coding
  • Provides portable code across various chips
  • Trade-off: generated code is usually less efficient

"Pure C" VS Arduino


→ add them to arduino preferences : additional boards manager

Arduino IDE is a development environment

  • Writing, compiling, and uploading code
  • Syntax highlighting, serial monitor+plotter, library management, boards management
  • Available in v1 and v2 versions
  • IDE v2: better editor but may have compatibility issues
Arduino IDE 2

Good practice

Document your code (as you go...)

  • Every programming language has special "commented" code sections
  • Comments explain your logic and reasoning
  • Makes code easier to understand and maintain
  • Future you (and others) will thank present you

Write modular and readable

  • Break code into modular components for better readability
  • Organize into separate functions/modules by functionality
  • Facilitates debugging and future updates
  • Flat files are difficult to modify and maintain

Modular writing


Write "parametric"

  • Avoid hardcoding constants directly into code
  • Use symbolic names or macros with const/#define
  • Improves code clarity and readability
  • Allows easier modifications in the future

Parametric : Example


Parametric : Example


Use Classes / Objects / Libraries

  • Allows you to "think as objects"
  • Is called "object oriented" (C++ vs C)
  • Widely used by Arduino hardware specific libraries

Classes


Simulate your circuit

  • Use simulators to test and debug your code before deploying on hardware
  • Wokwi (PIO!), Tinkercad, Proteus, etc.
  • Save time and prevent damage to hardware

Optimizations

Some tips :

  • lookup tables (vs complex maths)
  • inline
  • pointers
  • "simple" arithmetics : 2n divisions = >>
  • Proper type : uint8_t, int16_t, etc. (pecularly on 8bits proc)
  • ...

Fit-for-purpose processor

  • Select microcontroller wisely
  • Consider underclocking and sleep for power-sensitive projects
  • Underclocking can be as useful as overclocking!
  • Power (instr. bootcamp 2026)

Reduce Power Consumption

  • Power consumption is critical for battery-powered and remote devices
  • Multiple strategies available to optimize energy usage
  • Different approaches suitable for different applications
  • Combine multiple techniques for best results

Strategy 1: Underclocking

  • Reduce CPU clock frequency for lower power consumption
  • Lower frequency = lower power (linear)
  • Example: 1 MHz instead of 20 MHz = 95% savings!

Strategy 2: Disable Unused Peripherals

  • Each peripheral (ADC, UART, SPI, ...) consumes power when enabled
  • Disable peripherals not used in your application
  • Avoid "floating" pins
  • Can disable at init or dynamically during runtime

Strategy 3: Sleep Modes & Interrupts

  • Microcontrollers "Inception" : multiple sleep states (idle, light, deep, hibernation)
  • Use interrupts to wake when needed
  • Extremely effective for event-driven applications

Practical Power Optimization

  • Start with sleep modes for maximum impact
  • Add peripheral disabling for fine-tuning
  • Consider underclocking
  • Profile your code to identify power hotspots
  • Use oscilloscope/power meter to verify improvements

Credits

  • Comics : XKCD
  • Beautiful microprocessors : pinouts.org
  • Fragments of codes : our brains, some AI and Neil

Time for debugging

Attitude

Write down what you do

The Pragmatic Programmer

Talk to me

Narrowing down the problem

  • Reproduce the problem
  • Reproduce the problem
  • Always first do visual check
  • Reproduce the problem
  • Always first do visual check
    1. traces
      soldering
      components
  • Reproduce the problem
  • Always first do visual check
    1. traces
      soldering
      components
  • Keep in mind that the problem
    might not be visible without a microscope

4. Keep in Mind: The Problem May Not Always Be Visible

Isolate the possible problem

Multimeter

Continuity

  • Test power supply to power pins continuity
  • Check fuses, diodes orientations, ...
  • Check short-circuits
  • Check traces
  • Parallel measurement => check your cables!
  • ! absolute maximum ratings (may burn your component)
  • Power supply impedence / max power, badly selected
  • GND/VCC loop

Continuity

Voltage drop

Logic Analyzer

Logic Analayzer

Miniware LA104

LA104 and alternative firmware and apps

Oscilloscope

Radio communications

RTL-SDR RTL2832U DVB-T Tuner Dongles

Flashing your board

and what can go wrong

USB

SWD/JTag

UPDI

Unified Program and Debug Interface

Serial (or any) "Hello world!"


#define DEBUG_MODE 1
        ...
#if DEBUG_MODE
         Serial.print("DEBUG -- MyVal value = ");
        Serial.println(MyVal, DEC);
#endif

Read The F*cking Manual