2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
23 #include "drivers/bus.h"
24 #include "drivers/io_types.h"
25 #include "drivers/bus.h"
26 #include "drivers/rcc_types.h"
29 #include "pg/pg_ids.h"
32 #define SPI_IO_AF_CFG IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL)
33 #define SPI_IO_AF_SCK_CFG IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_DOWN)
34 #define SPI_IO_AF_SDI_CFG IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP)
35 #define SPI_IO_CS_CFG IO_CONFIG(GPIO_Mode_OUT, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL)
36 #elif defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
37 #define SPI_IO_AF_CFG IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_NOPULL)
38 #define SPI_IO_AF_SCK_CFG_HIGH IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP)
39 #define SPI_IO_AF_SCK_CFG_LOW IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLDOWN)
40 #define SPI_IO_AF_SDI_CFG IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP)
41 #define SPI_IO_CS_CFG IO_CONFIG(GPIO_MODE_OUTPUT_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_NOPULL)
43 #define SPI_IO_AF_CFG IO_CONFIG(GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL , GPIO_PULL_NONE)
44 #define SPI_IO_AF_SCK_CFG_HIGH IO_CONFIG(GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL , GPIO_PULL_UP)
45 #define SPI_IO_AF_SCK_CFG_LOW IO_CONFIG(GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL , GPIO_PULL_DOWN)
46 #define SPI_IO_AF_SDI_CFG IO_CONFIG(GPIO_MODE_MUX, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL , GPIO_PULL_UP)
47 #define SPI_IO_CS_CFG IO_CONFIG(GPIO_MODE_OUTPUT, GPIO_DRIVE_STRENGTH_STRONGER, GPIO_OUTPUT_PUSH_PULL , GPIO_PULL_NONE)
50 // De facto standard mode
51 // See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
59 SPI_MODE0_POL_LOW_EDGE_1ST
= 0,
60 SPI_MODE1_POL_LOW_EDGE_2ND
,
61 SPI_MODE2_POL_HIGH_EDGE_1ST
,
62 SPI_MODE3_POL_HIGH_EDGE_2ND
65 typedef enum SPIDevice
{
76 #define SPIDEV_COUNT 3
77 #elif defined(STM32F7)
78 #define SPIDEV_COUNT 4
79 #elif defined(STM32H7)
80 #define SPIDEV_COUNT 6
82 #define SPIDEV_COUNT 4
85 // Macros to convert between CLI bus number and SPIDevice.
86 #define SPI_CFG_TO_DEV(x) ((x) - 1)
87 #define SPI_DEV_TO_CFG(x) ((x) + 1)
89 // Work around different check routines in the libraries for different MCU types
91 #define CHECK_SPI_RX_DATA_AVAILABLE(instance) LL_SPI_IsActiveFlag_RXWNE(instance)
92 #define SPI_RX_DATA_REGISTER(base) ((base)->RXDR)
94 #define CHECK_SPI_RX_DATA_AVAILABLE(instance) LL_SPI_IsActiveFlag_RXNE(instance)
95 #define SPI_RX_DATA_REGISTER(base) ((base)->DR)
98 void spiPreinit(void);
99 void spiPreinitRegister(ioTag_t iotag
, uint8_t iocfg
, uint8_t init
);
100 void spiPreinitByIO(const IO_t io
);
101 void spiPreinitByTag(ioTag_t tag
);
103 bool spiInit(SPIDevice device
);
105 // Called after all devices are initialised to enable SPI DMA where streams are available.
106 void spiInitBusDMA();
109 SPIDevice
spiDeviceByInstance(const SPI_TypeDef
*instance
);
110 SPI_TypeDef
*spiInstanceByDevice(SPIDevice device
);
114 // Mark a device's associated bus as being SPI
115 bool spiSetBusInstance(extDevice_t
*dev
, uint32_t device
);
116 // Determine the divisor to use for a given bus frequency
117 uint16_t spiCalculateDivider(uint32_t freq
);
118 // Return the SPI clock based on the given divisor
119 uint32_t spiCalculateClock(uint16_t spiClkDivisor
);
120 // Set the clock divisor to be used for accesses by the given device
121 void spiSetClkDivisor(const extDevice_t
*dev
, uint16_t divider
);
122 // Set the clock phase/polarity to be used for accesses by the given device
123 void spiSetClkPhasePolarity(const extDevice_t
*dev
, bool leadingEdge
);
124 // Enable/disable DMA on a specific device. Enabled by default.
125 void spiDmaEnable(const extDevice_t
*dev
, bool enable
);
127 // DMA transfer setup and start
128 void spiSequence(const extDevice_t
*dev
, busSegment_t
*segments
);
129 // Wait for DMA completion
130 void spiWait(const extDevice_t
*dev
);
131 // Negate CS if held asserted after a transfer
132 void spiRelease(const extDevice_t
*dev
);
133 // Return true if DMA engine is busy
134 bool spiIsBusy(const extDevice_t
*dev
);
136 // Link two segment lists
137 void spiLinkSegments(const extDevice_t
*dev
, busSegment_t
*firstSegment
, busSegment_t
*secondSegment
);
140 * Routine naming convention is:
141 * spi[Read][Write][Reg][Msk][Buf][RB]
143 * Read: Perform a read, returning the value read unless 'Buf' is specified
144 * Write Perform a write
145 * ReadWrite: Perform both a read and write, returning the value read unless 'Buf' is specified
146 * Reg: Register number 'reg' is written prior to the read being performed
147 * Msk: Register number is logically ORed with 0x80 as some devices indicate a read by accessing a register with bit 7 set
148 * Buf: Pass data of given length by reference
149 * RB: Return false immediately if the bus is busy, otherwise complete the access and return true
151 uint8_t spiReadReg(const extDevice_t
*dev
, uint8_t reg
);
152 uint8_t spiReadRegMsk(const extDevice_t
*dev
, uint8_t reg
);
153 void spiReadRegBuf(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
);
154 bool spiReadRegBufRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
);
155 bool spiReadRegMskBufRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
);
157 void spiWrite(const extDevice_t
*dev
, uint8_t data
);
158 void spiWriteReg(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
);
159 bool spiWriteRegRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
);
161 uint8_t spiReadWrite(const extDevice_t
*dev
, uint8_t data
);
163 void spiWriteRegBuf(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint32_t length
);
164 uint8_t spiReadWriteReg(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
);
165 void spiReadWriteBuf(const extDevice_t
*dev
, uint8_t *txData
, uint8_t *rxData
, int len
);
166 bool spiReadWriteBufRB(const extDevice_t
*dev
, uint8_t *txData
, uint8_t *rxData
, int length
);
172 struct spiPinConfig_s
;
173 void spiPinConfigure(const struct spiPinConfig_s
*pConfig
);
174 bool spiUseDMA(const extDevice_t
*dev
);
175 bool spiUseSDO_DMA(const extDevice_t
*dev
);
176 void spiBusDeviceRegister(const extDevice_t
*dev
);
177 uint8_t spiGetRegisteredDeviceCount(void);
178 uint8_t spiGetExtDeviceCount(const extDevice_t
*dev
);