Low level driver for SPI for F7
[betaflight.git] / src / main / drivers / bus_spi_ll.c
blobec6c8b146e798fdba01034855e73e0d543ee8096
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>
20 #include <string.h>
22 #include <platform.h>
24 #if defined(USE_SPI) && defined(USE_LOWLEVEL_DRIVER)
26 #include "common/utils.h"
28 #include "drivers/bus.h"
29 #include "drivers/bus_spi.h"
30 #include "drivers/bus_spi_impl.h"
31 #include "drivers/dma.h"
32 #include "drivers/io.h"
33 #include "drivers/nvic.h"
34 #include "drivers/rcc.h"
36 spiDevice_t spiDevice[SPIDEV_COUNT];
38 #ifndef SPI2_SCK_PIN
39 #define SPI2_NSS_PIN PB12
40 #define SPI2_SCK_PIN PB13
41 #define SPI2_MISO_PIN PB14
42 #define SPI2_MOSI_PIN PB15
43 #endif
45 #ifndef SPI3_SCK_PIN
46 #define SPI3_NSS_PIN PA15
47 #define SPI3_SCK_PIN PB3
48 #define SPI3_MISO_PIN PB4
49 #define SPI3_MOSI_PIN PB5
50 #endif
52 #ifndef SPI4_SCK_PIN
53 #define SPI4_NSS_PIN PA15
54 #define SPI4_SCK_PIN PB3
55 #define SPI4_MISO_PIN PB4
56 #define SPI4_MOSI_PIN PB5
57 #endif
59 #ifndef SPI1_NSS_PIN
60 #define SPI1_NSS_PIN NONE
61 #endif
62 #ifndef SPI2_NSS_PIN
63 #define SPI2_NSS_PIN NONE
64 #endif
65 #ifndef SPI3_NSS_PIN
66 #define SPI3_NSS_PIN NONE
67 #endif
68 #ifndef SPI4_NSS_PIN
69 #define SPI4_NSS_PIN NONE
70 #endif
72 #define SPI_DEFAULT_TIMEOUT 10
74 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
76 #ifdef USE_SPI_DEVICE_1
77 if (instance == SPI1)
78 return SPIDEV_1;
79 #endif
81 #ifdef USE_SPI_DEVICE_2
82 if (instance == SPI2)
83 return SPIDEV_2;
84 #endif
86 #ifdef USE_SPI_DEVICE_3
87 if (instance == SPI3)
88 return SPIDEV_3;
89 #endif
91 #ifdef USE_SPI_DEVICE_4
92 if (instance == SPI4)
93 return SPIDEV_4;
94 #endif
96 return SPIINVALID;
99 SPI_TypeDef *spiInstanceByDevice(SPIDevice device)
101 if (device >= SPIDEV_COUNT) {
102 return NULL;
105 return spiDevice[device].dev;
108 void spiInitDevice(SPIDevice device)
110 spiDevice_t *spi = &(spiDevice[device]);
112 #ifdef SDCARD_SPI_INSTANCE
113 if (spi->dev == SDCARD_SPI_INSTANCE) {
114 spi->leadingEdge = true;
116 #endif
117 #ifdef RX_SPI_INSTANCE
118 if (spi->dev == RX_SPI_INSTANCE) {
119 spi->leadingEdge = true;
121 #endif
123 // Enable SPI clock
124 RCC_ClockCmd(spi->rcc, ENABLE);
125 RCC_ResetCmd(spi->rcc, ENABLE);
127 IOInit(IOGetByTag(spi->sck), OWNER_SPI_SCK, RESOURCE_INDEX(device));
128 IOInit(IOGetByTag(spi->miso), OWNER_SPI_MISO, RESOURCE_INDEX(device));
129 IOInit(IOGetByTag(spi->mosi), OWNER_SPI_MOSI, RESOURCE_INDEX(device));
131 if (spi->leadingEdge == true)
132 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_LOW, spi->sckAF);
133 else
134 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_HIGH, spi->sckAF);
135 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG, spi->misoAF);
136 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->mosiAF);
138 LL_SPI_Disable(spi->dev);
139 LL_SPI_DeInit(spi->dev);
141 LL_SPI_InitTypeDef init =
143 .TransferDirection = SPI_DIRECTION_2LINES,
144 .Mode = SPI_MODE_MASTER,
145 .DataWidth = SPI_DATASIZE_8BIT,
146 .ClockPolarity = spi->leadingEdge ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH,
147 .ClockPhase = spi->leadingEdge ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE,
148 .NSS = SPI_NSS_SOFT,
149 .BaudRate = SPI_BAUDRATEPRESCALER_8,
150 .BitOrder = SPI_FIRSTBIT_MSB,
151 .CRCPoly = 7,
152 .CRCCalculation = SPI_CRCCALCULATION_DISABLE,
154 LL_SPI_SetRxFIFOThreshold(spi->dev, SPI_RXFIFO_THRESHOLD_QF);
156 LL_SPI_Init(spi->dev, &init);
157 LL_SPI_Enable(spi->dev);
160 bool spiInit(SPIDevice device)
162 switch (device) {
163 case SPIINVALID:
164 return false;
165 case SPIDEV_1:
166 #if defined(USE_SPI_DEVICE_1)
167 spiInitDevice(device);
168 return true;
169 #else
170 break;
171 #endif
172 case SPIDEV_2:
173 #if defined(USE_SPI_DEVICE_2)
174 spiInitDevice(device);
175 return true;
176 #else
177 break;
178 #endif
179 case SPIDEV_3:
180 #if defined(USE_SPI_DEVICE_3)
181 spiInitDevice(device);
182 return true;
183 #else
184 break;
185 #endif
186 case SPIDEV_4:
187 #if defined(USE_SPI_DEVICE_4)
188 spiInitDevice(device);
189 return true;
190 #else
191 break;
192 #endif
194 return false;
197 uint32_t spiTimeoutUserCallback(SPI_TypeDef *instance)
199 SPIDevice device = spiDeviceByInstance(instance);
200 if (device == SPIINVALID) {
201 return -1;
203 spiDevice[device].errorCount++;
204 return spiDevice[device].errorCount;
207 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t txByte)
209 uint16_t spiTimeout = 1000;
211 while (!LL_SPI_IsActiveFlag_TXE(instance))
212 if ((spiTimeout--) == 0)
213 return spiTimeoutUserCallback(instance);
215 LL_SPI_TransmitData8(instance, txByte);
217 spiTimeout = 1000;
218 while (!LL_SPI_IsActiveFlag_RXNE(instance))
219 if ((spiTimeout--) == 0)
220 return spiTimeoutUserCallback(instance);
222 return (uint8_t)LL_SPI_ReceiveData8(instance);
226 * Return true if the bus is currently in the middle of a transmission.
228 bool spiIsBusBusy(SPI_TypeDef *instance)
230 return LL_SPI_GetTxFIFOLevel(instance) != LL_SPI_TX_FIFO_EMPTY
231 || LL_SPI_IsActiveFlag_BSY(instance);
234 bool spiTransfer(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData, int len)
236 uint16_t spiTimeout = 1000;
238 uint8_t b;
239 instance->DR;
240 while (len--) {
241 b = txData ? *(txData++) : 0xFF;
242 while (!LL_SPI_IsActiveFlag_TXE(instance)) {
243 if ((spiTimeout--) == 0)
244 return spiTimeoutUserCallback(instance);
246 LL_SPI_TransmitData8(instance, b);
248 spiTimeout = 1000;
249 while (!LL_SPI_IsActiveFlag_RXNE(instance)) {
250 if ((spiTimeout--) == 0)
251 return spiTimeoutUserCallback(instance);
253 b = LL_SPI_ReceiveData8(instance);
255 if (rxData)
256 *(rxData++) = b;
259 return true;
262 bool spiBusTransfer(const busDevice_t *bus, const uint8_t *txData, uint8_t *rxData, int length)
264 IOLo(bus->busdev_u.spi.csnPin);
265 spiTransfer(bus->busdev_u.spi.instance, txData, rxData, length);
266 IOHi(bus->busdev_u.spi.csnPin);
267 return true;
270 void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
272 LL_SPI_Disable(instance);
273 #define BR_CLEAR_MASK 0xFFC7
275 const uint16_t tempRegister = (instance->CR1 & BR_CLEAR_MASK);
276 instance->CR1 = (tempRegister | ((ffs(divisor | 0x100) - 2) << 3));
278 //LL_SPI_SetBaudRatePrescaler(instance, baudRatePrescaler);
279 LL_SPI_Enable(instance);
282 uint16_t spiGetErrorCounter(SPI_TypeDef *instance)
284 SPIDevice device = spiDeviceByInstance(instance);
285 if (device == SPIINVALID) {
286 return 0;
288 return spiDevice[device].errorCount;
291 void spiResetErrorCounter(SPI_TypeDef *instance)
293 SPIDevice device = spiDeviceByInstance(instance);
294 if (device != SPIINVALID) {
295 spiDevice[device].errorCount = 0;
299 bool spiBusWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data)
301 IOLo(bus->busdev_u.spi.csnPin);
302 spiTransferByte(bus->busdev_u.spi.instance, reg);
303 spiTransferByte(bus->busdev_u.spi.instance, data);
304 IOHi(bus->busdev_u.spi.csnPin);
306 return true;
309 bool spiBusReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t *data, uint8_t length)
311 IOLo(bus->busdev_u.spi.csnPin);
312 spiTransferByte(bus->busdev_u.spi.instance, reg | 0x80); // read transaction
313 spiTransfer(bus->busdev_u.spi.instance, NULL, data, length);
314 IOHi(bus->busdev_u.spi.csnPin);
316 return true;
319 uint8_t spiBusReadRegister(const busDevice_t *bus, uint8_t reg)
321 uint8_t data;
322 IOLo(bus->busdev_u.spi.csnPin);
323 spiTransferByte(bus->busdev_u.spi.instance, reg | 0x80); // read transaction
324 spiTransfer(bus->busdev_u.spi.instance, NULL, &data, 1);
325 IOHi(bus->busdev_u.spi.csnPin);
327 return data;
330 void spiBusSetInstance(busDevice_t *bus, SPI_TypeDef *instance)
332 bus->busdev_u.spi.instance = instance;
335 #endif