1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-21 07:15:18 +03:00

[4.4.2] If CS is asserted between transfers then consider bus to be busy for … (#12784)

If CS is asserted between transfers then consider bus to be busy for all but owning device (#12604)

* If CS is asserted between transfers then consider bus to be busy for all but owning device

* Track if MAX7456 is mid DMA transfer, not simply that the SPI bus is busy

* Enable SPI DMA TX/RX together

Co-authored-by: Steve Evans <SteveCEvans@users.noreply.github.com>
This commit is contained in:
Mark Haslinghuis 2023-05-12 23:39:00 +02:00 committed by GitHub
parent 5a737a47e0
commit 167bd0f3d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 10 deletions

View file

@ -42,6 +42,7 @@ typedef enum {
BUS_ABORT BUS_ABORT
} busStatus_e; } busStatus_e;
struct extDevice_s;
// Bus interface, independent of connected device // Bus interface, independent of connected device
typedef struct busDevice_s { typedef struct busDevice_s {
@ -74,6 +75,7 @@ typedef struct busDevice_s {
#endif #endif
#endif // UNIT_TEST #endif // UNIT_TEST
volatile struct busSegment_s* volatile curSegment; volatile struct busSegment_s* volatile curSegment;
volatile struct extDevice_s *csLockDevice;
bool initSegment; bool initSegment;
} busDevice_t; } busDevice_t;

View file

@ -156,6 +156,10 @@ bool spiInit(SPIDevice device)
// Return true if DMA engine is busy // Return true if DMA engine is busy
bool spiIsBusy(const extDevice_t *dev) bool spiIsBusy(const extDevice_t *dev)
{ {
if (dev->bus->csLockDevice && (dev->bus->csLockDevice != dev)) {
// If CS is still asserted, but not by the current device, the bus is busy
return true;
}
return (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE); return (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE);
} }
@ -163,7 +167,7 @@ bool spiIsBusy(const extDevice_t *dev)
void spiWait(const extDevice_t *dev) void spiWait(const extDevice_t *dev)
{ {
// Wait for completion // Wait for completion
while (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE); while (spiIsBusy(dev));
} }
// Wait for bus to become free, then read/write block of data // Wait for bus to become free, then read/write block of data
@ -419,6 +423,11 @@ FAST_IRQ_HANDLER static void spiIrqHandler(const extDevice_t *dev)
spiSequenceStart(nextDev); spiSequenceStart(nextDev);
} else { } else {
// The end of the segment list has been reached, so mark transactions as complete // The end of the segment list has been reached, so mark transactions as complete
if (bus->curSegment->negateCS) {
bus->csLockDevice = (extDevice_t *)NULL;
} else {
bus->csLockDevice = (extDevice_t *)dev;
}
bus->curSegment = (busSegment_t *)BUS_SPI_FREE; bus->curSegment = (busSegment_t *)BUS_SPI_FREE;
} }
} else { } else {
@ -729,6 +738,11 @@ void spiSequence(const extDevice_t *dev, busSegment_t *segments)
// Safe to discard the volatile qualifier as we're in an atomic block // Safe to discard the volatile qualifier as we're in an atomic block
busSegment_t *endCmpSegment = (busSegment_t *)bus->curSegment; busSegment_t *endCmpSegment = (busSegment_t *)bus->curSegment;
/* It is possible that the endCmpSegment may be NULL as the bus is held busy by csLockDevice.
* If this is the case this transfer will be silently dropped. Therefore holding CS low after a transfer,
* as is done with the SD card, MUST not be done on a bus where interrupts may trigger a transfer
* on an idle bus, such as would be the case with a gyro. This would be result in skipped gyro transfers.
*/
if (endCmpSegment) { if (endCmpSegment) {
while (true) { while (true) {
// Find the last segment of the current transfer // Find the last segment of the current transfer
@ -750,11 +764,11 @@ void spiSequence(const extDevice_t *dev, busSegment_t *segments)
endCmpSegment = (busSegment_t *)endCmpSegment->u.link.segments; endCmpSegment = (busSegment_t *)endCmpSegment->u.link.segments;
} }
} }
}
// Record the dev and segments parameters in the terminating segment entry // Record the dev and segments parameters in the terminating segment entry
endCmpSegment->u.link.dev = dev; endCmpSegment->u.link.dev = dev;
endCmpSegment->u.link.segments = segments; endCmpSegment->u.link.segments = segments;
}
return; return;
} else { } else {

View file

@ -398,13 +398,11 @@ void spiInternalStartDMA(const extDevice_t *dev)
LL_DMA_Init(dmaTx->dma, dmaTx->stream, bus->initTx); LL_DMA_Init(dmaTx->dma, dmaTx->stream, bus->initTx);
LL_DMA_Init(dmaRx->dma, dmaRx->stream, bus->initRx); LL_DMA_Init(dmaRx->dma, dmaRx->stream, bus->initRx);
LL_SPI_EnableDMAReq_RX(dev->bus->busType_u.spi.instance);
// Enable channels // Enable channels
LL_DMA_EnableChannel(dmaTx->dma, dmaTx->stream); LL_DMA_EnableChannel(dmaTx->dma, dmaTx->stream);
LL_DMA_EnableChannel(dmaRx->dma, dmaRx->stream); LL_DMA_EnableChannel(dmaRx->dma, dmaRx->stream);
LL_SPI_EnableDMAReq_TX(dev->bus->busType_u.spi.instance); SET_BIT(dev->bus->busType_u.spi.instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
#else #else
DMA_Stream_TypeDef *streamRegsTx = (DMA_Stream_TypeDef *)dmaTx->ref; DMA_Stream_TypeDef *streamRegsTx = (DMA_Stream_TypeDef *)dmaTx->ref;
DMA_Stream_TypeDef *streamRegsRx = (DMA_Stream_TypeDef *)dmaRx->ref; DMA_Stream_TypeDef *streamRegsRx = (DMA_Stream_TypeDef *)dmaRx->ref;

View file

@ -194,6 +194,7 @@ extDevice_t *dev = &max7456Device;
static bool max7456DeviceDetected = false; static bool max7456DeviceDetected = false;
static uint16_t max7456SpiClockDiv; static uint16_t max7456SpiClockDiv;
static volatile bool max7456ActiveDma = false;
uint16_t maxScreenSize = VIDEO_BUFFER_CHARS_PAL; uint16_t maxScreenSize = VIDEO_BUFFER_CHARS_PAL;
@ -540,7 +541,7 @@ bool max7456LayerCopy(displayPortLayer_e destLayer, displayPortLayer_e sourceLay
bool max7456DmaInProgress(void) bool max7456DmaInProgress(void)
{ {
return spiIsBusy(dev); return max7456ActiveDma;
} }
bool max7456BuffersSynced(void) bool max7456BuffersSynced(void)
@ -611,13 +612,23 @@ bool max7456ReInitIfRequired(bool forceStallCheck)
return stalled; return stalled;
} }
// Called in ISR context
busStatus_e max7456_callbackReady(uint32_t arg)
{
UNUSED(arg);
max7456ActiveDma = false;
return BUS_READY;
}
// Return true if screen still being transferred // Return true if screen still being transferred
bool max7456DrawScreen(void) bool max7456DrawScreen(void)
{ {
static uint16_t pos = 0; static uint16_t pos = 0;
// This routine doesn't block so need to use static data // This routine doesn't block so need to use static data
static busSegment_t segments[] = { static busSegment_t segments[] = {
{.u.link = {NULL, NULL}, 0, true, NULL}, {.u.link = {NULL, NULL}, 0, true, max7456_callbackReady},
{.u.link = {NULL, NULL}, 0, true, NULL}, {.u.link = {NULL, NULL}, 0, true, NULL},
}; };
@ -706,6 +717,8 @@ bool max7456DrawScreen(void)
segments[0].u.buffers.txData = spiBuf; segments[0].u.buffers.txData = spiBuf;
segments[0].len = spiBufIndex; segments[0].len = spiBufIndex;
max7456ActiveDma = true;
spiSequence(dev, &segments[0]); spiSequence(dev, &segments[0]);
// Non-blocking, so transfer still in progress if using DMA // Non-blocking, so transfer still in progress if using DMA