From 16de4887bef79c965fec5c902b959c753a515d27 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 9 Apr 2024 09:17:05 +0200 Subject: [PATCH 1/6] docs: Update the documentation. Signed-off-by: iabdalkader --- docs/api.md | 86 ++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/docs/api.md b/docs/api.md index 11ef7f4..6b356a5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -20,7 +20,7 @@ AdvancedADC adc(analogPin); `void`. -### `begin()` +### `AdvancedADC.begin()` Initializes and configures the ADC with the specified parameters. To reconfigure the ADC, `stop()` must be called first. @@ -56,7 +56,7 @@ adc0.begin(resolution, sample_rate, n_samples, n_buffers) 1 on success, 0 on failure. -### `available()` +### `AdvancedADC.available()` Checks if the ADC is readable. @@ -74,11 +74,11 @@ None. Returns true, if there's at least one sample buffer in the read queue, otherwise returns false. -### `read()` +### `AdvancedADC.read()` Returns a sample buffer from the queue for reading. -### `start()` +### `AdvancedADC.start()` Starts the ADC sampling. @@ -92,7 +92,7 @@ adc.start() 1 on success, 0 on failure. -### `stop()` +### `AdvancedADC.stop()` Stops the ADC and releases all of its resources. @@ -127,7 +127,7 @@ AdvancedADCDual adc_dual(adc1, adc2); `void`. -### `begin()` +### `AdvancedADCDual.begin()` Initializes and starts the two ADCs with the specified parameters. @@ -162,7 +162,7 @@ adc_dual.begin(resolution, sample_rate, n_samples, n_buffers) 1 on success, 0 on failure. -### `stop()` +### `AdvancedADCDual.stop()` Stops the dual ADCs and releases all resources. @@ -187,7 +187,7 @@ AdvancedDAC dac1(A13); `void`. -### `begin()` +### `AdvancedDAC.begin()` Initializes the DAC with the specified parameters. To reconfigure the DAC, `stop()` must be called first. @@ -211,7 +211,7 @@ dac.begin(resolution, frequency, n_samples, n_buffers) 1 on success, 0 on failure. -### `available()` +### `AdvancedDAC.available()` Checks if the DAC is writable. @@ -229,7 +229,7 @@ None. Returns true, if there's at least one free sample buffer in the write queue, otherwise returns false. -### `dequeue()` +### `AdvancedDAC.dequeue()` Returns a sample buffer from the queue for writing. @@ -245,7 +245,7 @@ for (size_t i=0; i Date: Mon, 29 Apr 2024 14:22:23 +0200 Subject: [PATCH 2/6] misc: Update the library to use the API DMAPool. The DMAPool has been refactored and relocated to the core-api. This patch updates the all code to use the new API, and removes the duplicate DMAPool code. Signed-off-by: iabdalkader --- src/AdvancedADC.cpp | 21 ++-- src/AdvancedADC.h | 10 +- src/AdvancedAnalog.h | 2 +- src/AdvancedDAC.cpp | 14 +-- src/AdvancedDAC.h | 10 +- src/AdvancedI2S.cpp | 35 +++--- src/AdvancedI2S.h | 8 +- src/Arduino_AdvancedAnalog.h | 10 +- src/DMABuffer.h | 237 ----------------------------------- src/HALConfig.cpp | 1 + src/Queue.h | 81 ------------ src/WavReader.cpp | 6 +- src/WavReader.h | 10 +- 13 files changed, 59 insertions(+), 386 deletions(-) delete mode 100644 src/DMABuffer.h delete mode 100644 src/Queue.h diff --git a/src/AdvancedADC.cpp b/src/AdvancedADC.cpp index b3b889e..7c5b26e 100644 --- a/src/AdvancedADC.cpp +++ b/src/AdvancedADC.cpp @@ -30,7 +30,7 @@ struct adc_descr_t { IRQn_Type dma_irqn; TIM_HandleTypeDef tim; uint32_t tim_trig; - DMABufferPool *pool; + DMAPool *pool; DMABuffer *dmabuf[2]; }; @@ -124,7 +124,7 @@ DMABuffer &AdvancedADC::read() { while (!available()) { __WFI(); } - return *descr->pool->dequeue(); + return *descr->pool->alloc(DMA_BUFFER_READ); } return NULLBUF; } @@ -200,14 +200,14 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl } // Allocate DMA buffer pool. - descr->pool = new DMABufferPool(n_samples, n_channels, n_buffers); + descr->pool = new DMAPool(n_samples, n_channels, n_buffers); if (descr->pool == nullptr) { return 0; } // Allocate the two DMA buffers used for double buffering. - descr->dmabuf[0] = descr->pool->allocate(); - descr->dmabuf[1] = descr->pool->allocate(); + descr->dmabuf[0] = descr->pool->alloc(DMA_BUFFER_WRITE); + descr->dmabuf[1] = descr->pool->alloc(DMA_BUFFER_WRITE); // Init and config DMA. if (hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY) < 0) { @@ -325,19 +325,16 @@ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *adc) { if (descr->pool->writable()) { // Make sure any cached data is discarded. descr->dmabuf[ct]->invalidate(); - // Move current DMA buffer to ready queue. - descr->pool->enqueue(descr->dmabuf[ct]); - + descr->dmabuf[ct]->release(); // Allocate a new free buffer. - descr->dmabuf[ct] = descr->pool->allocate(); - + descr->dmabuf[ct] = descr->pool->alloc(DMA_BUFFER_WRITE); // Currently, all multi-channel buffers are interleaved. if (descr->dmabuf[ct]->channels() > 1) { - descr->dmabuf[ct]->setflags(DMA_BUFFER_INTRLVD); + descr->dmabuf[ct]->set_flags(DMA_BUFFER_INTRLVD); } } else { - descr->dmabuf[ct]->setflags(DMA_BUFFER_DISCONT); + descr->dmabuf[ct]->set_flags(DMA_BUFFER_DISCONT); } // Update the next DMA target pointer. diff --git a/src/AdvancedADC.h b/src/AdvancedADC.h index 27a466a..a290d4d 100644 --- a/src/AdvancedADC.h +++ b/src/AdvancedADC.h @@ -17,12 +17,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include "DMABuffer.h" -#include "AdvancedAnalog.h" +#ifndef __ADVANCED_ADC_H__ +#define __ADVANCED_ADC_H__ -#ifndef ARDUINO_ADVANCED_ADC_H_ -#define ARDUINO_ADVANCED_ADC_H_ +#include "AdvancedAnalog.h" struct adc_descr_t; @@ -96,4 +94,4 @@ class AdvancedADCDual { int stop(); }; -#endif /* ARDUINO_ADVANCED_ADC_H_ */ +#endif // __ADVANCED_ADC_H__ diff --git a/src/AdvancedAnalog.h b/src/AdvancedAnalog.h index d2c46d6..0ffcb2c 100644 --- a/src/AdvancedAnalog.h +++ b/src/AdvancedAnalog.h @@ -21,7 +21,7 @@ #define __ADVANCED_ANALOG_H__ #include "Arduino.h" -#include "DMABuffer.h" +#include "api/DMAPool.h" #include "pinDefinitions.h" enum { diff --git a/src/AdvancedDAC.cpp b/src/AdvancedDAC.cpp index 54684dd..bcd5967 100644 --- a/src/AdvancedDAC.cpp +++ b/src/AdvancedDAC.cpp @@ -30,7 +30,7 @@ struct dac_descr_t { uint32_t tim_trig; uint32_t resolution; uint32_t dmaudr_flag; - DMABufferPool *pool; + DMAPool *pool; DMABuffer *dmabuf[2]; }; @@ -114,7 +114,7 @@ DMABuffer &AdvancedDAC::dequeue() { while (!available()) { __WFI(); } - return *descr->pool->allocate(); + return *descr->pool->alloc(DMA_BUFFER_WRITE); } return NULLBUF; } @@ -128,11 +128,11 @@ void AdvancedDAC::write(DMABuffer &dmabuf) { // Make sure any cached data is flushed. dmabuf.flush(); - descr->pool->enqueue(&dmabuf); + dmabuf.release(); if (descr->dmabuf[0] == nullptr && (++buf_count % 3) == 0) { - descr->dmabuf[0] = descr->pool->dequeue(); - descr->dmabuf[1] = descr->pool->dequeue(); + descr->dmabuf[0] = descr->pool->alloc(DMA_BUFFER_READ); + descr->dmabuf[1] = descr->pool->alloc(DMA_BUFFER_READ); // Start DAC DMA. HAL_DAC_Start_DMA(descr->dac, descr->channel, @@ -167,7 +167,7 @@ int AdvancedDAC::begin(uint32_t resolution, uint32_t frequency, size_t n_samples } // Allocate DMA buffer pool. - descr->pool = new DMABufferPool(n_samples, n_channels, n_buffers); + descr->pool = new DMAPool(n_samples, n_channels, n_buffers); if (descr->pool == nullptr) { descr = nullptr; return 0; @@ -226,7 +226,7 @@ void DAC_DMAConvCplt(DMA_HandleTypeDef *dma, uint32_t channel) { // NOTE: CT bit is inverted, to get the DMA buffer that's Not currently in use. size_t ct = ! hal_dma_get_ct(dma); descr->dmabuf[ct]->release(); - descr->dmabuf[ct] = descr->pool->dequeue(); + descr->dmabuf[ct] = descr->pool->alloc(DMA_BUFFER_READ); hal_dma_update_memory(dma, descr->dmabuf[ct]->data()); } else { dac_descr_deinit(descr, false); diff --git a/src/AdvancedDAC.h b/src/AdvancedDAC.h index da199a6..d1084a6 100644 --- a/src/AdvancedDAC.h +++ b/src/AdvancedDAC.h @@ -17,12 +17,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include "DMABuffer.h" -#include "AdvancedAnalog.h" +#ifndef __ADVANCED_DAC_H__ +#define __ADVANCED_DAC_H__ -#ifndef ARDUINO_ADVANCED_DAC_H_ -#define ARDUINO_ADVANCED_DAC_H_ +#include "AdvancedAnalog.h" struct dac_descr_t; @@ -52,4 +50,4 @@ class AdvancedDAC { int frequency(uint32_t const frequency); }; -#endif /* ARDUINO_ADVANCED_DAC_H_ */ +#endif // __ADVANCED_DAC_H__ diff --git a/src/AdvancedI2S.cpp b/src/AdvancedI2S.cpp index b0d0c98..812e035 100644 --- a/src/AdvancedI2S.cpp +++ b/src/AdvancedI2S.cpp @@ -25,11 +25,11 @@ struct i2s_descr_t { I2S_HandleTypeDef i2s; DMA_HandleTypeDef dmatx; IRQn_Type dmatx_irqn; - DMABufferPool *dmatx_pool; + DMAPool *dmatx_pool; DMABuffer *dmatx_buf[2]; DMA_HandleTypeDef dmarx; IRQn_Type dmarx_irqn; - DMABufferPool *dmarx_pool; + DMAPool *dmarx_pool; DMABuffer *dmarx_buf[2]; }; @@ -154,16 +154,16 @@ static int i2s_start_dma_transfer(i2s_descr_t *descr, i2s_mode_t i2s_mode) { if (i2s_mode & AN_I2S_MODE_IN) { // Start I2S DMA. - descr->dmarx_buf[0] = descr->dmarx_pool->allocate(); - descr->dmarx_buf[1] = descr->dmarx_pool->allocate(); + descr->dmarx_buf[0] = descr->dmarx_pool->alloc(DMA_BUFFER_WRITE); + descr->dmarx_buf[1] = descr->dmarx_pool->alloc(DMA_BUFFER_WRITE); rx_buf = (uint16_t *) descr->dmarx_buf[0]->data(); buf_size = descr->dmarx_buf[0]->size(); HAL_NVIC_DisableIRQ(descr->dmarx_irqn); } if (i2s_mode & AN_I2S_MODE_OUT) { - descr->dmatx_buf[0] = descr->dmatx_pool->dequeue(); - descr->dmatx_buf[1] = descr->dmatx_pool->dequeue(); + descr->dmatx_buf[0] = descr->dmatx_pool->alloc(DMA_BUFFER_READ); + descr->dmatx_buf[1] = descr->dmatx_pool->alloc(DMA_BUFFER_READ); tx_buf = (uint16_t *) descr->dmatx_buf[0]->data(); buf_size = descr->dmatx_buf[0]->size(); HAL_NVIC_DisableIRQ(descr->dmatx_irqn); @@ -183,7 +183,7 @@ static int i2s_start_dma_transfer(i2s_descr_t *descr, i2s_mode_t i2s_mode) { return 0; } } - + HAL_I2S_DMAPause(&descr->i2s); // Re/enable DMA double buffer mode. if (i2s_mode & AN_I2S_MODE_IN) { hal_dma_enable_dbm(&descr->dmarx, descr->dmarx_buf[0]->data(), descr->dmarx_buf[1]->data()); @@ -194,6 +194,7 @@ static int i2s_start_dma_transfer(i2s_descr_t *descr, i2s_mode_t i2s_mode) { hal_dma_enable_dbm(&descr->dmatx, descr->dmatx_buf[0]->data(), descr->dmatx_buf[1]->data()); HAL_NVIC_EnableIRQ(descr->dmatx_irqn); } + HAL_I2S_DMAResume(&descr->i2s); return 1; } @@ -216,7 +217,7 @@ DMABuffer &AdvancedI2S::read() { while (!descr->dmarx_pool->readable()) { __WFI(); } - return *descr->dmarx_pool->dequeue(); + return *descr->dmarx_pool->alloc(DMA_BUFFER_READ); } return NULLBUF; } @@ -227,7 +228,7 @@ DMABuffer &AdvancedI2S::dequeue() { while (!descr->dmatx_pool->writable()) { __WFI(); } - return *descr->dmatx_pool->allocate(); + return *descr->dmatx_pool->alloc(DMA_BUFFER_WRITE); } return NULLBUF; } @@ -241,7 +242,7 @@ void AdvancedI2S::write(DMABuffer &dmabuf) { // Make sure any cached data is flushed. dmabuf.flush(); - descr->dmatx_pool->enqueue(&dmabuf); + dmabuf.release(); if (descr->dmatx_buf[0] == nullptr && (++buf_count % 3) == 0) { i2s_start_dma_transfer(descr, i2s_mode); @@ -285,7 +286,7 @@ int AdvancedI2S::begin(i2s_mode_t i2s_mode, uint32_t sample_rate, size_t n_sampl if (i2s_mode & AN_I2S_MODE_IN) { // Allocate DMA buffer pool. - descr->dmarx_pool = new DMABufferPool(n_samples, 2, n_buffers); + descr->dmarx_pool = new DMAPool(n_samples, 2, n_buffers); if (descr->dmarx_pool == nullptr) { descr = nullptr; return 0; @@ -299,7 +300,7 @@ int AdvancedI2S::begin(i2s_mode_t i2s_mode, uint32_t sample_rate, size_t n_sampl if (i2s_mode & AN_I2S_MODE_OUT) { // Allocate DMA buffer pool. - descr->dmatx_pool = new DMABufferPool(n_samples, 2, n_buffers); + descr->dmatx_pool = new DMAPool(n_samples, 2, n_buffers); if (descr->dmatx_pool == nullptr) { descr = nullptr; return 0; @@ -358,7 +359,7 @@ void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *i2s) { // the next DMA memory address target. if (descr->dmatx_pool->readable()) { descr->dmatx_buf[ct]->release(); - descr->dmatx_buf[ct] = descr->dmatx_pool->dequeue(); + descr->dmatx_buf[ct] = descr->dmatx_pool->alloc(DMA_BUFFER_READ); hal_dma_update_memory(&descr->dmatx, descr->dmatx_buf[ct]->data()); } else { i2s_descr_deinit(descr, false); @@ -384,15 +385,15 @@ void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *i2s) { // Make sure any cached data is discarded. descr->dmarx_buf[ct]->invalidate(); // Move current DMA buffer to ready queue. - descr->dmarx_pool->enqueue(descr->dmarx_buf[ct]); + descr->dmarx_buf[ct]->release(); // Allocate a new free buffer. - descr->dmarx_buf[ct] = descr->dmarx_pool->allocate(); + descr->dmarx_buf[ct] = descr->dmarx_pool->alloc(DMA_BUFFER_WRITE); // Currently, all multi-channel buffers are interleaved. if (descr->dmarx_buf[ct]->channels() > 1) { - descr->dmarx_buf[ct]->setflags(DMA_BUFFER_INTRLVD); + descr->dmarx_buf[ct]->set_flags(DMA_BUFFER_INTRLVD); } } else { - descr->dmarx_buf[ct]->setflags(DMA_BUFFER_DISCONT); + descr->dmarx_buf[ct]->set_flags(DMA_BUFFER_DISCONT); } // Update the next DMA target pointer. diff --git a/src/AdvancedI2S.h b/src/AdvancedI2S.h index d269e8c..99614d7 100644 --- a/src/AdvancedI2S.h +++ b/src/AdvancedI2S.h @@ -16,11 +16,9 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ARDUINO_ADVANCED_I2S_H -#define ARDUINO_ADVANCED_I2S_H +#ifndef __ADVANCED_I2S_H__ +#define __ADVANCED_I2S_H__ -#include -#include "DMABuffer.h" #include "AdvancedAnalog.h" struct i2s_descr_t; @@ -55,4 +53,4 @@ class AdvancedI2S { int stop(); }; -#endif // ARDUINO_ADVANCED_I2S_H +#endif // __ADVANCED_I2S_H__ diff --git a/src/Arduino_AdvancedAnalog.h b/src/Arduino_AdvancedAnalog.h index 13a3b3a..ac89e8b 100644 --- a/src/Arduino_AdvancedAnalog.h +++ b/src/Arduino_AdvancedAnalog.h @@ -17,16 +17,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ADVANCEDANALOGREDUX_ARDUINO_ADVANCEDANALOG_H -#define ADVANCEDANALOGREDUX_ARDUINO_ADVANCEDANALOG_H - -/************************************************************************************** - * INCLUDE - **************************************************************************************/ +#ifndef __ARDUINO_ADVANCED_ANALOG_H__ +#define __ARDUINO_ADVANCED_ANALOG_H__ #include "AdvancedADC.h" #include "AdvancedDAC.h" #include "AdvancedI2S.h" #include "WavReader.h" -#endif /* ADVANCEDANALOGREDUX_ARDUINO_ADVANCEDANALOG_H */ +#endif // __ARDUINO_ADVANCED_ANALOG_H__ diff --git a/src/DMABuffer.h b/src/DMABuffer.h deleted file mode 100644 index 50289fe..0000000 --- a/src/DMABuffer.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - This file is part of the Arduino_AdvancedAnalog library. - Copyright (c) 2023 Arduino SA. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __DMA_BUFFER_H__ -#define __DMA_BUFFER_H__ - -#include "Arduino.h" -#include "Queue.h" - -#ifndef __SCB_DCACHE_LINE_SIZE -#define __SCB_DCACHE_LINE_SIZE 32 -#endif - -template class AlignedAlloc { - // AlignedAlloc allocates extra memory before the aligned memory start, and uses that - // extra memory to stash the pointer returned from malloc. Note memory allocated with - // Aligned::alloc must be free'd later with Aligned::free. - public: - static void *malloc(size_t size) { - void **ptr, *stashed; - size_t offset = A - 1 + sizeof(void *); - if ((A % 2) || !((stashed = ::malloc(size + offset)))) { - return nullptr; - } - ptr = (void **) (((uintptr_t) stashed + offset) & ~(A - 1)); - ptr[-1] = stashed; - return ptr; - } - - static void free(void *ptr) { - if (ptr != nullptr) { - ::free(((void **) ptr)[-1]); - } - } - - static size_t round(size_t size) { - return ((size + (A-1)) & ~(A-1)); - } -}; - -enum { - DMA_BUFFER_DISCONT = (1 << 0), - DMA_BUFFER_INTRLVD = (1 << 1), -}; - -template class DMABufferPool; - -template class DMABuffer { - typedef DMABufferPool Pool; - - private: - Pool *pool; - size_t n_samples; - size_t n_channels; - T *ptr; - uint32_t ts; - uint32_t flags; - - public: - DMABuffer(Pool *pool=nullptr, size_t samples=0, size_t channels=0, T *mem=nullptr): - pool(pool), n_samples(samples), n_channels(channels), ptr(mem), ts(0), flags(0) { - } - - T *data() { - return ptr; - } - - size_t size() { - return n_samples * n_channels; - } - - size_t bytes() { - return n_samples * n_channels * sizeof(T); - } - - void flush() { - #if __DCACHE_PRESENT - if (ptr) { - SCB_CleanDCache_by_Addr(data(), bytes()); - } - #endif - } - - void invalidate() { - #if __DCACHE_PRESENT - if (ptr) { - SCB_InvalidateDCache_by_Addr(data(), bytes()); - } - #endif - } - - uint32_t timestamp() { - return ts; - } - - void timestamp(uint32_t ts) { - this->ts = ts; - } - - uint32_t channels() { - return n_channels; - } - - void release() { - if (pool && ptr) { - pool->release(this); - } - } - - void setflags(uint32_t f) { - flags |= f; - } - - bool getflags(uint32_t f) { - return flags & f; - } - - void clrflags(uint32_t f=0xFFFFFFFFU) { - flags &= (~f); - } - - T& operator[](size_t i) - { - assert(ptr && i < size()); - return ptr[i]; - } - - const T& operator[](size_t i) const - { - assert(ptr && i < size()); - return ptr[i]; - } - - operator bool() const { - return (ptr != nullptr); - } -}; - -template class DMABufferPool { - private: - Queue*> wr_queue; - Queue*> rd_queue; - std::unique_ptr::free)> pool; - - public: - DMABufferPool(size_t n_samples, size_t n_channels, size_t n_buffers): - wr_queue(n_buffers), rd_queue(n_buffers), pool(nullptr, AlignedAlloc::free) { - // Round up to next multiple of alignment. - size_t bufsize = AlignedAlloc::round(n_samples * n_channels * sizeof(T)); - if (bufsize && rd_queue && wr_queue) { - // Allocate an aligned memory pool for DMA buffers. - pool.reset((uint8_t *) AlignedAlloc::malloc(n_buffers * bufsize)); - if (!pool) { - // Failed to allocate memory pool. - return; - } - // Allocate the DMA buffers, initialize them using aligned - // pointers from the pool, and add them to the ready queue. - for (size_t i=0; i *buf = new DMABuffer( - this, n_samples, n_channels, (T *) &pool.get()[i * bufsize] - ); - if (buf == nullptr) { - break; - } - wr_queue.push(buf); - } - } - } - - ~DMABufferPool() { - size_t count = 0; - DMABuffer *buf = nullptr; - - while (readable()) { - delete dequeue(); - count ++; - } - - while (writable()) { - delete allocate(); - count ++; - } - } - - bool writable() { - return !(wr_queue.empty()); - } - - bool readable() { - return !(rd_queue.empty()); - } - - void flush() { - while (readable()) { - release(dequeue()); - } - } - - DMABuffer *allocate() { - // Get a DMA buffer from the free queue. - return wr_queue.pop(); - } - - void release(DMABuffer *buf) { - // Return DMA buffer to the free queue. - buf->clrflags(); - wr_queue.push(buf); - } - - void enqueue(DMABuffer *buf) { - // Add DMA buffer to the ready queue. - rd_queue.push(buf); - } - - DMABuffer *dequeue() { - // Return a DMA buffer from the ready queue. - return rd_queue.pop(); - } -}; -#endif //__DMA_BUFFER_H__ diff --git a/src/HALConfig.cpp b/src/HALConfig.cpp index f82a9d3..2493211 100644 --- a/src/HALConfig.cpp +++ b/src/HALConfig.cpp @@ -271,6 +271,7 @@ int hal_i2s_config(I2S_HandleTypeDef *i2s, uint32_t sample_rate, uint32_t mode, i2s->Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_RIGHT; i2s->Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE; + HAL_I2S_DeInit(i2s); if (HAL_I2S_Init(i2s) != HAL_OK) { return -1; } diff --git a/src/Queue.h b/src/Queue.h deleted file mode 100644 index 0b7e9f0..0000000 --- a/src/Queue.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - This file is part of the Arduino_AdvancedAnalog library. - Copyright (c) 2023 Arduino SA. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __QUEUE_H__ -#define __QUEUE_H__ - -#include "Arduino.h" - -template class Queue { - private: - size_t capacity; - volatile size_t tail; - volatile size_t head; - std::unique_ptr buff; - - private: - inline size_t next_pos(size_t x) { - return (((x) + 1) % (capacity)); - } - - public: - Queue(size_t size=0): - capacity(size), tail(0), head(0), buff(nullptr) { - if (size) { - tail = head = 0; - capacity = size + 1; - buff.reset(new T[capacity]); - } - } - - void reset() { - tail = head = 0; - } - - size_t empty() { - return tail == head; - } - - operator bool() const { - return buff.get() != nullptr; - } - - bool push(T data) { - bool ret = false; - size_t next = next_pos(head); - if (buff && (next != tail)) { - buff[head] = data; - head = next; - ret = true; - } - return ret; - } - - T pop(bool peek=false) { - if (buff && (tail != head)) { - T data = buff[tail]; - if (!peek) { - tail = next_pos(tail); - } - return data; - } - return T(); - } -}; -#endif //__QUEUE_H__ diff --git a/src/WavReader.cpp b/src/WavReader.cpp index f5753ec..9040d1c 100644 --- a/src/WavReader.cpp +++ b/src/WavReader.cpp @@ -44,7 +44,7 @@ int WavReader::begin(const char *path, size_t n_samples, size_t n_buffers, bool } // Allocate the DMA buffer pool. - pool = new DMABufferPool(n_samples, header.num_channels, n_buffers); + pool = new DMAPool(n_samples, header.num_channels, n_buffers); if (pool == nullptr) { stop(); return 0; @@ -75,7 +75,7 @@ DMABuffer &WavReader::read() { __WFI(); } - DMABuffer *buf = pool->allocate(); + DMABuffer *buf = pool->alloc(DMA_BUFFER_WRITE); size_t offset = 0; Sample *rawbuf = buf->data(); size_t n_samples = buf->size(); @@ -95,6 +95,8 @@ DMABuffer &WavReader::read() { } } } + buf->clr_flags(); + buf->set_flags(DMA_BUFFER_READ); return *buf; } diff --git a/src/WavReader.h b/src/WavReader.h index 43058ad..2bbc840 100644 --- a/src/WavReader.h +++ b/src/WavReader.h @@ -17,10 +17,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "AdvancedAnalog.h" +#ifndef __ADVANCED_WAV_READER_H__ +#define __ADVANCED_WAV_READER_H__ -#ifndef ARDUINO_WAV_READER_H_ -#define ARDUINO_WAV_READER_H_ +#include "AdvancedAnalog.h" class WavReader { typedef struct { @@ -43,7 +43,7 @@ class WavReader { FILE *file; bool loop; WavHeader header; - DMABufferPool *pool; + DMAPool *pool; public: WavReader(): file(nullptr), loop(false), pool(nullptr) { @@ -71,4 +71,4 @@ class WavReader { SampleBuffer read(); int rewind(); }; -#endif /* ARDUINO_WAV_READER_H_ */ +#endif // __ADVANCED_WAV_READER_H__ From cd0684218ba6d856d4bbe5b8b1ede98fc22282ed Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 5 Jun 2024 10:38:12 +0200 Subject: [PATCH 3/6] AdvancedDAC: Add support for loop mode. Loop mode starts the DAC automatically when all buffers in the queue are written. Once started, the DAC will continuously cycle through all of the buffers in the queue. Signed-off-by: iabdalkader --- src/AdvancedDAC.cpp | 26 ++++++++++++++++---------- src/AdvancedDAC.h | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/AdvancedDAC.cpp b/src/AdvancedDAC.cpp index bcd5967..1872489 100644 --- a/src/AdvancedDAC.cpp +++ b/src/AdvancedDAC.cpp @@ -32,6 +32,7 @@ struct dac_descr_t { uint32_t dmaudr_flag; DMAPool *pool; DMABuffer *dmabuf[2]; + bool loop_mode; }; // NOTE: Both DAC channel descriptors share the same DAC handle. @@ -39,9 +40,9 @@ static DAC_HandleTypeDef dac = {0}; static dac_descr_t dac_descr_all[] = { {&dac, DAC_CHANNEL_1, {DMA1_Stream4, {DMA_REQUEST_DAC1_CH1}}, DMA1_Stream4_IRQn, {TIM4}, - DAC_TRIGGER_T4_TRGO, DAC_ALIGN_12B_R, DAC_FLAG_DMAUDR1, nullptr, {nullptr, nullptr}}, + DAC_TRIGGER_T4_TRGO, DAC_ALIGN_12B_R, DAC_FLAG_DMAUDR1, nullptr, {nullptr, nullptr}, false}, {&dac, DAC_CHANNEL_2, {DMA1_Stream5, {DMA_REQUEST_DAC1_CH2}}, DMA1_Stream5_IRQn, {TIM5}, - DAC_TRIGGER_T5_TRGO, DAC_ALIGN_12B_R, DAC_FLAG_DMAUDR2, nullptr, {nullptr, nullptr}}, + DAC_TRIGGER_T5_TRGO, DAC_ALIGN_12B_R, DAC_FLAG_DMAUDR2, nullptr, {nullptr, nullptr}, false}, }; static uint32_t DAC_RES_LUT[] = { @@ -130,7 +131,9 @@ void AdvancedDAC::write(DMABuffer &dmabuf) { dmabuf.flush(); dmabuf.release(); - if (descr->dmabuf[0] == nullptr && (++buf_count % 3) == 0) { + if (!descr->dmabuf[0] && + ((descr->loop_mode && !descr->pool->writable()) || + (!descr->loop_mode && (++buf_count % 3 == 0)))) { descr->dmabuf[0] = descr->pool->alloc(DMA_BUFFER_READ); descr->dmabuf[1] = descr->pool->alloc(DMA_BUFFER_READ); @@ -148,7 +151,7 @@ void AdvancedDAC::write(DMABuffer &dmabuf) { } } -int AdvancedDAC::begin(uint32_t resolution, uint32_t frequency, size_t n_samples, size_t n_buffers) { +int AdvancedDAC::begin(uint32_t resolution, uint32_t frequency, size_t n_samples, size_t n_buffers, bool loop) { // Sanity checks. if (resolution >= AN_ARRAY_SIZE(DAC_RES_LUT) || descr != nullptr) { return 0; @@ -172,6 +175,8 @@ int AdvancedDAC::begin(uint32_t resolution, uint32_t frequency, size_t n_samples descr = nullptr; return 0; } + + descr->loop_mode = loop; descr->resolution = DAC_RES_LUT[resolution]; // Init and config DMA. @@ -192,8 +197,7 @@ int AdvancedDAC::begin(uint32_t resolution, uint32_t frequency, size_t n_samples return 1; } -int AdvancedDAC::stop() -{ +int AdvancedDAC::stop() { if (descr != nullptr) { dac_descr_deinit(descr, true); descr = nullptr; @@ -201,8 +205,7 @@ int AdvancedDAC::stop() return 1; } -int AdvancedDAC::frequency(uint32_t const frequency) -{ +int AdvancedDAC::frequency(uint32_t const frequency) { if (descr != nullptr) { // Reconfigure the trigger timer. dac_descr_deinit(descr, false); @@ -210,8 +213,7 @@ int AdvancedDAC::frequency(uint32_t const frequency) } } -AdvancedDAC::~AdvancedDAC() -{ +AdvancedDAC::~AdvancedDAC() { dac_descr_deinit(descr, true); } @@ -227,6 +229,10 @@ void DAC_DMAConvCplt(DMA_HandleTypeDef *dma, uint32_t channel) { size_t ct = ! hal_dma_get_ct(dma); descr->dmabuf[ct]->release(); descr->dmabuf[ct] = descr->pool->alloc(DMA_BUFFER_READ); + if (descr->loop_mode) { + // Move a buffer from the write queue to the read queue. + descr->pool->alloc(DMA_BUFFER_WRITE)->release(); + } hal_dma_update_memory(dma, descr->dmabuf[ct]->data()); } else { dac_descr_deinit(descr, false); diff --git a/src/AdvancedDAC.h b/src/AdvancedDAC.h index d1084a6..99d6176 100644 --- a/src/AdvancedDAC.h +++ b/src/AdvancedDAC.h @@ -45,7 +45,7 @@ class AdvancedDAC { bool available(); SampleBuffer dequeue(); void write(SampleBuffer dmabuf); - int begin(uint32_t resolution, uint32_t frequency, size_t n_samples=0, size_t n_buffers=0); + int begin(uint32_t resolution, uint32_t frequency, size_t n_samples=0, size_t n_buffers=0, bool loop=false); int stop(); int frequency(uint32_t const frequency); }; From cb081a5ab181ff4f1a7cbee85c2d2a4c1288bc42 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 15 Jul 2024 10:13:14 +0300 Subject: [PATCH 4/6] docs: Update DAC docs. Signed-off-by: iabdalkader Co-authored-by: Leonardo Cavagnis <45899760+leonardocavagnis@users.noreply.github.com> --- docs/api.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/api.md b/docs/api.md index 6b356a5..41e1a5c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -189,12 +189,12 @@ AdvancedDAC dac1(A13); ### `AdvancedDAC.begin()` -Initializes the DAC with the specified parameters. To reconfigure the DAC, `stop()` must be called first. +Initializes the DAC with the specified parameters. To reconfigure the DAC, `stop()` must be called first. The DAC has a special mode called _loop mode_ enabled by setting `loop` parameter to `true`. In loop mode, the DAC will start automatically after all buffers are filled, and continuously cycle through over all buffers. #### Syntax ``` -dac.begin(resolution, frequency, n_samples, n_buffers) +dac.begin(resolution, frequency, n_samples, n_buffers, loop=false) ``` #### Parameters @@ -206,6 +206,7 @@ dac.begin(resolution, frequency, n_samples, n_buffers) - `int` - **frequency** - the output frequency in Hertz, e.g. `8000`. - `int` - **n_samples** - the number of samples per sample buffer. See [SampleBuffer](#samplebuffer) for more details. - `int` - **n_buffers** - the number of sample buffers in the queue. See [SampleBuffer](#samplebuffer) for more details. +- `bool`- **loop** - enables loop mode. #### Returns From f530b02b32f15e02a27e7080efb55cfeb7b6079c Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 15 Jul 2024 10:19:47 +0300 Subject: [PATCH 5/6] examples: Add DAC loop mode example. Signed-off-by: iabdalkader --- examples/Advanced/DAC_Loop/DAC_Loop.ino | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 examples/Advanced/DAC_Loop/DAC_Loop.ino diff --git a/examples/Advanced/DAC_Loop/DAC_Loop.ino b/examples/Advanced/DAC_Loop/DAC_Loop.ino new file mode 100644 index 0000000..27556ee --- /dev/null +++ b/examples/Advanced/DAC_Loop/DAC_Loop.ino @@ -0,0 +1,41 @@ +// This examples shows how to use the DAC in loop mode. In loop mode the +// DAC starts automatically after all buffers are filled, and continuously +// cycle through over all buffers. +#include + +AdvancedDAC dac1(A12); + +void setup() { + Serial.begin(9600); + + while (!Serial) { + + } + + // Start DAC in loop mode. + if (!dac1.begin(AN_RESOLUTION_12, 16000, 32, 16, true)) { + Serial.println("Failed to start DAC1 !"); + while (1); + } + + // Write all buffers. + uint16_t sample = 0; + while (dac1.available()) { + // Get a free buffer for writing. + SampleBuffer buf = dac1.dequeue(); + + // Write data to buffer. + for (int i=0; i Date: Mon, 15 Jul 2024 11:41:07 +0200 Subject: [PATCH 6/6] Update library.properties - v1.5.0 --- library.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index fb0afaf..c719cab 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=Arduino_AdvancedAnalog -version=1.4.0 +version=1.5.0 author=Arduino maintainer=Arduino -sentence=Advanced analog functionalities for STM32H7 boards -paragraph= +sentence=Advanced Analog library for STM32H7 boards +paragraph=Enables high performance DAC, ADC and I2S applications on boards based on the STM32H7 microcontrollers category=Other url=https://github.com/arduino-libraries/Arduino_AdvancedAnalog architectures=mbed,mbed_portenta,mbed_nicla,mbed_giga