Merge pull request #10558 from iNavFlight/MrD_Correct-comments-on-OSD-symbols
[inav.git] / src / main / drivers / bus_spi.c
blob8220ad01cd945d7e31957d3d6496a4f21b818067
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>
21 #include <platform.h>
23 #ifdef USE_SPI
25 #include "drivers/bus_spi.h"
26 #include "drivers/exti.h"
27 #include "drivers/io.h"
28 #include "drivers/io_impl.h"
29 #include "drivers/rcc.h"
31 #ifndef SPI1_SCK_PIN
32 #define SPI1_NSS_PIN PA4
33 #define SPI1_SCK_PIN PA5
34 #define SPI1_MISO_PIN PA6
35 #define SPI1_MOSI_PIN PA7
36 #endif
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 SPI1_NSS_PIN
53 #define SPI1_NSS_PIN NONE
54 #endif
55 #ifndef SPI2_NSS_PIN
56 #define SPI2_NSS_PIN NONE
57 #endif
58 #ifndef SPI3_NSS_PIN
59 #define SPI3_NSS_PIN NONE
60 #endif
62 #if defined(STM32F4)
63 #if defined(USE_SPI_DEVICE_1)
64 static const uint32_t spiDivisorMapFast[] = {
65 SPI_BaudRatePrescaler_256, // SPI_CLOCK_INITIALIZATON 328.125 KBits/s
66 SPI_BaudRatePrescaler_128, // SPI_CLOCK_SLOW 656.25 KBits/s
67 SPI_BaudRatePrescaler_8, // SPI_CLOCK_STANDARD 10.5 MBits/s
68 SPI_BaudRatePrescaler_4, // SPI_CLOCK_FAST 21.0 MBits/s
69 SPI_BaudRatePrescaler_2 // SPI_CLOCK_ULTRAFAST 42.0 MBits/s
71 #endif
73 #if defined(USE_SPI_DEVICE_2) || defined(USE_SPI_DEVICE_3)
74 static const uint32_t spiDivisorMapSlow[] = {
75 SPI_BaudRatePrescaler_256, // SPI_CLOCK_INITIALIZATON 164.062 KBits/s
76 SPI_BaudRatePrescaler_64, // SPI_CLOCK_SLOW 656.25 KBits/s
77 SPI_BaudRatePrescaler_4, // SPI_CLOCK_STANDARD 10.5 MBits/s
78 SPI_BaudRatePrescaler_2, // SPI_CLOCK_FAST 21.0 MBits/s
79 SPI_BaudRatePrescaler_2 // SPI_CLOCK_ULTRAFAST 21.0 MBits/s
81 #endif
83 static spiDevice_t spiHardwareMap[] = {
84 #ifdef USE_SPI_DEVICE_1
85 { .dev = SPI1, .nss = IO_TAG(SPI1_NSS_PIN), .sck = IO_TAG(SPI1_SCK_PIN), .miso = IO_TAG(SPI1_MISO_PIN), .mosi = IO_TAG(SPI1_MOSI_PIN), .rcc = RCC_APB2(SPI1), .af = GPIO_AF_SPI1, .divisorMap = spiDivisorMapFast },
86 #else
87 { .dev = NULL }, // No SPI1
88 #endif
89 #ifdef USE_SPI_DEVICE_2
90 { .dev = SPI2, .nss = IO_TAG(SPI2_NSS_PIN), .sck = IO_TAG(SPI2_SCK_PIN), .miso = IO_TAG(SPI2_MISO_PIN), .mosi = IO_TAG(SPI2_MOSI_PIN), .rcc = RCC_APB1(SPI2), .af = GPIO_AF_SPI2, .divisorMap = spiDivisorMapSlow },
91 #else
92 { .dev = NULL }, // No SPI2
93 #endif
94 #ifdef USE_SPI_DEVICE_3
95 { .dev = SPI3, .nss = IO_TAG(SPI3_NSS_PIN), .sck = IO_TAG(SPI3_SCK_PIN), .miso = IO_TAG(SPI3_MISO_PIN), .mosi = IO_TAG(SPI3_MOSI_PIN), .rcc = RCC_APB1(SPI3), .af = GPIO_AF_SPI3, .divisorMap = spiDivisorMapSlow },
96 #else
97 { .dev = NULL }, // No SPI3
98 #endif
99 { .dev = NULL }, // No SPI4
101 #else
102 #error "Invalid CPU"
103 #endif
105 SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
107 if (instance == SPI1)
108 return SPIDEV_1;
110 if (instance == SPI2)
111 return SPIDEV_2;
113 if (instance == SPI3)
114 return SPIDEV_3;
116 return SPIINVALID;
119 bool spiInitDevice(SPIDevice device, bool leadingEdge)
121 spiDevice_t *spi = &(spiHardwareMap[device]);
123 if (!spi->dev) {
124 return false;
127 if (spi->initDone) {
128 return true;
131 // Enable SPI clock
132 RCC_ClockCmd(spi->rcc, ENABLE);
133 RCC_ResetCmd(spi->rcc, DISABLE);
135 IOInit(IOGetByTag(spi->sck), OWNER_SPI, RESOURCE_SPI_SCK, device + 1);
136 IOInit(IOGetByTag(spi->miso), OWNER_SPI, RESOURCE_SPI_MISO, device + 1);
137 IOInit(IOGetByTag(spi->mosi), OWNER_SPI, RESOURCE_SPI_MOSI, device + 1);
139 #if defined(STM32F4)
140 if (leadingEdge) {
141 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG, spi->af);
142 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG, spi->af);
143 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->af);
144 } else {
145 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_CFG, spi->af);
146 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_CFG, spi->af);
147 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->af);
150 if (spi->nss) {
151 IOConfigGPIOAF(IOGetByTag(spi->nss), SPI_IO_CS_CFG, spi->af);
153 #endif
155 // Init SPI hardware
156 SPI_I2S_DeInit(spi->dev);
158 SPI_InitTypeDef spiInit;
159 spiInit.SPI_Mode = SPI_Mode_Master;
160 spiInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
161 spiInit.SPI_DataSize = SPI_DataSize_8b;
162 spiInit.SPI_NSS = SPI_NSS_Soft;
163 spiInit.SPI_FirstBit = SPI_FirstBit_MSB;
164 spiInit.SPI_CRCPolynomial = 7;
165 spiInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
167 if (leadingEdge) {
168 // SPI_MODE0
169 spiInit.SPI_CPOL = SPI_CPOL_Low;
170 spiInit.SPI_CPHA = SPI_CPHA_1Edge;
171 } else {
172 // SPI_MODE3
173 spiInit.SPI_CPOL = SPI_CPOL_High;
174 spiInit.SPI_CPHA = SPI_CPHA_2Edge;
177 SPI_Init(spi->dev, &spiInit);
178 SPI_Cmd(spi->dev, ENABLE);
180 if (spi->nss) {
181 // Drive NSS high to disable connected SPI device.
182 IOHi(IOGetByTag(spi->nss));
185 spi->initDone = true;
186 return true;
189 uint32_t spiTimeoutUserCallback(SPI_TypeDef *instance)
191 SPIDevice device = spiDeviceByInstance(instance);
192 if (device == SPIINVALID) {
193 return -1;
195 spiHardwareMap[device].errorCount++;
196 return spiHardwareMap[device].errorCount;
199 // return uint8_t value or -1 when failure
200 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t data)
202 uint16_t spiTimeout = 1000;
204 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET)
205 if ((spiTimeout--) == 0)
206 return spiTimeoutUserCallback(instance);
208 SPI_I2S_SendData(instance, data);
210 spiTimeout = 1000;
211 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET)
212 if ((spiTimeout--) == 0)
213 return spiTimeoutUserCallback(instance);
215 return ((uint8_t)SPI_I2S_ReceiveData(instance));
219 * Return true if the bus is currently in the middle of a transmission.
221 bool spiIsBusBusy(SPI_TypeDef *instance)
223 return SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
226 bool spiTransfer(SPI_TypeDef *instance, uint8_t *out, const uint8_t *in, int len)
228 uint16_t spiTimeout = 1000;
230 instance->DR;
231 while (len--) {
232 uint8_t b = in ? *(in++) : 0xFF;
233 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET) {
234 if ((spiTimeout--) == 0)
235 return spiTimeoutUserCallback(instance);
237 SPI_I2S_SendData(instance, b);
238 spiTimeout = 1000;
239 while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET) {
240 if ((spiTimeout--) == 0)
241 return spiTimeoutUserCallback(instance);
243 b = SPI_I2S_ReceiveData(instance);
244 if (out)
245 *(out++) = b;
248 return true;
251 void spiSetSpeed(SPI_TypeDef *instance, SPIClockSpeed_e speed)
253 #define BR_CLEAR_MASK 0xFFC7
254 SPIDevice device = spiDeviceByInstance(instance);
255 if (device == SPIINVALID) {
256 return;
259 SPI_Cmd(instance, DISABLE);
261 uint16_t tempRegister = instance->CR1;
262 tempRegister &= BR_CLEAR_MASK;
263 tempRegister |= spiHardwareMap[device].divisorMap[speed];
264 instance->CR1 = tempRegister;
266 SPI_Cmd(instance, ENABLE);
269 uint16_t spiGetErrorCounter(SPI_TypeDef *instance)
271 SPIDevice device = spiDeviceByInstance(instance);
272 if (device == SPIINVALID) {
273 return 0;
275 return spiHardwareMap[device].errorCount;
278 void spiResetErrorCounter(SPI_TypeDef *instance)
280 SPIDevice device = spiDeviceByInstance(instance);
281 if (device != SPIINVALID) {
282 spiHardwareMap[device].errorCount = 0;
286 SPI_TypeDef * spiInstanceByDevice(SPIDevice device)
288 return spiHardwareMap[device].dev;
290 #endif // USE_SPI