Merge remote-tracking branch 'upstream/master' into abo_RTH_sanity_fix
[inav.git] / src / main / drivers / bus_spi_hal_ll.c
blob25662f2f2d28f39896a2ea58c96496e677f3612a
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 { .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 },
95 #else
96 { .dev = NULL }, // No SPI1
97 #endif
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 },
100 #else
101 { .dev = NULL }, // No SPI2
102 #endif
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 },
105 #else
106 { .dev = NULL }, // No SPI3
107 #endif
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 }
110 #else
111 { .dev = NULL } // No SPI4
112 #endif
114 #else
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 },
118 #else
119 { .dev = NULL }, // No SPI1
120 #endif
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 },
123 #else
124 { .dev = NULL }, // No SPI2
125 #endif
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 },
128 #else
129 { .dev = NULL }, // No SPI3
130 #endif
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 }
133 #else
134 { .dev = NULL } // No SPI4
135 #endif
137 #endif
139 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
141 if (instance == SPI1)
142 return SPIDEV_1;
144 if (instance == SPI2)
145 return SPIDEV_2;
147 if (instance == SPI3)
148 return SPIDEV_3;
150 if (instance == SPI4)
151 return SPIDEV_4;
153 return SPIINVALID;
156 void spiTimeoutUserCallback(SPI_TypeDef *instance)
158 SPIDevice device = spiDeviceByInstance(instance);
159 if (device == SPIINVALID) {
160 return;
163 spiHardwareMap[device].errorCount++;
166 bool spiInitDevice(SPIDevice device, bool leadingEdge)
168 spiDevice_t *spi = &(spiHardwareMap[device]);
170 if (!spi->dev) {
171 return false;
174 if (spi->initDone) {
175 return true;
178 // Enable SPI clock
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);
186 if (leadingEdge) {
187 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_LOW, spi->af);
188 } else {
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);
194 if (spi->nss) {
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,
209 .NSS = SPI_NSS_SOFT,
210 .BaudRate = SPI_BAUDRATEPRESCALER_8,
211 .BitOrder = SPI_FIRSTBIT_MSB,
212 .CRCPoly = 7,
213 .CRCCalculation = SPI_CRCCALCULATION_DISABLE,
216 #if defined(STM32H7)
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);
222 #else
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);
229 #endif
231 if (spi->nss) {
232 IOHi(IOGetByTag(spi->nss));
235 spi->initDone = true;
236 return true;
239 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t txByte)
241 uint8_t value = 0xFF;
242 if (!spiTransfer(instance, &value, &txByte, 1)) {
243 return 0xFF;
245 return value;
249 * Return true if the bus is currently in the middle of a transmission.
251 bool spiIsBusBusy(SPI_TypeDef *instance)
253 #if defined(STM32H7)
254 UNUSED(instance);
255 // H7 doesnt really have a busy flag. its should be done when the transfer is.
256 return false;
257 #else
258 return (LL_SPI_GetTxFIFOLevel(instance) != LL_SPI_TX_FIFO_EMPTY) || LL_SPI_IsActiveFlag_BSY(instance);
259 #endif
262 bool spiTransfer(SPI_TypeDef *instance, uint8_t *rxData, const uint8_t *txData, int len)
264 #if defined(STM32H7)
265 LL_SPI_SetTransferSize(instance, len);
266 LL_SPI_Enable(instance);
267 LL_SPI_StartMasterTransfer(instance);
268 while (len) {
269 int spiTimeout = 1000;
270 while(!LL_SPI_IsActiveFlag_TXP(instance)) {
271 if ((spiTimeout--) == 0) {
272 spiTimeoutUserCallback(instance);
273 return false;
276 uint8_t b = txData ? *(txData++) : 0xFF;
277 LL_SPI_TransmitData8(instance, b);
279 spiTimeout = 1000;
280 while (!LL_SPI_IsActiveFlag_RXP(instance)) {
281 if ((spiTimeout--) == 0) {
282 spiTimeoutUserCallback(instance);
283 return false;
286 b = LL_SPI_ReceiveData8(instance);
287 if (rxData) {
288 *(rxData++) = b;
290 --len;
292 while (!LL_SPI_IsActiveFlag_EOT(instance));
293 LL_SPI_ClearFlag_TXTF(instance);
294 LL_SPI_Disable(instance);
295 #else
296 SET_BIT(instance->CR2, SPI_RXFIFO_THRESHOLD);
298 while (len) {
299 int spiTimeout = 1000;
300 while (!LL_SPI_IsActiveFlag_TXE(instance)) {
301 if ((spiTimeout--) == 0) {
302 spiTimeoutUserCallback(instance);
303 return false;
306 uint8_t b = txData ? *(txData++) : 0xFF;
307 LL_SPI_TransmitData8(instance, b);
309 spiTimeout = 1000;
310 while (!LL_SPI_IsActiveFlag_RXNE(instance)) {
311 if ((spiTimeout--) == 0) {
312 spiTimeoutUserCallback(instance);
313 return false;
316 b = LL_SPI_ReceiveData8(instance);
317 if (rxData) {
318 *(rxData++) = b;
320 --len;
322 #endif
324 return true;
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;