Skip to content

Commit 734b435

Browse files
committed
DRAFT R2ROutput
1 parent 9538017 commit 734b435

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

src/AudioLibs/R2ROutput.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#pragma once
2+
3+
#include "AudioConfig.h"
4+
#include "AudioTimer/AudioTimer.h"
5+
#include "AudioTools/AudioLogger.h"
6+
#include "AudioTools/AudioOutput.h"
7+
#include "AudioTools/Buffers.h"
8+
9+
namespace audio_tools {
10+
11+
/**
12+
* @brief R2R configuration
13+
* @author Phil Schatzmann
14+
* @copyright GPLv3
15+
*/
16+
17+
class R2RConfig : public AudioInfo {
18+
public:
19+
Vector<int> channel1_pins{0};
20+
Vector<int> channel2_pins{0};
21+
};
22+
23+
/**
24+
* @brief DRAFT implementation for Output to R2R DAC
25+
* @ingroup io
26+
* @author Phil Schatzmann
27+
* @copyright GPLv3
28+
*/
29+
30+
class R2ROutput : public AudioOutput {
31+
public:
32+
R2RConfig defaultConfig() {
33+
R2RConfig r;
34+
return r;
35+
}
36+
37+
bool begin(R2RConfig c) {
38+
cfg = c;
39+
rcfg = c;
40+
return begin();
41+
}
42+
43+
bool begin() override {
44+
if (cfg.channels == 0 || cfg.channels > 2) {
45+
LOGE("channels is %d", cfg.channels);
46+
return false;
47+
}
48+
if (rcfg.channel1_pins.size() == 0) {
49+
LOGE("channel1_pins not defined");
50+
return false;
51+
}
52+
if (cfg.channels == 2 &&
53+
rcfg.channel2_pins.size() != rcfg.channel1_pins.size()) {
54+
LOGE("channel2_pins not defined");
55+
return false;
56+
}
57+
setupPins();
58+
timer.setCallbackParameter(this);
59+
return timer.begin(r2r_timer_callback, cfg.sample_rate, HZ);
60+
}
61+
62+
size_t write(const uint8_t *data, size_t len) override {
63+
size_t result = buffer.writeArray(data, len);
64+
// activate output when buffer is full
65+
if (!is_active && buffer.isFull()) {
66+
is_active = true;
67+
}
68+
return result;
69+
}
70+
71+
protected:
72+
TimerAlarmRepeating timer;
73+
NBuffer<uint8_t> buffer{1024, 2};
74+
R2RConfig rcfg;
75+
76+
void setupPins() {
77+
for (int j = 0; j < rcfg.channel1_pins.size(); j++) {
78+
pinMode(rcfg.channel1_pins[j], OUTPUT);
79+
}
80+
for (int j = 0; j < rcfg.channel2_pins.size(); j++) {
81+
pinMode(rcfg.channel2_pins[j], OUTPUT);
82+
}
83+
}
84+
85+
void writeValue(int channel) {
86+
switch (cfg.bits_per_sample) {
87+
case 8:
88+
return writeValueT<int8_t>(channel);
89+
case 16:
90+
return writeValueT<int16_t>(channel);
91+
case 24:
92+
return writeValueT<int24_t>(channel);
93+
case 32:
94+
return writeValueT<int32_t>(channel);
95+
}
96+
}
97+
98+
template <typename T>
99+
void writeValueT(int channel) {
100+
// don't do anything if we do not have enough data
101+
if (buffer.available()< sizeof(T)) return;
102+
103+
// get next value from buffer
104+
T value = 0;
105+
buffer.readArray((uint8_t *)&value, sizeof(T));
106+
// convert to unsigned
107+
unsigned uvalue = (int)value + NumberConverter::maxValueT<T>() + 1;
108+
// scale value
109+
uvalue = uvalue >> ((sizeof(T) * 8) - rcfg.channel1_pins.size());
110+
// output pins
111+
switch (channel) {
112+
case 0:
113+
for (int j = 0; j < rcfg.channel1_pins.size(); j++) {
114+
digitalWrite(rcfg.channel1_pins[j], (uvalue >> j) & 1);
115+
}
116+
break;
117+
case 1:
118+
for (int j = 0; j < rcfg.channel2_pins.size(); j++) {
119+
digitalWrite(rcfg.channel2_pins[j], (uvalue >> j) & 1);
120+
}
121+
break;
122+
}
123+
}
124+
125+
static void r2r_timer_callback(void *ptr) {
126+
R2ROutput *self = (R2ROutput *)ptr;
127+
if (self->is_active) {
128+
// output channel 1
129+
self->writeValue(0);
130+
// output channel 2
131+
if (self->cfg.channels == 2) self->writeValue(1);
132+
};
133+
}
134+
};
135+
136+
} // namespace audio_tools

src/AudioTimer/AudioTimerSTM32.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class TimerAlarmRepeatingDriverSTM32 : public TimerAlarmRepeatingDriverBase {
5959
case US:
6060
timer->setOverflow(time, MICROSEC_FORMAT); // 10 Hz
6161
break;
62+
case HZ:
63+
// convert hz to time in us
64+
uint64_t time_us = AudioTime::toTimeUs(time);
65+
timer->setOverflow(time_us, MICROSEC_FORMAT); // 10 Hz
66+
break;
6267
}
6368
timer->resume();
6469
return true;

0 commit comments

Comments
 (0)