2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
29 #include "common/maths.h"
30 #include "drivers/bus.h"
31 #include "drivers/bus_spi.h"
32 #include "drivers/bus_spi_impl.h"
33 #include "drivers/exti.h"
34 #include "drivers/io.h"
35 #include "drivers/rcc.h"
36 #include "drivers/time.h"
38 static SPI_InitTypeDef defaultInit
= {
39 .SPI_Mode
= SPI_Mode_Master
,
40 .SPI_Direction
= SPI_Direction_2Lines_FullDuplex
,
41 .SPI_DataSize
= SPI_DataSize_8b
,
42 .SPI_NSS
= SPI_NSS_Soft
,
43 .SPI_FirstBit
= SPI_FirstBit_MSB
,
44 .SPI_CRCPolynomial
= 7,
45 .SPI_BaudRatePrescaler
= SPI_BaudRatePrescaler_8
,
48 void spiInitDevice(SPIDevice device
, bool leadingEdge
)
50 spiDevice_t
*spi
= &(spiDevice
[device
]);
56 #ifndef USE_SPI_TRANSACTION
57 spi
->leadingEdge
= leadingEdge
;
63 RCC_ClockCmd(spi
->rcc
, ENABLE
);
64 RCC_ResetCmd(spi
->rcc
, ENABLE
);
66 IOInit(IOGetByTag(spi
->sck
), OWNER_SPI_SCK
, RESOURCE_INDEX(device
));
67 IOInit(IOGetByTag(spi
->miso
), OWNER_SPI_MISO
, RESOURCE_INDEX(device
));
68 IOInit(IOGetByTag(spi
->mosi
), OWNER_SPI_MOSI
, RESOURCE_INDEX(device
));
70 #if defined(STM32F3) || defined(STM32F4)
71 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_CFG
, spi
->af
);
72 IOConfigGPIOAF(IOGetByTag(spi
->miso
), SPI_IO_AF_CFG
, spi
->af
);
73 IOConfigGPIOAF(IOGetByTag(spi
->mosi
), SPI_IO_AF_CFG
, spi
->af
);
74 #elif defined(STM32F10X)
75 IOConfigGPIO(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG
);
76 IOConfigGPIO(IOGetByTag(spi
->miso
), SPI_IO_AF_MISO_CFG
);
77 IOConfigGPIO(IOGetByTag(spi
->mosi
), SPI_IO_AF_MOSI_CFG
);
79 #error Undefined MCU architecture
83 SPI_I2S_DeInit(spi
->dev
);
85 #ifndef USE_SPI_TRANSACTION
86 if (spi
->leadingEdge
) {
87 defaultInit
.SPI_CPOL
= SPI_CPOL_Low
;
88 defaultInit
.SPI_CPHA
= SPI_CPHA_1Edge
;
92 defaultInit
.SPI_CPOL
= SPI_CPOL_High
;
93 defaultInit
.SPI_CPHA
= SPI_CPHA_2Edge
;
97 // Configure for 8-bit reads.
98 SPI_RxFIFOThresholdConfig(spi
->dev
, SPI_RxFIFOThreshold_QF
);
101 SPI_Init(spi
->dev
, &defaultInit
);
102 SPI_Cmd(spi
->dev
, ENABLE
);
105 // return uint8_t value or -1 when failure
106 uint8_t spiTransferByte(SPI_TypeDef
*instance
, uint8_t txByte
)
108 timeUs_t timeoutStartUs
= microsISR();
110 DISCARD(instance
->DR
);
112 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_TXE
) == RESET
) {
113 if (cmpTimeUs(microsISR(), timeoutStartUs
) >= SPI_TIMEOUT_US
) {
114 return spiTimeoutUserCallback(instance
);
119 SPI_SendData8(instance
, txByte
);
121 SPI_I2S_SendData(instance
, txByte
);
123 timeoutStartUs
= microsISR();
124 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_RXNE
) == RESET
) {
125 if (cmpTimeUs(microsISR(), timeoutStartUs
) >= SPI_TIMEOUT_US
) {
126 return spiTimeoutUserCallback(instance
);
131 return ((uint8_t)SPI_ReceiveData8(instance
));
133 return ((uint8_t)SPI_I2S_ReceiveData(instance
));
138 * Return true if the bus is currently in the middle of a transmission.
140 bool spiIsBusBusy(SPI_TypeDef
*instance
)
143 return SPI_GetTransmissionFIFOStatus(instance
) != SPI_TransmissionFIFOStatus_Empty
|| SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_BSY
) == SET
;
145 return SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_TXE
) == RESET
|| SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_BSY
) == SET
;
150 bool spiTransfer(SPI_TypeDef
*instance
, const uint8_t *txData
, uint8_t *rxData
, int len
)
152 timeUs_t timeoutStartUs
;
155 DISCARD(instance
->DR
);
157 b
= txData
? *(txData
++) : 0xFF;
158 timeoutStartUs
= microsISR();
159 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_TXE
) == RESET
) {
160 if (cmpTimeUs(microsISR(), timeoutStartUs
) >= SPI_TIMEOUT_US
) {
161 return spiTimeoutUserCallback(instance
);
165 SPI_SendData8(instance
, b
);
167 SPI_I2S_SendData(instance
, b
);
170 timeoutStartUs
= microsISR();
172 while (SPI_I2S_GetFlagStatus(instance
, SPI_I2S_FLAG_RXNE
) == RESET
) {
173 if (cmpTimeUs(microsISR(), timeoutStartUs
) >= SPI_TIMEOUT_US
) {
174 return spiTimeoutUserCallback(instance
);
178 b
= SPI_ReceiveData8(instance
);
180 b
= SPI_I2S_ReceiveData(instance
);
190 static uint16_t spiDivisorToBRbits(SPI_TypeDef
*instance
, uint16_t divisor
)
192 #if !(defined(STM32F1) || defined(STM32F3))
193 // SPI2 and SPI3 are on APB1/AHB1 which PCLK is half that of APB2/AHB2.
195 if (instance
== SPI2
|| instance
== SPI3
) {
196 divisor
/= 2; // Safe for divisor == 0 or 1
202 divisor
= constrain(divisor
, 2, 256);
204 return (ffs(divisor
) - 2) << 3; // SPI_CR1_BR_Pos
207 static void spiSetDivisorBRreg(SPI_TypeDef
*instance
, uint16_t divisor
)
209 #define BR_BITS ((BIT(5) | BIT(4) | BIT(3)))
210 const uint16_t tempRegister
= (instance
->CR1
& ~BR_BITS
);
211 instance
->CR1
= tempRegister
| spiDivisorToBRbits(instance
, divisor
);
215 void spiSetDivisor(SPI_TypeDef
*instance
, uint16_t divisor
)
217 SPI_Cmd(instance
, DISABLE
);
218 spiSetDivisorBRreg(instance
, divisor
);
219 SPI_Cmd(instance
, ENABLE
);
222 #ifdef USE_SPI_TRANSACTION
224 void spiBusTransactionInit(busDevice_t
*bus
, SPIMode_e mode
, uint16_t divider
)
227 case SPI_MODE0_POL_LOW_EDGE_1ST
:
228 defaultInit
.SPI_CPOL
= SPI_CPOL_Low
;
229 defaultInit
.SPI_CPHA
= SPI_CPHA_1Edge
;
231 case SPI_MODE1_POL_LOW_EDGE_2ND
:
232 defaultInit
.SPI_CPOL
= SPI_CPOL_Low
;
233 defaultInit
.SPI_CPHA
= SPI_CPHA_2Edge
;
235 case SPI_MODE2_POL_HIGH_EDGE_1ST
:
236 defaultInit
.SPI_CPOL
= SPI_CPOL_High
;
237 defaultInit
.SPI_CPHA
= SPI_CPHA_1Edge
;
239 case SPI_MODE3_POL_HIGH_EDGE_2ND
:
240 defaultInit
.SPI_CPOL
= SPI_CPOL_High
;
241 defaultInit
.SPI_CPHA
= SPI_CPHA_2Edge
;
245 // Initialize the SPI instance to setup CR1
247 SPI_Init(bus
->busdev_u
.spi
.instance
, &defaultInit
);
248 spiSetDivisorBRreg(bus
->busdev_u
.spi
.instance
, divider
);
250 // Configure for 8-bit reads.
251 SPI_RxFIFOThresholdConfig(bus
->busdev_u
.spi
.instance
, SPI_RxFIFOThreshold_QF
);
254 bus
->busdev_u
.spi
.modeCache
= bus
->busdev_u
.spi
.instance
->CR1
;
255 bus
->busdev_u
.spi
.device
= &spiDevice
[spiDeviceByInstance(bus
->busdev_u
.spi
.instance
)];
258 void spiBusTransactionSetup(const busDevice_t
*bus
)
260 // We rely on MSTR bit to detect valid modeCache
262 if (bus
->busdev_u
.spi
.modeCache
&& bus
->busdev_u
.spi
.modeCache
!= bus
->busdev_u
.spi
.device
->cr1SoftCopy
) {
263 bus
->busdev_u
.spi
.instance
->CR1
= bus
->busdev_u
.spi
.modeCache
;
264 bus
->busdev_u
.spi
.device
->cr1SoftCopy
= bus
->busdev_u
.spi
.modeCache
;
266 // SCK seems to require some time to switch to a new initial level after CR1 is written.
267 // Here we buy some time in addition to the software copy save above.
271 #endif // USE_SPI_TRANSACTION