Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AdvancedDAC: Add support for loop mode. #75

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading