What's Actually on the Board
The Blue Pill looks like an Arduino Nano -- similar footprint, similar two-row header layout, similar "just wire it up" first impression. It isn't one. It runs at 3.3V, several of its pins carry restrictions the silkscreen never mentions, and the board itself is among the most commonly cloned pieces of hardware in the hobbyist supply chain. None of that makes it a bad choice -- at $2-3 for a 72MHz ARM Cortex-M3 with two ADCs, three USARTs, and a genuine hardware debug interface, it remains one of the best value boards available. It does mean the pinout needs to be understood correctly before wiring anything to it, because the assumptions that work on 5V AVR boards don't carry over.
The "Blue Pill" name refers to the board, not the chip. The chip is an STM32F103C8T6 -- a 72MHz ARM Cortex-M3 with 64KB of flash (nominally) and 20KB of SRAM. The board itself is a low-cost breakout for that chip, manufactured by a large number of different factories with inconsistent quality control.
Physically, the board carries two header rows, a USB Mini/Micro-B connector (power only -- it is not natively used for programming), a reset button, and a 4-pin header labeled SWD for hardware debugging via an ST-Link probe. A jumper block near the USB port selects BOOT0 and BOOT1 -- leave BOOT0 low for normal operation.
The chip operates at 3.3V logic, and the board is not universally 5V tolerant. Most GPIO pins on the STM32F103 are marked "FT" (5V-tolerant) in the datasheet, but not all -- PA11 and PA12 (adjacent to the USB interface) are not 5V tolerant, and neither are pins actively configured as ADC inputs while in analog mode. The safe working assumption is 3.3V logic throughout.
Power Pins
| Pin | Function | Notes |
|---|---|---|
| 5V | 5V in | From USB or external supply |
| 3V3 | 3.3V out | From onboard regulator |
| GND | Ground | Present on both headers |
| VB (VBAT) | Backup domain power (RTC) | Tie to 3V3 if unused |
The right header carries the same physical GPIO signals as the left header, broken out a second time on the opposite edge -- a deliberate layout choice so you can route to whichever side is physically closer, not a documentation error. Clone boards from different manufacturers occasionally shuffle which side a given pin lands on, so confirm against your specific board's silkscreen before wiring anything for the first time.
Board quality note: the onboard regulator (typically silkscreened AMS1117 or a clone) is sometimes underspec or counterfeit. Brownout resets when powering anything current-hungry off the 3V3 pin point toward this -- feeding 3.3V directly from a bench supply, bypassing the onboard regulator, is a quick way to confirm.
GPIO Pins and Naming
STM32 pins are named by port letter + number (PA0, PB6, PC13...) rather than a flat sequential number like an Arduino. Every pin below is on Port A, B, or C.
| Pin | Alternate Functions | Notes |
|---|---|---|
| PC13 | GPIO / onboard LED | Active LOW, shared with GPIO, limited current sink |
| PC14 | GPIO / OSC32_IN | 32.768kHz crystal, if fitted |
| PC15 | GPIO / OSC32_OUT | 32.768kHz crystal, if fitted |
| PA0–PA7 | GPIO / ADC1 channels 0–7 / TIM2-3 | See ADC and PWM sections |
| PB0, PB1 | GPIO / ADC1 channels 8–9 / TIM3 | |
| PB3–PB5, PB8, PB9 | GPIO, general-purpose | No ADC, no fixed peripheral role |
| PA9, PA10 | GPIO / USART1 | 5V tolerant -- see Communication Pins |
| PA11, PA12 | GPIO / USB D-/D+ | Not 5V tolerant |
| PB6, PB7 | GPIO / I2C1 | See Communication Pins |
| PB10, PB11 | GPIO / I2C2 or USART3 | Shared -- one or the other, not both |
PC13 and the Inverted LED
A standard blink routine on most microcontroller platforms turns an LED on with a HIGH signal. On the Blue Pill, the onboard LED on PC13 is wired active LOW -- a HIGH signal turns it off.
#define LED_PIN PC13
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, LOW); // LED ON
delay(500);
digitalWrite(LED_PIN, HIGH); // LED OFF
delay(500);
}
This single detail accounts for more "the board isn't working" reports than any other issue with this platform -- an inverted blink at a glance looks identical to a stuck-on LED. PC13 also shares its power domain with the RTC backup registers and can only sink a modest current cleanly; fine for an LED, not for driving anything with meaningful current draw.
Communication Pins
UART / USART
Three hardware USARTs are available:
| Bus | Pins (TX / RX) | Notes |
|---|---|---|
| USART1 | PA9 / PA10 | 5V tolerant -- most common for serial debug, allows direct connection to 5V TTL devices |
| USART2 | PA2 / PA3 | Shares pins with ADC1 channels 2/3 |
| USART3 | PB10 / PB11 | Conflicts with I2C2 -- see I2C below |
PA9/PA10 being 5V tolerant is a practical advantage -- certain GPS or Bluetooth modules can connect directly without a level shifter. That tolerance is specific to these two pins and shouldn't be assumed elsewhere.
SPI
| Bus | NSS / SCK / MISO / MOSI | Notes |
|---|---|---|
| SPI1 | PA4 / PA5 / PA6 / PA7 | Primary SPI bus |
| SPI2 | PB12 / PB13 / PB14 / PB15 | Secondary SPI bus |
I2C
| Bus | SCL / SDA | Notes |
|---|---|---|
| I2C1 | PB6 / PB7 | Primary I2C bus |
| I2C2 | PB10 / PB11 | Conflicts with USART3 -- physically the same pins, pick one or the other |
The chip's AFIO remap registers allow partial remapping on several peripherals if the default pins are unavailable, though most projects at this level won't need it. CAN and USB also share PA11/PA12 -- a project needing both simultaneously needs a different STM32 variant with more pins (an STM32F103RB on a Nucleo, for instance).
#include <Wire.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme;
void setup() {
Serial.begin(115200);
Wire.begin(); // Defaults to PB6 (SCL), PB7 (SDA) on Blue Pill
if (!bme.begin(0x76)) {
Serial.println("BME280 not found -- check wiring and I2C address");
while (1) delay(10);
}
}
void loop() {
Serial.printf("Temp: %.2f C Humidity: %.1f%% Pressure: %.1f hPa\n",
bme.readTemperature(), bme.readHumidity(), bme.readPressure() / 100.0F);
delay(1000);
}
Wiring for the example above: BME280 VCC to 3V3, GND to GND, SCL to PB6, SDA to PB7. The library API is identical to what the same sensor uses on an ESP32 or Arduino -- only the physical pins differ.
ADC Pins
The STM32F103C8T6 carries two 12-bit ADCs (ADC1 and ADC2), both wired on the Blue Pill to the same physical pins -- PA0 through PA7, plus PB0 and PB1. That's up to 10 analog input channels, more than double what most equivalently-priced boards offer.
void setup() {
Serial.begin(115200);
}
void loop() {
int raw = analogRead(PA0); // 12-bit, 0-4095
float voltage = raw * (3.3 / 4095.0);
Serial.printf("Raw: %d Voltage: %.3fV\n", raw, voltage);
delay(200);
}
Two details matter when porting code from 8-bit AVR platforms: resolution is 12-bit (0–4095), not 10-bit (0–1023), and the reference voltage is 3.3V, not 5V -- a sensor outputting 0–5V will clip against the ADC's usable input range, or on a non-tolerant pin, exceed its rated input entirely.
PWM and Timers
Four general-purpose timers (TIM2, TIM3, TIM4) plus one advanced-control timer (TIM1) provide PWM output across most GPIO pins listed above. With the Arduino core for STM32 (STM32duino), the timer mapping rarely needs direct tracking:
#define PWM_PIN PA6
void setup() {
pinMode(PWM_PIN, PWM);
}
void loop() {
for (int duty = 0; duty <= 255; duty++) {
pwmWrite(PWM_PIN, duty);
delay(5);
}
}
It matters when two PWM signals need to stay in phase -- driving a bridge circuit or a stepper motor. Two channels on the same timer (PA6 and PA7, both TIM3, for example) share a counter and prescaler and stay phase-locked by construction; channels on different timers can drift unless explicitly synchronized.
Board-Specific Pins: Boot Mode and SWD
Two methods exist for loading code onto this board.
SWD via ST-Link (the standard approach). Four wires -- 3.3V, GND, SWDIO, SWCLK -- from an ST-Link V2 (or clone) to the board's 4-pin SWD header:
ST-Link V2 Blue Pill
3.3V → 3V3
GND → GND
SWDIO → DIO
SWCLK → CLK
Flashing over SWD works directly through PlatformIO, STM32CubeIDE, or the Arduino IDE (STM32CubeProgrammer upload method). BOOT0 stays LOW throughout -- no jumper changes between flashing and running.
UART bootloader (the alternate method). A USB-to-serial adapter wired to PA9/PA10, with BOOT0 pulled HIGH before power-on to force the built-in serial bootloader. Flashing uses the Arduino IDE's "STM32duino bootloader" method or stm32flash. BOOT0 must return to LOW before the next reset to run the uploaded program -- forgetting this leaves the chip re-entering bootloader mode on every reset, which looks identical to a dead board to anyone unfamiliar with the mechanism.
Common Mistakes and How to Avoid Them
Assuming 5V tolerance across the board. Most pins are FT-rated, but PA11, PA12, and any pin actively in ADC mode are not. A level shifter is the safe default when uncertain.
Reading the inverted PC13 LED as a dead board. HIGH is off, LOW is on -- this single detail accounts for a large share of "the board doesn't work" reports.
Forgetting to return BOOT0 to LOW after UART flashing. The board isn't broken -- it's still in bootloader mode.
Wiring a 5V sensor's data line directly to a non-tolerant pin. Confirm the FT rating for the specific pin before connecting anything not purpose-designed for 3.3V.
Mislabeled flash size on clone boards. Some boards silkscreened "STM32F103C8T6" (64KB flash) carry the cheaper 32KB die in the same package. An upload failing partway on a sketch that should fit comfortably warrants checking actual flash size via SWD or your upload tool.
Trusting a pinout reference without checking the board's own silkscreen. Clone hardware varies -- these tables reflect the common layout, not a universal one across unauthorized clone manufacturing.
Summary: Blue Pill Pin Reference at a Glance
STM32 Blue Pill · STM32F103C8T6 · Cortex-M3 @ 72MHz · 64KB Flash (nominal) · 20KB SRAM · 2× 12-bit ADC (10 channels) · 3× USART · 2× SPI · 2× I2C · SWD debug
The Blue Pill rewards a modest amount of upfront reference-checking more than most boards at this price point. Once the 3.3V logic requirement, the inverted LED, the shared I2C2/USART3 pins, and the SWD-versus-bootloader flashing distinction are accounted for, it stops being a source of confusion and becomes one of the better-value microcontrollers available.
Quick Answers to Common Blue Pill Pin Questions
Is the Blue Pill 5V tolerant? Most GPIO pins are FT-rated and tolerate 5V signals, but PA11, PA12, and any pin in active ADC mode are not. Treat the board as 3.3V-only unless you've confirmed a specific pin's FT rating.
Why won't my LED blink code work? If it's wired to PC13, the onboard LED, remember it's active LOW -- your code is probably running correctly, just inverted from what you expect.
Can I use I2C2 and a third serial port at the same time? No -- I2C2 and USART3 share the same physical pins (PB10/PB11) on this chip. Pick one, or use AFIO remapping if your project needs both.
My board won't boot after flashing over UART -- is it broken? Almost certainly BOOT0 is still HIGH. Set it back to LOW and reset.
Why does my board's flash upload fail partway through? Check the actual flash size -- some clone boards silkscreened as 64KB parts carry a 32KB die.
Where to Go From Here
Once the 3.3V logic and the inverted PC13 LED stop being surprises, STM32's low-power modes — Sleep, Stop, and Standby — are the natural next thing to explore for any battery-powered project on this board. From there, the SWD-versus-bootloader flashing distinction covered above becomes the deciding factor in whether STM32 development feels closer to Arduino or to a full embedded toolchain, which is worth weighing before committing a project to this platform over something like the Arduino Uno.