From 2f5e8e72ee68afc7783bc4681e77a0f9cdcade7c Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Sat, 10 Feb 2018 21:23:03 -0500 Subject: [PATCH] Working checking, needs performance enhancement --- src/AudioEffectAnalogDelay.cpp | 13 ++- src/BASpiMemory.cpp | 153 ++++++++++++++++++--------------- src/BASpiMemory.h | 21 +++-- src/LibBasicFunctions.cpp | 5 -- src/LibBasicFunctions.h | 3 +- src/LibMemoryManagement.cpp | 39 +++++---- src/LibMemoryManagement.h | 10 ++- 7 files changed, 135 insertions(+), 109 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index 9be70e5..8782923 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -123,7 +123,7 @@ void AudioEffectAnalogDelay::update(void) // consider doing the BBD post processing here to use up more time while waiting // for the read data to come back audio_block_t *blockToRelease = m_memory->addBlock(preProcessed); - if (blockToRelease) release(blockToRelease); + // BACK TO OUTPUT PROCESSING // audio_block_t *blockToOutput = nullptr; @@ -134,10 +134,11 @@ void AudioEffectAnalogDelay::update(void) // // copy over data // m_memory->getSamples(blockToOutput, m_delaySamples); - // Check if external DMA, if so, we need to copy out of the DMA buffer + // Check if external DMA, if so, we need to be sure the read is completed if (m_externalMemory && m_memory->getSlot()->isUseDma()) { // Using DMA - m_memory->readDmaBufferContents(blockToOutput); + unsigned loopCount = 0; + while (m_memory->getSlot()->isReadBusy()) { /*Serial.println(String("RB:") + loopCount); loopCount++; */} } // perform the wet/dry mix mix @@ -147,6 +148,12 @@ void AudioEffectAnalogDelay::update(void) release(inputAudioBlock); release(m_previousBlock); m_previousBlock = blockToOutput; + if (m_externalMemory && m_memory->getSlot()->isUseDma()) { + // Using DMA + unsigned loopCount = 0; + while (m_memory->getSlot()->isWriteBusy()) { /*Serial.println(String("WB:") + loopCount); loopCount++; */} + } + if (blockToRelease) release(blockToRelease); } void AudioEffectAnalogDelay::delay(float milliseconds) diff --git a/src/BASpiMemory.cpp b/src/BASpiMemory.cpp index e970940..b091f73 100644 --- a/src/BASpiMemory.cpp +++ b/src/BASpiMemory.cpp @@ -45,6 +45,8 @@ constexpr int SPI_ADDR_1_MASK = 0x00FF00; constexpr int SPI_ADDR_1_SHIFT = 8; constexpr int SPI_ADDR_0_MASK = 0x0000FF; +constexpr int CMD_ADDRESS_SIZE = 4; +constexpr int MAX_DMA_XFER_SIZE = 0x4000; BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId) { @@ -262,8 +264,8 @@ void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords) ///////////////////////////////////////////////////////////////////////////// // BASpiMemoryDMA ///////////////////////////////////////////////////////////////////////////// -BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, size_t bufferSizeBytes) -: BASpiMemory(memDeviceId), m_bufferSize(bufferSizeBytes) +BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId) +: BASpiMemory(memDeviceId) { int cs; switch (memDeviceId) { @@ -277,15 +279,15 @@ BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, size_t bufferSizeBytes) cs = SPI_CS_MEM0; } m_cs = new ActiveLowChipSelect(cs, m_settings); - // add 4 bytes to buffer for SPI CMD and 3 bytes of addresse - m_txBuffer = new uint8_t[bufferSizeBytes+4]; - m_rxBuffer = new uint8_t[bufferSizeBytes+4]; - m_txTransfer = new DmaSpi::Transfer(); - m_rxTransfer = new DmaSpi::Transfer(); + // add 4 bytes to buffer for SPI CMD and 3 bytes of address + m_txCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; + m_rxCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; + m_txTransfer = new DmaSpi::Transfer[2]; + m_rxTransfer = new DmaSpi::Transfer[2]; } -BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz, size_t bufferSizeBytes) -: BASpiMemory(memDeviceId, speedHz), m_bufferSize(bufferSizeBytes) +BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz) +: BASpiMemory(memDeviceId, speedHz) { int cs; switch (memDeviceId) { @@ -299,19 +301,19 @@ BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz, size_t cs = SPI_CS_MEM0; } m_cs = new ActiveLowChipSelect(cs, m_settings); - m_txBuffer = new uint8_t[bufferSizeBytes+4]; - m_rxBuffer = new uint8_t[bufferSizeBytes+4]; - m_txTransfer = new DmaSpi::Transfer(); - m_rxTransfer = new DmaSpi::Transfer(); + m_txCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; + m_rxCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; + m_txTransfer = new DmaSpi::Transfer[2]; + m_rxTransfer = new DmaSpi::Transfer[2]; } BASpiMemoryDMA::~BASpiMemoryDMA() { delete m_cs; - if (m_txBuffer) delete [] m_txBuffer; - if (m_rxBuffer) delete [] m_rxBuffer; - if (m_txTransfer) delete m_txTransfer; - if (m_rxTransfer) delete m_rxTransfer; + if (m_txTransfer) delete [] m_txTransfer; + if (m_rxTransfer) delete [] m_rxTransfer; + if (m_txCommandBuffer) delete [] m_txCommandBuffer; + if (m_rxCommandBuffer) delete [] m_txCommandBuffer; } void BASpiMemoryDMA::m_setSpiCmdAddr(int command, size_t address, uint8_t *dest) @@ -358,91 +360,102 @@ void BASpiMemoryDMA::begin(void) m_started = true; } + + // SPI must build up a payload that starts the teh CMD/Address first. It will cycle // through the payloads in a circular buffer and use the transfer objects to check if they // are done before continuing. void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes) { - while ( m_txTransfer->busy()) {} // wait until not busy - uint16_t transferCount = numBytes + 4; // transfer must be increased by the SPI command and address - m_setSpiCmdAddr(SPI_WRITE_CMD, address, m_txBuffer); - memcpy(m_txBuffer+4, src, numBytes); - *m_txTransfer = DmaSpi::Transfer(m_txBuffer, transferCount, nullptr, 0, m_cs); - m_spiDma->registerTransfer(*m_txTransfer); + size_t bytesRemaining = numBytes; + uint8_t *srcPtr = src; + size_t nextAddress = address; + while (bytesRemaining > 0) { + m_txXferCount = min(bytesRemaining, MAX_DMA_XFER_SIZE); + while ( m_txTransfer[1].busy()) {Serial.println("W1");} // wait until not busy + m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); + m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); + m_spiDma->registerTransfer(m_txTransfer[1]); + + while ( m_txTransfer[0].busy()) { Serial.println("W2");} // wait until not busy + m_txTransfer[0] = DmaSpi::Transfer(srcPtr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); + m_spiDma->registerTransfer(m_txTransfer[0]); + bytesRemaining -= m_txXferCount; + srcPtr += m_txXferCount; + nextAddress += m_txXferCount; + } } + void BASpiMemoryDMA::zero(size_t address, size_t numBytes) { - while ( m_txTransfer->busy()) {} - uint16_t transferCount = numBytes + 4; - m_setSpiCmdAddr(SPI_WRITE_CMD, address, m_txBuffer); - memset(m_txBuffer+4, 0, numBytes); - *m_txTransfer = DmaSpi::Transfer(m_txBuffer, transferCount, nullptr, 0, m_cs); - m_spiDma->registerTransfer(*m_txTransfer); + size_t bytesRemaining = numBytes; + size_t nextAddress = address; + while (bytesRemaining > 0) { + m_txXferCount = min(bytesRemaining, MAX_DMA_XFER_SIZE); + while ( m_txTransfer[1].busy()) {} // wait until not busy + m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); + m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); + m_spiDma->registerTransfer(m_txTransfer[1]); + + while ( m_txTransfer[0].busy()) {} // wait until not busy + m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); + m_spiDma->registerTransfer(m_txTransfer[0]); + bytesRemaining -= m_txXferCount; + nextAddress += m_txXferCount; + } } + void BASpiMemoryDMA::write16(size_t address, uint16_t *src, size_t numWords) { - while ( m_txTransfer->busy()) {} - size_t numBytes = sizeof(uint16_t)*numWords; - uint16_t transferCount = numBytes + 4; - m_setSpiCmdAddr(SPI_WRITE_CMD, address, m_txBuffer); - memcpy(m_txBuffer+4, src, numBytes); - *m_txTransfer = DmaSpi::Transfer(m_txBuffer, transferCount, nullptr, 0, m_cs); - m_spiDma->registerTransfer(*m_txTransfer); + write(address, reinterpret_cast(src), sizeof(uint16_t)*numWords); } void BASpiMemoryDMA::zero16(size_t address, size_t numWords) { - while ( m_txTransfer->busy()) {} - size_t numBytes = sizeof(uint16_t)*numWords; - uint16_t transferCount = numBytes + 4; - m_setSpiCmdAddr(SPI_WRITE_CMD, address, m_txBuffer); - memset(m_txBuffer+4, 0, numBytes); - *m_txTransfer = DmaSpi::Transfer(m_txBuffer, transferCount, nullptr, 0, m_cs); - m_spiDma->registerTransfer(*m_txTransfer); + zero(address, sizeof(uint16_t)*numWords); } + void BASpiMemoryDMA::read(size_t address, uint8_t *dest, size_t numBytes) { - UNUSED(dest); - while ( m_rxTransfer->busy()) {} - uint16_t transferCount = numBytes + 4; - m_setSpiCmdAddr(SPI_READ_CMD, address, m_rxBuffer); - *m_rxTransfer = DmaSpi::Transfer(m_rxBuffer, transferCount, m_rxBuffer, 0, m_cs); - m_spiDma->registerTransfer(*m_rxTransfer); + size_t bytesRemaining = numBytes; + uint8_t *destPtr = dest; + size_t nextAddress = address; + while (bytesRemaining > 0) { + m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer); + + while ( m_rxTransfer[1].busy()) { Serial.println("R1"); } + m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); + m_spiDma->registerTransfer(m_rxTransfer[1]); + + m_rxXferCount = min(bytesRemaining, MAX_DMA_XFER_SIZE); + while ( m_rxTransfer[0].busy()) {Serial.println("R2");} + m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS); + m_spiDma->registerTransfer(m_rxTransfer[0]); + + bytesRemaining -= m_rxXferCount; + destPtr += m_rxXferCount; + nextAddress += m_rxXferCount; + } } -void BASpiMemoryDMA::read16(size_t address, uint16_t *dest, size_t numWords) -{ - UNUSED(dest); - while ( m_rxTransfer->busy()) {} - m_setSpiCmdAddr(SPI_READ_CMD, address, m_rxBuffer); - size_t numBytes = sizeof(uint16_t)*numWords; - uint16_t transferCount = numBytes + 4; - *m_rxTransfer = DmaSpi::Transfer(m_rxBuffer, transferCount, m_rxBuffer, 0, m_cs); - m_spiDma->registerTransfer(*m_rxTransfer); -} -bool BASpiMemoryDMA::isWriteBusy(void) +void BASpiMemoryDMA::read16(size_t address, uint16_t *dest, size_t numWords) { - return m_txTransfer->busy(); + read(address, reinterpret_cast(dest), sizeof(uint16_t)*numWords); } -bool BASpiMemoryDMA::isReadBusy(void) -{ - return m_rxTransfer->busy(); -} -void BASpiMemoryDMA::readBufferContents(uint16_t *dest, size_t numWords, size_t wordOffset) +bool BASpiMemoryDMA::isWriteBusy(void) const { - readBufferContents(reinterpret_cast(dest), sizeof(uint16_t)*numWords, sizeof(uint16_t)*wordOffset); + return (m_txTransfer[0].busy() or m_txTransfer[1].busy()); } -void BASpiMemoryDMA::readBufferContents(uint8_t *dest, size_t numBytes, size_t byteOffset) +bool BASpiMemoryDMA::isReadBusy(void) const { - while (m_rxTransfer->busy()) {} // ensure transfer is complete - memcpy(dest, m_rxBuffer+4+byteOffset, numBytes); + return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy()); } } /* namespace BAGuitar */ diff --git a/src/BASpiMemory.h b/src/BASpiMemory.h index 5fb58f8..e31c7e9 100644 --- a/src/BASpiMemory.h +++ b/src/BASpiMemory.h @@ -128,14 +128,12 @@ public: /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2). /// @details default is 20 Mhz /// @param memDeviceId specify which MEM to control with SpiDeviceId. - /// @param bufferSize size of buffer to store DMA transfers - BASpiMemoryDMA(SpiDeviceId memDeviceId, size_t bufferSizeBytes); + BASpiMemoryDMA(SpiDeviceId memDeviceId); /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2) /// @param memDeviceId specify which MEM to control with SpiDeviceId. /// @param speedHz specify the desired speed in Hz. - /// @param bufferSize size of buffer to store DMA transfers - BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz, size_t bufferSizeBytes); + BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz); virtual ~BASpiMemoryDMA(); /// initialize and configure the SPI peripheral @@ -177,11 +175,11 @@ public: /// Check if a DMA write is in progress /// @returns true if a write DMA is in progress, else false - bool isWriteBusy(); + bool isWriteBusy() const; /// Check if a DMA read is in progress /// @returns true if a read DMA is in progress, else false - bool isReadBusy(); + bool isReadBusy() const; /// Readout the 8-bit contents of the DMA storage buffer to the specified destination /// @param dest pointer to the destination @@ -198,12 +196,17 @@ public: private: AbstractDmaSpi *m_spiDma = nullptr; ActiveLowChipSelect *m_cs = nullptr; - size_t m_bufferSize; - uint8_t *m_txBuffer = nullptr; + //size_t m_bufferSize; + //uint8_t *m_txBuffer = nullptr; + uint8_t *m_txCommandBuffer = nullptr; DmaSpi::Transfer *m_txTransfer; - uint8_t *m_rxBuffer = nullptr; + //uint8_t *m_rxBuffer = nullptr; + uint8_t *m_rxCommandBuffer = nullptr; DmaSpi::Transfer *m_rxTransfer; + uint16_t m_txXferCount; + uint16_t m_rxXferCount; + void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest); }; diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index 23159cc..74ec2c3 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -234,11 +234,6 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample } -void AudioDelay::readDmaBufferContents(audio_block_t *dest, size_t numSamples, size_t bufferOffset) -{ - m_slot->readDmaBufferContents(reinterpret_cast(dest->data), sizeof(int16_t)*numSamples, sizeof(int16_t)*bufferOffset); -} - //////////////////////////////////////////////////// // IirBiQuadFilter //////////////////////////////////////////////////// diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index 2f88c2f..32872cc 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -93,6 +93,7 @@ class RingBuffer; // forward declare so AudioDelay can use it. * approach. When using EXTERNAL memory, data is actually copyied to/from an external * SRAM device. *****************************************************************************/ +constexpr size_t AUDIO_BLOCK_SIZE = sizeof(int16_t)*AUDIO_BLOCK_SAMPLES; class AudioDelay { public: AudioDelay() = delete; @@ -140,8 +141,6 @@ public: /// @returns pointer to the underlying ExtMemSlot. ExtMemSlot *getSlot() const { return m_slot; } - void readDmaBufferContents(audio_block_t *dest, size_t numSamples = AUDIO_BLOCK_SAMPLES, size_t bufferOffset = 0); - RingBuffer *getRingBuffer() const { return m_ringBuffer; } private: diff --git a/src/LibMemoryManagement.cpp b/src/LibMemoryManagement.cpp index 529844b..07c8c02 100644 --- a/src/LibMemoryManagement.cpp +++ b/src/LibMemoryManagement.cpp @@ -175,16 +175,6 @@ bool ExtMemSlot::zeroAdvance16(size_t numWords) return true; } -void ExtMemSlot::readDmaBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset) -{ - if (m_useDma) { - (static_cast(m_spi))->readBufferContents(dest, numBytes, bufferOffset); -// BASpiMemoryDMA *spi = nullptr; -// spi = static_cast(m_spi); -// spi->readBufferContents(dest, numBytes, bufferOffset); - } -} - bool ExtMemSlot::writeAdvance16(int16_t data) { @@ -219,6 +209,21 @@ bool ExtMemSlot::isEnabled() const else return false; } +bool ExtMemSlot::isWriteBusy() const +{ + if (m_useDma) { + return (static_cast(m_spi))->isWriteBusy(); + } else { return false; } +} + +bool ExtMemSlot::isReadBusy() const +{ + if (m_useDma) { + return (static_cast(m_spi))->isReadBusy(); + } else { return false; } +} + + void ExtMemSlot::printStatus(void) const { Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \ @@ -261,14 +266,14 @@ size_t ExternalSramManager::availableMemory(BAGuitar::MemSelect mem) return m_memConfig[mem].totalAvailable; } -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem, size_t dmaBufferSize) +bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem, bool useDma) { // convert the time to numer of samples size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); - return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, dmaBufferSize); + return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma); } -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem, size_t dmaBufferSize) +bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem, bool useDma) { if (m_memConfig[mem].totalAvailable >= sizeBytes) { @@ -281,16 +286,16 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGu slot->m_size = sizeBytes; if (!m_memConfig[mem].m_spi) { - if (dmaBufferSize > 0) { - m_memConfig[mem].m_spi = new BAGuitar::BASpiMemoryDMA(static_cast(mem), dmaBufferSize); + if (useDma) { + m_memConfig[mem].m_spi = new BAGuitar::BASpiMemoryDMA(static_cast(mem)); slot->m_useDma = true; } else { m_memConfig[mem].m_spi = new BAGuitar::BASpiMemory(static_cast(mem)); slot->m_useDma = false; } if (!m_memConfig[mem].m_spi) { - Serial.println("requestMemory: new failed! m_spi is a nullptr"); } else { + Serial.println("Calling spi begin()"); m_memConfig[mem].m_spi->begin(); } } @@ -301,7 +306,9 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGu m_memConfig[mem].totalAvailable -= sizeBytes; slot->m_valid = true; if (!slot->isEnabled()) { slot->enable(); } + Serial.println("Clear the memory\n"); Serial.flush(); slot->clear(); + Serial.println("Done Request memory\n"); Serial.flush(); return true; } else { // there is not enough memory available for the request diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index fe9948c..8ce5074 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -128,8 +128,6 @@ public: /// @returns true on success, else false on error bool zeroAdvance16(size_t numWords); - void readDmaBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset = 0); - /// Get the size of the memory slot /// @returns size of the slot in bytes size_t size() const { return m_size; } @@ -144,6 +142,10 @@ public: bool isUseDma() const { return m_useDma; } + bool isWriteBusy() const; + + bool isReadBusy() const; + /// DEBUG USE: prints out the slot member variables void printStatus(void) const; @@ -188,7 +190,7 @@ public: /// @param mem specify which external memory to allocate from /// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, size_t dmaBufferSize = 0); + bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false); /// Request memory be allocated for the provided slot /// @param slot a pointer to the global slot object to which memory will be allocated @@ -196,7 +198,7 @@ public: /// @param mem specify which external memory to allocate from /// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, size_t dmaBufferSize = 0); + bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false); private: static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project