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 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 *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); };