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/>.
23 #include "drivers/bus_spi.h"
25 #include "drivers/io.h"
27 #include "drivers/nvic.h"
31 #define SPI1_NSS_PIN PA4
32 #define SPI1_SCK_PIN PA5
33 #define SPI1_MISO_PIN PA6
34 #define SPI1_MOSI_PIN PA7
38 #define SPI2_NSS_PIN PB12
39 #define SPI2_SCK_PIN PB13
40 #define SPI2_MISO_PIN PB14
41 #define SPI2_MOSI_PIN PB15
45 #define SPI3_NSS_PIN PA15
46 #define SPI3_SCK_PIN PB3
47 #define SPI3_MISO_PIN PB4
48 #define SPI3_MOSI_PIN PB5
52 #define SPI4_NSS_PIN PA15
53 #define SPI4_SCK_PIN PB3
54 #define SPI4_MISO_PIN PB4
55 #define SPI4_MOSI_PIN PB5
59 #define SPI1_NSS_PIN NONE
62 #define SPI2_NSS_PIN NONE
65 #define SPI3_NSS_PIN NONE
68 #define SPI4_NSS_PIN NONE
71 #if defined(USE_SPI_DEVICE_1)
72 static const uint32_t spiDivisorMapFast
[] = {
73 LL_SPI_BAUDRATEPRESCALER_DIV256
, // SPI_CLOCK_INITIALIZATON 421.875 KBits/s
74 LL_SPI_BAUDRATEPRESCALER_DIV32
, // SPI_CLOCK_SLOW 843.75 KBits/s
75 LL_SPI_BAUDRATEPRESCALER_DIV16
, // SPI_CLOCK_STANDARD 6.75 MBits/s
76 LL_SPI_BAUDRATEPRESCALER_DIV8
, // SPI_CLOCK_FAST 13.5 MBits/s
77 LL_SPI_BAUDRATEPRESCALER_DIV4
// SPI_CLOCK_ULTRAFAST 27.0 MBits/s
81 #if defined(USE_SPI_DEVICE_2) || defined(USE_SPI_DEVICE_3) || defined(USE_SPI_DEVICE_4)
82 static const uint32_t spiDivisorMapSlow
[] = {
83 LL_SPI_BAUDRATEPRESCALER_DIV256
, // SPI_CLOCK_INITIALIZATON 210.937 KBits/s
84 LL_SPI_BAUDRATEPRESCALER_DIV64
, // SPI_CLOCK_SLOW 843.75 KBits/s
85 LL_SPI_BAUDRATEPRESCALER_DIV8
, // SPI_CLOCK_STANDARD 6.75 MBits/s
86 LL_SPI_BAUDRATEPRESCALER_DIV4
, // SPI_CLOCK_FAST 13.5 MBits/s
87 LL_SPI_BAUDRATEPRESCALER_DIV2
// SPI_CLOCK_ULTRAFAST 27.0 MBits/s
92 static spiDevice_t spiHardwareMap
[SPIDEV_COUNT
] = {
93 #ifdef USE_SPI_DEVICE_1
94 #if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
95 #if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
96 #error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
98 { .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
), .sckAF
= SPI1_SCK_AF
, .misoAF
= SPI1_MISO_AF
, .mosiAF
= SPI1_MOSI_AF
, .divisorMap
= spiDivisorMapFast
},
100 { .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
), .sckAF
= GPIO_AF5_SPI1
, .misoAF
= GPIO_AF5_SPI1
, .mosiAF
= GPIO_AF5_SPI1
, .divisorMap
= spiDivisorMapFast
},
103 { .dev
= NULL
}, // No SPI1
106 #ifdef USE_SPI_DEVICE_2
107 #if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
108 #if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
109 #error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
111 { .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_APB1L(SPI2
), .sckAF
= SPI2_SCK_AF
, .misoAF
= SPI2_MISO_AF
, .mosiAF
= SPI2_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
113 { .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_APB1L(SPI2
), .sckAF
= GPIO_AF5_SPI2
, .misoAF
= GPIO_AF5_SPI2
, .mosiAF
= GPIO_AF5_SPI2
, .divisorMap
= spiDivisorMapSlow
},
116 { .dev
= NULL
}, // No SPI2
119 #ifdef USE_SPI_DEVICE_3
120 #if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
121 #if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
122 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
124 { .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_APB1L(SPI3
), .sckAF
= SPI3_SCK_AF
, .misoAF
= SPI3_MISO_AF
, .mosiAF
= SPI3_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
126 { .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_APB1L(SPI3
), .sckAF
= GPIO_AF6_SPI3
, .misoAF
= GPIO_AF6_SPI3
, .mosiAF
= GPIO_AF6_SPI3
, .divisorMap
= spiDivisorMapSlow
},
129 { .dev
= NULL
}, // No SPI3
132 #ifdef USE_SPI_DEVICE_4
133 #if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
134 #if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
135 #error SPI4: SCK, MISO and MOSI AFs should be defined together in target.h!
137 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= SPI4_SCK_AF
, .misoAF
= SPI4_MISO_AF
, .mosiAF
= SPI4_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
}
139 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= GPIO_AF5_SPI4
, .misoAF
= GPIO_AF5_SPI4
, .mosiAF
= GPIO_AF5_SPI4
, .divisorMap
= spiDivisorMapSlow
}
142 { .dev
= NULL
} // No SPI4
146 static spiDevice_t spiHardwareMap
[] = {
147 #ifdef USE_SPI_DEVICE_1
148 #if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
149 #if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
150 #error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
152 { .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
), .sckAF
= SPI1_SCK_AF
, .misoAF
= SPI1_MISO_AF
, .mosiAF
= SPI1_MOSI_AF
, .divisorMap
= spiDivisorMapFast
},
154 { .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
), .sckAF
= GPIO_AF5_SPI1
, .misoAF
= GPIO_AF5_SPI1
, .mosiAF
= GPIO_AF5_SPI1
, .divisorMap
= spiDivisorMapFast
},
157 { .dev
= NULL
}, // No SPI1
160 #ifdef USE_SPI_DEVICE_2
161 #if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
162 #if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
163 #error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
165 { .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
), .sckAF
= SPI2_SCK_AF
, .misoAF
= SPI2_MISO_AF
, .mosiAF
= SPI2_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
167 { .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
), .sckAF
= GPIO_AF5_SPI2
, .misoAF
= GPIO_AF5_SPI2
, .mosiAF
= GPIO_AF5_SPI2
, .divisorMap
= spiDivisorMapSlow
},
170 { .dev
= NULL
}, // No SPI2
173 #ifdef USE_SPI_DEVICE_3
174 #if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
175 #if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
176 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
178 { .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
), .sckAF
= SPI3_SCK_AF
, .misoAF
= SPI3_MISO_AF
, .mosiAF
= SPI3_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
180 { .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
), .sckAF
= GPIO_AF6_SPI3
, .misoAF
= GPIO_AF6_SPI3
, .mosiAF
= GPIO_AF6_SPI3
, .divisorMap
= spiDivisorMapSlow
},
183 { .dev
= NULL
}, // No SPI3
186 #ifdef USE_SPI_DEVICE_4
187 #if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
188 #if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
189 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
191 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= SPI4_SCK_AF
, .misoAF
= SPI4_MISO_AF
, .mosiAF
= SPI4_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
}
193 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= GPIO_AF5_SPI4
, .misoAF
= GPIO_AF5_SPI4
, .mosiAF
= GPIO_AF5_SPI4
, .divisorMap
= spiDivisorMapSlow
}
196 { .dev
= NULL
} // No SPI4
201 SPIDevice
spiDeviceByInstance(SPI_TypeDef
*instance
)
203 if (instance
== SPI1
)
206 if (instance
== SPI2
)
209 if (instance
== SPI3
)
212 if (instance
== SPI4
)
218 void spiTimeoutUserCallback(SPI_TypeDef
*instance
)
220 SPIDevice device
= spiDeviceByInstance(instance
);
221 if (device
== SPIINVALID
) {
225 spiHardwareMap
[device
].errorCount
++;
228 bool spiInitDevice(SPIDevice device
, bool leadingEdge
)
230 spiDevice_t
*spi
= &(spiHardwareMap
[device
]);
241 RCC_ClockCmd(spi
->rcc
, ENABLE
);
242 RCC_ResetCmd(spi
->rcc
, DISABLE
);
244 IOInit(IOGetByTag(spi
->sck
), OWNER_SPI
, RESOURCE_SPI_SCK
, device
+ 1);
245 IOInit(IOGetByTag(spi
->miso
), OWNER_SPI
, RESOURCE_SPI_MISO
, device
+ 1);
246 IOInit(IOGetByTag(spi
->mosi
), OWNER_SPI
, RESOURCE_SPI_MOSI
, device
+ 1);
249 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG_LOW
, spi
->sckAF
);
251 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG_HIGH
, spi
->sckAF
);
253 IOConfigGPIOAF(IOGetByTag(spi
->miso
), SPI_IO_AF_MISO_CFG
, spi
->misoAF
);
255 IOConfigGPIOAF(IOGetByTag(spi
->mosi
), SPI_IO_AF_CFG
, spi
->mosiAF
);
258 IOInit(IOGetByTag(spi
->nss
), OWNER_SPI
, RESOURCE_SPI_CS
, device
+ 1);
259 IOConfigGPIO(IOGetByTag(spi
->nss
), SPI_IO_CS_CFG
);
262 LL_SPI_Disable(spi
->dev
);
263 LL_SPI_DeInit(spi
->dev
);
265 LL_SPI_InitTypeDef init
=
267 .TransferDirection
= SPI_DIRECTION_2LINES
,
268 .Mode
= SPI_MODE_MASTER
,
269 .DataWidth
= SPI_DATASIZE_8BIT
,
270 .ClockPolarity
= leadingEdge
? SPI_POLARITY_LOW
: SPI_POLARITY_HIGH
,
271 .ClockPhase
= leadingEdge
? SPI_PHASE_1EDGE
: SPI_PHASE_2EDGE
,
273 .BaudRate
= SPI_BAUDRATEPRESCALER_8
,
274 .BitOrder
= SPI_FIRSTBIT_MSB
,
276 .CRCCalculation
= SPI_CRCCALCULATION_DISABLE
,
280 // Prevent glitching when SPI is disabled
281 LL_SPI_EnableGPIOControl(spi
->dev
);
283 LL_SPI_SetFIFOThreshold(spi
->dev
, LL_SPI_FIFO_TH_01DATA
);
284 LL_SPI_Init(spi
->dev
, &init
);
286 LL_SPI_SetRxFIFOThreshold(spi
->dev
, SPI_RXFIFO_THRESHOLD_QF
);
288 LL_SPI_Init(spi
->dev
, &init
);
289 LL_SPI_Enable(spi
->dev
);
291 SET_BIT(spi
->dev
->CR2
, SPI_RXFIFO_THRESHOLD
);
295 IOHi(IOGetByTag(spi
->nss
));
298 spi
->initDone
= true;
302 uint8_t spiTransferByte(SPI_TypeDef
*instance
, uint8_t txByte
)
304 uint8_t value
= 0xFF;
305 if (!spiTransfer(instance
, &value
, &txByte
, 1)) {
312 * Return true if the bus is currently in the middle of a transmission.
314 bool spiIsBusBusy(SPI_TypeDef
*instance
)
318 // H7 doesnt really have a busy flag. its should be done when the transfer is.
321 return (LL_SPI_GetTxFIFOLevel(instance
) != LL_SPI_TX_FIFO_EMPTY
) || LL_SPI_IsActiveFlag_BSY(instance
);
325 bool spiTransfer(SPI_TypeDef
*instance
, uint8_t *rxData
, const uint8_t *txData
, int len
)
328 LL_SPI_SetTransferSize(instance
, len
);
329 LL_SPI_Enable(instance
);
330 LL_SPI_StartMasterTransfer(instance
);
332 int spiTimeout
= 1000;
333 while(!LL_SPI_IsActiveFlag_TXP(instance
)) {
334 if ((spiTimeout
--) == 0) {
335 spiTimeoutUserCallback(instance
);
339 uint8_t b
= txData
? *(txData
++) : 0xFF;
340 LL_SPI_TransmitData8(instance
, b
);
343 while (!LL_SPI_IsActiveFlag_RXP(instance
)) {
344 if ((spiTimeout
--) == 0) {
345 spiTimeoutUserCallback(instance
);
349 b
= LL_SPI_ReceiveData8(instance
);
355 while (!LL_SPI_IsActiveFlag_EOT(instance
));
356 LL_SPI_ClearFlag_TXTF(instance
);
357 LL_SPI_Disable(instance
);
359 SET_BIT(instance
->CR2
, SPI_RXFIFO_THRESHOLD
);
362 int spiTimeout
= 1000;
363 while (!LL_SPI_IsActiveFlag_TXE(instance
)) {
364 if ((spiTimeout
--) == 0) {
365 spiTimeoutUserCallback(instance
);
369 uint8_t b
= txData
? *(txData
++) : 0xFF;
370 LL_SPI_TransmitData8(instance
, b
);
373 while (!LL_SPI_IsActiveFlag_RXNE(instance
)) {
374 if ((spiTimeout
--) == 0) {
375 spiTimeoutUserCallback(instance
);
379 b
= LL_SPI_ReceiveData8(instance
);
390 void spiSetSpeed(SPI_TypeDef
*instance
, SPIClockSpeed_e speed
)
392 SPIDevice device
= spiDeviceByInstance(instance
);
393 LL_SPI_Disable(instance
);
394 LL_SPI_SetBaudRatePrescaler(instance
, spiHardwareMap
[device
].divisorMap
[speed
]);
395 LL_SPI_Enable(instance
);
398 SPI_TypeDef
* spiInstanceByDevice(SPIDevice device
)
400 return spiHardwareMap
[device
].dev
;