Skip to the content
PCBKitNew board
2 layers84 × 52 mmIR Programmer, the printed circuit board in 3D

A standalone, button-operated firmware programmer for STM32L0 microcontrollers, built on an STM32L073VBT. It stores a firmware image in its own flash and writes it to a target MCU over one of two links:

Size
84 × 52 mm
Copper layers
2
Thickness
1.6 mm
Parts
46
Nets
99
Pads
219
Tracks, vias
268, 58
Pours
181
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
29 Sep 2026
Updated
29 Sep 2026

Overview

IR Programmer is an open-source printed circuit board by ismaillgunes, from the ismaillgunes/IR_Programmer repository on GitHub. It is a 2-layer board of 84 × 52 mm with 46 parts on 99 nets, routed with 268 tracks and 58 vias.

It is built around the W25Q128JVPIQ, MMBT3904-TP and LTR-4206E. Its parts include 15 resistors, 13 capacitors, 4 connectors, 3 transistors and 3 switches. It belongs with the interfaces and adapters boards and the STM32 boards of this library.

Main components

3

README

README.md

IR_PROGRAMMER

A standalone, button-operated firmware programmer for STM32L0 microcontrollers, built on an STM32L073VBT. It stores a firmware image in its own flash and writes it to a target MCU over one of two links:

LinkButtonHow it worksNeeds a PC?Needs code on the target?
IR (infrared)SW3Talks to the target's built-in ROM bootloader (ST AN3155 USART protocol) through an IR LED / phototransistor pairNoNo
SWD (wired)SW1Bit-banged Serial Wire Debug: attaches to the core, halts it and programs the flash controller directlyNoNo

Press a button, wait for the beeps, and the next board is programmed. There is no PC, no debugger and no cable to the target on the IR path.

AI-generated code notice: This software was created with the help of AI (Claude Code by Anthropic). Review and test it on your own hardware before using it in production. See AI disclosure.


Why IR uses the target's internal bootloader

Every STM32 ships from the factory with a system bootloader in ROM ("system memory"). It is written by ST, it lives in a read-only area and it cannot be erased or overwritten. When the target starts from system memory, this bootloader listens on its USART and accepts the standard ST serial protocol described in AN3155. The protocol has commands to read the chip ID, erase flash, write memory and jump to the application.

This programmer uses that bootloader as the receiving end of the IR link. As a result:

  • The target needs no extra software. You do not have to flash a custom IR bootloader first, reserve flash space for one, or maintain one. A brand-new, blank STM32 can be programmed over IR straight from the factory.
  • Nothing on the target can "brick" the IR path. The ROM bootloader cannot be damaged by a bad application image, so you can always reflash over IR again.
  • The protocol is standard. The IR link carries the same bytes that STM32CubeProgrammer would send over a UART cable (8 data bits + even parity, 0x7F auto-baud, ACK 0x79 / NACK 0x1F). The IR hardware simply replaces the wire.

The target only needs hardware:

  1. An IR receiver/transmitter wired to one of the USART pins that its system bootloader listens on (see ST AN2606 for the pins of your exact part).
  2. A way to start the MCU in system memory boot mode. That usually means holding BOOT0 high (or configuring the equivalent option bytes) while power-cycling the target.

IR programming sequence

Once SW3 is pressed, the programmer runs the following steps (Program_Target() in firmware/Core/Src/main.c):

  1. Connect: sends 0x7F so the target bootloader can auto-detect the baud rate (115200 by default) and waits for ACK. Up to 5 attempts.
  2. Get ID (0x02): reads the target's product ID and writes it to the log.
  3. Erase (0x44, Extended Erase): erases only the pages the image occupies, in batches of 32 pages, the same way STM32CubeProgrammer does. A global mass erase is not used because some bootloader versions NACK it.
  4. Write (0x31, Write Memory): writes the image in 256-byte blocks starting at 0x08000000, with retries on every block.
  5. Go (0x21): jumps to the new application. There is no reset line on the IR link, so this command starts the firmware.

Each step retries on its own, so a weak or noisy IR link still gets through.


SWD programming

The SWD path is for wired production or bench use. It needs a 3-wire connection (SWCLK, SWDIO, NRST) plus GND. Pressing SW1 runs Program_Target_SWD():

  1. Pulses NRST, switches the target's debug port from JTAG to SWD and reads the DP IDCODE. It expects 0x0BC11477 (Cortex-M0+ SW-DP).
  2. Powers up the debug domain, sets up the AHB-AP and halts the core.
  3. Unlocks the flash controller (PECR), erases the affected 128-byte pages and programs the image in 64-byte half-page bursts for speed.
  4. Reads the whole image back and compares it with the source (verify).
  5. Pulses NRST and releases the SWD pins so the new firmware runs.

The driver in firmware/SWD/src/swd.c does not depend on the HAL. It drives the GPIO registers directly and can be reused in other projects.


Hardware

Programmer MCU: STM32L073VBT (LQFP100), running on HSI16 at 16 MHz. No external crystal is needed.

FunctionPinNotes
IR TX (LPUART1_TX)PD8Drives the IR LED cathode. Idle HIGH = LED off
IR RX (LPUART1_RX)PD9Phototransistor → transistor stage. Idle HIGH
SWD SWCLKPA2Connector J1
SWD SWDIOPA1Connector J1
SWD NRSTPA0Connector J1, open-drain
Log TX (USART1_TX)PB6Connector J3, 115200 8N1
Log RX (USART1_RX)PB7Connector J3
Button SW1 (start SWD)PC3Active HIGH
Button SW3 (start IR)PA12Active HIGH
BuzzerPD12Active HIGH, drives transistor Q3
W25Q128 CS / RESETPA4 / PC4External SPI flash. Held inactive; not used by this firmware

The SWD pins stay high-impedance (analog) until an SWD cycle starts, so the programmer does not disturb a target left connected to it.

PCB

IR_PROGRAMMER PCB, 3D view

The schematic and PCB layout are in hardware/ as a KiCad project. Open hardware/IR_Programmer.kicad_pro in KiCad to view or edit them, or to generate Gerber and BOM files for manufacturing.


Usage

  1. Power the programmer. One short beep means it is ready.
  2. IR: put the target in bootloader mode (BOOT0 high + power-cycle), point the IR windows at each other and press SW3. SWD: connect J1 to the target and press SW1.
  3. One short beep marks the start. While programming runs, a short beep repeats about once per second.
  4. Result:
    • Two short beeps: success.
    • One long beep followed by N short beeps: error code N (see the table below).
  5. Press the button again to program the next board or to retry. Button presses made while programming is in progress are ignored.

Error codes

BeepsLinkMeaning
1IRNo reply to 0x7F. The target is not in bootloader mode, the IR link is misaligned, or the baud rate is wrong
2IRGet ID failed
3IRErase failed
4IRWrite failed
5SWDAttach failed (no IDCODE, wrong chip, or the core could not be halted)
6SWDFlash unlock failed
7SWDErase/program failed
8SWDVerify mismatch

Connect a USB-UART adapter to J3 (115200 8N1) to see a step-by-step log of every cycle, including the target ID, progress and the reason for any failure.


Loading your own firmware image

The image to be programmed is compiled into the programmer as a C array in firmware/Core/Inc/fw_image.h:

c
static const uint8_t fw_data[] = { 0x00, 0x50, 0x00, 0x20, /* ... */ };
static const uint32_t fw_size = sizeof(fw_data);

The repository ships with a 3-byte placeholder. To use your own firmware:

  1. Build your target application and export a raw binary (.bin) that starts at 0x08000000.
  2. Convert it to a C array, for example:
    bash
    xxd -i -n fw_data app.bin > fw_array.txt
    Paste the array into fw_image.h and keep the fw_data / fw_size names.
  3. Rebuild and flash the programmer.

Both the IR and SWD paths use the same image. The image has to fit in the programmer's own flash (128 KB on the STM32L073VB) next to the programmer firmware (about 24 KB).


Configuration

These settings are at the top of firmware/Core/Src/main.c:

MacroDefaultPurpose
IR_BAUDRATE115200IR link speed. Try 57600 or 38400 if the link is marginal. After changing it, power-cycle the target, because the bootloader locks onto the first baud rate it sees
TARGET_FLASH_BASE0x08000000Address the image is written to
SWD_CLK_DELAY0SWD half-period delay. Increase it to 2–6 on long or noisy cables if you see parity, ACK or verify errors

Building

  • IDE: Keil MDK 5 (ARM Compiler 6). Open firmware/MDK-ARM/IR_PROGRAMMER.uvprojx.
  • A post-build step also creates firmware/MDK-ARM/IR_PROGRAMMER.bin.
  • MDK-Lite limitation: the free MDK-Lite edition cannot link images larger than 32 KB. With a real firmware image embedded in fw_image.h you will probably go over that limit. In that case, use a licensed MDK (the free MDK Community or MDK for STM32 licenses also work) or port the project to STM32CubeIDE / GCC.
  • STM32CubeMX: firmware/IR_PROGRAMMER.ioc matches the code and can be regenerated safely. All custom code is kept inside USER CODE BEGIN/END blocks. When you edit generated files, keep your changes inside those blocks, or CubeMX will overwrite them.

Project layout

text
firmware/
  Core/
    Inc/fw_image.h      firmware image to be programmed (placeholder)
    Inc/sys_conf.h      software version
    Src/main.c          IR bootloader client, SWD flow, buttons, buzzer, log
  SWD/
    inc/swd.h           SWD driver API and pin configuration
    src/swd.c           bit-bang SWD + STM32L0 flash programming
  Drivers/              STM32L0 HAL and CMSIS (from ST)
  MDK-ARM/              Keil project
  IR_PROGRAMMER.ioc     STM32CubeMX configuration
hardware/
  IR_Programmer.kicad_pro   KiCad project
  IR_Programmer.kicad_sch   schematic
  IR_Programmer.kicad_pcb   PCB layout
docs/
  pcb_3d.png            3D render of the board

Limitations

  • Target family: the SWD flash routines (PECR registers, 128-byte pages, 64-byte half-page programming) and the IR erase page size are written for the STM32L0 series. Other STM32 families need changes to swd.c and TARGET_PAGE_SIZE.
  • Read-out protection: the target must be at RDP level 0. A protected device rejects the bootloader's write commands and blocks SWD memory access.
  • No IR verify: the IR path relies on the bootloader's per-block ACK and does not read the image back. The SWD path does verify.
  • Target boot mode: there is no BOOT0 or reset line on the IR link. The target must already be in bootloader mode when you press SW3.

AI disclosure

This project was developed with the help of AI (Claude Code by Anthropic). The AI was used for:

  • writing the firmware source code (the IR bootloader client, the SWD driver and the application logic),
  • reviewing and cleaning up the code,
  • writing this documentation.

The code is provided as-is (see LICENSE). AI-generated code can contain mistakes that are hard to spot, so review the source and test it on your own hardware before relying on it, especially if you change the target family, the flash layout or the timing settings. Bug reports and pull requests are welcome.


License

The original code of this project is released under the MIT License. The bundled ST HAL (BSD-3-Clause) and CMSIS (Apache-2.0) files under firmware/Drivers/ keep their own licenses.


References

  • ST AN3155: USART protocol used in the STM32 bootloader
  • ST AN2606: STM32 microcontroller system memory boot mode (bootloader pins per device)
  • ST RM0367: STM32L0x3 reference manual (flash PECR programming)
  • Arm ADIv5: Debug Interface Architecture Specification (SWD protocol)

Parts

46
QtyValueFootprintReferences
910KResistor_SMD:R_0603_1608MetricR1, R2, R3, R5, R6, R8, R10, R13, R15
8100nFCapacitor_SMD:C_0603_1608MetricC3, C6, C7, C9, C10, C11, C13, C15
4CCapacitor_SMD:C_0603_1608MetricC1, C2, C4, C5
4MountingHoleMountingHole:MountingHole_3.5mm_PadH1, H2, H3, H4
2DS1042-03-1-8-KKR-160-10DS1042-03-1-8-KKR-160-10:DS1042-03-1-8-KKR-160-10SW1, SW3
2MMBT3904-TPPackage_TO_SOT_SMD:SOT-23-3Q2, Q3
1100RResistor_SMD:R_0603_1608MetricR9
110KRC0603FR-0710KL:RESC1607X60NR4
11KResistor_SMD:R_0603_1608MetricR12
11uFCapacitor_SMD:C_0603_1608MetricC14
122035025SmartCapLib:MOLEX_22035025J2
1220RResistor_SMD:R_0603_1608MetricR7
14.7KResistor_SMD:R_0603_1608MetricR14
1BuzzerBuzzer_Beeper:Buzzer_12x9.5RM7.6BZ1
1Conn_02x04_Odd_EvenConnector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_VerticalJ3
1Conn_02x05_Odd_EvenConnector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_VerticalJ1
1DS1042-07-1-1KRR16008DS1042-07-1-1KRR16008:SW_TS24-62-14-BL-200-SMT-TR-67SW2
1LEDDiode_THT:D_T-1_P2.54mm_Vertical_AnodeUpD1
1LTR-4206EDiode_THT:D_T-1_P2.54mm_Vertical_AnodeUpQ1
1PROGRAMMING_1X6Programming Connection:Programming ConnectionP1
1RResistor_SMD:R_0603_1608MetricR11
1STM32L073VBTxPackage_QFP:LQFP-100_14x14mm_P0.5mmU1
1W25Q128JVPIQMotorPilotLib:W25Q128JVPIQU2

Questions

How big is the IR Programmer PCB?

It measures 84 × 52 mm and has 2 copper layers, 1.6 mm thick.

What parts does the IR Programmer use?

46 parts, built around the W25Q128JVPIQ, MMBT3904-TP and LTR-4206E. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the IR Programmer KiCad files?

From the ismaillgunes/IR_Programmer repository on GitHub, at the commit this page was made from: the board is hardware/IR_Programmer.kicad_pcb and its schematic hardware/IR_Programmer.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the IR Programmer design in my own project?

Its repository states no licence, so its author keeps all rights: ask ismaillgunes before reusing the design.

Similar boards

  • 2 layers50 × 53 mmMicromouse, the printed circuit board in 3D

    Micromouse

    mmaakkyyii/Micromouse

    92 parts1MIT
  • 2 layers88.9 × 76.2 mmCHRP400, the printed circuit board in 3D

    CHRP400

    mirobotech/CHRP400

    CHRP4 (Common Hardware Robotics Project 4, rev. 0) KiCad schematic and PCB design files.

    78 partsMIT
  • 4 layers113.4 × 73 mmSUB-00156 REV00, the printed circuit board in 3D

    SUB-00156 REV00

    bcdevices/example-projects

    PCBA files to test with

    153 parts
  • 2 layers368.3 × 254 mmSMD500, the printed circuit board in 3D

    SMD500

    amigalisa/Amiga-SMD-500

    An SMD verson of the great Amiga 500

    606 parts69CERN-OHL-S-2.0
  • 2 layers40.6 × 108 mmUseq1, the printed circuit board in 3D

    Useq1

    Emute-Lab-Instruments/uSEQ

    Hardware & firmware of the uSEQ Live Coding CV & Gate Sequencer

    172 parts44
  • 2 layers236.8 × 129.1 mmCoCoTANG, the printed circuit board in 3D

    CoCoTANG

    lfantoniosi/CoCoTANG

    CoCoTANG upgrades the Radio Shack/Tandy Color Computer with a Tang Nano 20K FPGA board and CoCo 3 video and memory features.

    127 parts12
  • 4 layers100 × 120 mmPanoptes, the printed circuit board in 3D

    Panoptes

    jjCSE113NMT/dsp-neutron-spectrometer

    A place to keep all our material related to our senior design project.

    111 parts3
  • 2 layers124.5 × 129.5 mmSynth psoc, the printed circuit board in 3D

    Synth psoc

    pmusgrave/synth_psoc

    A drone synthesizer

    250 parts1