Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / drivers / bus_spi_ll.c
blobec5a70c0bd1192d9696e08c8e0b758e67db5b227
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 #if defined(USE_SPI)
29 #include "common/utils.h"
30 #include "common/maths.h"
32 #include "drivers/bus.h"
33 #include "drivers/bus_spi.h"
34 #include "drivers/bus_spi_impl.h"
35 #include "drivers/dma.h"
36 #include "drivers/io.h"
37 #include "drivers/rcc.h"
39 #ifndef SPI2_SCK_PIN
40 #define SPI2_NSS_PIN PB12
41 #define SPI2_SCK_PIN PB13
42 #define SPI2_MISO_PIN PB14
43 #define SPI2_MOSI_PIN PB15
44 #endif
46 #ifndef SPI3_SCK_PIN
47 #define SPI3_NSS_PIN PA15
48 #define SPI3_SCK_PIN PB3
49 #define SPI3_MISO_PIN PB4
50 #define SPI3_MOSI_PIN PB5
51 #endif
53 #ifndef SPI4_SCK_PIN
54 #define SPI4_NSS_PIN PA15
55 #define SPI4_SCK_PIN PB3
56 #define SPI4_MISO_PIN PB4
57 #define SPI4_MOSI_PIN PB5
58 #endif
60 #ifndef SPI1_NSS_PIN
61 #define SPI1_NSS_PIN NONE
62 #endif
63 #ifndef SPI2_NSS_PIN
64 #define SPI2_NSS_PIN NONE
65 #endif
66 #ifndef SPI3_NSS_PIN
67 #define SPI3_NSS_PIN NONE
68 #endif
69 #ifndef SPI4_NSS_PIN
70 #define SPI4_NSS_PIN NONE
71 #endif
73 #define SPI_DEFAULT_TIMEOUT 10
75 #ifdef STM32H7
76 #define IS_DTCM(p) (((uint32_t)p & 0xfffe0000) == 0x20000000)
77 #elif defined(STM32F7)
78 #define IS_DTCM(p) (((uint32_t)p & 0xffff0000) == 0x20000000)
79 #elif defined(STM32G4)
80 #define IS_CCM(p) ((((uint32_t)p & 0xffff8000) == 0x10000000) || (((uint32_t)p & 0xffff8000) == 0x20018000))
81 #endif
82 static LL_SPI_InitTypeDef defaultInit =
84 .TransferDirection = LL_SPI_FULL_DUPLEX,
85 .Mode = LL_SPI_MODE_MASTER,
86 .DataWidth = LL_SPI_DATAWIDTH_8BIT,
87 .NSS = LL_SPI_NSS_SOFT,
88 .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8,
89 .BitOrder = LL_SPI_MSB_FIRST,
90 .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
91 .ClockPolarity = LL_SPI_POLARITY_HIGH,
92 .ClockPhase = LL_SPI_PHASE_2EDGE,
95 static uint32_t spiDivisorToBRbits(SPI_TypeDef *instance, uint16_t divisor)
97 #if !defined(STM32H7)
98 // SPI2 and SPI3 are on APB1/AHB1 which PCLK is half that of APB2/AHB2.
100 if (instance == SPI2 || instance == SPI3) {
101 divisor /= 2; // Safe for divisor == 0 or 1
103 #else
104 UNUSED(instance);
105 #endif
107 divisor = constrain(divisor, 2, 256);
109 #if defined(STM32H7)
110 const uint32_t baudRatePrescaler[8] = {
111 LL_SPI_BAUDRATEPRESCALER_DIV2,
112 LL_SPI_BAUDRATEPRESCALER_DIV4,
113 LL_SPI_BAUDRATEPRESCALER_DIV8,
114 LL_SPI_BAUDRATEPRESCALER_DIV16,
115 LL_SPI_BAUDRATEPRESCALER_DIV32,
116 LL_SPI_BAUDRATEPRESCALER_DIV64,
117 LL_SPI_BAUDRATEPRESCALER_DIV128,
118 LL_SPI_BAUDRATEPRESCALER_DIV256,
120 int prescalerIndex = ffs(divisor) - 2; // prescaler begins at "/2"
122 return baudRatePrescaler[prescalerIndex];
123 #else
124 return (ffs(divisor) - 2) << SPI_CR1_BR_Pos;
125 #endif
128 void spiInitDevice(SPIDevice device)
130 spiDevice_t *spi = &spiDevice[device];
132 if (!spi->dev) {
133 return;
136 // Enable SPI clock
137 RCC_ClockCmd(spi->rcc, ENABLE);
138 RCC_ResetCmd(spi->rcc, ENABLE);
140 IOInit(IOGetByTag(spi->sck), OWNER_SPI_SCK, RESOURCE_INDEX(device));
141 IOInit(IOGetByTag(spi->miso), OWNER_SPI_MISO, RESOURCE_INDEX(device));
142 IOInit(IOGetByTag(spi->mosi), OWNER_SPI_MOSI, RESOURCE_INDEX(device));
144 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG, spi->misoAF);
145 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->mosiAF);
146 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_HIGH, spi->sckAF);
148 LL_SPI_Disable(spi->dev);
149 LL_SPI_DeInit(spi->dev);
151 #if defined(STM32H7)
152 // Prevent glitching when SPI is disabled
153 LL_SPI_EnableGPIOControl(spi->dev);
155 LL_SPI_SetFIFOThreshold(spi->dev, LL_SPI_FIFO_TH_01DATA);
156 LL_SPI_Init(spi->dev, &defaultInit);
157 #else
158 LL_SPI_SetRxFIFOThreshold(spi->dev, SPI_RXFIFO_THRESHOLD_QF);
160 LL_SPI_Init(spi->dev, &defaultInit);
161 LL_SPI_Enable(spi->dev);
162 #endif
165 void spiInternalResetDescriptors(busDevice_t *bus)
167 LL_DMA_InitTypeDef *initTx = bus->initTx;
169 LL_DMA_StructInit(initTx);
170 #if defined(STM32G4) || defined(STM32H7)
171 initTx->PeriphRequest = bus->dmaTx->channel;
172 #else
173 initTx->Channel = bus->dmaTx->channel;
174 #endif
175 initTx->Mode = LL_DMA_MODE_NORMAL;
176 initTx->Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
177 #if defined(STM32H7)
178 initTx->PeriphOrM2MSrcAddress = (uint32_t)&bus->busType_u.spi.instance->TXDR;
179 #else
180 initTx->PeriphOrM2MSrcAddress = (uint32_t)&bus->busType_u.spi.instance->DR;
181 #endif
182 initTx->Priority = LL_DMA_PRIORITY_LOW;
183 initTx->PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
184 initTx->PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
185 initTx->MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
187 if (bus->dmaRx) {
188 LL_DMA_InitTypeDef *initRx = bus->initRx;
190 LL_DMA_StructInit(initRx);
191 #if defined(STM32G4) || defined(STM32H7)
192 initRx->PeriphRequest = bus->dmaRx->channel;
193 #else
194 initRx->Channel = bus->dmaRx->channel;
195 #endif
196 initRx->Mode = LL_DMA_MODE_NORMAL;
197 initRx->Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
198 #if defined(STM32H7)
199 initRx->PeriphOrM2MSrcAddress = (uint32_t)&bus->busType_u.spi.instance->RXDR;
200 #else
201 initRx->PeriphOrM2MSrcAddress = (uint32_t)&bus->busType_u.spi.instance->DR;
202 #endif
203 initRx->Priority = LL_DMA_PRIORITY_LOW;
204 initRx->PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
205 initRx->PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
209 void spiInternalResetStream(dmaChannelDescriptor_t *descriptor)
211 // Disable the stream
212 #if defined(STM32G4)
213 LL_DMA_DisableChannel(descriptor->dma, descriptor->stream);
214 while (LL_DMA_IsEnabledChannel(descriptor->dma, descriptor->stream));
215 #else
216 LL_DMA_DisableStream(descriptor->dma, descriptor->stream);
217 while (LL_DMA_IsEnabledStream(descriptor->dma, descriptor->stream));
218 #endif
220 // Clear any pending interrupt flags
221 DMA_CLEAR_FLAG(descriptor, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
225 static bool spiInternalReadWriteBufPolled(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData, int len)
227 #if defined(STM32H7)
228 LL_SPI_SetTransferSize(instance, len);
229 LL_SPI_Enable(instance);
230 LL_SPI_StartMasterTransfer(instance);
231 while (len) {
232 while (!LL_SPI_IsActiveFlag_TXP(instance));
233 uint8_t b = txData ? *(txData++) : 0xFF;
234 LL_SPI_TransmitData8(instance, b);
236 while (!LL_SPI_IsActiveFlag_RXP(instance));
237 b = LL_SPI_ReceiveData8(instance);
238 if (rxData) {
239 *(rxData++) = b;
241 --len;
243 while (!LL_SPI_IsActiveFlag_EOT(instance));
244 LL_SPI_ClearFlag_TXTF(instance);
245 LL_SPI_Disable(instance);
246 #else
247 // set 16-bit transfer
248 CLEAR_BIT(instance->CR2, SPI_RXFIFO_THRESHOLD);
249 while (len > 1) {
250 while (!LL_SPI_IsActiveFlag_TXE(instance));
251 uint16_t w;
252 if (txData) {
253 w = *((uint16_t *)txData);
254 txData += 2;
255 } else {
256 w = 0xFFFF;
258 LL_SPI_TransmitData16(instance, w);
260 while (!LL_SPI_IsActiveFlag_RXNE(instance));
261 w = LL_SPI_ReceiveData16(instance);
262 if (rxData) {
263 *((uint16_t *)rxData) = w;
264 rxData += 2;
266 len -= 2;
268 // set 8-bit transfer
269 SET_BIT(instance->CR2, SPI_RXFIFO_THRESHOLD);
270 if (len) {
271 while (!LL_SPI_IsActiveFlag_TXE(instance));
272 uint8_t b = txData ? *(txData++) : 0xFF;
273 LL_SPI_TransmitData8(instance, b);
275 while (!LL_SPI_IsActiveFlag_RXNE(instance));
276 b = LL_SPI_ReceiveData8(instance);
277 if (rxData) {
278 *(rxData++) = b;
280 --len;
282 #endif
284 return true;
287 void spiInternalInitStream(const extDevice_t *dev, bool preInit)
289 STATIC_DMA_DATA_AUTO uint8_t dummyTxByte = 0xff;
290 STATIC_DMA_DATA_AUTO uint8_t dummyRxByte;
291 busDevice_t *bus = dev->bus;
293 busSegment_t *segment = (busSegment_t *)bus->curSegment;
295 if (preInit) {
296 // Prepare the init structure for the next segment to reduce inter-segment interval
297 segment++;
298 if(segment->len == 0) {
299 // There's no following segment
300 return;
304 int len = segment->len;
306 uint8_t *txData = segment->u.buffers.txData;
307 LL_DMA_InitTypeDef *initTx = bus->initTx;
309 if (txData) {
310 #ifdef __DCACHE_PRESENT
311 #ifdef STM32H7
312 if ((txData < &_dmaram_start__) || (txData >= &_dmaram_end__)) {
313 #else
314 // No need to flush DTCM memory
315 if (!IS_DTCM(txData)) {
316 #endif
317 // Flush the D cache to ensure the data to be written is in main memory
318 SCB_CleanDCache_by_Addr(
319 (uint32_t *)((uint32_t)txData & ~CACHE_LINE_MASK),
320 (((uint32_t)txData & CACHE_LINE_MASK) + len - 1 + CACHE_LINE_SIZE) & ~CACHE_LINE_MASK);
322 #endif // __DCACHE_PRESENT
323 initTx->MemoryOrM2MDstAddress = (uint32_t)txData;
324 initTx->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
325 } else {
326 initTx->MemoryOrM2MDstAddress = (uint32_t)&dummyTxByte;
327 initTx->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT;
329 initTx->NbData = len;
331 #if !defined(STM32G4) && !defined(STM32H7)
332 if (dev->bus->dmaRx) {
333 #endif
334 uint8_t *rxData = segment->u.buffers.rxData;
335 LL_DMA_InitTypeDef *initRx = bus->initRx;
337 if (rxData) {
338 /* Flush the D cache for the start and end of the receive buffer as
339 * the cache will be invalidated after the transfer and any valid data
340 * just before/after must be in memory at that point
342 #ifdef __DCACHE_PRESENT
343 // No need to flush/invalidate DTCM memory
344 #ifdef STM32H7
345 if ((rxData < &_dmaram_start__) || (rxData >= &_dmaram_end__)) {
346 #else
347 // No need to flush DTCM memory
348 if (!IS_DTCM(rxData)) {
349 #endif
350 SCB_CleanInvalidateDCache_by_Addr(
351 (uint32_t *)((uint32_t)rxData & ~CACHE_LINE_MASK),
352 (((uint32_t)rxData & CACHE_LINE_MASK) + len - 1 + CACHE_LINE_SIZE) & ~CACHE_LINE_MASK);
354 #endif // __DCACHE_PRESENT
355 initRx->MemoryOrM2MDstAddress = (uint32_t)rxData;
356 initRx->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
357 } else {
358 initRx->MemoryOrM2MDstAddress = (uint32_t)&dummyRxByte;
359 initRx->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT;
361 initRx->NbData = len;
362 #if !defined(STM32G4) && !defined(STM32H7)
364 #endif
367 void spiInternalStartDMA(const extDevice_t *dev)
369 busDevice_t *bus = dev->bus;
371 dmaChannelDescriptor_t *dmaTx = bus->dmaTx;
372 dmaChannelDescriptor_t *dmaRx = bus->dmaRx;
374 #if !defined(STM32G4) && !defined(STM32H7)
375 if (dmaRx) {
376 #endif
377 // Use the correct callback argument
378 dmaRx->userParam = (uint32_t)dev;
380 // Clear transfer flags
381 DMA_CLEAR_FLAG(dmaTx, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
382 DMA_CLEAR_FLAG(dmaRx, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
384 #ifdef STM32G4
385 // Disable channels to enable update
386 LL_DMA_DisableChannel(dmaTx->dma, dmaTx->stream);
387 LL_DMA_DisableChannel(dmaRx->dma, dmaRx->stream);
389 /* Use the Rx interrupt as this occurs once the SPI operation is complete whereas the Tx interrupt
390 * occurs earlier when the Tx FIFO is empty, but the SPI operation is still in progress
392 LL_DMA_EnableIT_TC(dmaRx->dma, dmaRx->stream);
394 // Update channels
395 LL_DMA_Init(dmaTx->dma, dmaTx->stream, bus->initTx);
396 LL_DMA_Init(dmaRx->dma, dmaRx->stream, bus->initRx);
398 LL_SPI_EnableDMAReq_RX(dev->bus->busType_u.spi.instance);
400 // Enable channels
401 LL_DMA_EnableChannel(dmaTx->dma, dmaTx->stream);
402 LL_DMA_EnableChannel(dmaRx->dma, dmaRx->stream);
404 LL_SPI_EnableDMAReq_TX(dev->bus->busType_u.spi.instance);
405 #else
406 DMA_Stream_TypeDef *streamRegsTx = (DMA_Stream_TypeDef *)dmaTx->ref;
407 DMA_Stream_TypeDef *streamRegsRx = (DMA_Stream_TypeDef *)dmaRx->ref;
409 // Disable streams to enable update
410 LL_DMA_WriteReg(streamRegsTx, CR, 0U);
411 LL_DMA_WriteReg(streamRegsRx, CR, 0U);
413 /* Use the Rx interrupt as this occurs once the SPI operation is complete whereas the Tx interrupt
414 * occurs earlier when the Tx FIFO is empty, but the SPI operation is still in progress
416 LL_EX_DMA_EnableIT_TC(streamRegsRx);
418 // Update streams
419 LL_DMA_Init(dmaTx->dma, dmaTx->stream, bus->initTx);
420 LL_DMA_Init(dmaRx->dma, dmaRx->stream, bus->initRx);
422 /* Note from AN4031
424 * If the user enables the used peripheral before the corresponding DMA stream, a “FEIF”
425 * (FIFO Error Interrupt Flag) may be set due to the fact the DMA is not ready to provide
426 * the first required data to the peripheral (in case of memory-to-peripheral transfer).
429 // Enable the SPI DMA Tx & Rx requests
430 #if defined(STM32H7)
431 LL_SPI_SetTransferSize(dev->bus->busType_u.spi.instance, dev->bus->curSegment->len);
432 LL_DMA_EnableStream(dmaTx->dma, dmaTx->stream);
433 LL_DMA_EnableStream(dmaRx->dma, dmaRx->stream);
434 SET_BIT(dev->bus->busType_u.spi.instance->CFG1, SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN);
435 LL_SPI_Enable(dev->bus->busType_u.spi.instance);
436 LL_SPI_StartMasterTransfer(dev->bus->busType_u.spi.instance);
437 #else
438 // Enable streams
439 LL_DMA_EnableStream(dmaTx->dma, dmaTx->stream);
440 LL_DMA_EnableStream(dmaRx->dma, dmaRx->stream);
442 SET_BIT(dev->bus->busType_u.spi.instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
443 #endif
444 #if !defined(STM32G4) && !defined(STM32H7)
445 } else {
446 DMA_Stream_TypeDef *streamRegsTx = (DMA_Stream_TypeDef *)dmaTx->ref;
448 // Use the correct callback argument
449 dmaTx->userParam = (uint32_t)dev;
451 // Clear transfer flags
452 DMA_CLEAR_FLAG(dmaTx, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
454 // Disable streams to enable update
455 LL_DMA_WriteReg(streamRegsTx, CR, 0U);
457 LL_EX_DMA_EnableIT_TC(streamRegsTx);
459 // Update streams
460 LL_DMA_Init(dmaTx->dma, dmaTx->stream, bus->initTx);
462 /* Note from AN4031
464 * If the user enables the used peripheral before the corresponding DMA stream, a “FEIF”
465 * (FIFO Error Interrupt Flag) may be set due to the fact the DMA is not ready to provide
466 * the first required data to the peripheral (in case of memory-to-peripheral transfer).
469 // Enable the SPI DMA Tx request
470 // Enable streams
471 LL_DMA_EnableStream(dmaTx->dma, dmaTx->stream);
473 SET_BIT(dev->bus->busType_u.spi.instance->CR2, SPI_CR2_TXDMAEN);
475 #endif
476 #endif
479 void spiInternalStopDMA (const extDevice_t *dev)
481 busDevice_t *bus = dev->bus;
483 dmaChannelDescriptor_t *dmaTx = bus->dmaTx;
484 dmaChannelDescriptor_t *dmaRx = bus->dmaRx;
485 SPI_TypeDef *instance = bus->busType_u.spi.instance;
487 #if !defined(STM32G4) && !defined(STM32H7)
488 if (dmaRx) {
489 #endif
490 // Disable the DMA engine and SPI interface
491 #ifdef STM32G4
492 LL_DMA_DisableChannel(dmaTx->dma, dmaTx->stream);
493 LL_DMA_DisableChannel(dmaRx->dma, dmaRx->stream);
494 #else
495 LL_DMA_DisableStream(dmaRx->dma, dmaRx->stream);
496 LL_DMA_DisableStream(dmaTx->dma, dmaTx->stream);
497 #endif
499 // Clear transfer flags
500 DMA_CLEAR_FLAG(dmaRx, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
502 LL_SPI_DisableDMAReq_TX(instance);
503 LL_SPI_DisableDMAReq_RX(instance);
504 #if defined(STM32H7)
505 LL_SPI_ClearFlag_TXTF(dev->bus->busType_u.spi.instance);
506 LL_SPI_Disable(dev->bus->busType_u.spi.instance);
507 #endif
508 #if !defined(STM32G4) && !defined(STM32H7)
509 } else {
510 SPI_TypeDef *instance = bus->busType_u.spi.instance;
512 // Ensure the current transmission is complete
513 while (LL_SPI_IsActiveFlag_BSY(instance));
515 // Drain the RX buffer
516 while (LL_SPI_IsActiveFlag_RXNE(instance)) {
517 instance->DR;
520 // Disable the DMA engine and SPI interface
521 LL_DMA_DisableStream(dmaTx->dma, dmaTx->stream);
523 DMA_CLEAR_FLAG(dmaTx, DMA_IT_HTIF | DMA_IT_TEIF | DMA_IT_TCIF);
525 LL_SPI_DisableDMAReq_TX(instance);
526 #endif
527 #if !defined(STM32G4) && !defined(STM32H7)
529 #endif
532 // DMA transfer setup and start
533 void spiSequenceStart(const extDevice_t *dev)
535 busDevice_t *bus = dev->bus;
536 SPI_TypeDef *instance = bus->busType_u.spi.instance;
537 spiDevice_t *spi = &spiDevice[spiDeviceByInstance(instance)];
538 bool dmaSafe = dev->useDMA;
539 uint32_t xferLen = 0;
540 uint32_t segmentCount = 0;
542 bus->initSegment = true;
544 // Switch bus speed
545 #if !defined(STM32H7)
546 LL_SPI_Disable(instance);
547 #endif
549 if (dev->busType_u.spi.speed != bus->busType_u.spi.speed) {
550 LL_SPI_SetBaudRatePrescaler(instance, spiDivisorToBRbits(instance, dev->busType_u.spi.speed));
551 bus->busType_u.spi.speed = dev->busType_u.spi.speed;
554 // Switch SPI clock polarity/phase if necessary
555 if (dev->busType_u.spi.leadingEdge != bus->busType_u.spi.leadingEdge) {
556 if (dev->busType_u.spi.leadingEdge) {
557 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_LOW, spi->sckAF);
558 LL_SPI_SetClockPhase(instance, LL_SPI_PHASE_1EDGE);
559 LL_SPI_SetClockPolarity(instance, LL_SPI_POLARITY_LOW);
561 else {
562 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG_HIGH, spi->sckAF);
563 LL_SPI_SetClockPhase(instance, LL_SPI_PHASE_2EDGE);
564 LL_SPI_SetClockPolarity(instance, LL_SPI_POLARITY_HIGH);
567 bus->busType_u.spi.leadingEdge = dev->busType_u.spi.leadingEdge;
570 #if !defined(STM32H7)
571 LL_SPI_Enable(instance);
572 #endif
574 /* Where data is being read into a buffer which is cached, where the start or end of that
575 * buffer is not cache aligned, there is a risk of corruption of other data in that cache line.
576 * After the read is complete, the cache lines covering the structure will be invalidated to ensure
577 * that the processor sees the read data, not what was in cache previously. Unfortunately if
578 * there is any other data in the area covered by those cache lines, at the start or end of the
579 * buffer, it too will be invalidated, so had the processor written to those locations during the DMA
580 * operation those written values will be lost.
583 // Check that any reads are cache aligned and of multiple cache lines in length
584 for (busSegment_t *checkSegment = (busSegment_t *)bus->curSegment; checkSegment->len; checkSegment++) {
585 // Check there is no receive data as only transmit DMA is available
586 if ((checkSegment->u.buffers.rxData) && (bus->dmaRx == (dmaChannelDescriptor_t *)NULL)) {
587 dmaSafe = false;
588 break;
590 #ifdef STM32H7
591 // Check if RX data can be DMAed
592 if ((checkSegment->u.buffers.rxData) &&
593 // DTCM can't be accessed by DMA1/2 on the H7
594 (IS_DTCM(checkSegment->u.buffers.rxData) ||
595 // Memory declared as DMA_RAM will have an address between &_dmaram_start__ and &_dmaram_end__
596 (((checkSegment->u.buffers.rxData < &_dmaram_start__) || (checkSegment->u.buffers.rxData >= &_dmaram_end__)) &&
597 (((uint32_t)checkSegment->u.buffers.rxData & (CACHE_LINE_SIZE - 1)) || (checkSegment->len & (CACHE_LINE_SIZE - 1)))))) {
598 dmaSafe = false;
599 break;
601 // Check if TX data can be DMAed
602 else if ((checkSegment->u.buffers.txData) && IS_DTCM(checkSegment->u.buffers.txData)) {
603 dmaSafe = false;
604 break;
606 #elif defined(STM32F7)
607 if ((checkSegment->u.buffers.rxData) &&
608 // DTCM is accessible and uncached on the F7
609 (!IS_DTCM(checkSegment->u.buffers.rxData) &&
610 (((uint32_t)checkSegment->u.buffers.rxData & (CACHE_LINE_SIZE - 1)) || (checkSegment->len & (CACHE_LINE_SIZE - 1))))) {
611 dmaSafe = false;
612 break;
614 #elif defined(STM32G4)
615 // Check if RX data can be DMAed
616 if ((checkSegment->u.buffers.rxData) &&
617 // CCM can't be accessed by DMA1/2 on the G4
618 IS_CCM(checkSegment->u.buffers.rxData)) {
619 dmaSafe = false;
620 break;
622 if ((checkSegment->u.buffers.txData) &&
623 // CCM can't be accessed by DMA1/2 on the G4
624 IS_CCM(checkSegment->u.buffers.txData)) {
625 dmaSafe = false;
626 break;
628 #endif
629 // Note that these counts are only valid if dmaSafe is true
630 segmentCount++;
631 xferLen += checkSegment->len;
634 // Use DMA if possible
635 // If there are more than one segments, or a single segment with negateCS negated then force DMA irrespective of length
636 if (bus->useDMA && dmaSafe && ((segmentCount > 1) || (xferLen >= 8) || !bus->curSegment->negateCS)) {
637 // Intialise the init structures for the first transfer
638 spiInternalInitStream(dev, false);
640 // Assert Chip Select
641 IOLo(dev->busType_u.spi.csnPin);
643 // Start the transfers
644 spiInternalStartDMA(dev);
645 } else {
646 busSegment_t *lastSegment = NULL;
648 // Manually work through the segment list performing a transfer for each
649 while (bus->curSegment->len) {
650 if (!lastSegment || lastSegment->negateCS) {
651 // Assert Chip Select if necessary - it's costly so only do so if necessary
652 IOLo(dev->busType_u.spi.csnPin);
655 spiInternalReadWriteBufPolled(
656 bus->busType_u.spi.instance,
657 bus->curSegment->u.buffers.txData,
658 bus->curSegment->u.buffers.rxData,
659 bus->curSegment->len);
661 if (bus->curSegment->negateCS) {
662 // Negate Chip Select
663 IOHi(dev->busType_u.spi.csnPin);
666 if (bus->curSegment->callback) {
667 switch(bus->curSegment->callback(dev->callbackArg)) {
668 case BUS_BUSY:
669 // Repeat the last DMA segment
670 bus->curSegment--;
671 break;
673 case BUS_ABORT:
674 bus->curSegment = (busSegment_t *)BUS_SPI_FREE;
675 return;
677 case BUS_READY:
678 default:
679 // Advance to the next DMA segment
680 break;
683 lastSegment = (busSegment_t *)bus->curSegment;
684 bus->curSegment++;
687 if (lastSegment && !lastSegment->negateCS) {
688 // Negate Chip Select if not done so already
689 IOHi(dev->busType_u.spi.csnPin);
692 // If a following transaction has been linked, start it
693 if (bus->curSegment->u.link.dev) {
694 const extDevice_t *nextDev = bus->curSegment->u.link.dev;
695 busSegment_t *nextSegments = (busSegment_t *)bus->curSegment->u.link.segments;
696 busSegment_t *endSegment = (busSegment_t *)bus->curSegment;
697 bus->curSegment = nextSegments;
698 endSegment->u.link.dev = NULL;
699 spiSequenceStart(nextDev);
700 } else {
701 // The end of the segment list has been reached, so mark transactions as complete
702 bus->curSegment = (busSegment_t *)BUS_SPI_FREE;
706 #endif