ES: Flashing and Debugging

Firmware flashing is a fundamental process in embedded systems development, enabling you to load new or updated firmware onto microcontrollers and other programmable devices.

Flashing is not just “copying a file” — it is a controlled sequence of memory erase, program, verify, and reset operations that interact directly with the microcontroller’s internal flash controller. Debugging, on the other hand, allows you to halt, inspect, and control the CPU while it executes instructions, giving you deep visibility into registers, memory, stack, peripherals, and timing behavior.

Before tools and cables, understand the architecture.

An MCU system looks like this internally:

txt
		 +-----------------------+
		 |        CPU Core       |
		 |   (ARM Cortex-M)      |
		 +-----------+-----------+
					 |
					 |
		 +-----------v-----------+
		 |        Bus Matrix     |
		 +-----+-----------+-----+
			   |           |
 +-------------v--+   +----v-------------+
 |     Flash      |   |       SRAM       |
 | (Non-volatile) |   | (Volatile)       |
 +----------------+   +------------------+

  • Flashing = Writing machine code into Flash memory.
  • Debugging = Controlling the CPU while it executes from Flash.

Flashing modifies memory contents.

Debugging controls CPU execution state.

These are two completely different layers.

In professional embedded development, flashing and debugging are tightly connected but technically different layers. Flashing modifies non-volatile memory. Debugging controls the processor execution state.

To understand this properly, we must examine the hardware path from the PC to the CPU.

txt
PC (IDE / CLI Tool)
        |
        v
Debug Probe (J-Link / ST-Link / CMSIS-DAP)
        |
        v
Debug Interface (JTAG / SWD / UART)
        |
        v
MCU Debug Logic / Bootloader
        |
        v
Flash Controller
        |
        v
Internal Flash Memory


Flash Firmware

Flashing firmware means transferring a compiled binary image (.bin, .hex, .elf) into non-volatile memory (Flash) of the microcontroller so that it executes after reset.

Flashing can happen at different system layers:

  • Via Debug Interface (JTAG/SWD)
  • Via Bootloader (UART, USB, CAN)
  • Via Network (OTA)
  • Via External Programmer (Mass production)

The difference is who controls the flash controller.

JTAG (Joint Test Action Group):

is a standard that was originally developed for boundary-scan testing of digital circuits, JTAG typically uses a set of pins such as :

TDI (data input)

TDO (data output)

TMS (test mode select)

TCK (clock),

TRST (reset).

It provides full access to the microcontroller's internal resources and allows for sophisticated debugging, you typically need a JTAG programmer (such as a J-Link or ST-Link) connected to your development system and the target device.

The programmer allows you to access the microcontroller’s memory and load the firmware using appropriate software tools, such as OpenOCD or SEGGER J-Link tools.

SWD (Serial Wire Debug):

is an ARM-specific two-wire debugging protocol used to interact with ARM Cortex-M microcontrollers, SWD uses just two main data lines:

SWDIO (data input/output)

SWCLK (clock)—along

with optional RESET and GND lines.

Flashing with SWD is similar to JTAG but requires an SWD-compatible debug probe.

For ARM Cortex-M devices, tools like ST-Link, J-Link, or CMSIS-DAP can be used to interact with the SWD interface.

Most IDEs, such as Keil, Eclipse, or Visual Studio Code (with extensions like PlatformIO), support SWD for programming and debugging.

Let us examine each method deeply.


Flashing via Debug Interface (JTAG / SWD)

This is the most direct method during development.

txt
PC (IDE)
   |
   v
Debug Probe (J-Link / ST-Link / CMSIS-DAP)
   |
   v
SWD / JTAG
   |
   v
Debug Access Port (DAP)
   |
   v
Flash Controller
   |
   v
Internal Flash

When you press “Flash” in:

  • Visual Studio Code
  • Keil MDK
  • OpenOCD

The debugger:

  • Halts CPU
  • Unlocks flash controller
  • Erases sectors
  • Writes words to flash
  • Verifies CRC
  • Resets CPU

Advantages:

  • Full memory access
  • Fast flashing
  • Debug immediately after flash
  • No bootloader required

Disadvantages

  • Requires debug pins exposed
  • Not ideal for field updates
  • Debug port must be enabled (security risk)

Flashing via UART Bootloader

UART (Universal Asynchronous Receiver-Transmitter)

is a serial communication protocol primarily used for data transfer between devices, UART is useful for bootloader communication (where a bootloader over UART allows you to flash firmware) and for sending debug information from the MCU to an external terminal.

UART-based flashing is often performed using a bootloader that listens for a firmware file via a serial connection.

Many microcontrollers, particularly those from the ESP32 or STM32 families, support bootloaders that facilitate flashing over UART.

Tools like esptool.py for ESP32 and STM32CubeProgrammer for STM32 devices allow you to send a firmware image over a serial port and write it to flash. For devices like the ESP32, the flashing process involves putting the device into bootloader mode by manipulating the

IO0 or GPIO0 pins,

after which you can use a UART-to-USB adapter to send the firmware.

UART flashing is bootloader-level flashing.

The MCU contains:

  • ROM Bootloader (factory programmed)
  • OR

  • Custom Bootloader in flash

Example devices:

  • ESP32
  • STM32F4

Boot Flow

txt
Power ON
   |
   v
ROM Bootloader
   |
   +-- Check Boot Pins
   |
   +-- If Boot Mode → Listen on UART
   |
   +-- Receive Firmware
   |
   +-- Program Flash
   |
   +-- Reset

UART Flash Architecture

txt
PC (esptool.py / STM32CubeProgrammer)
      |
      | TX/RX Serial
      |
+----------------------+
|   Bootloader         |
|   Flash Controller   |
+----------+-----------+
           |
           v
         Flash

Tools:

  • esptool.py
  • STM32CubeProgrammer

Characteristics

  • Slower than SWD
  • Does not allow debugging
  • Simple wiring (TX, RX, GND)
  • Good for production flashing

USB Bootloader Flashing

Some MCUs include USB DFU (Device Firmware Upgrade).

Example:

  • STM32 DFU mode

Architecture:

txt
PC
 |
 | USB
 |
+------------------+
| USB Bootloader   |
| Flash Controller |
+--------+---------+
         |
         v
       Flash

Advantages:

  • Faster than UART
  • No external debugger required
  • User-friendly update

OTA (Over-The-Air) Flashing

OTA is modern firmware updating through network.

Used in:

  • IoT devices
  • Industrial gateways
  • Wi-Fi modules
  • BLE devices

Example:

  • ESP32

OTA Architecture

txt
Cloud Server
     |
     | HTTPS
     |
WiFi Router
     |
     v
Device (Running Firmware)
     |
     +-- Download New Image
     +-- Store in Secondary Partition
     +-- Verify Signature
     +-- Swap Boot Partition
     +-- Reset

Dual Partition Model

txt
+--------------------+
| Bootloader         |
+--------------------+
| App Partition A    |  <-- Running
+--------------------+
| App Partition B    |  <-- New image
+--------------------+

OTA Steps:

  • Download firmware
  • Validate checksum
  • Validate signature
  • Mark new partition active
  • Reset
  • Rollback if failure

Advantages

  • Remote update
  • No physical access required
  • Essential for IoT SaaS

Disadvantages

  • Requires secure boot
  • Needs partition planning
  • Power failure risk must be handled

External Production Programmer

Used in mass manufacturing.

Architecture:

txt
Gang Programmer
     |
     v
Multiple PCBs
     |
     v
Flash via SWD / JTAG / UART

Used when:

  • High production volume
  • Need speed optimization
  • Automated test fixtures

DEBUGGING TOOLS

Debugging is about controlling and observing the CPU while running firmware.

Debugging tools are divided into:

  • Hardware Debuggers
  • Software Debuggers

Hardware Debugging Tools

These physically connect to MCU debug pins.

Examples:

  • J-Link
  • ST-Link
  • CMSIS-DAP

Architecture:

txt
PC
 |
 | USB
 |
Debug Probe
 |
 | SWD / JTAG
 |
MCU Debug Access Port
 |
CPU

Capabilities

  • Halt CPU
  • Read/Write memory
  • Breakpoints
  • Watchpoints
  • Step execution
  • Reset control
  • Flash programming

Internal Debug Units (Cortex-M)

  • FPB (Flash Patch & Breakpoint)
  • DWT (Data Watchpoint & Trace)
  • ITM (Instrumentation Trace Macrocell)
  • ETM (Embedded Trace Macrocell)

Software Debugging Tools

Software tools interpret debug data and control execution.

Examples:

  • GDB
  • Visual Studio Code
  • Eclipse IDE
  • Keil MDK

txt
IDE
 |
 v
GDB
 |
 v
OpenOCD
 |
 v
SWD
 |
 v
MCU


Types of Debugging

Breakpoint Debugging

  • Stops CPU at specific instruction
  • Hardware or software breakpoint

txt
if(x == 5)   <-- Breakpoint here


Watchpoint Debugging

  • Trigger when memory address changes

txt
Watch variable: temperature  
Break when modified


Trace Debugging

  • Records instruction flow
  • Used for timing analysis
  • Requires ETM support

Serial Debug (printf Debugging)

Using UART:

cpp
printf("Value = %d\n", x);

Simple but:

  • Adds timing overhead
  • Not real-time safe
  • Cannot inspect registers
FeatureJTAGSWDUART
PurposeDebugging, testing, programmingDebugging, programming ARM Cortex-MSerial communication between devices
Pins10-20 pins4 pins (SWDIO, SWCLK, GND, RESET)2 main pins (TX, RX), optional GND/VCC
SpeedHigh speed, but more complexFaster than UART, simpler than JTAGLower speed, best for basic data transfer
ComplexityHigh (requires specific hardware and setup)Low to moderate (designed for ARM Cortex-M)Very low, simple communication
Use CaseLow-level access to MCU for debugging and testingEfficient debugging and programming for ARM devicesCommunication for peripherals, logging, or control