1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-12 19:10:32 +03:00

Add support for SPI DMA (#14483)

This commit is contained in:
Steve Evans 2025-06-30 02:21:56 +01:00 committed by GitHub
parent aeda0905c5
commit 9fed1f9ebb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 112 additions and 36 deletions

View file

@ -1830,7 +1830,7 @@ case MSP_NAME:
} }
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
for (unsigned j; j < ARRAYLEN(gyroDeviceConfig(i)->customAlignment.raw); j++) { for (unsigned j = 0; j < ARRAYLEN(gyroDeviceConfig(i)->customAlignment.raw); j++) {
sbufWriteU16(dst, i < GYRO_COUNT ? gyroDeviceConfig(i)->customAlignment.raw[j] : 0); sbufWriteU16(dst, i < GYRO_COUNT ? gyroDeviceConfig(i)->customAlignment.raw[j] : 0);
} }
} }

View file

@ -33,7 +33,7 @@
#include "platform.h" #include "platform.h"
#ifdef USE_SPI #ifdef USE_SPI
#define TESTING_NO_DMA 1 //#define TESTING_NO_DMA 1
#include "common/maths.h" #include "common/maths.h"
#include "drivers/bus.h" #include "drivers/bus.h"
@ -43,6 +43,7 @@
#include "drivers/io.h" #include "drivers/io.h"
#include "drivers/io_def.h" #include "drivers/io_def.h"
#include "drivers/io_impl.h" #include "drivers/io_impl.h"
#include "drivers/nvic.h"
#include "hardware/spi.h" #include "hardware/spi.h"
#include "hardware/gpio.h" #include "hardware/gpio.h"
@ -126,6 +127,8 @@ const spiHardware_t spiHardware[] = {
}, },
}; };
extern busDevice_t spiBusDevice[SPIDEV_COUNT];
void spiPinConfigure(const struct spiPinConfig_s *pConfig) void spiPinConfigure(const struct spiPinConfig_s *pConfig)
{ {
for (size_t hwindex = 0 ; hwindex < ARRAYLEN(spiHardware) ; hwindex++) { for (size_t hwindex = 0 ; hwindex < ARRAYLEN(spiHardware) ; hwindex++) {
@ -242,11 +245,84 @@ void spiInitDevice(SPIDevice device)
gpio_set_function(IO_PINBYTAG(spi->sck), GPIO_FUNC_SPI); gpio_set_function(IO_PINBYTAG(spi->sck), GPIO_FUNC_SPI);
} }
void spiInternalStopDMA (const extDevice_t *dev)
{
dmaChannelDescriptor_t *dmaRx = dev->bus->dmaRx;
dmaChannelDescriptor_t *dmaTx = dev->bus->dmaTx;
if (dmaRx && dma_channel_is_busy(dmaRx->channel)) {
// Abort active DMA - this should never happen
dma_channel_abort(dmaRx->channel);
}
if (dmaTx && dma_channel_is_busy(dmaTx->channel)) {
// Abort active DMA - this should never happen as Tx should complete before Rx
dma_channel_abort(dmaTx->channel);
}
}
// Interrupt handler for SPI receive DMA completion
FAST_IRQ_HANDLER static void spiRxIrqHandler(dmaChannelDescriptor_t* descriptor)
{
const extDevice_t *dev = (const extDevice_t *)descriptor->userParam;
if (!dev) {
return;
}
busDevice_t *bus = dev->bus;
if (bus->curSegment->negateCS) {
// Negate Chip Select
IOHi(dev->busType_u.spi.csnPin);
}
spiInternalStopDMA(dev);
spiIrqHandler(dev);
}
extern dmaChannelDescriptor_t dmaDescriptors[];
void spiInitBusDMA(void) void spiInitBusDMA(void)
{ {
//TODO: implement for (uint32_t device = 0; device < SPIDEV_COUNT; device++) {
// if required to set up mappings of peripherals to DMA instances? busDevice_t *bus = &spiBusDevice[device];
// can just start off with dma_claim_unused_channel in spiInternalInitStream? int32_t channel_tx;
int32_t channel_rx;
if (bus->busType != BUS_TYPE_SPI) {
// This bus is not in use
continue;
}
channel_tx = dma_claim_unused_channel(true);
if (channel_tx == -1) {
// no more available channels so give up
return;
}
channel_rx = dma_claim_unused_channel(true);
if (channel_rx == -1) {
// no more available channels so give up, first releasing the one
// channel we did claim
dma_channel_unclaim(channel_tx);
return;
}
bus->dmaTx = &dmaDescriptors[DMA_CHANNEL_TO_INDEX(channel_tx)];
bus->dmaTx->channel = channel_tx;
bus->dmaRx = &dmaDescriptors[DMA_CHANNEL_TO_INDEX(channel_rx)];
bus->dmaRx->channel = channel_rx;
// The transaction concludes when the data has been received which will be after transmission is complete
dmaSetHandler(DMA_CHANNEL_TO_IDENTIFIER(bus->dmaRx->channel), spiRxIrqHandler, NVIC_PRIO_SPI_DMA, 0);
// We got the required resources, so we can use DMA on this bus
bus->useDMA = true;
}
} }
void spiInternalResetStream(dmaChannelDescriptor_t *descriptor) void spiInternalResetStream(dmaChannelDescriptor_t *descriptor)
@ -271,26 +347,26 @@ void spiInternalInitStream(const extDevice_t *dev, bool preInit)
#else #else
UNUSED(preInit); UNUSED(preInit);
int dma_tx = dma_claim_unused_channel(true); busDevice_t *bus = dev->bus;
int dma_rx = dma_claim_unused_channel(true);
dev->bus->dmaTx->channel = dma_tx; volatile busSegment_t *segment = bus->curSegment;
dev->bus->dmaRx->channel = dma_rx;
dev->bus->dmaTx->irqHandlerCallback = NULL;
dev->bus->dmaRx->irqHandlerCallback = spiInternalResetStream; // TODO: implement - correct callback
const spiDevice_t *spi = &spiDevice[spiDeviceByInstance(dev->bus->busType_u.spi.instance)]; const spiDevice_t *spi = &spiDevice[spiDeviceByInstance(dev->bus->busType_u.spi.instance)];
dma_channel_config config = dma_channel_get_default_config(dma_tx); dma_channel_config config = dma_channel_get_default_config(dev->bus->dmaTx->channel);
channel_config_set_transfer_data_size(&config, DMA_SIZE_8); channel_config_set_transfer_data_size(&config, DMA_SIZE_8);
channel_config_set_read_increment(&config, true);
channel_config_set_write_increment(&config, false);
channel_config_set_dreq(&config, spi_get_dreq(SPI_INST(spi->dev), true)); channel_config_set_dreq(&config, spi_get_dreq(SPI_INST(spi->dev), true));
dma_channel_configure(dma_tx, &config, &spi_get_hw(SPI_INST(spi->dev))->dr, dev->txBuf, 0, false); dma_channel_configure(dev->bus->dmaTx->channel, &config, &spi_get_hw(SPI_INST(spi->dev))->dr, segment->u.buffers.txData, 0, false);
config = dma_channel_get_default_config(dma_rx); config = dma_channel_get_default_config(dev->bus->dmaRx->channel);
channel_config_set_transfer_data_size(&config, DMA_SIZE_8); channel_config_set_transfer_data_size(&config, DMA_SIZE_8);
channel_config_set_read_increment(&config, false);
channel_config_set_write_increment(&config, true);
channel_config_set_dreq(&config, spi_get_dreq(SPI_INST(spi->dev), false)); channel_config_set_dreq(&config, spi_get_dreq(SPI_INST(spi->dev), false));
dma_channel_configure(dma_rx, &config, dev->rxBuf, &spi_get_hw(SPI_INST(spi->dev))->dr, 0, false); dma_channel_configure(dev->bus->dmaRx->channel, &config, segment->u.buffers.rxData, &spi_get_hw(SPI_INST(spi->dev))->dr, 0, false);
#endif #endif
} }
@ -300,12 +376,13 @@ void spiInternalStartDMA(const extDevice_t *dev)
#ifndef USE_DMA #ifndef USE_DMA
UNUSED(dev); UNUSED(dev);
#else #else
dev->bus->dmaRx->userParam = (uint32_t)dev;
// TODO check correct, was len + 1 now len // TODO check correct, was len + 1 now len
dma_channel_set_trans_count(dev->bus->dmaTx->channel, dev->bus->curSegment->len, false); dma_channel_set_trans_count(dev->bus->dmaTx->channel, dev->bus->curSegment->len, false);
dma_channel_set_trans_count(dev->bus->dmaRx->channel, dev->bus->curSegment->len, false); dma_channel_set_trans_count(dev->bus->dmaRx->channel, dev->bus->curSegment->len, false);
dma_channel_start(dev->bus->dmaTx->channel); dma_start_channel_mask((1 << dev->bus->dmaTx->channel) | (1 << dev->bus->dmaRx->channel));
dma_channel_start(dev->bus->dmaRx->channel);
#endif #endif
} }

View file

@ -34,9 +34,6 @@
#include "hardware/dma.h" #include "hardware/dma.h"
#include "hardware/irq.h" #include "hardware/irq.h"
volatile bool dma_irq0_handler_registered = false;
volatile bool dma_irq1_handler_registered = false;
dmaChannelDescriptor_t dmaDescriptors[DMA_LAST_HANDLER] = { dmaChannelDescriptor_t dmaDescriptors[DMA_LAST_HANDLER] = {
DEFINE_DMA_CHANNEL(DMA_CH0_HANDLER), DEFINE_DMA_CHANNEL(DMA_CH0_HANDLER),
DEFINE_DMA_CHANNEL(DMA_CH1_HANDLER), DEFINE_DMA_CHANNEL(DMA_CH1_HANDLER),
@ -103,7 +100,7 @@ dmaIdentifier_e dmaGetFreeIdentifier(void)
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam) void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
{ {
if (identifier < DMA_CH0_HANDLER || identifier > DMA_LAST_HANDLER) { if (identifier < DMA_FIRST_HANDLER || identifier > DMA_LAST_HANDLER) {
return; // Invalid identifier return; // Invalid identifier
} }
@ -129,22 +126,24 @@ void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callbac
const int index = DMA_IDENTIFIER_TO_INDEX(identifier); const int index = DMA_IDENTIFIER_TO_INDEX(identifier);
const uint32_t channel = dmaDescriptors[index].channel; const uint32_t channel = dmaDescriptors[index].channel;
static bool dma_irqN_handler_registered[2];
if (!dma_irqN_handler_registered[core]) {
// Register the DMA IRQ handler if needed
dmaDescriptors[index].irqN = core ? DMA_IRQ_1_IRQn : DMA_IRQ_0_IRQn;
irq_handler_t irq_handler = core ? dma_irq1_handler : dma_irq0_handler;
irq_set_exclusive_handler(dmaDescriptors[index].irqN, irq_handler);
irq_set_enabled(dmaDescriptors[index].irqN, true);
dma_irqN_handler_registered[core] = true;
}
if (core) { if (core) {
// Core 1 uses DMA IRQ1 dma_channel_set_irq1_enabled(channel, true);
if (!dma_irq1_handler_registered) {
irq_set_exclusive_handler(DMA_IRQ_1, dma_irq1_handler);
irq_set_enabled(DMA_IRQ_1, true);
dma_channel_set_irq1_enabled(channel, true);
dma_irq1_handler_registered = true;
}
} else { } else {
// Core 0 uses DMA IRQ0 dma_channel_set_irq0_enabled(channel, true);
if (!dma_irq0_handler_registered) {
irq_set_exclusive_handler(DMA_IRQ_0, dma_irq0_handler);
irq_set_enabled(DMA_IRQ_0, true);
dma_channel_set_irq0_enabled(channel, true);
dma_irq0_handler_registered = true;
}
} }
dmaDescriptors[index].irqHandlerCallback = callback; dmaDescriptors[index].irqHandlerCallback = callback;

View file

@ -61,7 +61,6 @@ typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
//#define SystemCoreClock //#define SystemCoreClock
//#define EXTI_TypeDef //#define EXTI_TypeDef
//#define EXTI_InitTypeDef //#define EXTI_InitTypeDef
//#define IRQn_Type void*
// We have to use SPI0_Type (or void) because config will pass in SPI0, SPI1, // We have to use SPI0_Type (or void) because config will pass in SPI0, SPI1,
// which are defined in pico-sdk as SPI0_Type*. // which are defined in pico-sdk as SPI0_Type*.

View file

@ -53,6 +53,7 @@
#define USE_SPI #define USE_SPI
#define USE_SPI_DEVICE_0 #define USE_SPI_DEVICE_0
#define USE_SPI_DEVICE_1 #define USE_SPI_DEVICE_1
#define USE_SPI_DMA_ENABLE_LATE
#define USE_I2C #define USE_I2C
#define USE_I2C_DEVICE_0 #define USE_I2C_DEVICE_0