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/>.
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"
32 #define SPI1_NSS_PIN PA4
33 #define SPI1_SCK_PIN PA5
34 #define SPI1_MISO_PIN PA6
35 #define SPI1_MOSI_PIN PA7
39 #define SPI2_NSS_PIN PB12
40 #define SPI2_SCK_PIN PB13
41 #define SPI2_MISO_PIN PB14
42 #define SPI2_MOSI_PIN PB15
46 #define SPI3_NSS_PIN PA15
47 #define SPI3_SCK_PIN PB3
48 #define SPI3_MISO_PIN PB4
49 #define SPI3_MOSI_PIN PB5
53 #define SPI1_NSS_PIN NONE
56 #define SPI2_NSS_PIN NONE
59 #define SPI3_NSS_PIN NONE
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
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
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
},
87 { .dev
= NULL
}, // No SPI1
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
},
92 { .dev
= NULL
}, // No SPI2
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
},
97 { .dev
= NULL
}, // No SPI3
99 { .dev
= NULL
}, // No SPI4
105 SPIDevice
spiDeviceByInstance(SPI_TypeDef
*instance
)
107 if (instance
== SPI1
)
110 if (instance
== SPI2
)
113 if (instance
== SPI3
)
119 bool spiInitDevice(SPIDevice device
, bool leadingEdge
)
121 spiDevice_t
*spi
= &(spiHardwareMap
[device
]);
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);
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
);
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
);
151 IOConfigGPIOAF(IOGetByTag(spi
->nss
), SPI_IO_CS_CFG
, spi
->af
);
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
;
169 spiInit
.SPI_CPOL
= SPI_CPOL_Low
;
170 spiInit
.SPI_CPHA
= SPI_CPHA_1Edge
;
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
);
181 // Drive NSS high to disable connected SPI device.
182 IOHi(IOGetByTag(spi
->nss
));
185 spi
->initDone
= true;
189 uint32_t spiTimeoutUserCallback(SPI_TypeDef
*instance
)
191 SPIDevice device
= spiDeviceByInstance(instance
);
192 if (device
== SPIINVALID
) {
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
);
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;
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
);
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
);
251 void spiSetSpeed(SPI_TypeDef
*instance
, SPIClockSpeed_e speed
)
253 #define BR_CLEAR_MASK 0xFFC7
254 SPIDevice device
= spiDeviceByInstance(instance
);
255 if (device
== SPIINVALID
) {
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
) {
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
;