New SPI API supporting DMA
[betaflight.git] / src / main / drivers / bus_spi.c
blobe7835150c60f7999cd15cc0c107aca1bd9a73aa3
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 #include "build/atomic.h"
29 #ifdef USE_SPI
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"
39 #include "nvic.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
49 if (instance == SPI1)
50 return SPIDEV_1;
51 #endif
53 #ifdef USE_SPI_DEVICE_2
54 if (instance == SPI2)
55 return SPIDEV_2;
56 #endif
58 #ifdef USE_SPI_DEVICE_3
59 if (instance == SPI3)
60 return SPIDEV_3;
61 #endif
63 #ifdef USE_SPI_DEVICE_4
64 if (instance == SPI4)
65 return SPIDEV_4;
66 #endif
68 return SPIINVALID;
71 SPI_TypeDef *spiInstanceByDevice(SPIDevice device)
73 if (device == SPIINVALID || device >= SPIDEV_COUNT) {
74 return NULL;
77 return spiDevice[device].dev;
80 bool spiInit(SPIDevice device)
82 switch (device) {
83 case SPIINVALID:
84 return false;
86 case SPIDEV_1:
87 #ifdef USE_SPI_DEVICE_1
88 spiInitDevice(device);
89 return true;
90 #else
91 break;
92 #endif
94 case SPIDEV_2:
95 #ifdef USE_SPI_DEVICE_2
96 spiInitDevice(device);
97 return true;
98 #else
99 break;
100 #endif
102 case SPIDEV_3:
103 #if defined(USE_SPI_DEVICE_3) && !defined(STM32F1)
104 spiInitDevice(device);
105 return true;
106 #else
107 break;
108 #endif
110 case SPIDEV_4:
111 #if defined(USE_SPI_DEVICE_4)
112 spiInitDevice(device);
113 return true;
114 #else
115 break;
116 #endif
118 case SPIDEV_5:
119 #if defined(USE_SPI_DEVICE_5)
120 spiInitDevice(device);
121 return true;
122 #else
123 break;
124 #endif
126 case SPIDEV_6:
127 #if defined(USE_SPI_DEVICE_6)
128 spiInitDevice(device);
129 return true;
130 #else
131 break;
132 #endif
134 return false;
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
158 do {
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);
165 } else {
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
188 spiWaitClaim(dev);
190 spiSequence(dev, &segments[0]);
192 spiWait(dev);
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)) {
200 return false;
203 spiReadWriteBuf(dev, txData, rxData, length);
205 return true;
208 // Wait for bus to become free, then read/write a single byte
209 uint8_t spiReadWrite(const extDevice_t *dev, uint8_t data)
211 uint8_t retval;
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
220 spiWaitClaim(dev);
222 spiSequence(dev, &segments[0]);
224 spiWait(dev);
226 return retval;
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)
232 uint8_t retval;
234 // This routine blocks so no need to use static data
235 busSegment_t segments[] = {
236 {&reg, 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
242 spiWaitClaim(dev);
244 spiSequence(dev, &segments[0]);
246 spiWait(dev);
248 return retval;
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
261 spiWaitClaim(dev);
263 spiSequence(dev, &segments[0]);
265 spiWait(dev);
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 {&reg, 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
279 spiWaitClaim(dev);
281 spiSequence(dev, &segments[0]);
283 spiWait(dev);
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)) {
291 return false;
294 spiWriteReg(dev, reg, data);
296 return true;
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 {&reg, 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
310 spiWaitClaim(dev);
312 spiSequence(dev, &segments[0]);
314 spiWait(dev);
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)) {
322 return false;
325 spiReadRegBuf(dev, reg, data, length);
327 return true;
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 {&reg, 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
347 spiWaitClaim(dev);
349 spiSequence(dev, &segments[0]);
351 spiWait(dev);
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)
357 uint8_t data;
358 // This routine blocks so no need to use static data
359 busSegment_t segments[] = {
360 {&reg, 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
366 spiWaitClaim(dev);
368 spiSequence(dev, &segments[0]);
370 spiWait(dev);
372 return data;
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;
387 #else
388 #error "Base SPI clock not defined for this architecture"
389 #endif
391 uint16_t divisor = 2;
393 spiClk >>= 1;
395 for (; (spiClk > freq) && (divisor < 256); divisor <<= 1, spiClk >>= 1);
397 return divisor;
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;
405 if (!dev) {
406 return;
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
419 #ifdef STM32H7
420 if (bus->curSegment->rxData &&
421 ((bus->curSegment->rxData < &_dmaram_start__) || (bus->curSegment->rxData >= &_dmaram_end__))) {
422 #else
423 if (bus->curSegment->rxData) {
424 #endif
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)) {
435 case BUS_BUSY:
436 // Repeat the last DMA segment
437 bus->curSegment--;
438 // Reinitialise the cached init values as segment is not progressing
439 spiInternalInitStream(dev, true);
440 break;
442 case BUS_ABORT:
443 bus->curSegment = (busSegment_t *)NULL;
444 return;
446 case BUS_READY:
447 default:
448 // Advance to the next DMA segment
449 break;
453 // Advance through the segment list
454 bus->curSegment++;
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;
459 } else {
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) {
478 return false;
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++;
486 return true;
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) {
494 return false;
497 bus->busType = BUS_TYPE_SPI;
498 dev->useDMA = true;
499 bus->useDMA = false;
500 bus->useAtomicWait = false;
501 bus->deviceCount = 1;
502 bus->owner = owner;
503 bus->initTx = &dev->initTx;
504 bus->initRx = &dev->initRx;
506 return true;
509 void spiInitBusDMA()
511 uint32_t device;
512 #ifdef STM32F4
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);
519 #endif
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
526 continue;
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;
539 continue;
541 #ifdef STM32F4
542 if (dshotBitbangActive && (DMA_DEVICE_NO(dmaTxIdentifier) == 2)) {
543 dmaTxIdentifier = DMA_NONE;
544 break;
546 #endif
547 bus->dmaTxChannel = dmaTxChannelSpec->channel;
548 dmaInit(dmaTxIdentifier, bus->owner, 0);
549 break;
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;
560 continue;
562 #ifdef STM32F4
563 if (dshotBitbangActive && (DMA_DEVICE_NO(dmaRxIdentifier) == 2)) {
564 dmaRxIdentifier = DMA_NONE;
565 break;
567 #endif
568 bus->dmaRxChannel = dmaRxChannelSpec->channel;
569 dmaInit(dmaRxIdentifier, bus->owner, 0);
570 break;
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);
589 bus->useDMA = true;
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)
618 UNUSED(dev);
620 spiRegisteredDeviceCount++;
623 uint8_t spiGetRegisteredDeviceCount(void)
625 return spiRegisteredDeviceCount;
628 uint8_t spiGetExtDeviceCount(const extDevice_t *dev)
630 return dev->bus->deviceCount;
632 #endif