Blackbox device type 'file' (SITL) considered working when file handler is available
[inav.git] / src / main / drivers / bus_spi_hal_ll.c
blobfac8a82761af0652e3d9aaf5c06526c8a75b27be
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
21 #include <platform.h>
23 #include "drivers/bus_spi.h"
24 #include "dma.h"
25 #include "drivers/io.h"
26 #include "io_impl.h"
27 #include "drivers/nvic.h"
28 #include "rcc.h"
30 #ifndef SPI1_SCK_PIN
31 #define SPI1_NSS_PIN PA4
32 #define SPI1_SCK_PIN PA5
33 #define SPI1_MISO_PIN PA6
34 #define SPI1_MOSI_PIN PA7
35 #endif
37 #ifndef SPI2_SCK_PIN
38 #define SPI2_NSS_PIN PB12
39 #define SPI2_SCK_PIN PB13
40 #define SPI2_MISO_PIN PB14
41 #define SPI2_MOSI_PIN PB15
42 #endif
44 #ifndef SPI3_SCK_PIN
45 #define SPI3_NSS_PIN PA15
46 #define SPI3_SCK_PIN PB3
47 #define SPI3_MISO_PIN PB4
48 #define SPI3_MOSI_PIN PB5
49 #endif
51 #ifndef SPI4_SCK_PIN
52 #define SPI4_NSS_PIN PA15
53 #define SPI4_SCK_PIN PB3
54 #define SPI4_MISO_PIN PB4
55 #define SPI4_MOSI_PIN PB5
56 #endif
58 #ifndef SPI1_NSS_PIN
59 #define SPI1_NSS_PIN NONE
60 #endif
61 #ifndef SPI2_NSS_PIN
62 #define SPI2_NSS_PIN NONE
63 #endif
64 #ifndef SPI3_NSS_PIN
65 #define SPI3_NSS_PIN NONE
66 #endif
67 #ifndef SPI4_NSS_PIN
68 #define SPI4_NSS_PIN NONE
69 #endif
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
79 #endif
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
89 #endif
91 #if defined(STM32H7)
92 static spiDevice_t spiHardwareMap[SPIDEV_COUNT] = {
93 #ifdef USE_SPI_DEVICE_1
94 #if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
95 #if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
96 #error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
97 #endif
98 { .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 },
99 #else
100 { .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 },
101 #endif
102 #else
103 { .dev = NULL }, // No SPI1
104 #endif
106 #ifdef USE_SPI_DEVICE_2
107 #if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
108 #if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
109 #error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
110 #endif
111 { .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 },
112 #else
113 { .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 },
114 #endif
115 #else
116 { .dev = NULL }, // No SPI2
117 #endif
119 #ifdef USE_SPI_DEVICE_3
120 #if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
121 #if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
122 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
123 #endif
124 { .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 },
125 #else
126 { .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 },
127 #endif
128 #else
129 { .dev = NULL }, // No SPI3
130 #endif
132 #ifdef USE_SPI_DEVICE_4
133 #if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
134 #if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
135 #error SPI4: SCK, MISO and MOSI AFs should be defined together in target.h!
136 #endif
137 { .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 }
138 #else
139 { .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 }
140 #endif
141 #else
142 { .dev = NULL } // No SPI4
143 #endif
145 #else
146 static spiDevice_t spiHardwareMap[] = {
147 #ifdef USE_SPI_DEVICE_1
148 #if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
149 #if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
150 #error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
151 #endif
152 { .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 },
153 #else
154 { .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 },
155 #endif
156 #else
157 { .dev = NULL }, // No SPI1
158 #endif
160 #ifdef USE_SPI_DEVICE_2
161 #if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
162 #if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
163 #error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
164 #endif
165 { .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 },
166 #else
167 { .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 },
168 #endif
169 #else
170 { .dev = NULL }, // No SPI2
171 #endif
173 #ifdef USE_SPI_DEVICE_3
174 #if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
175 #if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
176 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
177 #endif
178 { .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 },
179 #else
180 { .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 },
181 #endif
182 #else
183 { .dev = NULL }, // No SPI3
184 #endif
186 #ifdef USE_SPI_DEVICE_4
187 #if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
188 #if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
189 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
190 #endif
191 { .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 }
192 #else
193 { .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 }
194 #endif
195 #else
196 { .dev = NULL } // No SPI4
197 #endif
199 #endif
201 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
203 if (instance == SPI1)
204 return SPIDEV_1;
206 if (instance == SPI2)
207 return SPIDEV_2;
209 if (instance == SPI3)
210 return SPIDEV_3;
212 if (instance == SPI4)
213 return SPIDEV_4;
215 return SPIINVALID;
218 void spiTimeoutUserCallback(SPI_TypeDef *instance)
220 SPIDevice device = spiDeviceByInstance(instance);
221 if (device == SPIINVALID) {
222 return;
225 spiHardwareMap[device].errorCount++;
228 bool spiInitDevice(SPIDevice device, bool leadingEdge)
230 spiDevice_t *spi = &(spiHardwareMap[device]);
232 if (!spi->dev) {
233 return false;
236 if (spi->initDone) {
237 return true;
240 // Enable SPI clock
241 RCC_ClockCmd(spi->rcc, ENABLE);
242 RCC_ResetCmd(spi->rcc, DISABLE);
244 IOInit(IOGetByTag(spi->sck), OWNER_SPI, RESOURCE_SPI_SCK, device + 1);
245 IOInit(IOGetByTag(spi->miso), OWNER_SPI, RESOURCE_SPI_MISO, device + 1);
246 IOInit(IOGetByTag(spi->mosi), OWNER_SPI, RESOURCE_SPI_MOSI, device + 1);
248 if (leadingEdge) {
249 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_LOW, spi->sckAF);
250 } else {
251 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_HIGH, spi->sckAF);
253 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG, spi->misoAF);
255 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->mosiAF);
257 if (spi->nss) {
258 IOInit(IOGetByTag(spi->nss), OWNER_SPI, RESOURCE_SPI_CS, device + 1);
259 IOConfigGPIO(IOGetByTag(spi->nss), SPI_IO_CS_CFG);
262 LL_SPI_Disable(spi->dev);
263 LL_SPI_DeInit(spi->dev);
265 LL_SPI_InitTypeDef init =
267 .TransferDirection = SPI_DIRECTION_2LINES,
268 .Mode = SPI_MODE_MASTER,
269 .DataWidth = SPI_DATASIZE_8BIT,
270 .ClockPolarity = leadingEdge ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH,
271 .ClockPhase = leadingEdge ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE,
272 .NSS = SPI_NSS_SOFT,
273 .BaudRate = SPI_BAUDRATEPRESCALER_8,
274 .BitOrder = SPI_FIRSTBIT_MSB,
275 .CRCPoly = 7,
276 .CRCCalculation = SPI_CRCCALCULATION_DISABLE,
279 #if defined(STM32H7)
280 // Prevent glitching when SPI is disabled
281 LL_SPI_EnableGPIOControl(spi->dev);
283 LL_SPI_SetFIFOThreshold(spi->dev, LL_SPI_FIFO_TH_01DATA);
284 LL_SPI_Init(spi->dev, &init);
285 #else
286 LL_SPI_SetRxFIFOThreshold(spi->dev, SPI_RXFIFO_THRESHOLD_QF);
288 LL_SPI_Init(spi->dev, &init);
289 LL_SPI_Enable(spi->dev);
291 SET_BIT(spi->dev->CR2, SPI_RXFIFO_THRESHOLD);
292 #endif
294 if (spi->nss) {
295 IOHi(IOGetByTag(spi->nss));
298 spi->initDone = true;
299 return true;
302 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t txByte)
304 uint8_t value = 0xFF;
305 if (!spiTransfer(instance, &value, &txByte, 1)) {
306 return 0xFF;
308 return value;
312 * Return true if the bus is currently in the middle of a transmission.
314 bool spiIsBusBusy(SPI_TypeDef *instance)
316 #if defined(STM32H7)
317 UNUSED(instance);
318 // H7 doesnt really have a busy flag. its should be done when the transfer is.
319 return false;
320 #else
321 return (LL_SPI_GetTxFIFOLevel(instance) != LL_SPI_TX_FIFO_EMPTY) || LL_SPI_IsActiveFlag_BSY(instance);
322 #endif
325 bool spiTransfer(SPI_TypeDef *instance, uint8_t *rxData, const uint8_t *txData, int len)
327 #if defined(STM32H7)
328 LL_SPI_SetTransferSize(instance, len);
329 LL_SPI_Enable(instance);
330 LL_SPI_StartMasterTransfer(instance);
331 while (len) {
332 int spiTimeout = 1000;
333 while(!LL_SPI_IsActiveFlag_TXP(instance)) {
334 if ((spiTimeout--) == 0) {
335 spiTimeoutUserCallback(instance);
336 return false;
339 uint8_t b = txData ? *(txData++) : 0xFF;
340 LL_SPI_TransmitData8(instance, b);
342 spiTimeout = 1000;
343 while (!LL_SPI_IsActiveFlag_RXP(instance)) {
344 if ((spiTimeout--) == 0) {
345 spiTimeoutUserCallback(instance);
346 return false;
349 b = LL_SPI_ReceiveData8(instance);
350 if (rxData) {
351 *(rxData++) = b;
353 --len;
355 while (!LL_SPI_IsActiveFlag_EOT(instance));
356 LL_SPI_ClearFlag_TXTF(instance);
357 LL_SPI_Disable(instance);
358 #else
359 SET_BIT(instance->CR2, SPI_RXFIFO_THRESHOLD);
361 while (len) {
362 int spiTimeout = 1000;
363 while (!LL_SPI_IsActiveFlag_TXE(instance)) {
364 if ((spiTimeout--) == 0) {
365 spiTimeoutUserCallback(instance);
366 return false;
369 uint8_t b = txData ? *(txData++) : 0xFF;
370 LL_SPI_TransmitData8(instance, b);
372 spiTimeout = 1000;
373 while (!LL_SPI_IsActiveFlag_RXNE(instance)) {
374 if ((spiTimeout--) == 0) {
375 spiTimeoutUserCallback(instance);
376 return false;
379 b = LL_SPI_ReceiveData8(instance);
380 if (rxData) {
381 *(rxData++) = b;
383 --len;
385 #endif
387 return true;
390 void spiSetSpeed(SPI_TypeDef *instance, SPIClockSpeed_e speed)
392 SPIDevice device = spiDeviceByInstance(instance);
393 LL_SPI_Disable(instance);
394 LL_SPI_SetBaudRatePrescaler(instance, spiHardwareMap[device].divisorMap[speed]);
395 LL_SPI_Enable(instance);
398 SPI_TypeDef * spiInstanceByDevice(SPIDevice device)
400 return spiHardwareMap[device].dev;