STM32H757 system bootloader (SPI2) never sends ACK
Summary
We program a slave STM32H757 through its system bootloader over SPI (AN4286), driven by a second STM32H757 acting as SPI master. About 20 % of our production boards cannot be programmed: after the 0x5A synchronization byte, the bootloader returns the byte 0xA5 on every poll and never 0x79 (ACK) or 0x1F (NACK). The other 80 % of the boards are programmed reliably with exactly the same master firmware.
Bootloader version (0x91), device ID (0x450) and silicon revision (Rev V) are identical on working and failing boards. The failing boards are otherwise fully functional: firmware loaded through JTAG/SWD runs normally on them. Register dumps taken through SWD show that the bootloader has selected SPI2 and is running, but that the SPI2 slave is in TX underrun (SR.UDR = 1) on failing boards and not on working boards.
Hardware configuration
| Item | Value |
|---|---|
| Slave device | STM32H757XI , device ID 0x450, Rev V, bootloader V9.1 (0x91) (identical on working and failing boards) |
| Slave clock | 25 MHz crystal on HSE (PH0/PH1) |
| Slave supply | VDD = 3.3 V; SMPS configuration |
| Slave option bytes | original options bytes |
| Boot control | BOOT0 driven by the master (push-pull GPIO); NRST driven by the master (push-pull GPIO with internal pull-up, not open-drain); PDR_ON is not driven by the master (no power-on reset possible by software) |
| SPI link, slave side | SPI2: PI0 = NSS, PI1 = SCK, PI2 = MISO, PI3 = MOSI (SPI2 is the only SPI clock enabled in RCC during the failure) |
| Master device | STM32H757, firmware running on the CM4 core |
| SPI link, master side | SPI4: PE11 = NSS (software GPIO, push-pull, no pull), PE12 = SCK, PE13 = MISO, PE14 = MOSI (AF5, medium speed, no pull) |
| SPI settings | Master, full duplex, 8-bit, MSB first, CPOL = 0, CPHA = 0 (mode 0), no CRC, FIFO threshold 1 data, no inter-data idleness, NSS active low |
| SPI clock | Kernel clock HSI 64 MHz, prescaler /8, SCK = 8 MHz (4 MHz and 2 MHz also tested) |
| Logic level | 3.3 V (scope: MISO high level about 3.3 V on a working board) |
| Wiring | Board-level traces, one master and one slave, no other device on the SPI nets |
Boot and synchronization sequence (master side)
- BOOT0 = 1.
- NRST low for 300 ms, then NRST high.
- Wait 60 ms (160 ms also tested). AN2606 gives 53.975 ms as the startup time for STM32H74x/75x.
-
- NSS low, held for the whole frame (AN4286 figure 3):send
0x5A; - wait at least 10 µs, then poll with
0x00bytes, at least 10 µs apart, for up to 5 ms, checking every received byte; - on
0x79, send0x79(Get ACK procedure, AN4286 figure 2). On0x1Fthe procedure ends.
- NSS low, held for the whole frame (AN4286 figure 3):send
- NSS high.
- If no ACK: repeat step 4 up to 200 times, then repeat the whole sequence (new reset) up to 4 times, so up to 800 synchronization attempts per power-up.
Pseudo-code of the exchange:
NSS_LOW();tx = 0x5A; spi_txrx(&tx, &rx); // rx not useddo{ delay_us(10); // AN2606: 10 us SPI connection, 8 us between bytes tx = 0x00; spi_txrx(&tx, &rx);} while ((rx != 0x79) && (rx != 0x1F) && (elapsed < 5 ms));if (rx == 0x79) { delay_us(10); tx = 0x79; spi_txrx(&tx, &rx); }NSS_HIGH();Observed behaviour
- Working boards (about 80 %):
0x79is received and programming works every time. - Failing boards (about 20 %): the master reads
0xA5on every poll, indefinitely. Never0x79, never0x1F. Not a single ACK in 800 attempts per power-up. - The failure is reproducible per board. Two failing boards were analysed in detail (including one named Board028).
- Rare exceptions: on one failing board, programming succeeded once during a series of tests and then never again. Another failing board started working spontaneously for some time, and now fails again one month later with the same symptom (
0xA5, no ACK). - The problem does not depend on the SPI frequency (8, 4 or 2 MHz), on the master firmware timing, or on temperature (hot air had no effect).
- X-ray inspection of a failing board shows no visible defect.
What we tried
| # | Test | Result |
|---|---|---|
| 1 | Sync loop re-sending 0x5A (our original code) replaced by one 0x5A followed by 0x00 polls, as per AN4286 | No change |
| 2 | AN2606 timings (10 µs after 0x5A, at least 8 µs between bytes). Also single-stepping with the debugger, which gives delays of milliseconds to seconds between bytes | No change. Still 0xA5, no ACK |
| 3 | SCK 8 MHz, 4 MHz, 2 MHz, with slow GPIO edges (low speed setting) | No change. SR.UDR stays 1 on failing boards |
| 4 | Internal pull-down on master SCK; master MasterKeepIOState (AFCNTR) enabled | No change |
| 5 | NSS held low over the whole frame versus one NSS frame per byte. With NSS low and the HAL disabling SPI4 between bytes, we saw the idle pattern read back bit-shifted (0x4B, 0x96), meaning extra SCK edges | Fixed by AFCNTR or by NSS per byte: 0xA5 is then read correctly aligned, but still no ACK |
| 6 | Delay after NRST release 160 ms versus 60 ms; up to 800 synchronization attempts per power-up | No ACK |
| 7 | Master stopped for 1 s (debugger halt) inside the frame, then one more poll | Still idle pattern, no ACK |
| 8 | Hot air on the board | No change |
| 9 | X-ray of a failing board | Nothing visible |
| 10 | Slave test program flashed through JTAG that logs the state of all bootloader interface pins (USART, I2C, FDCAN, SPI, USB): pull-up / pull-down probing and activity | Identical on working and failing boards; all other interfaces' RX pins are floating on both. Limitation: run in application mode, not during the bootloader detection window. PA3 (USART2_RX) has an external 100 kΩ pull-down |
| 11 | Register dumps of the slave through SWD hot-plug (STM32CubeProgrammer) on working and failing boards | See section 6 |
| 12 | Bootloader version and device ID | Identical: V9.1 (0x91), ID 0x450, Rev V |
Register evidence (slave, SWD hot-plug, bootloader running)
Working board versus failing boards (two failing boards, same result):
| Register | Working board | Failing boards |
|---|---|---|
| RCC peripheral clocks | only SPI2 enabled | only SPI2 enabled |
| SPI2 CR1 (SPE, SSI), CFG1, CFG2, IER (0x320) | same | same |
| SPI2 UDRDR | 0xA5A5A5A5 | 0xA5A5A5A5 |
| SPI2 SR | 0x0000 (0x1002 during detection phase), UDR = 0 | 0x1022, UDR = 1 |
| DMA1 LISR | 0 | 0x40 (FEIF1, FEIE = 0) |
| NVIC ISPR1 | 0 | 0x10 (IRQ 36, SPI2, pending) |
| SCB ICSR | 0 | 0x00400000 (ISRPENDING) |
| CFSR / HFSR | 0 / 0 | 0 / 0 (no fault; VECTACTIVE = 0) |
Additional observations on the failing board:
- SPI2 TX is fed by DMA1 Stream 1 in circular mode (S1CR = 0x0002055F, NDTR = 20, PAR = SPI2_TXDR, M0AR = 0x24000790, DMAMUX1_C1CR = 0x28), reading a 20-byte buffer filled with 0xA5. No
0x79is present in the buffer. - The CPU is not in a fault, and interrupts are not being serviced for SPI2 (UDR flag and pending IRQ remain set).
Caveat: all dumps were taken with a debugger attached in hot-plug mode, which halts the core.
Related link
SPI Bootloader Synchronization Issue | Community
ROM Bootloader - only responds with 0xA5 | Community
STM32L496 SPI Bootloader fails to synchronize | Community
STM32G473 system bootloader responds with 0xA5 continuously on SPI1 | Community
Some topics already spoke of this problem but I didn’t found a solution that is working for me. Do you have any ideas of more tests to do in order to find the root cause? Do you know a solution or a workaround on this problem?
Thanks in advanced for your help
