ENGINEERING · CHECKED LIST · UPDATED 2026-07-24

Migrating STM32F103 to GD32F103: a checked pitfall list

GD32F103 is a P2P-graded, engineering-review candidate for STM32F103 — the pinout and register map match, and GigaDevice publishes an official compatibility document. It is not identical silicon: the eleven differences below are the ones that actually break firmware and hardware in migration, each traceable to the official documentation. Work the list top to bottom before first power-on; items 1–3 catch most failed bring-ups.

Sources: GigaDevice "Compatibility sum-up between GD32 and STM32" V2.0 and the GD32F103 software migration guide — both archived in our evidence store. Where a pitfall applies only to specific densities, that is stated.

1. BOOT0 must be pulled down — floating works on ST, not on GD

Symptom: The board boots fine with an STM32F103 but a GD32F103 starts unreliably or enters the bootloader. On ST parts BOOT0 may float when booting from flash; GigaDevice requires it pulled down.

What to do: Fit a 10 kΩ pull-down on BOOT0. This is the single most common hardware change and costs one resistor.

2. Minimum supply is 2.6 V, not 2.0 V

Symptom: Designs that ride through brown-outs at 2.0–2.6 V on ST silicon fail on GD32F10x, whose specified range is 2.6–3.6 V. High-power modules (Wi-Fi, GSM, GPS) sharing the 3.3 V rail can dip the LDO output into exactly this window at power-on.

What to do: Review the power budget and LDO output capacitance (GigaDevice suggests low-ESR, e.g. tantalum, and a larger value). Residual VCC above the power-on-reset threshold but below 2.6 V can also block start-up.

3. HSE start-up takes longer — raise HSE_STARTUP_TIMEOUT

Symptom: Clock init intermittently falls back to HSI because the external oscillator is not released before the ST library's default timeout expires. GD32F10x start-up time can reach hundreds of milliseconds.

What to do: Change HSE_STARTUP_TIMEOUT from 0x0500 to 0xFFFF in the device header (per GigaDevice's software migration guide). Also re-check wake-up timing in low-power flows.

4. 108 MHz ceiling changes every hard-coded timing assumption

Symptom: Delay loops, timer reloads and baud-rate maths calibrated for 72 MHz run fast if the PLL is reconfigured for 108 MHz. A documented field case: raising SYSCLK broke a 1200-baud UART until the APB divider was changed.

What to do: Either keep the PLL at 72 MHz for the first article, or audit every clock-derived constant (SysTick, timer prescalers, UART/I2C/SPI dividers) before using the headroom. USB still needs a valid 48 MHz derivation.

5. Flash timing differs in both directions

Symptom: Execution: the code area is zero-wait (SRAM-buffered), so cycle-counted routines run faster than on ST. Erase/program: a 1 KB page erase is ~60 ms versus ~30 ms on ST, so IAP and option-byte code with ST's default timeouts fails.

What to do: Raise EraseTimeout/ProgramTimeout (GigaDevice suggests 0x000FFFFF / 0x0000FFFF). On parts above 256 KB, the data area executes with large delay — keep real-time code in the code area (scatter-load if needed).

6. Unlock/option-byte sequences need a readback

Symptom: On GD32F10x, flash option-byte operations copied verbatim from ST's library intermittently fail because the unlock state is not yet effective when the next write lands.

What to do: After writing the KEY register sequence, poll the control register (or insert two NOPs) before proceeding, per the official compatibility document.

7. ADC behaves differently in five specific ways

Symptom: Readings stuck at zero, values lower than expected, or ADC2 sampling zero in sync mode — firmware that worked on ST.

What to do: Configure sample pins as analog input (ST tolerates floating; GD does not). Keep ADC clock at or below the allowed maximum (14 MHz on F1). On sub-256 KB F103/F101, insert ~20 µs delay after ADC enable. Input impedance is lower — lengthen sample cycles or reduce divider resistance. Validate absolute accuracy in-circuit; GigaDevice's own document notes it is slightly lower.

8. USART inserts an idle bit between bytes

Symptom: Back-to-back byte streams show inter-byte gaps that trip tight receiver-side timeout logic or bit-banged protocol emulation on the other end.

What to do: Budget for the idle bit in protocol timing, or verify the receiving side tolerates it. Continuous-transmission assumptions from ST do not carry over.

9. DMA flag and request timing differ

Symptom: Occasional data dislocation on ADC+DMA, or a stale DMA request being answered immediately after re-enable.

What to do: Clear DMA requests explicitly when reconfiguring (reset the peripheral's DMA enable bit in the transfer-complete handler), and re-test every DMA-driven peripheral rather than assuming ST behaviour.

10. SWD drive is weaker — programming can fail on long leads

Symptom: "Flash download failed" from Keil/IAR with cables that work fine on ST boards.

What to do: Add 10 kΩ pull-up on SWDIO and 10 kΩ pull-down on SWCLK, keep the debug lead short (under ~20 cm) and drop the adapter clock to 4 MHz or below.

11. Sleep currents are an order of magnitude higher

Symptom: Battery products: GD32F103 (≤256 KB class) deep-sleep is ~1.4 mA versus ~24 µA on ST, and standby ~10.5 µA versus ~3.4 µA. Run current is lower (~32 mA vs ~52 mA at 72 MHz), which can mask the problem in bench tests.

What to do: Re-measure the real duty-cycle power budget. For designs that live in deep-sleep, this difference alone can disqualify the swap — check it before committing the BOM.

Per-part starting points

The graded cross-reference pages list these differences per exact part with cited evidence: STM32F103C8T6, STM32F103CBT6, STM32F103RBT6, STM32F103RCT6, STM32F103VET6 — or browse the full STM32F103 family table.

A successful bench port is not a production qualification: validate ADC accuracy, USB enumeration, sleep currents and your production programming flow on the exact suffix and silicon lot you will ship.

Migrating a specific BOM?
Send the part list — we return graded candidates, disclosed differences and cited evidence for engineering review.
Free BOM cross-check