MCU / Board: STM32F446ZET6 on a custom home-made 3D-printer controller
Clock: External HSE 8 MHz (verified), PLL to 168/180 MHz as needed
USB: Full-Speed device, DP=PA12, DM=PA11 (no HS PHY), 22 Ω series, USBLC6, 5.1 k on CC (for C-to-A cable adapter), VBUS to connector only (no VBUS sense)
Boot pins: BOOT0=GND, NRST pull-up OK
Tooling: PlatformIO (Arduino STM32 core) for Marlin, ST-Link + STM32CubeIDE/CubeProgrammer + GDB
What works (outside Marlin)
A CubeIDE USB CDC FS project (HSE=8 MHz, PLLQ=7) enumerates and prints reliably.
D+ sits at ~3.2 V; Mac shows /dev/cu.usbmodem….
LEDs on PA8 / PA15 toggle fine.
So the hardware + clocks + USB FS are good.
What fails (inside Marlin)
Environment: STM32F446ZE_btt (Octopus) on Marlin 2.1.2.5
USB never enumerates on the host. D+ sits at ~0 V unless I start a debug session.
Without a debugger the board looks dead (even an early LED write in setup() doesn’t run).
With the debugger attached, Marlin runs. I can break in manage_inactivity() and walk around the code.
Earlier I did hit a MAXTEMP kill (fixed by disabling temp sensors for bring-up), but even with temps disabled the board still won’t start stand-alone.
Current Marlin / PlatformIO config (USB + bring-up)
[env: STM32F446ZE_btt]
extends = stm32_variant
platform = ststm32@~12.1
board = marlin_BigTree_Octopus_v1
framework = arduino
upload_protocol = stlink
debug_tool = stlink
board_build.usb = CDC
build_flags =
${stm32_variant.build_flags}
-DUSBCON
-DUSBD_USE_CDC=1
-DHAL_PCD_MODULE_ENABLED
-DUSBD_VBUS_SENSE=0
-DPCD_VBUS_SENSING_DISABLED
-DUSE_USB_FS
-DHSE_VALUE=8000000U
-DNO_WATCHDOG
build_unflags =
${stm32_variant.build_unflags}
-DUSE_USB_HS_IN_FS
-DUSBD_USE_HS
Thermals temporarily disabled (no hotend/bed sensors) to avoid kills.
For sanity I also tested making watchdog_init() / watchdog_refresh() no-ops in HAL.cpp (same behavior).
What I see in the debugger (Marlin/Arduino core)
Breakpoints hit in order on a “good” (debug) boot:
USBD_Start() → HAL_PCD_Start() (so USB device is being started)
Later I do hit OTG_FS_IRQHandler()
When stopped in OTG_FS_IRQHandler, registers look sane:
RCC->AHB2ENR = 0x00000080 (OTGFSEN set)
USBx->GAHBCFG = 0x00000001 (GINT=1)
USBx->DCTL = 0x00000000 (SDIS=0)
USBx->GRXFSIZ = 0x00000080
USBx->DIEPTXF0_HNPTXFSIZ = 0x44008c20
USBx->DIEPTXF1 = 0x803c3810
But without the debugger, the host never sees a device and even my “breadcrumb” LED write at the top of setup() doesn’t fire.
Things I already tried
Full erase, reflash, option bytes sane (RDP=AA, IWDG/WWDG SW, BOR enabled).
Verified SCB->VTOR == 0x08000000 and reset vector looks correct when attached.
Made LED “turn on at entry” both in Marlin setup() and also tried very early in HAL init.
Confirmed my HSE is 8 MHz everywhere (-DHSE_VALUE=8000000U).
Disabled all temp sensors / thermal protection for bring-up.
Temporarily neutered watchdog calls in HAL.
Also tried the Arduino STM32 usbd_conf.c path with vbus sensing disabled.
Some questions:
Variant / clock mismatch in the Octopus variant: Is there a hidden SystemClock_Config() assuming 12 MHz HSE for this env that could early-fault without debugger timing? What’s the authoritative place in the STM32F446ZE_btt setup to force HSE=8 MHz and the USB 48 MHz path for the Arduino core build?
Watchdog still active despite -DNO_WATCHDOG: Does the IWatchdog library still run on this env unless more is undefined? If so, what’s the correct Marlin-side switch to guarantee no IWDG touches during bring-up?
USB soft-connect timing: In this Arduino core, is there a known race where USBD_LL_Start doesn’t properly clear DCTL.SDIS or enable GINT unless something else is called?
Board/env choice: Is STM32F446ZE_btt (Octopus) the right starting point for an 8 MHz HSE custom F446ZE board? If you have a known-good PlatformIO env (or variant files) for a generic F446ZE + USB CDC FS, please share
Why it only runs under debugger: If someone has seen Marlin on F446 “only run with SWD attached,” what was the root cause in your case (clock, watchdog, vector offset, something else)?
What’s the correct way to set up Marlin’s F446 USB CDC FS (Arduino STM32 core) with HSE=8 MHz, no VBUS sense, and ensure it enumerates reliably without a debugger?
I’m happy to provide full logs, map/ELF, or step through any function you suggest. Thanks!