Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / bus_spi.h
blobefd4c45906378f4cb3bcb31f15f8fc1e3f6beb31
1 /*
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)
8 * any later version.
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/>.
21 #pragma once
23 #include "drivers/bus.h"
24 #include "drivers/io_types.h"
25 #include "drivers/bus.h"
26 #include "drivers/rcc_types.h"
28 #include "pg/pg.h"
29 #include "pg/pg_ids.h"
31 #if defined(STM32F4) || defined(STM32F3)
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_MISO_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_MISO_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)
42 #elif defined(STM32F1)
43 #define SPI_IO_AF_SCK_CFG IO_CONFIG(GPIO_Mode_AF_PP, GPIO_Speed_50MHz)
44 #define SPI_IO_AF_MOSI_CFG IO_CONFIG(GPIO_Mode_AF_PP, GPIO_Speed_50MHz)
45 #define SPI_IO_AF_MISO_CFG IO_CONFIG(GPIO_Mode_IN_FLOATING, GPIO_Speed_50MHz)
46 #define SPI_IO_CS_CFG IO_CONFIG(GPIO_Mode_Out_PP, GPIO_Speed_50MHz)
47 #endif
49 // De facto standard mode
50 // See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
52 // Mode CPOL CPHA
53 // 0 0 0
54 // 1 0 1
55 // 2 1 0
56 // 3 1 1
57 typedef enum {
58 SPI_MODE0_POL_LOW_EDGE_1ST = 0,
59 SPI_MODE1_POL_LOW_EDGE_2ND,
60 SPI_MODE2_POL_HIGH_EDGE_1ST,
61 SPI_MODE3_POL_HIGH_EDGE_2ND
62 } SPIMode_e;
64 typedef enum SPIDevice {
65 SPIINVALID = -1,
66 SPIDEV_1 = 0,
67 SPIDEV_2,
68 SPIDEV_3,
69 SPIDEV_4,
70 SPIDEV_5,
71 SPIDEV_6
72 } SPIDevice;
74 #if defined(STM32F1)
75 #define SPIDEV_COUNT 2
76 #elif defined(STM32F3) || defined(STM32F4)
77 #define SPIDEV_COUNT 3
78 #elif defined(STM32F7)
79 #define SPIDEV_COUNT 4
80 #elif defined(STM32H7)
81 #define SPIDEV_COUNT 6
82 #else
83 #define SPIDEV_COUNT 4
84 #endif
86 // Macros to convert between CLI bus number and SPIDevice.
87 #define SPI_CFG_TO_DEV(x) ((x) - 1)
88 #define SPI_DEV_TO_CFG(x) ((x) + 1)
90 // Work around different check routines in the libraries for different MCU types
91 #if defined(STM32H7)
92 #define CHECK_SPI_RX_DATA_AVAILABLE(instance) LL_SPI_IsActiveFlag_RXWNE(instance)
93 #define SPI_RX_DATA_REGISTER(base) ((base)->RXDR)
94 #else
95 #define CHECK_SPI_RX_DATA_AVAILABLE(instance) LL_SPI_IsActiveFlag_RXNE(instance)
96 #define SPI_RX_DATA_REGISTER(base) ((base)->DR)
97 #endif
99 void spiPreinit(void);
100 void spiPreinitRegister(ioTag_t iotag, uint8_t iocfg, uint8_t init);
101 void spiPreinitByIO(IO_t io);
102 void spiPreinitByTag(ioTag_t tag);
104 bool spiInit(SPIDevice device);
106 // Called after all devices are initialised to enable SPI DMA where streams are available.
107 void spiInitBusDMA();
110 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance);
111 SPI_TypeDef *spiInstanceByDevice(SPIDevice device);
113 // BusDevice API
115 // Mark a device's associated bus as being SPI
116 bool spiSetBusInstance(extDevice_t *dev, uint32_t device);
117 // Determine the divisor to use for a given bus frequency
118 uint16_t spiCalculateDivider(uint32_t freq);
119 // Return the SPI clock based on the given divisor
120 uint32_t spiCalculateClock(uint16_t spiClkDivisor);
121 // Set the clock divisor to be used for accesses by the given device
122 void spiSetClkDivisor(const extDevice_t *dev, uint16_t divider);
123 // Set the clock phase/polarity to be used for accesses by the given device
124 void spiSetClkPhasePolarity(const extDevice_t *dev, bool leadingEdge);
125 // Enable/disable DMA on a specific device. Enabled by default.
126 void spiDmaEnable(const extDevice_t *dev, bool enable);
128 // DMA transfer setup and start
129 void spiSequence(const extDevice_t *dev, busSegment_t *segments);
130 // Wait for DMA completion
131 void spiWait(const extDevice_t *dev);
132 // Return true if DMA engine is busy
133 bool spiIsBusy(const extDevice_t *dev);
136 * Routine naming convention is:
137 * spi[Read][Write][Reg][Msk][Buf][RB]
139 * Read: Perform a read, returning the value read unless 'Buf' is specified
140 * Write Perform a write
141 * ReadWrite: Perform both a read and write, returning the value read unless 'Buf' is specified
142 * Reg: Register number 'reg' is written prior to the read being performed
143 * Msk: Register number is logically ORed with 0x80 as some devices indicate a read by accessing a register with bit 7 set
144 * Buf: Pass data of given length by reference
145 * RB: Return false immediately if the bus is busy, otherwise complete the access and return true
147 uint8_t spiReadReg(const extDevice_t *dev, uint8_t reg);
148 uint8_t spiReadRegMsk(const extDevice_t *dev, uint8_t reg);
149 void spiReadRegBuf(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length);
150 bool spiReadRegBufRB(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length);
151 bool spiReadRegMskBufRB(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length);
153 void spiWrite(const extDevice_t *dev, uint8_t data);
154 void spiWriteReg(const extDevice_t *dev, uint8_t reg, uint8_t data);
155 bool spiWriteRegRB(const extDevice_t *dev, uint8_t reg, uint8_t data);
157 uint8_t spiReadWrite(const extDevice_t *dev, uint8_t data);
159 void spiWriteRegBuf(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint32_t length);
160 uint8_t spiReadWriteReg(const extDevice_t *dev, uint8_t reg, uint8_t data);
161 void spiReadWriteBuf(const extDevice_t *dev, uint8_t *txData, uint8_t *rxData, int len);
162 bool spiReadWriteBufRB(const extDevice_t *dev, uint8_t *txData, uint8_t *rxData, int length);
165 // Config
168 struct spiPinConfig_s;
169 void spiPinConfigure(const struct spiPinConfig_s *pConfig);
170 bool spiUseDMA(const extDevice_t *dev);
171 bool spiUseMOSI_DMA(const extDevice_t *dev);
172 void spiBusDeviceRegister(const extDevice_t *dev);
173 uint8_t spiGetRegisteredDeviceCount(void);
174 uint8_t spiGetExtDeviceCount(const extDevice_t *dev);