Skip to content

Fix SPI GPIO alternate function assignment on STM32H7/F7#11389

Open
sensei-hacker wants to merge 2 commits intoiNavFlight:maintenance-9.xfrom
sensei-hacker:fix/spi-af-lookup-table
Open

Fix SPI GPIO alternate function assignment on STM32H7/F7#11389
sensei-hacker wants to merge 2 commits intoiNavFlight:maintenance-9.xfrom
sensei-hacker:fix/spi-af-lookup-table

Conversation

@sensei-hacker
Copy link
Member

@sensei-hacker sensei-hacker commented Mar 2, 2026

Problem

On STM32H743, non-default SPI pins couldn't be used without adding esoteric macros like define SPI3_MISO_AF GPIO_AF6_SPI3

Contrast UART and i2c, where the AF is automtically looked up in a table.
This PR adds automatic lookup for SPI, similar to uart, i2c, etc.

bus_spi_hal_ll.c applied GPIO_AF6_SPI3 to all SPI3 pins when no explicit AF was defined in target.h. On this H7 AF6 on PB5 is SPI3_MISO — the MOSI function requires AF7. Targets routing SPI3_MOSI to PB5 without an explicit override received no MOSI signal, silently breaking any SPI3 peripheral on that pin (e.g. the MAX7456 OSD on HAKRCH743).

The same structural issue existed in the STM32F7 path (hardcoded single-AF fallbacks), though the F7 AF assignments happen to be correct for the pins used by current targets.

Solution

Create a macro of AF lookup tables and use them to auto-resolve the correct alternate function per pin at compile time:

  • bus_spi_stm32h7xx.h — AF table for STM32H743, verified against DS12110 Tables 10–14
  • bus_spi_stm32f7xx.h — AF table for STM32F722/F745/F765, verified against DS11853/DS10916/DS11532 Table 9
  • bus_spi_hal_ll.c — replace hardcoded single-AF fallbacks with #ifndef guards that auto-resolve from the table; targets may still define SPI*_SCK/MISO/MOSI_AF in target.h to override

If a target uses a pin not in the table the build fails with an "undefined identifier" error — a safe, explicit failure rather than silently applying the wrong AF.

Targets built and verified

  • HAKRCH743 (STM32H743, SPI3/PB5 MOSI — the original bug target)
  • MATEKF765 (STM32F765, SPI1/SPI3)
  • KAKUTEH7 (STM32H743, SPI4/PE2/PE5/PE6)
  • ANYFCM7 (STM32F722, SPI2/PC1 MOSI)

Create per-pin AF lookup tables (bus_spi_stm32h7xx.h and
bus_spi_stm32f7xx.h) and use them in bus_spi_hal_ll.c to
automatically resolve the correct GPIO AF for each SPI pin.

Previously, SPI3 on STM32H743 applied AF6 to all pins. On H743,
AF6 on PB5 is SPI3_MISO - the MOSI function requires AF7. Targets
routing SPI3_MOSI to PB5 (e.g. HAKRCH743 MAX7456 OSD) received no
MOSI signal. Targets may still define SPI*_SCK/MISO/MOSI_AF in
target.h to override the table.
@qodo-code-review
Copy link
Contributor

Review Summary by Qodo

Fix SPI GPIO alternate function assignment on STM32H7/F7

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• This description is generated by an AI tool. It may have inaccuracies
• Replace hardcoded SPI alternate function fallbacks with per-pin lookup tables for STM32H7 and
  STM32F7
• Fix SPI3_MOSI on STM32H743 PB5 requiring AF7 instead of AF6 (broken on HAKRCH743 MAX7456 OSD)
• Auto-resolve correct GPIO AF per pin at compile time using SPI_PIN_AF_HELPER macro
• Allow targets to override individual pin AFs via target.h while maintaining safe defaults
Diagram
flowchart LR
  A["bus_spi_hal_ll.c<br/>Hardcoded AF fallbacks"] -->|Replace with| B["bus_spi_stm32h7xx.h<br/>Per-pin AF lookup table"]
  A -->|Replace with| C["bus_spi_stm32f7xx.h<br/>Per-pin AF lookup table"]
  B -->|SPI_PIN_AF_HELPER| D["Auto-resolve AF<br/>at compile time"]
  C -->|SPI_PIN_AF_HELPER| D
  D -->|Fail safely| E["Undefined identifier<br/>if pin not in table"]
  D -->|Allow override| F["target.h explicit<br/>SPI*_AF defines"]
Loading

Grey Divider

File Changes

1. src/main/drivers/bus_spi_hal_ll.c 🐞 Bug fix +107/-57

Replace hardcoded AF fallbacks with lookup table resolution

• Include new per-chip AF lookup headers (bus_spi_stm32h7xx.h and bus_spi_stm32f7xx.h)
• Replace hardcoded single-AF fallbacks (e.g., GPIO_AF6_SPI3 for all pins) with
 SPI_PIN_AF_HELPER macro calls
• Use #ifndef guards to allow target-level overrides while auto-resolving from lookup tables
• Remove error-prone conditional logic that required all three AFs (SCK/MISO/MOSI) to be defined
 together
• Simplify device initialization by removing duplicate conditional branches

src/main/drivers/bus_spi_hal_ll.c


2. src/main/drivers/bus_spi_stm32h7xx.h ✨ Enhancement +79/-0

Add STM32H7 SPI pin AF lookup table

• Create new STM32H7 SPI pin alternate function lookup table verified against DS12110 Tables 10-14
• Define SPI_PIN_AF_HELPER macro that resolves pin-specific AF values at compile time
• Document SPI3 MOSI exceptions on H743: PB2 and PB5 require AF7 (not AF6), PD6 requires AF5
• Cover SPI1/2/4 pins (all AF5) and SPI3 pins with their correct AF assignments
• Provide safe failure mode: undefined identifier if pin not in table

src/main/drivers/bus_spi_stm32h7xx.h


3. src/main/drivers/bus_spi_stm32f7xx.h ✨ Enhancement +78/-0

Add STM32F7 SPI pin AF lookup table

• Create new STM32F7 SPI pin alternate function lookup table verified against DS11853/DS10916 Table
 9
• Define SPI_PIN_AF_HELPER macro matching H7 implementation for consistent resolution
• Document SPI3 MOSI exceptions on F7: PB2 requires AF7 (not AF6), PD6 requires AF5
• Note key difference from H7: PB5 SPI3_MOSI uses AF6 on F7 but AF7 on H7
• Cover SPI1/2/4 pins (all AF5) and SPI3 pins with their correct AF assignments

src/main/drivers/bus_spi_stm32f7xx.h


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Mar 2, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Headers rely on transitive CONCAT4🐞 Bug ⛯ Reliability
Description
The new bus_spi_stm32{h7,f7}xx.h headers use CONCAT4 but do not include the header that defines it,
relying on current include order/transitive includes from other headers. This is a latent build
fragility: a future refactor or reuse of these headers elsewhere can cause compile failures (e.g.,
CONCAT4 undefined).
Code

src/main/drivers/bus_spi_stm32h7xx.h[R34-37]

+// Resolves to SPI_PIN_AF_SPIn_Pxy, which is defined below for each valid pin.
+// If a pin is not in the table the build will fail with "undefined identifier",
+// which is preferable to silently applying the wrong AF.
+#define SPI_PIN_AF_HELPER(spi, pin)  CONCAT4(SPI_PIN_AF_SPI, spi, _, pin)
Evidence
Both new AF-table headers define SPI_PIN_AF_HELPER using CONCAT4, but neither includes
common/utils.h where CONCAT4 is defined. Today this works only because bus_spi_hal_ll.c includes
drivers/io.h, which includes io_def.h, which includes common/utils.h (thus providing CONCAT4) before
including the AF-table headers. This coupling to include order is fragile.

src/main/drivers/bus_spi_stm32h7xx.h[34-37]
src/main/drivers/bus_spi_stm32f7xx.h[38-42]
src/main/common/utils.h[35-36]
src/main/drivers/io_def.h[1-4]
src/main/drivers/io.h[106-108]
src/main/drivers/bus_spi_hal_ll.c[21-26]
src/main/drivers/bus_spi_hal_ll.c[91-93]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new SPI AF lookup table headers use `CONCAT4(...)` but do not include the header that defines it (`common/utils.h`). They currently compile only due to transitive includes (via `drivers/io.h` → `io_def.h` → `common/utils.h`) and therefore are fragile to include-order changes or reuse.
### Issue Context
This is a latent build fragility / maintainability issue: it may not break today, but it can break later during refactors or if another file includes these headers without including `common/utils.h` first.
### Fix Focus Areas
- src/main/drivers/bus_spi_stm32h7xx.h[32-38]
- src/main/drivers/bus_spi_stm32f7xx.h[36-42]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@github-actions
Copy link

github-actions bot commented Mar 2, 2026

Test firmware build ready — commit 6817a66

Download firmware for PR #11389

223 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

Both bus_spi_stm32h7xx.h and bus_spi_stm32f7xx.h use CONCAT4 but relied
on transitive includes from the including translation unit to provide it.
Add an explicit include to make the dependency self-contained.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant