The flash chip was fine the whole time
The quad flips as soon as it lifts off, so I finally went back to the blackbox flash. Two days of blaming the chip and one night of thinking I'd killed the board, and it ended up being a missing line in Betaflight.

The airframe went together on the 12th and all four motors spin. It also tries to flip over as soon as it starts to lift, every time. I don't think it's the frame. The gyro alignment in my target is still a placeholder I guessed for the old IMU, and I've never checked which motor each output drives or which way they spin, and any one of those would make a quad do this. The annoying part is that a gyro that's 180° out and a mirrored motor map look the same from the air, so watching it flip doesn't tell me which one it is. I need to do a props-off tilt test on the bench (I hadn't done one before arming it the first time, which I probably should have).
The flip is also why the flash suddenly mattered. Without a blackbox log all I've got is watching it flip, so the chip I'd written off on September 3 was the next thing to fix.
When I went back over why I'd decided it was dead, it didn't hold up that well. A JEDEC ID of all zeros fits a dead die, but it also fits a chip that never gets selected, or a MISO line that something else is holding low. Three of the checks I'd counted as passes would have passed in all three cases:
- /CS idles at 3.3 V. With the pull-up fitted it reads 3.3 V whether the MCU ever drives it or not.
- Continuity from each U3 pin to the MCU. Fine for finding an open, but it wouldn't catch a bridge to another net.
- MISO to ground measured 1.4 MΩ, unpowered. That won't catch anything that only pulls the line low once the board is on.
Somewhere in there I was also poking at pins on the powered 0.5 mm LQFP with a handheld meter, and not long after that the board stopped enumerating. Power LED on, status LED off, no USB, and the F405 hot to the touch. Unpowered, I got about 3 Ω from VCAP_1 to ground. I pulled C12, measured again and still got about 3 Ω, so I figured the short was inside the die, wrote the board off and started planning a respin.
The next day I plugged it in with a scope attached and it just booted like nothing had happened. Turns out the 3 Ω was me probing the ground-side pad of C12's empty footprint, so I was measuring ground to ground (2.4 Ω raw, with 1.6 Ω of that being the leads, was never a short). The real fault was C12 itself, a flex-cracked MLCC shorting the core regulator's output. That's what made the chip hot and stopped it starting, and pulling it had already fixed the board. I should have just tried powering it again before deciding anything.
Once I had C12 replaced and a working board again, I spent the evening going back over the flash wiring, this time with tests that could actually fail:
- Drove /CS from Betaflight as a PINIO and watched it swing cleanly between 3.3 V and 0 V, so the chip select path is fine.
- Put 10 kΩ from MISO up to 3.3 V. The net sat at 3.3 V, so the chip wasn't holding it low.
- Reassigned PC2, the MISO pin, as a battery voltage input. It read 3.3 V, so the pin, its trace and its solder joint all work.
So MISO was high, the MCU could read it as high, and flash_info still printed zeros. At that point it had to be firmware somewhere. I built a debug version of Betaflight that records which exit flashSpiInit() takes and prints the raw ID bytes instead of the tidied-up result. Output from the first boot is below, the last line is the one that matters:
stage: 4 TRANSACTED
resolved pins: sck=B13 sdi=C02 sdo=B15 regbase=0x40003800
spi regs: cr1=0x0357 spe=1 mstr=1 br=2
sdi pin: moder=2 (alternate function) af=5 (SPI2 on F4)
rdid: issued=1 raw=c8 40 15 c8C8 40 15 is the ID straight out of the GigaDevice datasheet, so the chip had been answering fine since September 3. Betaflight 4.5.5 just doesn't have the GD25Q16E in its chip table, so the driver didn't recognise the reply, gave up, and flash_info printed an empty struct. That's where the 0x00000000 came from, not from anything on the wire.
My July 30 entry says the part is already in that table. It isn't, at least not in the release I'm running. I'd been going off that note the whole time, which is a big part of why I spent two days on the hardware.
{ 0xC84015, 104, 50, 32, 256 }, // GigaDevice GD25Q16E, 2 MB
// geometry copied from the Winbond W25Q16 entry above itThe Winbond W25Q16 entry right above it has the same 2 MB layout, so I copied its geometry rather than guessing. It isn't upstream, so I have to remember to re-apply it after every clean build or fresh clone.
Blackbox works now. Next up: set the sample rate to 1/4 so the 2 MB chip doesn't fill in 22 seconds, check motor mapping and direction, test failsafe, and then log a flight so I can look at the flip in actual data.

