Skip to main content
Mathan Raja
Associate III
September 23, 2026
Solved

TIM1 break flag (BIF) stays latched forever, MOE never sets — STSPIN32G0602Q

Hi,

Chip: STSPIN32G0602Q (STM32G031 core + integrated 3-phase gate driver)


Board: custom BLDC driver board, powered via 115VAC through an isolation transformer into the board's own AC input; the board's onboard PFC/rectifier stage converts this to the internal DC buses (HV+ ~400V DC bus, and VBUS ~50-120V DC, which is the rail actually switched by the MOSFETs under test)


Purpose of this test: end-of-line (EOL) production test — statically turning on one high-side MOSFET and one low-side MOSFET on different phases (e.g. U-high + V-low) for a short, controlled period, then checking output voltage/current, to verify each MOSFET pair switches correctly before the board ships. This is a functional pass/fail check, not normal motor operation — no continuous PWM switching or motor commutation is involved.


Problem: TIM1's gate outputs never turn on. Root cause traced to: BIF (break flag) is always set, so MOE can never be enabled.

What happens

  1. I start a TIM1 channel (HAL_TIM_PWM_Start + HAL_TIMEx_PWMN_Start).
  2. TIM1->SR bit 7 (BIF) is already 1 — even before I do anything else.
  3. I clear it with __HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_BREAK). It comes right back to 1 immediately. I tried clearing it up to 1000 times in a loop — never stays cleared.
  4. Because of this, __HAL_TIM_MOE_ENABLE() never actually results in MOE=1 (checked directly in TIM1->BDTR).
  5. Result: the driver output pin never moves — it just floats.

What I already checked and ruled out

  • PB12 (break input pin, = FAULT output of the driver): reads HIGH (healthy) every single time I check it, even at the exact same moment BIF=1. No visible problem at the pin itself.
  • VCC (driver's 18V supply): steady 15V, confirmed with multimeter, even during the fault.
  • Current sense signals feeding the comparator (CIN): checked with an oscilloscope at both slow and fast timebase — steady ~220-230mV, well below the ~460mV fault threshold, no glitches or spikes.
  • TIM1->AF1 register: only BKINE/BKINP are set (external pin enabled, active-low). Comparator break sources are 0 (this chip has no comparator hardware anyway).
  • TIM1->EGR (BG bit): 0 — not a software-triggered break.
  • BKBID / BKDSRM / LOCK bits in BDTR: all 0 — not a bidirectional-mode or lock issue.
  • PWR->CR2 (PVDE bit): 0 — voltage detector is not enabled.
  • CSS (clock security): not applicable, I'm running on HSI+PLL, not HSE.
  • Official errata sheet (ES0487, STM32G031x4/x6/x8): no matching issue listed.

My question

I've ruled out every break source I can find in the reference manual. The pin itself always looks healthy when I check it, but BIF won't stay cleared no matter what.

Is there anything about the STSPIN32G0602's internal FAULT-to-PB12 connection that could cause a break condition too brief to see on a slow multimeter check or a paused debugger snapshot, but persistent enough that TIM1 always re-detects it? For example: an internal UVLO edge case, internal filtering/latching behavior on the FAULT line, or a known power-up sequencing issue between the driver section and the MCU core?

Or does this look more like a defective/damaged individual unit rather than something explainable by configuration?

Happy to share scope captures, schematic excerpts, and register dumps if useful.

Setup: STM32CubeIDE, HAL drivers, TIM1 at 128MHz kernel clock, center-aligned mode, ARR=1599. Channels are configured in CubeMX as "PWM Generation CH1/CH1N" etc. (this sets up polarity, dead-time, CCER, and break config correctly via HAL_TIM_PWM_Init/ConfigChannel) — but after that init, I directly overwrite the OC1M/OC2M/OC3M bits in CCMR1/CCMR2 at runtime to force each channel to a static active/inactive level (0x5/0x4), instead of using PWM duty cycle. This is done to statically hold one high-side + one low-side MOSFET on for an EOL functional test, and to avoid the known center-aligned-mode CCR=ARR edge case. The break/MOE issue described above happens regardless of whether the channel is left in plain PWM1 mode or switched to forced mode — I've confirmed both behave the same way.

rich.g.williamsBest answer
Associate II
September 24, 2026

That's good to know, as regards the high side drivers, is it possible they rely on toggling at speed to operate. Or is there any other prerequisite they rely on that's missing. It might be a good idea to discover as much as you can about how they work internally?

PS impressed by how quickly you configured the GPIO test! it would have taken me a day or two to sort it out. Cheers 

 

10 replies

Associate II
September 23, 2026

What you could do is, instead of going through TIM1, you could set the output ports used to control the high-side MOSFET and one low-side MOSFET test as normal GPIO outputs and use a simple test loop to toggle the output pins - easier than wrestling with TIM1 settings.

That’s based on what you say about only wanting to test your mosfets and that the production code is tested separately.

As a GPIO its easy to try with different output transition speeds and drive strength, even apply pull up or pull down resistor in the MCU or even use open collector.

Just an idea if it meets your test specs.

Mathan Raja
Associate III
September 24, 2026

Hi @rich.g.williams — I wish I could, but that's not possible on this specific part. This chip (STSPIN32G0602Q) is a system-in-package that combines the STM32G031 core with an integrated 3-phase gate driver on the same die/package. The gate driver's HIN/LIN inputs are internally hardwired to TIM1's channel outputs (PA8/PB13 = CH1/CH1N, etc.) — there's no way to reconfigure those specific pins as plain GPIO and still reach the gate driver, since the driver only listens to the timer peripheral, not arbitrary GPIO toggling. So TIM1 isn't something I can route around here — it's the only path to the gates at all.

To be clear on the actual symptom: TIM1's BIF (break flag) is set and won't clear, which blocks MOE, regardless of channel mode (PWM or forced-output). I've confirmed the break input pin itself (PB12) reads healthy every time I check it, and ruled out every break source I can find in the reference manual (software break, comparator sources — not present on this chip anyway, PVD, lock bits). Still looking for what else could cause this.

Richard Li
Senior
September 23, 2026

In AN4013 Rev 14 page 34 , it noticed:  “Break inputs Break1 and Break2 are not available on the original series.”

I am not sure your software used these break 1 and Break 2.

Mathan Raja
Associate III
September 24, 2026

Hi @Richard Li — good thing to double check, but this doesn't apply to my case. AN4013 p.34's note is about the original/basic STM32 series only having one break input, before ST added the independent Break2 on later series. My STM32G031 fully supports Break1 (BKE/BKP/BKF bits in TIM1_BDTR), and that's the only break input I'm using — I never touch Break2 (BRKINPUTSOURCE for BRK2 stays disabled in my config). I've also directly confirmed via register readout that BKE=1, BKP=0 (active-low), and BKF=6 are all set correctly, so this is standard Break1 usage on a series that supports it.

Richard Li
Senior
September 23, 2026
Mathan Raja
Associate III
September 24, 2026

Good point on the wording — the doc only explicitly excludes F0/F1/F2/F4/F37x, it doesn't explicitly confirm G0 has Break2. But I don't need to infer that from the text either way: my own register readout proves it directly. TIM1_BDTR on my STM32G031 has live BK2E/BK2P/BK2F/BK2DSRM bits (all readable/writable, currently 0 since I have Break2 disabled) — this hardware simply wouldn't exist if my chip lacked Break2 support. CubeMX also offers Break2 as a configurable option for this part, which wouldn't be possible if the silicon didn't implement it. So regardless of how AN4013's wording is interpreted, the chip itself confirms it.

Associate II
September 24, 2026

​@Mathan Raja   

You can access the pins you need and configure them as GPIO output. Please have a look at the following:-

 

 

I created a minimal project in ST Core MX with the “bare bones” startup, a summary hinting at the code:-

 

//GPIO port clock enable register (RCC_IOPENR)    RM0444 page 192
//GPIO port mode register (GPIOx_MODER)
//GPIO port output data register (GPIOx_ODR)


LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);


LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_12);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_13);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_14);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_15);
LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_9);
LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_10);
LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_11);


GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_13;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_14;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);


GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

All it is is turning clocks on and using MODER register to set pins as outputs, using ODR registers to toggle them.

You could use ODR registers to toggle the seven driver pins.  You could load a very basic program into Flash or even RAM either by using STLINK or the built in bootloader. I have no idea how you would want to toggle the pins I just assume a simple continuous loop could cycle through GPIO pins PA11, PA10, PA9, PB15, PB14, PB13, PB12 in a safe sequence for your tests.

You could also configure PB12 as a GPIO input with firmware pull up and then poll it to terminate the test immediately if a fault arose signalled on PB12.

The core SYSCLK runs at 16MHz from reset (from the internal RC oscillator HSI) from reset and can stay at 16MHz for the tests, no need to configure the PLL.

Hope that helps, let me know if I can help any further.

Mathan Raja
Associate III
September 24, 2026

Hi @rich.g.williams,

Thanks for the diagram — you're right, I was wrong earlier. HIN/LIN are bonded directly to the MCU pins, not to TIM1 specifically, so plain GPIO works fine on this part. I tried it.

Setup: Reconfigured PA8/PA9/PA10 (HIN1/2/3) and PB13/PB14/PB15 (LIN1/2/3) as GPIO_Output (push-pull, no pull, idle HIGH = off, matching active-low logic), toggled them directly with HAL_GPIO_WritePin(), no TIM1 involved at all. PA11 (EN_GATE) stayed GPIO_Output, initial low. PB12 (FAULT) stayed GPIO_Input with pull-up, unchanged.

Result: Same as before. Low-side works perfectly every time (output reads 0V). High-side still doesn't turn on — output stays stuck at ~14V instead of rising to the bus voltage, tested at both 90V DC and 115VAC.

So this rules out TIM1 completely — the problem isn't the timer or my config, it's something in the driver's high-side stage itself, even though HIN is being driven correctly, EN is on, FAULT is clean, and the bootstrap cap charges fine beforehand.

Thanks for pushing me to test this — good to have TIM1 ruled out for certain now.

rich.g.williamsBest answer
Associate II
September 24, 2026

That's good to know, as regards the high side drivers, is it possible they rely on toggling at speed to operate. Or is there any other prerequisite they rely on that's missing. It might be a good idea to discover as much as you can about how they work internally?

PS impressed by how quickly you configured the GPIO test! it would have taken me a day or two to sort it out. Cheers 

 

Mathan Raja
Associate III
September 25, 2026

Hi @rich.g.williams,

Solved. Thanks, your question about "prerequisites for the high-side drivers" was the key.

Root cause: the high side runs from the bootstrap capacitor, and my test held it ON statically for seconds.
1. The bootstrap cap discharges (VBO drops below the ~7.5 V UVLO), so HVG switches off.
2. Per DS14512 section 6.1.4, after VBO UVLO recovery, HVG stays OFF until the next HIN transition. In my sequence, HIN was set before EN went high, so the driver never saw an edge.

Fix:
- Enable EN with all inputs OFF.
- Precharge the bootstrap: low side ON for ~5 ms.
- Then drive HIN low (a fresh edge).
- For long holds, refresh every ~10 ms: HIN off, LIN pulse (~0.5 ms), HIN on.

With this, all three high-side FETs switch correctly at 115 V, and our EOL power-stage test now passes.

A side note for our board (not an ST issue): the U and W phases turned out to be wired to driver channels 3 and 1 respectively, which also caused some confusion during debugging.

Thanks again for the help!