Boards

The STM32F411 Black Pill

A Cortex-M4 at 84 MHz with GPIO, timers, an ADC, USART1 and SysTick.

The overview, with examples running, is on the board page and The STM32F411 model (every register).

What it is

The WeAct MiniF4 "Black Pill", an STM32F411CEU6 running on our own Cortex-M core in its ARMv7-M profile with Thumb-2. The registers come from the manufacturer's reference manual and datasheet at their real addresses, so the same source cross-compiled against the vendor headers would work on silicon.

The clock is fixed: 84 MHz for the CPU, the bus and the timers, and 42 MHz on the slower peripheral bus. The same die on ST's Nucleo board runs at 100 MHz: the Nucleo-F411RE.

The pins

Two twenty-pin headers on a 0.1 inch pitch and a four-pin SWD header across the bottom edge, in the order of WeAct's own pinout diagram, with USB-C at the top.

Left header, top to bottom: PB12, PB13, PB14, PB15, PA8 to PA12, PA15, PB3 to PB9, then 5V, G and 3V3.

Right header, top to bottom: 5V, G, 3V3, PB10, PB2, PB1, PB0, PA7 down to PA0, R (NRST), PC15, PC14, PC13, and VB (VBAT) at the far end from the USB socket.

SWD header, left to right: 3V3, DIO (PA13), SCK (PA14), G. A board pushed into a breadboard does not plug these in, as the real header points up or is not fitted; wire to them directly.

The extra rails have their own names in a diagram, because every pin name is unique: the right row's are 5Vb, GNDc and 3V3b, the SWD header's are 3V3c and GNDb. All of them are the same rails.

A project saved before Mokxi drew the real order (late October 2026) has this board end for end, with VBAT beside the USB socket and PA13, PA14 and a ground folded into the left row. It opens that way, with its header setting on early, so a board in a breadboard keeps every pin in the hole it was in. Set header to board for the real order: wires to pins follow them, but a board sitting in a breadboard then reaches different holes.

PB11 is absent, because the 48-pin part does not bring it out. So port B is fifteen pins, not sixteen.

A pin here is a port and a number, not a board number: PA5, not 5. That catches people coming from an Arduino, and the learning path leads with it.

The LED is the other way around

PC13 carries the on-board blue LED with its anode to 3.3 V through 470 ohms and its cathode on the pin. It lights when PC13 is driven low. The board's first lesson is called "The LED that is on when the pin is low" for that reason.

What is modeled

GPIO, TIM1 to TIM5 and TIM10 in their counting and PWM modes, ADC1, USART1 and SysTick, plus enough of RCC to answer the register reads a program makes on the way up.

analogRead reads the ten ADC pins, PA0 to PA7, PB0 and PB1 (A0 to A9), in STM32duino's ten bits by default (0 to 1023 over 0 to 3.3 V); analogReadResolution(12) gives the converter's full twelve.

Every peripheral on a real STM32 starts with its clock switched off, and that is true here too: enabling the clock before touching a peripheral is part of the exercise, not a formality this model skips.

What is not

The clock tree and flash latency, DMA, USB, I2C, SPI, SDIO, the RTC, the watchdogs, TIM9 and TIM11, the CRC unit, low-power modes, the option bytes and flash programming. Their registers are unmapped, so touching one is a bus fault. The FPU is not modeled either: floats are computed in software, so they come out the same and take more cycles than on the chip.

The clock tree not being modeled cuts the other way too. The core runs at 84 MHz whatever RCC is programmed to, so a sketch that forgets to start the PLL keeps time here and runs five times slow on a real board. The 3V3 and 5V pins are ideal sources that cannot sag.

Input capture is not modeled. WFI and WFE park the core; deep sleep behaves as ordinary sleep.

Vendor stacks (the Cube HAL, libopencm3, the STM32duino core) are out of scope for the same reason the Pico SDK is: they bring up hardware that is not here.

The register tables are in the STM32F411 model.

Serial

USART1 carries the serial monitor. The full detail, including what happens when the receive queue overflows, is in the contract document.

Stock Arduino libraries

A tutorial that includes Servo.h, Wire.h, SPI.h, EEPROM.h, LiquidCrystal_I2C.h, Adafruit_GFX.h with Adafruit_SSD1306.h and DHT.h compiles here as it stands. Each is Mokxi's own header under the upstream name, written on the drivers for the parts in the bin, and none of it is the upstream library's code.

  • Wire.begin() puts the I2C bus on PB7 (SDA) and PB6 (SCL).
  • EEPROM.h works, but this board's model has no EEPROM or writable flash, so the bytes live in 4 KB of RAM: they read back within a Run and are gone at a reset.
  • Adafruit_NeoPixel.h stops with a message: a WS2812 bit is too short to make by hand on this board. The AVR boards, the ESP32s, the Pico and the Uno R4 drive the strip.

The code editor and compiling lists what each one covers and how it differs from the upstream library.

The examples

Blink, Button, Serial, Fade and Chaser.

Assembly

The Firmware panel also offers Assembly (no Arduino): a Blink, a Button to LED, a UART hello and a Timer interrupt in ARM Thumb-2 assembly for the Cortex-M4. The board's files become one main.S, and nothing but that file is linked, so it carries its own vector table: .word _estack, then Reset_Handler, then its handlers. The starters turn the clocks on in RCC_AHB1ENR, drive PC13, read PA0, print on USART1 on PA9 at 115200 and run SysTick at 1 kHz from the 84 MHz core. A .S tab beside an ordinary sketch works too. See Writing assembly.

Elsewhere