Merge pull request #3425 from jflyper/bfdev-spi-minor-fix
[betaflight.git] / src / main / drivers / bus_spi.c
blob41ad4a4fb01b9a8ef7889aa43a21200710b4a97d
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 #ifdef USE_SPI
26 #include "drivers/bus.h"
27 #include "drivers/bus_spi.h"
28 #include "drivers/bus_spi_impl.h"
29 #include "drivers/exti.h"
30 #include "drivers/io.h"
31 #include "drivers/rcc.h"
33 spiDevice_t spiDevice[SPIDEV_COUNT];
35 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
37 #ifdef USE_SPI_DEVICE_1
38 if (instance == SPI1)
39 return SPIDEV_1;
40 #endif
42 #ifdef USE_SPI_DEVICE_2
43 if (instance == SPI2)
44 return SPIDEV_2;
45 #endif
47 #ifdef USE_SPI_DEVICE_3
48 if (instance == SPI3)
49 return SPIDEV_3;
50 #endif
52 #ifdef USE_SPI_DEVICE_4
53 if (instance == SPI4)
54 return SPIDEV_4;
55 #endif
57 return SPIINVALID;
60 void spiInitDevice(SPIDevice device)
62 spiDevice_t *spi = &(spiDevice[device]);
64 #ifdef SDCARD_SPI_INSTANCE
65 if (spi->dev == SDCARD_SPI_INSTANCE) {
66 spi->leadingEdge = true;
68 #endif
69 #ifdef RX_SPI_INSTANCE
70 if (spi->dev == RX_SPI_INSTANCE) {
71 spi->leadingEdge = true;
73 #endif
75 // Enable SPI clock
76 RCC_ClockCmd(spi->rcc, ENABLE);
77 RCC_ResetCmd(spi->rcc, ENABLE);
79 IOInit(IOGetByTag(spi->sck), OWNER_SPI_SCK, RESOURCE_INDEX(device));
80 IOInit(IOGetByTag(spi->miso), OWNER_SPI_MISO, RESOURCE_INDEX(device));
81 IOInit(IOGetByTag(spi->mosi), OWNER_SPI_MOSI, RESOURCE_INDEX(device));
83 #if defined(STM32F3) || defined(STM32F4)
84 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_CFG, spi->af);
85 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_CFG, spi->af);
86 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->af);
87 #endif
88 #if defined(STM32F10X)
89 IOConfigGPIO(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG);
90 IOConfigGPIO(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG);
91 IOConfigGPIO(IOGetByTag(spi->mosi), SPI_IO_AF_MOSI_CFG);
92 #endif
94 // Init SPI hardware
95 SPI_I2S_DeInit(spi->dev);
97 SPI_InitTypeDef spiInit;
98 spiInit.SPI_Mode = SPI_Mode_Master;
99 spiInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
100 spiInit.SPI_DataSize = SPI_DataSize_8b;
101 spiInit.SPI_NSS = SPI_NSS_Soft;
102 spiInit.SPI_FirstBit = SPI_FirstBit_MSB;
103 spiInit.SPI_CRCPolynomial = 7;
104 spiInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
106 if (spi->leadingEdge) {
107 spiInit.SPI_CPOL = SPI_CPOL_Low;
108 spiInit.SPI_CPHA = SPI_CPHA_1Edge;
109 } else {
110 spiInit.SPI_CPOL = SPI_CPOL_High;
111 spiInit.SPI_CPHA = SPI_CPHA_2Edge;
114 #ifdef STM32F303xC
115 // Configure for 8-bit reads.
116 SPI_RxFIFOThresholdConfig(spi->dev, SPI_RxFIFOThreshold_QF);
117 #endif
119 SPI_Init(spi->dev, &spiInit);
120 SPI_Cmd(spi->dev, ENABLE);
123 bool spiInit(SPIDevice device)
125 switch (device)
127 case SPIINVALID:
128 return false;
129 case SPIDEV_1:
130 #ifdef USE_SPI_DEVICE_1
131 spiInitDevice(device);
132 return true;
133 #else
134 break;
135 #endif
136 case SPIDEV_2:
137 #ifdef USE_SPI_DEVICE_2
138 spiInitDevice(device);
139 return true;
140 #else
141 break;
142 #endif
143 case SPIDEV_3:
144 #if defined(USE_SPI_DEVICE_3) && (defined(STM32F303xC) || defined(STM32F4))
145 spiInitDevice(device);
146 return true;
147 #else
148 break;
149 #endif
150 case SPIDEV_4:
151 #if defined(USE_SPI_DEVICE_4)
152 spiInitDevice(device);
153 return true;
154 #else
155 break;
156 #endif
158 return false;
161 uint32_t spiTimeoutUserCallback(SPI_TypeDef *instance)
163 SPIDevice device = spiDeviceByInstance(instance);
164 if (device == SPIINVALID)
165 return -1;
166 spiDevice[device].errorCount++;
167 return spiDevice[device].errorCount;
170 // return uint8_t value or -1 when failure
171 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t data)
173 uint16_t spiTimeout = 1000;
175 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET)
176 if ((spiTimeout--) == 0)
177 return spiTimeoutUserCallback(instance);
179 #ifdef STM32F303xC
180 SPI_SendData8(instance, data);
181 #else
182 SPI_I2S_SendData(instance, data);
183 #endif
184 spiTimeout = 1000;
185 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET)
186 if ((spiTimeout--) == 0)
187 return spiTimeoutUserCallback(instance);
189 #ifdef STM32F303xC
190 return ((uint8_t)SPI_ReceiveData8(instance));
191 #else
192 return ((uint8_t)SPI_I2S_ReceiveData(instance));
193 #endif
197 * Return true if the bus is currently in the middle of a transmission.
199 bool spiIsBusBusy(SPI_TypeDef *instance)
201 #ifdef STM32F303xC
202 return SPI_GetTransmissionFIFOStatus(instance) != SPI_TransmissionFIFOStatus_Empty || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
203 #else
204 return SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
205 #endif
209 bool spiTransfer(SPI_TypeDef *instance, uint8_t *out, const uint8_t *in, int len)
211 uint16_t spiTimeout = 1000;
213 uint8_t b;
214 instance->DR;
215 while (len--) {
216 b = in ? *(in++) : 0xFF;
217 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET) {
218 if ((spiTimeout--) == 0)
219 return spiTimeoutUserCallback(instance);
221 #ifdef STM32F303xC
222 SPI_SendData8(instance, b);
223 #else
224 SPI_I2S_SendData(instance, b);
225 #endif
226 spiTimeout = 1000;
227 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET) {
228 if ((spiTimeout--) == 0)
229 return spiTimeoutUserCallback(instance);
231 #ifdef STM32F303xC
232 b = SPI_ReceiveData8(instance);
233 #else
234 b = SPI_I2S_ReceiveData(instance);
235 #endif
236 if (out)
237 *(out++) = b;
240 return true;
243 bool spiBusTransfer(const busDevice_t *bus, uint8_t *rxData, const uint8_t *txData, int length)
245 IOLo(bus->spi.csnPin);
246 spiTransfer(bus->spi.instance, rxData, txData, length);
247 IOHi(bus->spi.csnPin);
248 return true;
251 void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
253 #define BR_CLEAR_MASK 0xFFC7
254 uint16_t tempRegister;
256 SPI_Cmd(instance, DISABLE);
258 tempRegister = (instance->CR1 & BR_CLEAR_MASK);
259 instance->CR1 = (tempRegister | ((ffs(divisor | 0x100) - 2) << 3));
261 SPI_Cmd(instance, ENABLE);
264 uint16_t spiGetErrorCounter(SPI_TypeDef *instance)
266 SPIDevice device = spiDeviceByInstance(instance);
267 if (device == SPIINVALID)
268 return 0;
269 return spiDevice[device].errorCount;
272 void spiResetErrorCounter(SPI_TypeDef *instance)
274 SPIDevice device = spiDeviceByInstance(instance);
275 if (device != SPIINVALID)
276 spiDevice[device].errorCount = 0;
279 bool spiWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data)
281 IOLo(bus->spi.csnPin);
282 spiTransferByte(bus->spi.instance, reg);
283 spiTransferByte(bus->spi.instance, data);
284 IOHi(bus->spi.csnPin);
286 return true;
289 bool spiReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t length, uint8_t *data)
291 IOLo(bus->spi.csnPin);
292 spiTransferByte(bus->spi.instance, reg | 0x80); // read transaction
293 spiTransfer(bus->spi.instance, data, NULL, length);
294 IOHi(bus->spi.csnPin);
296 return true;
299 uint8_t spiReadRegister(const busDevice_t *bus, uint8_t reg)
301 uint8_t data;
302 IOLo(bus->spi.csnPin);
303 spiTransferByte(bus->spi.instance, reg | 0x80); // read transaction
304 spiTransfer(bus->spi.instance, &data, NULL, 1);
305 IOHi(bus->spi.csnPin);
307 return data;
310 void spiBusSetInstance(busDevice_t *bus, SPI_TypeDef *instance)
312 bus->spi.instance = instance;
314 #endif