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)
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/>.
27 #include "build/atomic.h"
31 #include "drivers/bus.h"
32 #include "drivers/bus_spi.h"
33 #include "drivers/bus_spi_impl.h"
34 #include "drivers/dma_reqmap.h"
35 #include "drivers/exti.h"
36 #include "drivers/io.h"
37 #include "drivers/motor.h"
38 #include "drivers/rcc.h"
41 static uint8_t spiRegisteredDeviceCount
= 0;
43 spiDevice_t spiDevice
[SPIDEV_COUNT
];
44 busDevice_t spiBusDevice
[SPIDEV_COUNT
];
46 SPIDevice
spiDeviceByInstance(SPI_TypeDef
*instance
)
48 #ifdef USE_SPI_DEVICE_1
53 #ifdef USE_SPI_DEVICE_2
58 #ifdef USE_SPI_DEVICE_3
63 #ifdef USE_SPI_DEVICE_4
71 SPI_TypeDef
*spiInstanceByDevice(SPIDevice device
)
73 if (device
== SPIINVALID
|| device
>= SPIDEV_COUNT
) {
77 return spiDevice
[device
].dev
;
80 bool spiInit(SPIDevice device
)
87 #ifdef USE_SPI_DEVICE_1
88 spiInitDevice(device
);
95 #ifdef USE_SPI_DEVICE_2
96 spiInitDevice(device
);
103 #if defined(USE_SPI_DEVICE_3) && !defined(STM32F1)
104 spiInitDevice(device
);
111 #if defined(USE_SPI_DEVICE_4)
112 spiInitDevice(device
);
119 #if defined(USE_SPI_DEVICE_5)
120 spiInitDevice(device
);
127 #if defined(USE_SPI_DEVICE_6)
128 spiInitDevice(device
);
137 // Return true if DMA engine is busy
138 bool spiIsBusy(const extDevice_t
*dev
)
140 return (dev
->bus
->curSegment
!= (busSegment_t
*)NULL
);
143 // Indicate that the bus on which this device resides may initiate DMA transfers from interrupt context
144 void spiSetAtomicWait(const extDevice_t
*dev
)
146 dev
->bus
->useAtomicWait
= true;
149 // Wait for DMA completion and claim the bus driver
150 void spiWaitClaim(const extDevice_t
*dev
)
152 // If there is a device on the bus whose driver might call spiSequence from an ISR then an
153 // atomic access is required to claim the bus, however if not, then interrupts need not be
154 // disabled as this can result in edge triggered interrupts being missed
156 if (dev
->bus
->useAtomicWait
) {
157 // Prevent race condition where the bus appears free, but a gyro interrupt starts a transfer
159 ATOMIC_BLOCK(NVIC_PRIO_MPU_INT_EXTI
) {
160 if (dev
->bus
->curSegment
== (busSegment_t
*)NULL
) {
161 dev
->bus
->curSegment
= (busSegment_t
*)0x04;
164 } while (dev
->bus
->curSegment
!= (busSegment_t
*)0x04);
166 // Wait for completion
167 while (dev
->bus
->curSegment
!= (busSegment_t
*)NULL
);
171 // Wait for DMA completion
172 void spiWait(const extDevice_t
*dev
)
174 // Wait for completion
175 while (dev
->bus
->curSegment
!= (busSegment_t
*)NULL
);
178 // Wait for bus to become free, then read/write block of data
179 void spiReadWriteBuf(const extDevice_t
*dev
, uint8_t *txData
, uint8_t *rxData
, int len
)
181 // This routine blocks so no need to use static data
182 busSegment_t segments
[] = {
183 {txData
, rxData
, len
, true, NULL
},
184 {NULL
, NULL
, 0, true, NULL
},
187 // Ensure any prior DMA has completed before continuing
190 spiSequence(dev
, &segments
[0]);
195 // Read/Write a block of data, returning false if the bus is busy
196 bool spiReadWriteBufRB(const extDevice_t
*dev
, uint8_t *txData
, uint8_t *rxData
, int length
)
198 // Ensure any prior DMA has completed before continuing
199 if (spiIsBusy(dev
)) {
203 spiReadWriteBuf(dev
, txData
, rxData
, length
);
208 // Wait for bus to become free, then read/write a single byte
209 uint8_t spiReadWrite(const extDevice_t
*dev
, uint8_t data
)
213 // This routine blocks so no need to use static data
214 busSegment_t segments
[] = {
215 {&data
, &retval
, sizeof (data
), true, NULL
},
216 {NULL
, NULL
, 0, true, NULL
},
219 // Ensure any prior DMA has completed before continuing
222 spiSequence(dev
, &segments
[0]);
229 // Wait for bus to become free, then read/write a single byte from a register
230 uint8_t spiReadWriteReg(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
)
234 // This routine blocks so no need to use static data
235 busSegment_t segments
[] = {
236 {®
, NULL
, sizeof (reg
), false, NULL
},
237 {&data
, &retval
, sizeof (data
), true, NULL
},
238 {NULL
, NULL
, 0, true, NULL
},
241 // Ensure any prior DMA has completed before continuing
244 spiSequence(dev
, &segments
[0]);
251 // Wait for bus to become free, then write a single byte
252 void spiWrite(const extDevice_t
*dev
, uint8_t data
)
254 // This routine blocks so no need to use static data
255 busSegment_t segments
[] = {
256 {&data
, NULL
, sizeof (data
), true, NULL
},
257 {NULL
, NULL
, 0, true, NULL
},
260 // Ensure any prior DMA has completed before continuing
263 spiSequence(dev
, &segments
[0]);
268 // Write data to a register
269 void spiWriteReg(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
)
271 // This routine blocks so no need to use static data
272 busSegment_t segments
[] = {
273 {®
, NULL
, sizeof (reg
), false, NULL
},
274 {&data
, NULL
, sizeof (data
), true, NULL
},
275 {NULL
, NULL
, 0, true, NULL
},
278 // Ensure any prior DMA has completed before continuing
281 spiSequence(dev
, &segments
[0]);
286 // Write data to a register, returning false if the bus is busy
287 bool spiWriteRegRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t data
)
289 // Ensure any prior DMA has completed before continuing
290 if (spiIsBusy(dev
)) {
294 spiWriteReg(dev
, reg
, data
);
299 // Read a block of data from a register
300 void spiReadRegBuf(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
)
302 // This routine blocks so no need to use static data
303 busSegment_t segments
[] = {
304 {®
, NULL
, sizeof (reg
), false, NULL
},
305 {NULL
, data
, length
, true, NULL
},
306 {NULL
, NULL
, 0, true, NULL
},
309 // Ensure any prior DMA has completed before continuing
312 spiSequence(dev
, &segments
[0]);
317 // Read a block of data from a register, returning false if the bus is busy
318 bool spiReadRegBufRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
)
320 // Ensure any prior DMA has completed before continuing
321 if (spiIsBusy(dev
)) {
325 spiReadRegBuf(dev
, reg
, data
, length
);
330 // Read a block of data where the register is ORed with 0x80, returning false if the bus is busy
331 bool spiReadRegMskBufRB(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint8_t length
)
333 return spiReadRegBufRB(dev
, reg
| 0x80, data
, length
);
336 // Wait for bus to become free, then write a block of data to a register
337 void spiWriteRegBuf(const extDevice_t
*dev
, uint8_t reg
, uint8_t *data
, uint32_t length
)
339 // This routine blocks so no need to use static data
340 busSegment_t segments
[] = {
341 {®
, NULL
, sizeof (reg
), false, NULL
},
342 {data
, NULL
, length
, true, NULL
},
343 {NULL
, NULL
, 0, true, NULL
},
346 // Ensure any prior DMA has completed before continuing
349 spiSequence(dev
, &segments
[0]);
354 // Wait for bus to become free, then read a byte from a register
355 uint8_t spiReadReg(const extDevice_t
*dev
, uint8_t reg
)
358 // This routine blocks so no need to use static data
359 busSegment_t segments
[] = {
360 {®
, NULL
, sizeof (reg
), false, NULL
},
361 {NULL
, &data
, sizeof (data
), true, NULL
},
362 {NULL
, NULL
, 0, true, NULL
},
365 // Ensure any prior DMA has completed before continuing
368 spiSequence(dev
, &segments
[0]);
375 // Wait for bus to become free, then read a byte of data where the register is ORed with 0x80
376 uint8_t spiReadRegMsk(const extDevice_t
*dev
, uint8_t reg
)
378 return spiReadReg(dev
, reg
| 0x80);
381 uint16_t spiCalculateDivider(uint32_t freq
)
383 #if defined(STM32F4) || defined(STM32G4) || defined(STM32F7)
384 uint32_t spiClk
= SystemCoreClock
/ 2;
385 #elif defined(STM32H7)
386 uint32_t spiClk
= 100000000;
388 #error "Base SPI clock not defined for this architecture"
391 uint16_t divisor
= 2;
395 for (; (spiClk
> freq
) && (divisor
< 256); divisor
<<= 1, spiClk
>>= 1);
400 // Interrupt handler for SPI receive DMA completion
401 static void spiRxIrqHandler(dmaChannelDescriptor_t
* descriptor
)
403 const extDevice_t
*dev
= (const extDevice_t
*)descriptor
->userParam
;
409 busDevice_t
*bus
= dev
->bus
;
411 if (bus
->curSegment
->negateCS
) {
412 // Negate Chip Select
413 IOHi(dev
->busType_u
.spi
.csnPin
);
416 spiInternalStopDMA(dev
);
418 #ifdef __DCACHE_PRESENT
420 if (bus
->curSegment
->rxData
&&
421 ((bus
->curSegment
->rxData
< &_dmaram_start__
) || (bus
->curSegment
->rxData
>= &_dmaram_end__
))) {
423 if (bus
->curSegment
->rxData
) {
425 // Invalidate the D cache covering the area into which data has been read
426 SCB_InvalidateDCache_by_Addr(
427 (uint32_t *)((uint32_t)bus
->curSegment
->rxData
& ~CACHE_LINE_MASK
),
428 (((uint32_t)bus
->curSegment
->rxData
& CACHE_LINE_MASK
) +
429 bus
->curSegment
->len
- 1 + CACHE_LINE_SIZE
) & ~CACHE_LINE_MASK
);
431 #endif // __DCACHE_PRESENT
433 if (bus
->curSegment
->callback
) {
434 switch(bus
->curSegment
->callback(dev
->callbackArg
)) {
436 // Repeat the last DMA segment
438 // Reinitialise the cached init values as segment is not progressing
439 spiInternalInitStream(dev
, true);
443 bus
->curSegment
= (busSegment_t
*)NULL
;
448 // Advance to the next DMA segment
453 // Advance through the segment list
456 if (bus
->curSegment
->len
== 0) {
457 // The end of the segment list has been reached, so mark transactions as complete
458 bus
->curSegment
= (busSegment_t
*)NULL
;
460 // After the completion of the first segment setup the init structure for the subsequent segment
461 if (bus
->initSegment
) {
462 spiInternalInitStream(dev
, false);
463 bus
->initSegment
= false;
466 // Launch the next transfer
467 spiInternalStartDMA(dev
);
469 // Prepare the init structures ready for the next segment to reduce inter-segment time
470 spiInternalInitStream(dev
, true);
474 // Mark this bus as being SPI and record the first owner to use it
475 bool spiSetBusInstance(extDevice_t
*dev
, uint32_t device
, resourceOwner_e owner
)
477 if (device
> SPIDEV_COUNT
) {
481 dev
->bus
= &spiBusDevice
[SPI_CFG_TO_DEV(device
)];
483 if (dev
->bus
->busType
== BUS_TYPE_SPI
) {
484 // This bus has already been initialised
485 dev
->bus
->deviceCount
++;
489 busDevice_t
*bus
= dev
->bus
;
491 bus
->busType_u
.spi
.instance
= spiInstanceByDevice(SPI_CFG_TO_DEV(device
));
493 if (bus
->busType_u
.spi
.instance
== NULL
) {
497 bus
->busType
= BUS_TYPE_SPI
;
500 bus
->useAtomicWait
= false;
501 bus
->deviceCount
= 1;
503 bus
->initTx
= &dev
->initTx
;
504 bus
->initRx
= &dev
->initRx
;
513 /* Check https://www.st.com/resource/en/errata_sheet/dm00037591-stm32f405407xx-and-stm32f415417xx-device-limitations-stmicroelectronics.pdf
514 * section 2.1.10 which reports an errata that corruption may occurs on DMA2 if AHB peripherals (eg GPIO ports) are
515 * access concurrently with APB peripherals (eg SPI busses). Bitbang DSHOT uses DMA2 to write to GPIO ports. If this
516 * is enabled, then don't enable DMA on an SPI bus using DMA2
518 const bool dshotBitbangActive
= isDshotBitbangActive(&motorConfig()->dev
);
521 for (device
= 0; device
< SPIDEV_COUNT
; device
++) {
522 busDevice_t
*bus
= &spiBusDevice
[device
];
524 if (bus
->busType
!= BUS_TYPE_SPI
) {
525 // This bus is not in use
529 dmaIdentifier_e dmaTxIdentifier
= DMA_NONE
;
530 dmaIdentifier_e dmaRxIdentifier
= DMA_NONE
;
532 for (uint8_t opt
= 0; opt
< MAX_PERIPHERAL_DMA_OPTIONS
; opt
++) {
533 const dmaChannelSpec_t
*dmaTxChannelSpec
= dmaGetChannelSpecByPeripheral(DMA_PERIPH_SPI_TX
, device
, opt
);
535 if (dmaTxChannelSpec
) {
536 dmaTxIdentifier
= dmaGetIdentifier(dmaTxChannelSpec
->ref
);
537 if (dmaGetOwner(dmaTxIdentifier
)->owner
!= OWNER_FREE
) {
538 dmaTxIdentifier
= DMA_NONE
;
542 if (dshotBitbangActive
&& (DMA_DEVICE_NO(dmaTxIdentifier
) == 2)) {
543 dmaTxIdentifier
= DMA_NONE
;
547 bus
->dmaTxChannel
= dmaTxChannelSpec
->channel
;
548 dmaInit(dmaTxIdentifier
, bus
->owner
, 0);
553 for (uint8_t opt
= 0; opt
< MAX_PERIPHERAL_DMA_OPTIONS
; opt
++) {
554 const dmaChannelSpec_t
*dmaRxChannelSpec
= dmaGetChannelSpecByPeripheral(DMA_PERIPH_SPI_RX
, device
, opt
);
556 if (dmaRxChannelSpec
) {
557 dmaRxIdentifier
= dmaGetIdentifier(dmaRxChannelSpec
->ref
);
558 if (dmaGetOwner(dmaRxIdentifier
)->owner
!= OWNER_FREE
) {
559 dmaRxIdentifier
= DMA_NONE
;
563 if (dshotBitbangActive
&& (DMA_DEVICE_NO(dmaRxIdentifier
) == 2)) {
564 dmaRxIdentifier
= DMA_NONE
;
568 bus
->dmaRxChannel
= dmaRxChannelSpec
->channel
;
569 dmaInit(dmaRxIdentifier
, bus
->owner
, 0);
574 if (dmaTxIdentifier
&& dmaRxIdentifier
) {
575 bus
->dmaTx
= dmaGetDescriptorByIdentifier(dmaTxIdentifier
);
576 bus
->dmaRx
= dmaGetDescriptorByIdentifier(dmaRxIdentifier
);
578 // Ensure streams are disabled
579 spiInternalResetStream(bus
->dmaRx
);
580 spiInternalResetStream(bus
->dmaTx
);
582 spiInternalResetDescriptors(bus
);
584 /* Note that this driver may be called both from the normal thread of execution, or from USB interrupt
585 * handlers, so the DMA completion interrupt must be at a higher priority
587 dmaSetHandler(dmaRxIdentifier
, spiRxIrqHandler
, NVIC_PRIO_SPI_DMA
, 0);
594 void spiSetClkDivisor(const extDevice_t
*dev
, uint16_t divisor
)
596 ((extDevice_t
*)dev
)->busType_u
.spi
.speed
= divisor
;
599 // Set the clock phase/polarity to be used for accesses by the given device
600 void spiSetClkPhasePolarity(const extDevice_t
*dev
, bool leadingEdge
)
602 ((extDevice_t
*)dev
)->busType_u
.spi
.leadingEdge
= leadingEdge
;
605 // Enable/disable DMA on a specific device. Enabled by default.
606 void spiDmaEnable(const extDevice_t
*dev
, bool enable
)
608 ((extDevice_t
*)dev
)->useDMA
= enable
;
611 bool spiUseDMA(const extDevice_t
*dev
)
613 return dev
->bus
->useDMA
&& dev
->useDMA
;
616 void spiBusDeviceRegister(const extDevice_t
*dev
)
620 spiRegisteredDeviceCount
++;
623 uint8_t spiGetRegisteredDeviceCount(void)
625 return spiRegisteredDeviceCount
;
628 uint8_t spiGetExtDeviceCount(const extDevice_t
*dev
)
630 return dev
->bus
->deviceCount
;