2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #include "drivers/bus_spi.h"
25 #include "drivers/io.h"
27 #include "drivers/nvic.h"
31 #define SPI1_NSS_PIN PA4
32 #define SPI1_SCK_PIN PA5
33 #define SPI1_MISO_PIN PA6
34 #define SPI1_MOSI_PIN PA7
38 #define SPI2_NSS_PIN PB12
39 #define SPI2_SCK_PIN PB13
40 #define SPI2_MISO_PIN PB14
41 #define SPI2_MOSI_PIN PB15
45 #define SPI3_NSS_PIN PA15
46 #define SPI3_SCK_PIN PB3
47 #define SPI3_MISO_PIN PB4
48 #define SPI3_MOSI_PIN PB5
52 #define SPI4_NSS_PIN PA15
53 #define SPI4_SCK_PIN PB3
54 #define SPI4_MISO_PIN PB4
55 #define SPI4_MOSI_PIN PB5
59 #define SPI1_NSS_PIN NONE
62 #define SPI2_NSS_PIN NONE
65 #define SPI3_NSS_PIN NONE
68 #define SPI4_NSS_PIN NONE
71 #if defined(USE_SPI_DEVICE_1)
72 static const uint32_t spiDivisorMapFast
[] = {
73 LL_SPI_BAUDRATEPRESCALER_DIV256
, // SPI_CLOCK_INITIALIZATON 421.875 KBits/s
74 LL_SPI_BAUDRATEPRESCALER_DIV32
, // SPI_CLOCK_SLOW 843.75 KBits/s
75 LL_SPI_BAUDRATEPRESCALER_DIV16
, // SPI_CLOCK_STANDARD 6.75 MBits/s
76 LL_SPI_BAUDRATEPRESCALER_DIV8
, // SPI_CLOCK_FAST 13.5 MBits/s
77 LL_SPI_BAUDRATEPRESCALER_DIV4
// SPI_CLOCK_ULTRAFAST 27.0 MBits/s
81 #if defined(USE_SPI_DEVICE_2) || defined(USE_SPI_DEVICE_3) || defined(USE_SPI_DEVICE_4)
82 static const uint32_t spiDivisorMapSlow
[] = {
83 LL_SPI_BAUDRATEPRESCALER_DIV256
, // SPI_CLOCK_INITIALIZATON 210.937 KBits/s
84 LL_SPI_BAUDRATEPRESCALER_DIV64
, // SPI_CLOCK_SLOW 843.75 KBits/s
85 LL_SPI_BAUDRATEPRESCALER_DIV8
, // SPI_CLOCK_STANDARD 6.75 MBits/s
86 LL_SPI_BAUDRATEPRESCALER_DIV4
, // SPI_CLOCK_FAST 13.5 MBits/s
87 LL_SPI_BAUDRATEPRESCALER_DIV2
// SPI_CLOCK_ULTRAFAST 27.0 MBits/s
92 static spiDevice_t spiHardwareMap
[SPIDEV_COUNT
] = {
93 #ifdef USE_SPI_DEVICE_1
94 { .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
), .af
= GPIO_AF5_SPI1
, .divisorMap
= spiDivisorMapFast
},
96 { .dev
= NULL
}, // No SPI1
98 #ifdef USE_SPI_DEVICE_2
99 { .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
), .af
= GPIO_AF5_SPI2
, .divisorMap
= spiDivisorMapSlow
},
101 { .dev
= NULL
}, // No SPI2
103 #ifdef USE_SPI_DEVICE_3
104 { .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
), .af
= GPIO_AF6_SPI3
, .divisorMap
= spiDivisorMapSlow
},
106 { .dev
= NULL
}, // No SPI3
108 #ifdef USE_SPI_DEVICE_4
109 { .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
), .af
= GPIO_AF5_SPI4
, .divisorMap
= spiDivisorMapSlow
}
111 { .dev
= NULL
} // No SPI4
115 static spiDevice_t spiHardwareMap
[] = {
116 #ifdef USE_SPI_DEVICE_1
117 { .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
), .af
= GPIO_AF5_SPI1
, .divisorMap
= spiDivisorMapFast
},
119 { .dev
= NULL
}, // No SPI1
121 #ifdef USE_SPI_DEVICE_2
122 { .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
), .af
= GPIO_AF5_SPI2
, .divisorMap
= spiDivisorMapSlow
},
124 { .dev
= NULL
}, // No SPI2
126 #ifdef USE_SPI_DEVICE_3
127 { .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
), .af
= GPIO_AF6_SPI3
, .divisorMap
= spiDivisorMapSlow
},
129 { .dev
= NULL
}, // No SPI3
131 #ifdef USE_SPI_DEVICE_4
132 { .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
), .af
= GPIO_AF5_SPI4
, .divisorMap
= spiDivisorMapSlow
}
134 { .dev
= NULL
} // No SPI4
139 SPIDevice
spiDeviceByInstance(SPI_TypeDef
*instance
)
141 if (instance
== SPI1
)
144 if (instance
== SPI2
)
147 if (instance
== SPI3
)
150 if (instance
== SPI4
)
156 void spiTimeoutUserCallback(SPI_TypeDef
*instance
)
158 SPIDevice device
= spiDeviceByInstance(instance
);
159 if (device
== SPIINVALID
) {
163 spiHardwareMap
[device
].errorCount
++;
166 bool spiInitDevice(SPIDevice device
, bool leadingEdge
)
168 spiDevice_t
*spi
= &(spiHardwareMap
[device
]);
179 RCC_ClockCmd(spi
->rcc
, ENABLE
);
180 RCC_ResetCmd(spi
->rcc
, DISABLE
);
182 IOInit(IOGetByTag(spi
->sck
), OWNER_SPI
, RESOURCE_SPI_SCK
, device
+ 1);
183 IOInit(IOGetByTag(spi
->miso
), OWNER_SPI
, RESOURCE_SPI_MISO
, device
+ 1);
184 IOInit(IOGetByTag(spi
->mosi
), OWNER_SPI
, RESOURCE_SPI_MOSI
, device
+ 1);
187 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG_LOW
, spi
->af
);
189 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG_HIGH
, spi
->af
);
191 IOConfigGPIOAF(IOGetByTag(spi
->miso
), SPI_IO_AF_MISO_CFG
, spi
->af
);
192 IOConfigGPIOAF(IOGetByTag(spi
->mosi
), SPI_IO_AF_CFG
, spi
->af
);
195 IOInit(IOGetByTag(spi
->nss
), OWNER_SPI
, RESOURCE_SPI_CS
, device
+ 1);
196 IOConfigGPIO(IOGetByTag(spi
->nss
), SPI_IO_CS_CFG
);
199 LL_SPI_Disable(spi
->dev
);
200 LL_SPI_DeInit(spi
->dev
);
202 LL_SPI_InitTypeDef init
=
204 .TransferDirection
= SPI_DIRECTION_2LINES
,
205 .Mode
= SPI_MODE_MASTER
,
206 .DataWidth
= SPI_DATASIZE_8BIT
,
207 .ClockPolarity
= leadingEdge
? SPI_POLARITY_LOW
: SPI_POLARITY_HIGH
,
208 .ClockPhase
= leadingEdge
? SPI_PHASE_1EDGE
: SPI_PHASE_2EDGE
,
210 .BaudRate
= SPI_BAUDRATEPRESCALER_8
,
211 .BitOrder
= SPI_FIRSTBIT_MSB
,
213 .CRCCalculation
= SPI_CRCCALCULATION_DISABLE
,
217 // Prevent glitching when SPI is disabled
218 LL_SPI_EnableGPIOControl(spi
->dev
);
220 LL_SPI_SetFIFOThreshold(spi
->dev
, LL_SPI_FIFO_TH_01DATA
);
221 LL_SPI_Init(spi
->dev
, &init
);
223 LL_SPI_SetRxFIFOThreshold(spi
->dev
, SPI_RXFIFO_THRESHOLD_QF
);
225 LL_SPI_Init(spi
->dev
, &init
);
226 LL_SPI_Enable(spi
->dev
);
228 SET_BIT(spi
->dev
->CR2
, SPI_RXFIFO_THRESHOLD
);
232 IOHi(IOGetByTag(spi
->nss
));
235 spi
->initDone
= true;
239 uint8_t spiTransferByte(SPI_TypeDef
*instance
, uint8_t txByte
)
241 uint8_t value
= 0xFF;
242 if (!spiTransfer(instance
, &value
, &txByte
, 1)) {
249 * Return true if the bus is currently in the middle of a transmission.
251 bool spiIsBusBusy(SPI_TypeDef
*instance
)
255 // H7 doesnt really have a busy flag. its should be done when the transfer is.
258 return (LL_SPI_GetTxFIFOLevel(instance
) != LL_SPI_TX_FIFO_EMPTY
) || LL_SPI_IsActiveFlag_BSY(instance
);
262 bool spiTransfer(SPI_TypeDef
*instance
, uint8_t *rxData
, const uint8_t *txData
, int len
)
265 LL_SPI_SetTransferSize(instance
, len
);
266 LL_SPI_Enable(instance
);
267 LL_SPI_StartMasterTransfer(instance
);
269 int spiTimeout
= 1000;
270 while(!LL_SPI_IsActiveFlag_TXP(instance
)) {
271 if ((spiTimeout
--) == 0) {
272 spiTimeoutUserCallback(instance
);
276 uint8_t b
= txData
? *(txData
++) : 0xFF;
277 LL_SPI_TransmitData8(instance
, b
);
280 while (!LL_SPI_IsActiveFlag_RXP(instance
)) {
281 if ((spiTimeout
--) == 0) {
282 spiTimeoutUserCallback(instance
);
286 b
= LL_SPI_ReceiveData8(instance
);
292 while (!LL_SPI_IsActiveFlag_EOT(instance
));
293 LL_SPI_ClearFlag_TXTF(instance
);
294 LL_SPI_Disable(instance
);
296 SET_BIT(instance
->CR2
, SPI_RXFIFO_THRESHOLD
);
299 int spiTimeout
= 1000;
300 while (!LL_SPI_IsActiveFlag_TXE(instance
)) {
301 if ((spiTimeout
--) == 0) {
302 spiTimeoutUserCallback(instance
);
306 uint8_t b
= txData
? *(txData
++) : 0xFF;
307 LL_SPI_TransmitData8(instance
, b
);
310 while (!LL_SPI_IsActiveFlag_RXNE(instance
)) {
311 if ((spiTimeout
--) == 0) {
312 spiTimeoutUserCallback(instance
);
316 b
= LL_SPI_ReceiveData8(instance
);
327 void spiSetSpeed(SPI_TypeDef
*instance
, SPIClockSpeed_e speed
)
329 SPIDevice device
= spiDeviceByInstance(instance
);
330 LL_SPI_Disable(instance
);
331 LL_SPI_SetBaudRatePrescaler(instance
, spiHardwareMap
[device
].divisorMap
[speed
]);
332 LL_SPI_Enable(instance
);
335 SPI_TypeDef
* spiInstanceByDevice(SPIDevice device
)
337 return spiHardwareMap
[device
].dev
;