Skip to content

Commit

Permalink
Merge pull request #75 from arduino-libraries/dac_loop_mode
Browse files Browse the repository at this point in the history
AdvancedDAC: Add support for loop mode.
  • Loading branch information
iabdalkader authored Jul 15, 2024
2 parents 70a630e + f530b02 commit e015fc5
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 13 deletions.
5 changes: 3 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
41 changes: 41 additions & 0 deletions examples/Advanced/DAC_Loop/DAC_Loop.ino
Original file line number Diff line number Diff line change
@@ -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 <Arduino_AdvancedAnalog.h>

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<buf.size(); i++) {
buf.data()[i] = sample;
}

// Write the buffer to DAC.
dac1.write(buf);
sample += 256;
}
}


void loop() {
// In loop mode, no other DAC functions need to be called.
}
26 changes: 16 additions & 10 deletions src/AdvancedDAC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ struct dac_descr_t {
uint32_t dmaudr_flag;
DMAPool<Sample> *pool;
DMABuffer<Sample> *dmabuf[2];
bool loop_mode;
};

// NOTE: Both DAC channel descriptors share the same DAC handle.
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[] = {
Expand Down Expand Up @@ -130,7 +131,9 @@ void AdvancedDAC::write(DMABuffer<Sample> &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);

Expand All @@ -148,7 +151,7 @@ void AdvancedDAC::write(DMABuffer<Sample> &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;
Expand All @@ -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.
Expand All @@ -192,26 +197,23 @@ 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;
}
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);
hal_tim_config(&descr->tim, frequency);
}
}

AdvancedDAC::~AdvancedDAC()
{
AdvancedDAC::~AdvancedDAC() {
dac_descr_deinit(descr, true);
}

Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/AdvancedDAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down

0 comments on commit e015fc5

Please sign in to comment.