New memory section types for DMA
[betaflight.git] / src / main / drivers / bus_spi_stdperiph.c
blob0f9dec372ac315924273854ba091ca936390a280
1 /*
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)
8 * any later version.
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
27 #ifdef USE_SPI
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]);
52 if (!spi->dev) {
53 return;
56 #ifndef USE_SPI_TRANSACTION
57 spi->leadingEdge = leadingEdge;
58 #else
59 UNUSED(leadingEdge);
60 #endif
62 // Enable SPI clock
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);
78 #else
79 #error Undefined MCU architecture
80 #endif
82 // Init SPI hardware
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;
89 } else
90 #endif
92 defaultInit.SPI_CPOL = SPI_CPOL_High;
93 defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
96 #ifdef STM32F303xC
97 // Configure for 8-bit reads.
98 SPI_RxFIFOThresholdConfig(spi->dev, SPI_RxFIFOThreshold_QF);
99 #endif
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);
118 #ifdef STM32F303xC
119 SPI_SendData8(instance, txByte);
120 #else
121 SPI_I2S_SendData(instance, txByte);
122 #endif
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);
130 #ifdef STM32F303xC
131 return ((uint8_t)SPI_ReceiveData8(instance));
132 #else
133 return ((uint8_t)SPI_I2S_ReceiveData(instance));
134 #endif
138 * Return true if the bus is currently in the middle of a transmission.
140 bool spiIsBusBusy(SPI_TypeDef *instance)
142 #ifdef STM32F303xC
143 return SPI_GetTransmissionFIFOStatus(instance) != SPI_TransmissionFIFOStatus_Empty || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
144 #else
145 return SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
146 #endif
150 bool spiTransfer(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData, int len)
152 timeUs_t timeoutStartUs;
154 uint8_t b;
155 DISCARD(instance->DR);
156 while (len--) {
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);
164 #ifdef STM32F303xC
165 SPI_SendData8(instance, b);
166 #else
167 SPI_I2S_SendData(instance, b);
168 #endif
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);
177 #ifdef STM32F303xC
178 b = SPI_ReceiveData8(instance);
179 #else
180 b = SPI_I2S_ReceiveData(instance);
181 #endif
182 if (rxData) {
183 *(rxData++) = b;
187 return true;
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
198 #else
199 UNUSED(instance);
200 #endif
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);
212 #undef BR_BITS
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)
226 switch (mode) {
227 case SPI_MODE0_POL_LOW_EDGE_1ST:
228 defaultInit.SPI_CPOL = SPI_CPOL_Low;
229 defaultInit.SPI_CPHA = SPI_CPHA_1Edge;
230 break;
231 case SPI_MODE1_POL_LOW_EDGE_2ND:
232 defaultInit.SPI_CPOL = SPI_CPOL_Low;
233 defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
234 break;
235 case SPI_MODE2_POL_HIGH_EDGE_1ST:
236 defaultInit.SPI_CPOL = SPI_CPOL_High;
237 defaultInit.SPI_CPHA = SPI_CPHA_1Edge;
238 break;
239 case SPI_MODE3_POL_HIGH_EDGE_2ND:
240 defaultInit.SPI_CPOL = SPI_CPOL_High;
241 defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
242 break;
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);
249 #ifdef STM32F303xC
250 // Configure for 8-bit reads.
251 SPI_RxFIFOThresholdConfig(bus->busdev_u.spi.instance, SPI_RxFIFOThreshold_QF);
252 #endif
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.
268 __asm__("nop");
271 #endif // USE_SPI_TRANSACTION
272 #endif