Skip to content

Commit 915b73a

Browse files
committed
R2ROutput example
1 parent 73c6d84 commit 915b73a

File tree

2 files changed

+121
-35
lines changed

2 files changed

+121
-35
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @file streams-generator-r2r.ino
3+
* @author Phil Schatzmann
4+
* @brief Example for a self built resistor ladder DAC
5+
* @copyright GPLv3
6+
*/
7+
8+
#include "AudioTools.h"
9+
#include "AudioLibs/R2ROutput.h"
10+
11+
AudioInfo info(8000, 1, 16);
12+
SineWaveGenerator<int16_t> sineWave; // subclass of SoundGenerator with max amplitude of 32000
13+
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
14+
R2ROutput out;
15+
StreamCopy copier(out, sound); // copies sound into i2s
16+
17+
// Arduino Setup
18+
void setup(void) {
19+
// Open Serial
20+
Serial.begin(115200);
21+
while(!Serial);
22+
AudioLogger::instance().begin(Serial, AudioLogger::Info);
23+
24+
// start I2S
25+
Serial.println("starting R2R...");
26+
auto config = out.defaultConfig();
27+
config.copyFrom(info);
28+
// 8 pins for 8 bit DAC for channel 1
29+
config.channel1_pins = {13,12,14,27,26,25, 33, 32};
30+
// channel 2 would be config.channel2_pins
31+
out.begin(config);
32+
33+
// Setup sine wave
34+
sineWave.begin(info, N_B4);
35+
Serial.println("started...");
36+
}
37+
38+
// Arduino loop - copy sound to out
39+
void loop() {
40+
copier.copy();
41+
}

src/AudioLibs/R2ROutput.h

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,69 @@
99

1010
namespace audio_tools {
1111

12+
/**
13+
* @brief R2R driver base class
14+
* @ingroup platform
15+
* @author Phil Schatzmann
16+
* @copyright GPLv3
17+
*/
18+
19+
class R2RDriverBase {
20+
public:
21+
virtual void setupPins(std::vector<int> &channel1_pins,
22+
std::vector<int> &channel2_pins) = 0;
23+
24+
virtual void writePins(int channels, int channel, unsigned uvalue) = 0;
25+
};
26+
27+
/**
28+
* @brief R2R driver which uses the Arduino API to setup and write to the
29+
* digital pins
30+
* @ingroup platform
31+
* @author Phil Schatzmann
32+
* @copyright GPLv3
33+
*/
34+
35+
class R2RDriver : public R2RDriverBase {
36+
public:
37+
void setupPins(std::vector<int> &channel1_pins,
38+
std::vector<int> &channel2_pins) override {
39+
TRACED();
40+
p_channel1_pins = &channel1_pins;
41+
p_channel2_pins = &channel2_pins;
42+
43+
for (auto pin : channel1_pins) {
44+
LOGI("Setup channel1 pin %d", pin);
45+
pinMode(pin, OUTPUT);
46+
}
47+
for (int pin : channel2_pins) {
48+
LOGI("Setup channel2 pin %d", pin);
49+
pinMode(pin, OUTPUT);
50+
}
51+
};
52+
53+
void writePins(int channels, int channel, unsigned uvalue) override {
54+
switch (channel) {
55+
case 0:
56+
for (int j = 0; j < (*p_channel1_pins).size(); j++) {
57+
int pin = (*p_channel1_pins)[j];
58+
if (pin >= 0) digitalWrite(pin, (uvalue >> j) & 1);
59+
}
60+
break;
61+
case 1:
62+
for (int j = 0; j < (*p_channel2_pins).size(); j++) {
63+
int pin = (*p_channel2_pins)[j];
64+
if (pin >= 0) digitalWrite(pin, (uvalue >> j) & 1);
65+
}
66+
break;
67+
}
68+
}
69+
70+
protected:
71+
std::vector<int> *p_channel1_pins = nullptr;
72+
std::vector<int> *p_channel2_pins = nullptr;
73+
74+
} r2r_driver;
1275

1376
/**
1477
* @brief R2R configuration
@@ -20,8 +83,10 @@ class R2RConfig : public AudioInfo {
2083
public:
2184
std::vector<int> channel1_pins;
2285
std::vector<int> channel2_pins;
23-
uint16_t buffer_size = DEFAULT_BUFFER_SIZE; // automatic determination from write size
24-
uint16_t buffer_count = 2; // double buffer
86+
uint16_t buffer_size = DEFAULT_BUFFER_SIZE;
87+
uint16_t buffer_count = 2; // double buffer
88+
R2RDriverBase *driver = &r2r_driver; // by default use Arduino driver
89+
bool is_blocking = true;
2590
};
2691

2792
/**
@@ -60,12 +125,12 @@ class R2ROutput : public AudioOutput {
60125
LOGE("channel2_pins not defined");
61126
return false;
62127
}
63-
if (rcfg.buffer_size * rcfg.buffer_count == 0){
128+
if (rcfg.buffer_size * rcfg.buffer_count == 0) {
64129
LOGE("buffer_size or buffer_count is 0");
65130
return false;
66131
}
67132
buffer.resize(rcfg.buffer_size, rcfg.buffer_count);
68-
setupPins();
133+
rcfg.driver->setupPins(rcfg.channel1_pins, rcfg.channel2_pins);
69134
timer.setCallbackParameter(this);
70135
timer.setIsSave(true);
71136
return timer.begin(r2r_timer_callback, cfg.sample_rate, HZ);
@@ -74,9 +139,18 @@ class R2ROutput : public AudioOutput {
74139
size_t write(const uint8_t *data, size_t len) override {
75140
// if buffer has not been allocated (buffer_size==0)
76141
if (len > rcfg.buffer_size) {
77-
LOGE("buffer_size %d too small for write size: %d", rcfg.buffer_size, len);
142+
LOGE("buffer_size %d too small for write size: %d", rcfg.buffer_size,
143+
len);
78144
return len;
79145
}
146+
147+
// wait for buffer to have enough space
148+
if (rcfg.is_blocking){
149+
while(buffer.availableForWrite()<len){
150+
delay(5);
151+
}
152+
}
153+
80154
size_t result = buffer.writeArray(data, len);
81155
// activate output when buffer is half full
82156
if (!is_active && buffer.bufferCountFilled() >= rcfg.buffer_count / 2) {
@@ -92,18 +166,6 @@ class R2ROutput : public AudioOutput {
92166
NBuffer<uint8_t> buffer{DEFAULT_BUFFER_SIZE, 0};
93167
R2RConfig rcfg;
94168

95-
virtual void setupPins() {
96-
TRACED();
97-
for (auto pin : rcfg.channel1_pins) {
98-
LOGI("Setup channel1 pin %d", pin);
99-
pinMode(pin, OUTPUT);
100-
}
101-
for (int pin : rcfg.channel2_pins) {
102-
LOGI("Setup channel2 pin %d", pin);
103-
pinMode(pin, OUTPUT);
104-
}
105-
}
106-
107169
void writeValue(int channel) {
108170
switch (cfg.bits_per_sample) {
109171
case 8:
@@ -132,24 +194,7 @@ class R2ROutput : public AudioOutput {
132194
// Serial.println(uvalue);
133195

134196
// output pins
135-
writePins(channel, uvalue);
136-
}
137-
138-
virtual void writePins(int channel, unsigned uvalue){
139-
switch (channel) {
140-
case 0:
141-
for (int j = 0; j < rcfg.channel1_pins.size(); j++) {
142-
int pin = rcfg.channel1_pins[j];
143-
if (pin >= 0) digitalWrite(pin, (uvalue >> j) & 1);
144-
}
145-
break;
146-
case 1:
147-
for (int j = 0; j < rcfg.channel2_pins.size(); j++) {
148-
int pin = rcfg.channel2_pins[j];
149-
if (pin >= 0) digitalWrite(pin, (uvalue >> j) & 1);
150-
}
151-
break;
152-
}
197+
rcfg.driver->writePins(cfg.channels, channel, uvalue);
153198
}
154199

155200
static void r2r_timer_callback(void *ptr) {

0 commit comments

Comments
 (0)