mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-26 01:35:41 +03:00
Support dual gyros sharing a common SPI bus
This commit is contained in:
parent
a1c6cda572
commit
7ef7795944
10 changed files with 114 additions and 45 deletions
|
@ -137,7 +137,7 @@ bool spiInit(SPIDevice device)
|
|||
// Return true if DMA engine is busy
|
||||
bool spiIsBusy(const extDevice_t *dev)
|
||||
{
|
||||
return (dev->bus->curSegment != (busSegment_t *)NULL);
|
||||
return (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE);
|
||||
}
|
||||
|
||||
// Indicate that the bus on which this device resides may initiate DMA transfers from interrupt context
|
||||
|
@ -156,15 +156,15 @@ void spiWaitClaim(const extDevice_t *dev)
|
|||
if (dev->bus->useAtomicWait) {
|
||||
// Prevent race condition where the bus appears free, but a gyro interrupt starts a transfer
|
||||
do {
|
||||
ATOMIC_BLOCK(NVIC_PRIO_MPU_INT_EXTI) {
|
||||
if (dev->bus->curSegment == (busSegment_t *)NULL) {
|
||||
dev->bus->curSegment = (busSegment_t *)0x04;
|
||||
ATOMIC_BLOCK(NVIC_PRIO_MAX) {
|
||||
if (dev->bus->curSegment == (busSegment_t *)BUS_SPI_FREE) {
|
||||
dev->bus->curSegment = (busSegment_t *)BUS_SPI_LOCKED;
|
||||
}
|
||||
}
|
||||
} while (dev->bus->curSegment != (busSegment_t *)0x04);
|
||||
} while (dev->bus->curSegment != (busSegment_t *)BUS_SPI_LOCKED);
|
||||
} else {
|
||||
// Wait for completion
|
||||
while (dev->bus->curSegment != (busSegment_t *)NULL);
|
||||
while (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ void spiWaitClaim(const extDevice_t *dev)
|
|||
void spiWait(const extDevice_t *dev)
|
||||
{
|
||||
// Wait for completion
|
||||
while (dev->bus->curSegment != (busSegment_t *)NULL);
|
||||
while (dev->bus->curSegment != (busSegment_t *)BUS_SPI_FREE);
|
||||
}
|
||||
|
||||
// Wait for bus to become free, then read/write block of data
|
||||
|
@ -407,6 +407,7 @@ static void spiRxIrqHandler(dmaChannelDescriptor_t* descriptor)
|
|||
}
|
||||
|
||||
busDevice_t *bus = dev->bus;
|
||||
busSegment_t *nextSegment;
|
||||
|
||||
if (bus->curSegment->negateCS) {
|
||||
// Negate Chip Select
|
||||
|
@ -451,12 +452,23 @@ static void spiRxIrqHandler(dmaChannelDescriptor_t* descriptor)
|
|||
}
|
||||
|
||||
// Advance through the segment list
|
||||
bus->curSegment++;
|
||||
nextSegment = bus->curSegment + 1;
|
||||
|
||||
if (bus->curSegment->len == 0) {
|
||||
// The end of the segment list has been reached, so mark transactions as complete
|
||||
bus->curSegment = (busSegment_t *)NULL;
|
||||
if (nextSegment->len == 0) {
|
||||
// If a following transaction has been linked, start it
|
||||
if (nextSegment->txData) {
|
||||
const extDevice_t *nextDev = (const extDevice_t *)nextSegment->txData;
|
||||
busSegment_t *nextSegments = (busSegment_t *)nextSegment->rxData;
|
||||
nextSegment->txData = NULL;
|
||||
// The end of the segment list has been reached
|
||||
spiSequenceStart(nextDev, nextSegments);
|
||||
} else {
|
||||
// The end of the segment list has been reached, so mark transactions as complete
|
||||
bus->curSegment = (busSegment_t *)NULL;
|
||||
}
|
||||
} else {
|
||||
bus->curSegment = nextSegment;
|
||||
|
||||
// After the completion of the first segment setup the init structure for the subsequent segment
|
||||
if (bus->initSegment) {
|
||||
spiInternalInitStream(dev, false);
|
||||
|
@ -479,6 +491,7 @@ bool spiSetBusInstance(extDevice_t *dev, uint32_t device)
|
|||
}
|
||||
|
||||
dev->bus = &spiBusDevice[SPI_CFG_TO_DEV(device)];
|
||||
dev->useDMA = true;
|
||||
|
||||
if (dev->bus->busType == BUS_TYPE_SPI) {
|
||||
// This bus has already been initialised
|
||||
|
@ -495,7 +508,6 @@ bool spiSetBusInstance(extDevice_t *dev, uint32_t device)
|
|||
}
|
||||
|
||||
bus->busType = BUS_TYPE_SPI;
|
||||
dev->useDMA = true;
|
||||
bus->useDMA = false;
|
||||
bus->useAtomicWait = false;
|
||||
bus->deviceCount = 1;
|
||||
|
@ -637,4 +649,33 @@ uint8_t spiGetExtDeviceCount(const extDevice_t *dev)
|
|||
{
|
||||
return dev->bus->deviceCount;
|
||||
}
|
||||
|
||||
// DMA transfer setup and start
|
||||
void spiSequence(const extDevice_t *dev, busSegment_t *segments)
|
||||
{
|
||||
busDevice_t *bus = dev->bus;
|
||||
|
||||
ATOMIC_BLOCK(NVIC_PRIO_MAX) {
|
||||
if ((bus->curSegment != (busSegment_t *)BUS_SPI_LOCKED) && spiIsBusy(dev)) {
|
||||
/* Defer this transfer to be triggered upon completion of the current transfer. Blocking calls
|
||||
* and those from non-interrupt context will have already called spiWaitClaim() so this will
|
||||
* only happen for non-blocking calls called from an ISR.
|
||||
*/
|
||||
busSegment_t *endSegment = bus->curSegment;
|
||||
|
||||
if (endSegment) {
|
||||
// Find the last segment of the current transfer
|
||||
for (; endSegment->len; endSegment++);
|
||||
|
||||
// Record the dev and segments parameters in the terminating segment entry
|
||||
endSegment->txData = (uint8_t *)dev;
|
||||
endSegment->rxData = (uint8_t *)segments;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spiSequenceStart(dev, segments);
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue