From cd0684218ba6d856d4bbe5b8b1ede98fc22282ed Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 5 Jun 2024 10:38:12 +0200 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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