Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 107 additions & 57 deletions src/main/drivers/bus_spi_hal_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,109 +89,159 @@ static const uint32_t spiDivisorMapSlow[] = {
#endif

#if defined(STM32H7)
static spiDevice_t spiHardwareMap[SPIDEV_COUNT] = {
#include "bus_spi_stm32h7xx.h"

// Auto-resolve SPI AF per pin from the lookup table in bus_spi_stm32h7xx.h.
// Targets may still define individual SPI*_SCK/MISO/MOSI_AF values in target.h
// to override; explicit defines take priority via these #ifndef guards.
#ifdef USE_SPI_DEVICE_1
#if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
#if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
#error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
#ifndef SPI1_SCK_AF
#define SPI1_SCK_AF SPI_PIN_AF_HELPER(1, SPI1_SCK_PIN)
#endif
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = SPI1_SCK_AF, .misoAF = SPI1_MISO_AF, .mosiAF = SPI1_MOSI_AF, .divisorMap = spiDivisorMapFast },
#else
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = GPIO_AF5_SPI1, .misoAF = GPIO_AF5_SPI1, .mosiAF = GPIO_AF5_SPI1, .divisorMap = spiDivisorMapFast },
#ifndef SPI1_MISO_AF
#define SPI1_MISO_AF SPI_PIN_AF_HELPER(1, SPI1_MISO_PIN)
#endif
#ifndef SPI1_MOSI_AF
#define SPI1_MOSI_AF SPI_PIN_AF_HELPER(1, SPI1_MOSI_PIN)
#endif
#else
{ .dev = NULL }, // No SPI1
#endif

#ifdef USE_SPI_DEVICE_2
#if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
#if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
#error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
#ifndef SPI2_SCK_AF
#define SPI2_SCK_AF SPI_PIN_AF_HELPER(2, SPI2_SCK_PIN)
#endif
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1L(SPI2), .sckAF = SPI2_SCK_AF, .misoAF = SPI2_MISO_AF, .mosiAF = SPI2_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#ifndef SPI2_MISO_AF
#define SPI2_MISO_AF SPI_PIN_AF_HELPER(2, SPI2_MISO_PIN)
#endif
#ifndef SPI2_MOSI_AF
#define SPI2_MOSI_AF SPI_PIN_AF_HELPER(2, SPI2_MOSI_PIN)
#endif
#endif

#ifdef USE_SPI_DEVICE_3
#ifndef SPI3_SCK_AF
#define SPI3_SCK_AF SPI_PIN_AF_HELPER(3, SPI3_SCK_PIN)
#endif
#ifndef SPI3_MISO_AF
#define SPI3_MISO_AF SPI_PIN_AF_HELPER(3, SPI3_MISO_PIN)
#endif
#ifndef SPI3_MOSI_AF
#define SPI3_MOSI_AF SPI_PIN_AF_HELPER(3, SPI3_MOSI_PIN)
#endif
#endif

#ifdef USE_SPI_DEVICE_4
#ifndef SPI4_SCK_AF
#define SPI4_SCK_AF SPI_PIN_AF_HELPER(4, SPI4_SCK_PIN)
#endif
#ifndef SPI4_MISO_AF
#define SPI4_MISO_AF SPI_PIN_AF_HELPER(4, SPI4_MISO_PIN)
#endif
#ifndef SPI4_MOSI_AF
#define SPI4_MOSI_AF SPI_PIN_AF_HELPER(4, SPI4_MOSI_PIN)
#endif
#endif

static spiDevice_t spiHardwareMap[SPIDEV_COUNT] = {
#ifdef USE_SPI_DEVICE_1
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = SPI1_SCK_AF, .misoAF = SPI1_MISO_AF, .mosiAF = SPI1_MOSI_AF, .divisorMap = spiDivisorMapFast },
#else
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1L(SPI2), .sckAF = GPIO_AF5_SPI2, .misoAF = GPIO_AF5_SPI2, .mosiAF = GPIO_AF5_SPI2, .divisorMap = spiDivisorMapSlow },
{ .dev = NULL }, // No SPI1
#endif

#ifdef USE_SPI_DEVICE_2
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1L(SPI2), .sckAF = SPI2_SCK_AF, .misoAF = SPI2_MISO_AF, .mosiAF = SPI2_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#else
{ .dev = NULL }, // No SPI2
#endif

#ifdef USE_SPI_DEVICE_3
#if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
#if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
#error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
#endif
{ .dev = SPI3, .nss = IO_TAG(SPI3_NSS_PIN), .sck = IO_TAG(SPI3_SCK_PIN), .miso = IO_TAG(SPI3_MISO_PIN), .mosi = IO_TAG(SPI3_MOSI_PIN), .rcc = RCC_APB1L(SPI3), .sckAF = SPI3_SCK_AF, .misoAF = SPI3_MISO_AF, .mosiAF = SPI3_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#else
{ .dev = SPI3, .nss = IO_TAG(SPI3_NSS_PIN), .sck = IO_TAG(SPI3_SCK_PIN), .miso = IO_TAG(SPI3_MISO_PIN), .mosi = IO_TAG(SPI3_MOSI_PIN), .rcc = RCC_APB1L(SPI3), .sckAF = GPIO_AF6_SPI3, .misoAF = GPIO_AF6_SPI3, .mosiAF = GPIO_AF6_SPI3, .divisorMap = spiDivisorMapSlow },
#endif
#else
{ .dev = NULL }, // No SPI3
#endif

#ifdef USE_SPI_DEVICE_4
#if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
#if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
#error SPI4: SCK, MISO and MOSI AFs should be defined together in target.h!
#endif
{ .dev = SPI4, .nss = IO_TAG(SPI4_NSS_PIN), .sck = IO_TAG(SPI4_SCK_PIN), .miso = IO_TAG(SPI4_MISO_PIN), .mosi = IO_TAG(SPI4_MOSI_PIN), .rcc = RCC_APB2(SPI4), .sckAF = SPI4_SCK_AF, .misoAF = SPI4_MISO_AF, .mosiAF = SPI4_MOSI_AF, .divisorMap = spiDivisorMapSlow }
#else
{ .dev = SPI4, .nss = IO_TAG(SPI4_NSS_PIN), .sck = IO_TAG(SPI4_SCK_PIN), .miso = IO_TAG(SPI4_MISO_PIN), .mosi = IO_TAG(SPI4_MOSI_PIN), .rcc = RCC_APB2(SPI4), .sckAF = GPIO_AF5_SPI4, .misoAF = GPIO_AF5_SPI4, .mosiAF = GPIO_AF5_SPI4, .divisorMap = spiDivisorMapSlow }
#endif
#else
{ .dev = NULL } // No SPI4
#endif
};
#else
static spiDevice_t spiHardwareMap[] = {
#elif defined(STM32F7)
#include "bus_spi_stm32f7xx.h"

// Auto-resolve SPI AF per pin from the lookup table in bus_spi_stm32f7xx.h.
// Targets may still define individual SPI*_SCK/MISO/MOSI_AF values in target.h
// to override; explicit defines take priority via these #ifndef guards.
#ifdef USE_SPI_DEVICE_1
#if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
#if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
#error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
#ifndef SPI1_SCK_AF
#define SPI1_SCK_AF SPI_PIN_AF_HELPER(1, SPI1_SCK_PIN)
#endif
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = SPI1_SCK_AF, .misoAF = SPI1_MISO_AF, .mosiAF = SPI1_MOSI_AF, .divisorMap = spiDivisorMapFast },
#else
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = GPIO_AF5_SPI1, .misoAF = GPIO_AF5_SPI1, .mosiAF = GPIO_AF5_SPI1, .divisorMap = spiDivisorMapFast },
#ifndef SPI1_MISO_AF
#define SPI1_MISO_AF SPI_PIN_AF_HELPER(1, SPI1_MISO_PIN)
#endif
#ifndef SPI1_MOSI_AF
#define SPI1_MOSI_AF SPI_PIN_AF_HELPER(1, SPI1_MOSI_PIN)
#endif
#else
{ .dev = NULL }, // No SPI1
#endif

#ifdef USE_SPI_DEVICE_2
#if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
#if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
#error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
#ifndef SPI2_SCK_AF
#define SPI2_SCK_AF SPI_PIN_AF_HELPER(2, SPI2_SCK_PIN)
#endif
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1(SPI2), .sckAF = SPI2_SCK_AF, .misoAF = SPI2_MISO_AF, .mosiAF = SPI2_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#ifndef SPI2_MISO_AF
#define SPI2_MISO_AF SPI_PIN_AF_HELPER(2, SPI2_MISO_PIN)
#endif
#ifndef SPI2_MOSI_AF
#define SPI2_MOSI_AF SPI_PIN_AF_HELPER(2, SPI2_MOSI_PIN)
#endif
#endif

#ifdef USE_SPI_DEVICE_3
#ifndef SPI3_SCK_AF
#define SPI3_SCK_AF SPI_PIN_AF_HELPER(3, SPI3_SCK_PIN)
#endif
#ifndef SPI3_MISO_AF
#define SPI3_MISO_AF SPI_PIN_AF_HELPER(3, SPI3_MISO_PIN)
#endif
#ifndef SPI3_MOSI_AF
#define SPI3_MOSI_AF SPI_PIN_AF_HELPER(3, SPI3_MOSI_PIN)
#endif
#endif

#ifdef USE_SPI_DEVICE_4
#ifndef SPI4_SCK_AF
#define SPI4_SCK_AF SPI_PIN_AF_HELPER(4, SPI4_SCK_PIN)
#endif
#ifndef SPI4_MISO_AF
#define SPI4_MISO_AF SPI_PIN_AF_HELPER(4, SPI4_MISO_PIN)
#endif
#ifndef SPI4_MOSI_AF
#define SPI4_MOSI_AF SPI_PIN_AF_HELPER(4, SPI4_MOSI_PIN)
#endif
#endif

static spiDevice_t spiHardwareMap[] = {
#ifdef USE_SPI_DEVICE_1
{ .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .sckAF = SPI1_SCK_AF, .misoAF = SPI1_MISO_AF, .mosiAF = SPI1_MOSI_AF, .divisorMap = spiDivisorMapFast },
#else
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1(SPI2), .sckAF = GPIO_AF5_SPI2, .misoAF = GPIO_AF5_SPI2, .mosiAF = GPIO_AF5_SPI2, .divisorMap = spiDivisorMapSlow },
{ .dev = NULL }, // No SPI1
#endif

#ifdef USE_SPI_DEVICE_2
{ .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1(SPI2), .sckAF = SPI2_SCK_AF, .misoAF = SPI2_MISO_AF, .mosiAF = SPI2_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#else
{ .dev = NULL }, // No SPI2
#endif

#ifdef USE_SPI_DEVICE_3
#if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
#if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
#error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
#endif
{ .dev = SPI3, .nss = IO_TAG(SPI3_NSS_PIN), .sck = IO_TAG(SPI3_SCK_PIN), .miso = IO_TAG(SPI3_MISO_PIN), .mosi = IO_TAG(SPI3_MOSI_PIN), .rcc = RCC_APB1(SPI3), .sckAF = SPI3_SCK_AF, .misoAF = SPI3_MISO_AF, .mosiAF = SPI3_MOSI_AF, .divisorMap = spiDivisorMapSlow },
#else
{ .dev = SPI3, .nss = IO_TAG(SPI3_NSS_PIN), .sck = IO_TAG(SPI3_SCK_PIN), .miso = IO_TAG(SPI3_MISO_PIN), .mosi = IO_TAG(SPI3_MOSI_PIN), .rcc = RCC_APB1(SPI3), .sckAF = GPIO_AF6_SPI3, .misoAF = GPIO_AF6_SPI3, .mosiAF = GPIO_AF6_SPI3, .divisorMap = spiDivisorMapSlow },
#endif
#else
{ .dev = NULL }, // No SPI3
#endif

#ifdef USE_SPI_DEVICE_4
#if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
#if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
#error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
#endif
{ .dev = SPI4, .nss = IO_TAG(SPI4_NSS_PIN), .sck = IO_TAG(SPI4_SCK_PIN), .miso = IO_TAG(SPI4_MISO_PIN), .mosi = IO_TAG(SPI4_MOSI_PIN), .rcc = RCC_APB2(SPI4), .sckAF = SPI4_SCK_AF, .misoAF = SPI4_MISO_AF, .mosiAF = SPI4_MOSI_AF, .divisorMap = spiDivisorMapSlow }
#else
{ .dev = SPI4, .nss = IO_TAG(SPI4_NSS_PIN), .sck = IO_TAG(SPI4_SCK_PIN), .miso = IO_TAG(SPI4_MISO_PIN), .mosi = IO_TAG(SPI4_MOSI_PIN), .rcc = RCC_APB2(SPI4), .sckAF = GPIO_AF5_SPI4, .misoAF = GPIO_AF5_SPI4, .mosiAF = GPIO_AF5_SPI4, .divisorMap = spiDivisorMapSlow }
#endif
#else
{ .dev = NULL } // No SPI4
#endif
Expand Down
80 changes: 80 additions & 0 deletions src/main/drivers/bus_spi_stm32f7xx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* This file is part of INAV.
*
* INAV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* INAV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with INAV. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* STM32F7 SPI pin alternate function lookup table.
*
* Usage: SPI_PIN_AF_HELPER(3, PB5) expands to SPI_PIN_AF_SPI3_PB5,
* which is defined below as GPIO_AF6_SPI3.
*
* AF assignments from STM32F722 datasheet (DS11853) and STM32F745 datasheet
* (DS10916), Table 9.
*
* NOTE: The F7 AF table differs from the H7 for SPI3/PB5:
* On F7, PB5 SPI3_MOSI is AF6 (the default).
* On H7, PB5 SPI3_MOSI is AF7 (an exception — see bus_spi_stm32h7xx.h).
*
* SPI1, SPI2, SPI4 pins are all AF5 with no exceptions.
* SPI3 SCK/MISO are AF6. SPI3 MOSI has pin-dependent exceptions:
* PB2 uses AF7 (not AF6). PD6 uses AF5 (not AF6). PC12 and PB5 use AF6.
*/

#pragma once

#include "common/utils.h"

// Resolves to SPI_PIN_AF_SPIn_Pxy, 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)

/* SPI1 — all data pins use AF5 */
#define SPI_PIN_AF_SPI1_PA5 GPIO_AF5_SPI1 // SCK
#define SPI_PIN_AF_SPI1_PA6 GPIO_AF5_SPI1 // MISO
#define SPI_PIN_AF_SPI1_PA7 GPIO_AF5_SPI1 // MOSI
#define SPI_PIN_AF_SPI1_PB3 GPIO_AF5_SPI1 // SCK
#define SPI_PIN_AF_SPI1_PB4 GPIO_AF5_SPI1 // MISO
#define SPI_PIN_AF_SPI1_PB5 GPIO_AF5_SPI1 // MOSI

/* SPI2 — all data pins use AF5 */
#define SPI_PIN_AF_SPI2_PB13 GPIO_AF5_SPI2 // SCK
#define SPI_PIN_AF_SPI2_PB14 GPIO_AF5_SPI2 // MISO
#define SPI_PIN_AF_SPI2_PB15 GPIO_AF5_SPI2 // MOSI
#define SPI_PIN_AF_SPI2_PC1 GPIO_AF5_SPI2 // MOSI
#define SPI_PIN_AF_SPI2_PC2 GPIO_AF5_SPI2 // MISO
#define SPI_PIN_AF_SPI2_PC3 GPIO_AF5_SPI2 // MOSI

/*
* SPI3 — SCK and MISO use AF6, but MOSI has pin-dependent exceptions.
* PB2 carries SPI3_MOSI on AF7 (not AF6). PD6 uses AF5. PB5 and PC12 use AF6.
*/
#define SPI_PIN_AF_SPI3_PB2 GPIO_AF7_SPI3 // MOSI — exception: AF7, not AF6
#define SPI_PIN_AF_SPI3_PB3 GPIO_AF6_SPI3 // SCK
#define SPI_PIN_AF_SPI3_PB4 GPIO_AF6_SPI3 // MISO
#define SPI_PIN_AF_SPI3_PB5 GPIO_AF6_SPI3 // MOSI (AF6 on F7; H7 uses AF7 for this pin)
#define SPI_PIN_AF_SPI3_PC10 GPIO_AF6_SPI3 // SCK
#define SPI_PIN_AF_SPI3_PC11 GPIO_AF6_SPI3 // MISO
#define SPI_PIN_AF_SPI3_PC12 GPIO_AF6_SPI3 // MOSI
#define SPI_PIN_AF_SPI3_PD6 GPIO_AF5_SPI3 // MOSI — exception: AF5, not AF6

/* SPI4 — all data pins use AF5 */
#define SPI_PIN_AF_SPI4_PE2 GPIO_AF5_SPI4 // SCK
#define SPI_PIN_AF_SPI4_PE5 GPIO_AF5_SPI4 // MISO
#define SPI_PIN_AF_SPI4_PE6 GPIO_AF5_SPI4 // MOSI
#define SPI_PIN_AF_SPI4_PE12 GPIO_AF5_SPI4 // SCK
#define SPI_PIN_AF_SPI4_PE13 GPIO_AF5_SPI4 // MISO
#define SPI_PIN_AF_SPI4_PE14 GPIO_AF5_SPI4 // MOSI
81 changes: 81 additions & 0 deletions src/main/drivers/bus_spi_stm32h7xx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* This file is part of INAV.
*
* INAV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* INAV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with INAV. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* STM32H7 SPI pin alternate function lookup table.
*
* Usage: SPI_PIN_AF_HELPER(3, PB5) expands to SPI_PIN_AF_SPI3_PB5,
* which is defined below as GPIO_AF7_SPI3.
*
* This allows bus_spi_hal_ll.c to resolve the correct AF per pin automatically,
* without requiring each target to define SPI*_SCK_AF / SPI*_MISO_AF / SPI*_MOSI_AF
* manually in target.h. Targets may still override individual values if needed.
*
* Alternate function assignments are from the STM32H743 datasheet (DS12110),
* Tables 10-14.
*/

#pragma once

#include "common/utils.h"

// 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)

/* SPI1 — all data pins use AF5 */
#define SPI_PIN_AF_SPI1_PA5 GPIO_AF5_SPI1 // SCK
#define SPI_PIN_AF_SPI1_PA6 GPIO_AF5_SPI1 // MISO
#define SPI_PIN_AF_SPI1_PA7 GPIO_AF5_SPI1 // MOSI
#define SPI_PIN_AF_SPI1_PB3 GPIO_AF5_SPI1 // SCK
#define SPI_PIN_AF_SPI1_PB4 GPIO_AF5_SPI1 // MISO
#define SPI_PIN_AF_SPI1_PB5 GPIO_AF5_SPI1 // MOSI
#define SPI_PIN_AF_SPI1_PD7 GPIO_AF5_SPI1 // MOSI

/* SPI2 — all data pins use AF5 */
#define SPI_PIN_AF_SPI2_PA9 GPIO_AF5_SPI2 // SCK
#define SPI_PIN_AF_SPI2_PB10 GPIO_AF5_SPI2 // SCK
#define SPI_PIN_AF_SPI2_PB13 GPIO_AF5_SPI2 // SCK
#define SPI_PIN_AF_SPI2_PB14 GPIO_AF5_SPI2 // MISO
#define SPI_PIN_AF_SPI2_PB15 GPIO_AF5_SPI2 // MOSI
#define SPI_PIN_AF_SPI2_PC1 GPIO_AF5_SPI2 // MOSI
#define SPI_PIN_AF_SPI2_PC2 GPIO_AF5_SPI2 // MISO
#define SPI_PIN_AF_SPI2_PC3 GPIO_AF5_SPI2 // MOSI
#define SPI_PIN_AF_SPI2_PD3 GPIO_AF5_SPI2 // SCK

/*
* SPI3 — SCK and MISO use AF6, but MOSI has pin-dependent exceptions.
* PB2 and PB5 carry SPI3_MOSI on AF7 (not AF6). PD6 uses AF5.
* This is the only SPI bus on STM32H743 where a single-AF fallback is wrong.
*/
#define SPI_PIN_AF_SPI3_PB2 GPIO_AF7_SPI3 // MOSI — exception: AF7, not AF6
#define SPI_PIN_AF_SPI3_PB3 GPIO_AF6_SPI3 // SCK
#define SPI_PIN_AF_SPI3_PB4 GPIO_AF6_SPI3 // MISO
#define SPI_PIN_AF_SPI3_PB5 GPIO_AF7_SPI3 // MOSI — exception: AF7, not AF6
#define SPI_PIN_AF_SPI3_PC10 GPIO_AF6_SPI3 // SCK
#define SPI_PIN_AF_SPI3_PC11 GPIO_AF6_SPI3 // MISO
#define SPI_PIN_AF_SPI3_PC12 GPIO_AF6_SPI3 // MOSI
#define SPI_PIN_AF_SPI3_PD6 GPIO_AF5_SPI3 // MOSI — exception: AF5, not AF6

/* SPI4 — all data pins use AF5 */
#define SPI_PIN_AF_SPI4_PE2 GPIO_AF5_SPI4 // SCK
#define SPI_PIN_AF_SPI4_PE5 GPIO_AF5_SPI4 // MISO
#define SPI_PIN_AF_SPI4_PE6 GPIO_AF5_SPI4 // MOSI
#define SPI_PIN_AF_SPI4_PE12 GPIO_AF5_SPI4 // SCK
#define SPI_PIN_AF_SPI4_PE13 GPIO_AF5_SPI4 // MISO
#define SPI_PIN_AF_SPI4_PE14 GPIO_AF5_SPI4 // MOSI