本文へ移動
cccskills
無料GitHub で公開

stm32f401rc-blackpill

Firmware development for the 40-pin "Black Pill"-format board with an STM32F401RCT6 (STM32F401RC, LQFP64, 256 KB flash, 64 KB RAM, 84 MHz) that ships with the WeAct Studio HID Bootloader (USB 0483:572A, flash 0x08000000-0x08003FFF, app at 0x08004000) — its PC13 LED, KEY button on PA0, 25 MHz HSE, USB-C on USB_OTG_FS, and the PlatformIO + STM32Cube HAL setup around them, including a USB CDC virtual COM port for printf debugging. Use when working on this board, an unbranded F401RCT6 Black Pill clone, or any STM32F401/F411 board that enumerates as "WeAct Studio HID Bootloader": project setup, platformio.ini, linking at 0x08004000, flashing through the HID bootloader or ROM DFU, the app starting behind a bootloader (VTOR, SysTick, clock hand-off), clock/PLL configuration for 84 MHz plus 48 MHz USB, printf/serial console over USB (no /dev/cu or COM port), a blink that never starts or hangs in HAL_Delay, entering or recovering the bootloader, or debugging why something on the board does not work.

インストール方法を見る

含まれるファイル(23)

  • SKILL.md14.1 KB
  • assets/IMAGE.md87 B
  • reference/board-hardware.md20.9 KB
  • reference/recipes.md15.9 KB
  • template/.gitignore107 B
  • template/include/board.h1.3 KB
  • template/include/usb_device.h244 B
  • template/include/usbd_cdc_if.h1.0 KB
  • template/include/usbd_conf.h1.0 KB
  • template/include/usbd_desc.h137 B
  • template/ld/STM32F401RCTX_APP_0x08004000.ld5.2 KB
  • template/platformio.ini2.1 KB
  • template/README.md5.7 KB
  • template/scripts/hid_upload.py1.1 KB
  • template/scripts/weact_hid_flash.py8.0 KB
  • template/src/boot_handoff.c2.3 KB
  • template/src/main.c9.3 KB
  • template/src/usb_device.c583 B
  • template/src/usbd_cdc_if.c5.4 KB
  • template/src/usbd_conf.c8.0 KB
  • template/src/usbd_desc.c5.0 KB
  • template/variants/minimal/main.c4.3 KB
  • template/variants/new-project.sh1.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

STM32F401RCT6 "Black Pill" with the WeAct HID bootloader

Board-specific firmware knowledge. The board's defining feature is not the chip but what sits in the first 16 KB of its flash: WeAct's HID bootloader. Almost every failure on this board comes from code that assumes it owns 0x08000000 and a freshly reset chip — neither is true here. Read the reference files rather than guessing.

  • reference/board-hardware.md — the hardware (MCU, pins, header, clocks, memory map with the bootloader), a full description of the bootloader's behaviour and protocol, PlatformIO configuration, flashing and recovery routes, and a symptom → cause → fix table (§9).
  • reference/recipes.md — copy-paste code taken from template/: platformio.ini, the linker-script change, the hand-off Reset_Handler, the 84/48 MHz clock tree, the USB CDC console, the flasher, bootloader reinstall.
  • template/ — a working PlatformIO project: blink + USB CDC printf console, flashed over USB through the HID bootloader without touching a button, plus a scaffold script that can also produce a bare blink. See template/README.md.

Orientation

MCUSTM32F401RCT6 — Cortex-M4F, 84 MHz max, 256 KB flash, 64 KB SRAM, LQFP64. DEVID 0x423 (same die as the F401CC)
Board40-pin (2 × 20) Black Pill footprint, unbranded clone, USB-C, NRST + BOOT0 + KEY buttons
BootloaderWeAct Studio HID Bootloader V1.2 in sector 0, enumerates as HID 0483:572A, driverless
Flash map0x08000000 bootloader (16 KB, UID lock at 0x08003A28) · 0x08004000 app (240 KB)
CrystalsHSE 25 MHz (proven: the bootloader's PLLM=25 USB enumerates); LSE 32.768 kHz expected, untested
Working clock treePLL M25/N336/P4/Q7 → SYSCLK 84, HCLK 84, PCLK1 42, PCLK2 84, USB 48, FLASH_LATENCY_2, VOS Scale 2
LEDPC13, toggling verified; LOW = lit per WeAct convention (polarity not measured)
KEYPA0, pressed = LOW, needs GPIO_PULLUP — verified
USBUSB-C → USB_OTG_FS PA11/PA12. No USB-serial chip — a COM port exists only while firmware with a USB stack runs
DebugSWD on PA13/PA14 (4-pin header on most Black Pill boards)

Rules that prevent the expensive mistakes

  1. Link for 0x08004000 whenever the HID bootloader stays on the chip: board_build.ldscript = ld/STM32F401RCTX_APP_0x08004000.ld (ST's script with FLASH ORIGIN = 0x8004000, LENGTH = 240K). The bootloader writes whatever it receives to 0x08004000 regardless of how it was linked; a 0x08000000-linked image is accepted, written, and then jumps into the middle of the bootloader. scripts/weact_hid_flash.py refuses such an image.
  2. Replace Reset_Handler, do not just set VTOR in main(). The bootloader jumps to the app with VTOR still 0x08000000 — its own vector table — and interrupts unmasked. After HAL_Init() every SysTick lands in the bootloader's handler, which increments its uwTick (some random word of your RAM), so HAL_GetTick() never moves and the first HAL_Delay() hangs. V1.1 bootloaders also jump with SysTick already running, which corrupts .data/.bss during start-up. src/boot_handoff.c masks IRQs, stops SysTick, sets SCB->VTOR = g_pfnVectors, and only then copies .data / zeroes .bss. ST's startup declares Reset_Handler weak, so this simply overrides it.
  3. -DUSER_VECT_TAB_ADDRESS -DVECT_TAB_OFFSET=0x4000 does not work with framework = stm32cube — it makes things worse. The framework's system_stm32f4xx.c #defines VECT_TAB_OFFSET 0x00000000U unconditionally, so the file wins (one "redefined" warning), and SystemInit() then actively writes VTOR = 0x08000000 — verified in the disassembly. Rule 2 is the fix, and its VTOR write comes after SystemInit() for exactly this reason.
  4. HAL_RCC_DeInit() first in SystemClock_Config(). V1.2 jumps before touching the clocks (the app starts on HSI), but V1.1 — still found on boards — hands over with HSE + PLL already driving SYSCLK, and HAL_RCC_OscConfig() returns HAL_ERROR for any PLL setting that differs from the running one (M25/N336/P4/Q7). One line makes the clock code independent of which bootloader, or none, ran before it.
  5. Never upload_protocol = hid. PlatformIO's hid is Serasidis' hid-flash, which looks for 1209:BEBA and never finds this bootloader (0483:572A). The coreboard_f401rc board definition even lists hid — another reason the template uses genericSTM32F401RC. Use upload_protocol = custom + extra_scripts = scripts/hid_upload.py as in the template.
  6. ROM DFU and ST-Link write 0x08000000 and erase the HID bootloader, and never restore it from a dump of another board: the bootloader keeps this chip's UID at 0x08003A28 and, on a mismatch, copies itself to RAM and mass-erases the entire flash (V1.2 disassembly). Restore with WeAct's official V1.2 .hex, whose UID slot is blank — reference/recipes.md §7.
  7. Define SysTick_Handler() (HAL_IncTick()). framework-stm32cube ships no stm32f4xx_it.c; the weak default is an infinite loop and the board hangs in the first HAL_Delay() — which, behind this bootloader, looks exactly like rule 2.
  8. 84 MHz, Scale 2, two wait states, PCLK1 ≤ 42 MHz. This is an F401, not an F411: 96/100 MHz configurations copied from F411 Black Pill code overclock it, and PWR_REGULATOR_VOLTAGE_SCALE1 is not an F401 range (VOS=11 is reserved and behaves as Scale 2).
  9. -DHSE_VALUE=25000000 in build_flags. The F4 HAL template defaults to 25 MHz by luck; a CubeMX stm32f4xx_hal_conf.h from an 8 MHz board silently skews every baud rate and timer by 3.125×.
  10. KEY on PA0 needs GPIO_PULLUP, and holding it through a reset is the bootloader entry. A design that pulls PA0 low (a sensor on PA0, a pressed key at power-up) boots into the bootloader instead of your app.
  11. The temperature sensor is ADC_IN16 on the F401 (ADC_IN18 on the F411). Use ADC_CHANNEL_TEMPSENSOR, which the HAL maps per part, and ADC_SAMPLETIME_480CYCLES.
  12. Pins that exist on this chip are not necessarily on the header. The LQFP64 die has PC0–PC12 and PD2, but a 40-pin Black Pill layout only routes the 48-pin chip's set. PB11 does not exist on the F401 LQFP64 at all (VCAP_1). Read the silkscreen before picking a pin.
  13. No serial port unless the firmware makes one. The USB-C goes straight to the MCU, so /dev/cu.usbmodem* / ttyACM* / COMx appears only while firmware with USB CDC runs. The HID bootloader, ROM DFU and a firmware without USB show none — not a driver problem. For debug output use the template's CDC console (printf), or SWD.

When the task is "flash it"

pio run -t upload. With the template firmware running, that is all: the flasher (scripts/weact_hid_flash.py) opens the board's CDC port at 1200 baud, the firmware reboots into the bootloader, and the upload prints the bootloader's reply (V1.2 0x423 ROM: 256KB), writes 1 KB pages and reboots into the new app — verified, ~2.6 s, no buttons.

When nothing is listening on CDC (blank chip, the minimal blink, crashed or foreign firmware), the flasher asks for the manual entry and waits 30 s:

  1. Hold KEY, tap NRST, keep KEY held — PC13 flickers fast while KEY is down. Release. PC13 "breathes"; the board enumerates as 0483:572A "WeAct Studio HID Bootloader".
  2. The waiting upload continues by itself.

The bootloader also stays resident by itself when 0x08004000 holds no valid vector table (blank or erased app) — that is why a brand-new board shows up as HID with no button presses. python scripts/weact_hid_flash.py --info asks the bootloader for version, DEVID and flash size without writing anything: the quickest way to identify the die on an unknown board.

First upload installs the hidapi package into PlatformIO's Python (scripts/hid_upload.py). On Linux hidapi needs a udev rule for 0483:572A — reference/board-hardware.md §8.3.

Starting a new project

Do not hand-assemble one — the linker script, the Reset_Handler and the uploader have to agree. Scaffold from template/:

~/.claude/skills/stm32f401rc-blackpill/template/variants/new-project.sh <target-dir>            # full
~/.claude/skills/stm32f401rc-blackpill/template/variants/new-project.sh <target-dir> --minimal  # blink only
cd <target-dir> && pio run && pio run -t upload
variantwhat it isflash / RAM
--full (default)blink + USB CDC console: printf to the USB port, banner, 1 s heartbeat, KEY events, echo, commands; reboots into the bootloader on a 1200-baud open, so re-flashing needs no buttons20408 B / 4424 B
--minimalPC13 at 2 Hz, 10 Hz while KEY is held; no USB — every upload needs KEY + NRST3896 B / 44 B

Both use 84 MHz from the crystal and build with zero warnings under -Wall (PlatformIO ststm32 19.7.1, framework-stm32cubef4 1.28.1). Default to --full: the console is the board's only debug output without a probe. Three environments share one source tree:

envlinks atflashes viabootloader afterwards
hid (default)0x08004000USB, HID bootloader, custom uploaderkept
dfu0x08000000ROM DFU: hold BOOT0, tap NRST → 0483:DF11erased
stlink0x08000000SWD probeerased

The same boot_handoff.c is correct in all three; it is harmless when the chip boots straight in. When the user already has a project, bring its platformio.ini, linker script and Reset_Handler/SystemClock_Config() in line with the template rather than rewriting their code.

Debug output over USB

In the full template printf goes to the USB CDC port (0483:5740 "Black Pill F401RC VCP", /dev/cu.usbmodem<UID> on macOS). Read it with pio device monitor. Rules that keep it working — details in reference/board-hardware.md §8.4, code in reference/recipes.md §5:

  • end lines with \r\n; stdout is line-buffered, so a partial line appears only after fflush(stdout);
  • printf only from the main loop / thread context, never from an interrupt handler;
  • nothing is sent while no terminal has the port open (DTR low) — output from before the port was opened is lost, which is why the template prints its banner on every open;
  • never open the port at 1200 baud unless you want the bootloader;
  • adding peripherals keeps the USB working only if SystemClock_Config() keeps PLLQ = 48 MHz and nothing else claims PA11/PA12 or OTG_FS_IRQHandler.

The banner states the reset cause (power-on, NRST pin, software, IWDG/WWDG) — check it first when the board restarts unexpectedly.

Flashing

Routes, in order of preference:

  • HID bootloader — above. Nothing to install but Python's hidapi; no driver on any OS. Entry: 1200-baud touch of the template firmware, or KEY + NRST.
  • ROM DFU (pio run -e dfu -t upload) — hold BOOT0, tap NRST, release → 0483:DF11. Always available because it is in ROM, so it is the recovery route for anything — at the cost of the HID bootloader (rule 6). Without BOOT0: in the HID bootloader, hold KEY > 0.65 s and release — it jumps to the ROM bootloader (from the V1.2 code; not tried on hardware).
  • SWD (pio run -e stlink -t upload) — writes from 0x08000000 like DFU. For breakpoints behind the bootloader, pio debug -e hid loads the .elf at its own addresses (sector 1 up) and leaves sector 0 alone; the reset then runs the bootloader, which jumps to the app (untested here — no probe was attached).

Recovery: nothing flashed through the HID route can touch sector 0, so KEY + NRST always gets back to the bootloader. If it does not, the bootloader is gone (DFU/SWD write, or its UID self-erase): BOOT0 + NRST into ROM DFU, then reinstall it from WeAct's .hex (reference/recipes.md §7). Right after such a reinstall the first boot records the UID and then pulses PC13 briefly every 0.5 s forever — tap NRST once; that is not a fault.

Reporting

State honestly what was verified on hardware versus derived. On this skill's board (unbranded STM32F401RCT6 Black Pill, bootloader V1.2) verified: DEVID 0x423 / 256 KB, KEY + NRST entry (fast flicker, then "breathing"), HID flashing with the template's flasher, the app starting behind the bootloader, the 84 MHz clock from the 25 MHz HSE, PC13 blinking, KEY on PA0 active-low, BOOT0 + NRST enumerating as ROM DFU 0483:DF11 ("STM32 BOOTLOADER"; nothing written through it), and the full template's USB CDC console on macOS (banner, heartbeat, echo, i/b commands) with button-free re-flashing through the 1200-baud touch and DR19. One open observation: with an early test firmware, an app started after a DR19 entry was twice reset back into the bootloader ~11 s later; it did not recur with the template (board-hardware.md §6.1). From the V1.2 disassembly only: the UID self-erase, the long-press jump to ROM DFU. Not tested: Linux/Windows hosts for the console, [env:dfu]/[env:stlink] uploads. LED polarity, LSE crystal, power circuit and header order are not verified on this clone — check the silkscreen, and say so rather than presenting the WeAct layout as fact.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Firmware development for the Arduino Nano (A000005, ATmega328P @ 16 MHz, 5 V) — its 30 KB usable flash, 2 KB SRAM, 1 KB EEPROM, 8-channel 10-bit ADC, six 8-bit PWM pins across three timers, UART shared with the USB-serial chip, I2C on A4/A5, SPI on D10–D13, sleep modes, and the Arduino AVR core + PlatformIO setup around them. Use when working on this board or any ATmega328P Nano clone (FTDI or CH340 USB): project setup, platformio.ini, old-vs-new bootloader uploads, pin mapping, A6/A7 restrictions, timer/Servo/tone conflicts, the 2 KB SRAM budget, analog references, powering from VIN, ICSP recovery, or debugging why something on the board does not work.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

Firmware development for the Beetle — the CJMCU / DFRobot "Mini Arduino Leonardo" USB board (ATmega32U4 @ 16 MHz, 5 V, 21×28 mm, castellated pads) — its native USB (CDC serial + HID keyboard/mouse/joystick), Caterina bootloader and 1200 bps touch upload, ten exposed I/O pads, four PWM pins across Timer0/Timer1, five ADC channels, I2C on D2/D3, SPI on the back-side ICSP pads, 28 KB usable flash and 2.5 KB SRAM, and the PlatformIO + Arduino AVR core (`board = leonardo`) setup around them. Use when working on this board or any ATmega32U4 Leonardo/Micro/Pro-Micro-class clone: project setup, platformio.ini, why the board shows up as two different serial ports, uploads that fail or hang, recovering a bricked or HID-spamming board by shorting the ICSP reset pads, pin mapping and which pads are missing, PWM/timer conflicts, Servo and tone, USB HID keyboard projects, the SRAM budget, powering from the + pad, or debugging why something on the board does not work.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

Разработка прошивок для BE-U1000 (Baikal Electronics / Байкал Электроникс, три ядра RISC-V: BR-350 и BM-310) на отладочных платах EVU-BA-2.1, EVU-BA-2.0 и EVU-BA-1.2 — её eFlash и QSPI flash, UART0/BootROM CLI, PWMA (захват и импульсы), АЦП с DMA, CAN FD, SPI, WDT, CLIC, а также SDK Байкала и его система сборки на make. Use when working on this board or any BE-U1000 / BMCU_U project (SDK 2.1/2.3, riscv32-none-elf, dfu-util, OpenOCD): настройка проекта, Makefile и MEM_REG_ROM, карта выводов и разъёмы XP1/XP8/XP9/XP10, режимы начальной загрузки и страповые выводы, прошивка по UART XMODEM либо USB DFU, работа с eFlash и TCM, прерывания и CLIC, отладка по JTAG — и разбор, почему плата молчит, не стартует, зависает или почему периферия «настроилась», а обмена нет.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

Firmware development for the 30-pin ESP32-WROOM-32 development board — the DOIT ESP32 DevKit V1 / ESP32 CH340 Type-C / NodeMCU-ESP32 30-pin form factor, 15 pins per side, CH340G or CP2102 USB-UART bridge, AMS1117 LDO, user LED on GPIO2. Use when working on a 30-pin ESP32 devkit (ESP32-D0WDQ6 / ESP32-D0WD-V3, ESP-WROOM-32 module): project setup, platformio.ini and sdkconfig for ESP-IDF or Arduino, pin mapping and which GPIOs are safe, strapping pins, ADC1 vs ADC2 with Wi-Fi, SPI speed and IO_MUX pins, I2C, deep sleep and RTC wake pins, flashing over the CH340 bridge, BOOT/EN recovery, brownouts, or debugging why something on the board does not work.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

Firmware development for the 36-pin ESP32-WROOM-32 development board — the original DOIT ESP32 DevKit V1 with 18 pins per side, i.e. the 30-pin layout plus the six in-package flash pins (SD0 SD1 SD2 SD3 CMD CLK = GPIO6-11) broken out at the USB end, CH340G or CP2102 bridge, AMS1117 LDO, user LED on GPIO2, GPIO0 not on the header. Use when working on a 36-pin ESP32 devkit (ESP32-D0WDQ6 / ESP32-D0WD-V3, ESP-WROOM-32 module), or when identifying which ESP32 board size you have: project setup, platformio.ini and sdkconfig for ESP-IDF or Arduino, pin mapping and which GPIOs are safe, the flash-pin trap, strapping pins, ADC1 vs ADC2 with Wi-Fi, SPI speed and IO_MUX pins, deep sleep and RTC wake pins, flashing, BOOT/EN recovery, brownouts, or debugging why something on the board does not work.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

Firmware development for the 38-pin ESP32-WROOM-32 development board — Espressif ESP32-DevKitC V4, Ai-Thinker NodeMCU-32S, DOIT ESP32 DevKit V1 38-pin and their CH340/CP2102 clones, 19 pins per side, with GPIO0 and the six in-package flash pins (GPIO6-11, labelled D0 D1 D2 D3 CMD CLK or SD0-SD3) broken out. Use when working on a 38-pin ESP32 devkit (ESP32-D0WDQ6 / ESP32-D0WD-V3, ESP-WROOM-32 or ESP32-WROVER module): project setup, platformio.ini and sdkconfig for ESP-IDF or Arduino, pin mapping and which GPIOs are safe, the flash-pin and IO0 traps, WROVER GPIO16/17 PSRAM conflict, strapping pins, ADC1 vs ADC2 with Wi-Fi, SPI speed and IO_MUX pins, deep sleep and RTC wake pins, flashing, BOOT/EN recovery, brownouts, or debugging why something on the board does not work.

日本語の概要は準備中です。原文の説明を表示しています。

alexex1993/mcu-skills202026年10月16日 更新

alexex1993 のスキルをすべて見る

このスキルの問題を報告する