From 19baaa34bea7c8b6ac9b6c31e0940a581f7c891f Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Fri, 9 Feb 2018 16:13:03 -0500 Subject: [PATCH] More code development --- src/AudioEffectAnalogDelay.cpp | 34 ++++++++++++++++++++++++----- src/BASpiMemory.cpp | 13 ++++++----- src/BASpiMemory.h | 6 ++--- src/LibBasicFunctions.cpp | 32 ++++++++++++++++++--------- src/LibBasicFunctions.h | 4 +++- src/LibMemoryManagement.cpp | 40 ++++++++++++++++++++++++++++++---- src/LibMemoryManagement.h | 16 ++++++++++++-- 7 files changed, 113 insertions(+), 32 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index d074afc..df493f8 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -102,22 +102,44 @@ void AudioEffectAnalogDelay::update(void) } // Otherwise perform normal processing + // In order to make use of the SPI DMA, we need to request the read from memory first, + // then do other processing while it fills in the back. + audio_block_t *blockToOutput = nullptr; // this will hold the output audio + blockToOutput = allocate(); + if (!blockToOutput) return; // skip this update cycle due to failure + + // get the data. If using external memory with DMA, this won't be filled until + // later. + m_memory->getSamples(blockToOutput, m_delaySamples); + + // If using DMA, we need something else to do while that read executes, so + // move on to input preprocessing + // Preprocessing audio_block_t *preProcessed = allocate(); // mix the input with the feedback path in the pre-processing stage m_preProcessing(preProcessed, inputAudioBlock, m_previousBlock); + // 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); - // OUTPUT PROCESSING - audio_block_t *blockToOutput = nullptr; - blockToOutput = allocate(); + // BACK TO OUTPUT PROCESSING +// audio_block_t *blockToOutput = nullptr; +// blockToOutput = allocate(); // copy the output data - if (!blockToOutput) return; // skip this time due to failure - // copy over data - m_memory->getSamples(blockToOutput, m_delaySamples); +// if (!blockToOutput) return; // skip this time due to failure +// // copy over data +// m_memory->getSamples(blockToOutput, m_delaySamples); + + // Check if external DMA, if so, we need to copy out of the DMA buffer + if (m_externalMemory && m_memory->getSlot()->isUseDma()) { + // Using DMA + m_memory->readDmaBufferContents(blockToOutput); + } + // perform the wet/dry mix mix m_postProcessing(blockToOutput, inputAudioBlock, blockToOutput); transmit(blockToOutput); diff --git a/src/BASpiMemory.cpp b/src/BASpiMemory.cpp index 5f7a2fa..c130e49 100644 --- a/src/BASpiMemory.cpp +++ b/src/BASpiMemory.cpp @@ -355,8 +355,8 @@ void BASpiMemoryDMA::begin(void) // are done before continuing. void BASpiMemoryDMA::write(size_t address, uint8_t *data, size_t numBytes) { - while ( m_txTransfer->busy()) {} - uint16_t transferCount = numBytes + 4; + 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, data, numBytes); *m_txTransfer = DmaSpi::Transfer(m_txBuffer, transferCount, nullptr, 0, m_cs); @@ -394,8 +394,9 @@ void BASpiMemoryDMA::zero16(size_t address, size_t numWords) m_spiDma->registerTransfer(*m_txTransfer); } -void BASpiMemoryDMA::read(size_t address, uint8_t *data, size_t numBytes) +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); @@ -405,6 +406,7 @@ void BASpiMemoryDMA::read(size_t address, uint8_t *data, size_t numBytes) 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; @@ -413,9 +415,10 @@ void BASpiMemoryDMA::read16(size_t address, uint16_t *dest, size_t numWords) m_spiDma->registerTransfer(*m_rxTransfer); } -void BASpiMemoryDMA::readBufferContents(size_t bufferOffset, uint8_t *dest, size_t numBytes) +void BASpiMemoryDMA::readBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset) { - memcpy(dest, m_rxBuffer+4, numBytes); + while (m_rxTransfer->busy()) {} // ensure transfer is complete + memcpy(dest, m_rxBuffer+4+bufferOffset, numBytes); } } /* namespace BAGuitar */ diff --git a/src/BASpiMemory.h b/src/BASpiMemory.h index c0a6149..ed9c375 100644 --- a/src/BASpiMemory.h +++ b/src/BASpiMemory.h @@ -115,7 +115,7 @@ class BASpiMemoryDMA : public BASpiMemory { /// read a single 8-bit data word from the specified address /// @param address the address in the SPI RAM to read from /// @return the data that was read - void read(size_t address, uint8_t *data, size_t numBytes) override; + void read(size_t address, uint8_t *dest, size_t numBytes) override; /// read a block 16-bit data word from the specified address /// @param address the address in the SPI RAM to read from @@ -125,7 +125,7 @@ class BASpiMemoryDMA : public BASpiMemory { void begin() override; - void readBufferContents(size_t bufferOffset, uint8_t *dest, size_t numBytes); + void readBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset = 0); private: AbstractDmaSpi *m_spiDma = nullptr; @@ -137,8 +137,6 @@ private: DmaSpi::Transfer *m_rxTransfer; void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest); -// RingBuffer m_txFifo(MAX_DMA_XFERS); -// RingBuffer m_rxFifo(MAX_DMA_XFERS); }; diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index 305ff20..19c581a 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -119,11 +119,14 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block) // srcPtr--; // } - int16_t *srcPtr = block->data; - for (int i=0; iwriteAdvance16(*srcPtr); - srcPtr++; - } + m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); + + // Code below worked +// int16_t *srcPtr = block->data; +// for (int i=0; iwriteAdvance16(*srcPtr); +// srcPtr++; +// } } blockToRelease = block; @@ -210,11 +213,15 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample // destPtr--; // } - int16_t *destPtr = dest->data; - for (int i=0; ireadAdvance16(); - destPtr++; - } + m_slot->readAdvance16(AUDIO_BLOCK_SAMPLES); + +// // Code below worked +// int16_t *destPtr = dest->data; +// for (int i=0; ireadAdvance16(); +// destPtr++; +// } + return true; } else { // numSampmles is > than total slot size @@ -225,6 +232,11 @@ 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 757ce4d..63b5a23 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -109,7 +109,7 @@ public: /// Construct an audio buffer using a slot configured with the BAGuitar::ExternalSramManager /// @param slot a pointer to the slot representing the memory you wish to use for the buffer. - AudioDelay(ExtMemSlot *slot); + AudioDelay(ExtMemSlot *slot, bool useDma=true); ~AudioDelay(); @@ -140,6 +140,8 @@ 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 9927121..592bfc9 100644 --- a/src/LibMemoryManagement.cpp +++ b/src/LibMemoryManagement.cpp @@ -108,6 +108,28 @@ uint16_t ExtMemSlot::readAdvance16() return val; } +bool ExtMemSlot::readAdvance16(int16_t *dest=nullptr, size_t numWords) +{ + if (!m_valid) { return false; } + size_t numBytes = sizeof(int16_t)*numWords; + + if (m_currentRdPosition + numBytes-1 <= m_end) { + // entire block fits in memory slot without wrapping + m_spi->read16(m_currentWrPosition, reinterpret_cast(dest), numWords); // cast audio data to uint. + m_currentRdPosition += numBytes; + + } else { + // this read will wrap the memory slot + size_t rdBytes = m_end - m_currentRdPosition + 1; + size_t rdDataNum = rdBytes >> 1; // divide by two to get the number of data + m_spi->read16(m_currentRdPosition, reinterpret_cast(dest), rdDataNum); + size_t remainingData = numWords - rdDataNum; + m_spi->read16(m_start, reinterpret_cast(dest + rdDataNum), remainingData); // write remaining bytes are start + m_currentRdPosition = m_start + (remainingData*sizeof(int16_t)); + } + return true; +} + bool ExtMemSlot::writeAdvance16(int16_t *src, size_t numWords) { @@ -153,6 +175,11 @@ bool ExtMemSlot::zeroAdvance16(size_t numWords) return true; } +void ExtMemSlot::readDmaBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset = 0) +{ + m_spi->readBufferContents(dest, numBytes, bufferOffset); +} + bool ExtMemSlot::writeAdvance16(int16_t data) { @@ -229,14 +256,14 @@ size_t ExternalSramManager::availableMemory(BAGuitar::MemSelect mem) return m_memConfig[mem].totalAvailable; } -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem) +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); + return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma); } -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem) +bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem, bool useDma) { if (m_memConfig[mem].totalAvailable >= sizeBytes) { @@ -249,7 +276,11 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGu slot->m_size = sizeBytes; if (!m_memConfig[mem].m_spi) { - m_memConfig[mem].m_spi = new BAGuitar::BASpiMemory(static_cast(mem)); + if (useDma) { + m_memConfig[mem].m_spi = new BAGuitar::BASpiMemoryDma(static_cast(mem)); + } else { + m_memConfig[mem].m_spi = new BAGuitar::BASpiMemory(static_cast(mem)); + } if (!m_memConfig[mem].m_spi) { Serial.println("requestMemory: new failed! m_spi is a nullptr"); } else { @@ -264,6 +295,7 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGu slot->m_valid = true; if (!slot->isEnabled()) { slot->enable(); } slot->clear(); + slot->m_useDma = useDma; return true; } else { // there is not enough memory available for the request diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index e4e44c8..18b507e 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -104,6 +104,14 @@ public: /// @returns the next 16-bit data word in memory uint16_t readAdvance16(); + + /// Read the next block of numWords during circular operation + /// @details, dest is ignored when using DMA + /// @param dest pointer to the destination of the read. + /// @param numWords number of 16-bit words to transfer + /// @returns true on success, else false on error + bool readAdvance16(int16_t *dest=nullptr, size_t numWords); + /// Write a block of 16-bit data from the specified location in circular operation /// @param src pointer to the start of the block of data to write to memory /// @param numWords number of 16-bit words to transfer @@ -120,6 +128,7 @@ 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 @@ -133,6 +142,8 @@ public: /// @returns true if enabled, false if not enabled bool isEnabled() const; + bool isUseDma() const { return m_useDma; } + /// DEBUG USE: prints out the slot member variables void printStatus(void) const; @@ -144,6 +155,7 @@ private: size_t m_currentWrPosition = 0; ///< current write pointer for circular operation size_t m_currentRdPosition = 0; ///< current read pointer for circular operation size_t m_size = 0; ///< size of this slot in bytes + bool m_useDma = false; ///< when TRUE, BASpiMemoryDMA will be used. SpiDeviceId m_spiId; ///< the SPI Device ID BASpiMemory *m_spi = nullptr; ///< pointer to an instance of the BASpiMemory interface class }; @@ -175,14 +187,14 @@ public: /// @param delayMilliseconds request the amount of memory based on required time for audio samples, rather than number of bytes. /// @param mem specify which external memory to allocate from /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = true); /// Request memory be allocated for the provided slot /// @param slot a pointer to the global slot object to which memory will be allocated /// @param sizeBytes request the amount of memory in bytes to request /// @param mem specify which external memory to allocate from /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = true); private: static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project