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/>.
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
42 #ifdef USE_SPI_DEVICE_2
47 #ifdef USE_SPI_DEVICE_3
52 #ifdef USE_SPI_DEVICE_4
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;
69 #ifdef RX_SPI_INSTANCE
70 if (spi
->dev
== RX_SPI_INSTANCE
) {
71 spi
->leadingEdge
= true;
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
);
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
);
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
;
110 spiInit
.SPI_CPOL
= SPI_CPOL_High
;
111 spiInit
.SPI_CPHA
= SPI_CPHA_2Edge
;
115 // Configure for 8-bit reads.
116 SPI_RxFIFOThresholdConfig(spi
->dev
, SPI_RxFIFOThreshold_QF
);
119 SPI_Init(spi
->dev
, &spiInit
);
120 SPI_Cmd(spi
->dev
, ENABLE
);
123 bool spiInit(SPIDevice device
)
130 #ifdef USE_SPI_DEVICE_1
131 spiInitDevice(device
);
137 #ifdef USE_SPI_DEVICE_2
138 spiInitDevice(device
);
144 #if defined(USE_SPI_DEVICE_3) && (defined(STM32F303xC) || defined(STM32F4))
145 spiInitDevice(device
);
151 #if defined(USE_SPI_DEVICE_4)
152 spiInitDevice(device
);
161 uint32_t spiTimeoutUserCallback(SPI_TypeDef
*instance
)
163 SPIDevice device
= spiDeviceByInstance(instance
);
164 if (device
== SPIINVALID
)
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
);
180 SPI_SendData8(instance
, data
);
182 SPI_I2S_SendData(instance
, data
);
185 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_RXNE
) == RESET
)
186 if ((spiTimeout
--) == 0)
187 return spiTimeoutUserCallback(instance
);
190 return ((uint8_t)SPI_ReceiveData8(instance
));
192 return ((uint8_t)SPI_I2S_ReceiveData(instance
));
197 * Return true if the bus is currently in the middle of a transmission.
199 bool spiIsBusBusy(SPI_TypeDef
*instance
)
202 return SPI_GetTransmissionFIFOStatus(instance
) != SPI_TransmissionFIFOStatus_Empty
|| SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_BSY
) == SET
;
204 return SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_TXE
) == RESET
|| SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_BSY
) == SET
;
209 bool spiTransfer(SPI_TypeDef
*instance
, uint8_t *out
, const uint8_t *in
, int len
)
211 uint16_t spiTimeout
= 1000;
216 b
= in
? *(in
++) : 0xFF;
217 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_TXE
) == RESET
) {
218 if ((spiTimeout
--) == 0)
219 return spiTimeoutUserCallback(instance
);
222 SPI_SendData8(instance
, b
);
224 SPI_I2S_SendData(instance
, b
);
227 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_RXNE
) == RESET
) {
228 if ((spiTimeout
--) == 0)
229 return spiTimeoutUserCallback(instance
);
232 b
= SPI_ReceiveData8(instance
);
234 b
= SPI_I2S_ReceiveData(instance
);
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
);
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
)
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
);
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
);
299 uint8_t spiReadRegister(const busDevice_t
*bus
, uint8_t reg
)
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
);
310 void spiBusSetInstance(busDevice_t
*bus
, SPI_TypeDef
*instance
)
312 bus
->spi
.instance
= instance
;