arduino-audio-driver
Loading...
Searching...
No Matches
PCM1681.h
Go to the documentation of this file.
1
10#pragma once
11
13
14namespace audio_driver {
15
17enum class PCM1681Format {
18 RightJustified24 = 0x00,
19 RightJustified16 = 0x03,
20 I2S_16_24 = 0x04,
21 LeftJustified16_24 = 0x05,
22 I2S_TDM_24 = 0x06,
23 LeftJustifiedTDM24 = 0x07,
24 I2S_DSP_24 = 0x08,
25 LeftJustifiedDSP24 = 0x09,
26};
27
30 Rate44100 = 0x00,
31 Rate48000 = 0x01,
32 Rate32000 = 0x02,
33};
34
37 Sharp = 0x00,
38 Slow = 0x01,
39};
40
43 Fine = 0x00,
44 Wide = 0x01,
45};
46
56 public:
57 static constexpr int N_CHANNELS = 8;
58 static constexpr int N_REGISTERS = 20;
59
60 // ---- Register addresses ----
61 enum Reg : uint8_t {
62 REG_0 = 0x00,
63 AT1x_REG = 0x01,
64 AT2x_REG = 0x02,
65 AT3x_REG = 0x03,
66 AT4x_REG = 0x04,
67 AT5x_REG = 0x05,
68 AT6x_REG = 0x06,
69 MUTx_REG = 0x07,
70 DACx_REG = 0x08,
71 FMTx_REG = 0x09,
72 SRST_REG = 0x0A,
73 REVx_REG = 0x0B,
74 FLTx_REG = 0x0C,
75 DAMS_REG = 0x0D,
76 REG_14 = 0x0E,
77 REG_15 = 0x0F,
78 AT7x_REG = 0x10,
79 AT8x_REG = 0x11,
80 MUT_OR_REG = 0x12,
81 DAC_OR_REG = 0x13,
82 };
83
84 PCM1681() { i2c_addr = 0x4C; }
85
95 bool begin(uint32_t sample_rate, uint8_t bits) {
96 (void)sample_rate;
97 (void)bits;
99 }
100
101 bool begin(uint32_t sample_rate, uint8_t bits, codec_mode_t mode,
102 i2s_format_t fmt, bool is_master, uint8_t channels) override {
103 (void)mode;
104 (void)fmt;
105 (void)is_master;
106 (void)channels;
107 return begin(sample_rate, bits);
108 }
109
111 static const uint8_t default_reg_map[N_REGISTERS] = {
112 0x00, /* register 0x00. Factory use only */
113 0xFF, /* register 0x01 */
114 0xFF, /* register 0x02 */
115 0xFF, /* register 0x03 */
116 0xFF, /* register 0x04 */
117 0xFF, /* register 0x05 */
118 0xFF, /* register 0x06 */
119 0x00, /* register 0x07 */
120 0x00, /* register 0x08 */
121 0x05, /* register 0x09 */
122 0x00, /* register 0x0A */
123 0xFF, /* register 0x0B */
124 0x0F, /* register 0x0C */
125 0x00, /* register 0x0D */
126 0x00, /* register 0x0E. Read only */
127 0x00, /* register 0x0F. Factory use only */
128 0xFF, /* register 0x10 */
129 0xFF, /* register 0x11 */
130 0x00, /* register 0x12 */
131 0x00, /* register 0x13 */
132 };
133
134 for (int i = 0; i < N_REGISTERS; i++) reg_map[i] = default_reg_map[i];
135
136 bool rc = setFormat(format, false);
137 rc &= applyProperties();
138 return rc;
139 }
140
148 bool setVolume(uint8_t channel, uint8_t volume, bool apply = true) {
149 if (channel == 0 || channel > N_CHANNELS) return false;
150 if (volume > 100) volume = 100;
151
155
156 uint8_t attenuation =
158 ? (uint8_t)(101 * volume / 100 + 154 + 0.5)
159 : (uint8_t)(127 * volume / 100 + 128 + 0.5);
160
161 uint8_t reg = attenuationReg(channel);
162 reg_map[reg] = attenuation;
163
164 return apply ? writeReg(reg, attenuation) : true;
165 }
166
168 bool setVolume(uint8_t volume) {
169 bool rc = true;
170 for (uint8_t ch = 1; ch <= N_CHANNELS; ch++) {
171 rc &= setVolume(ch, volume, false);
172 }
173 return rc & applyProperties();
174 }
175
183 bool setMute(uint8_t channel, bool mute, bool apply = true) {
184 if (channel == 0 || channel > N_CHANNELS) return false;
185
186 uint8_t reg;
187 uint8_t pos;
188 if (channel < 7) {
189 reg = MUTx_REG;
190 pos = channel - 1;
191 } else {
192 reg = MUT_OR_REG;
193 pos = channel - 7;
194 }
195
196 updateBit(reg, pos, mute);
197 return apply ? writeReg(reg, reg_map[reg]) : true;
198 }
199
201 bool setMute(bool mute) override {
202 bool rc = true;
203 for (uint8_t ch = 1; ch <= N_CHANNELS; ch++) {
204 rc &= setMute(ch, mute, false);
205 }
206 return rc & applyProperties();
207 }
208
217 bool setDacEnabled(uint8_t channel, bool enable, bool apply = true) {
218 if (channel == 0 || channel > N_CHANNELS) return false;
219
220 uint8_t reg;
221 uint8_t pos;
222 if (channel < 7) {
223 reg = DACx_REG;
224 pos = channel - 1;
225 } else {
226 reg = DAC_OR_REG;
227 pos = channel - 7;
228 }
229
230 /* DAC_ENABLED = 0, DAC_DISABLED = 1 -> invert "enable" */
231 updateBit(reg, pos, !enable);
232 return apply ? writeReg(reg, reg_map[reg]) : true;
233 }
234
236 bool setDacEnabled(bool enable) {
237 bool rc = true;
238 for (uint8_t ch = 1; ch <= N_CHANNELS; ch++) {
239 rc &= setDacEnabled(ch, enable, false);
240 }
241 return rc & applyProperties();
242 }
243
250 bool setFormat(PCM1681Format format, bool apply = true) {
252 (uint8_t)((reg_map[FMTx_REG] & ~0x0F) | ((uint8_t)format & 0x0F));
253 return apply ? writeReg(FMTx_REG, reg_map[FMTx_REG]) : true;
254 }
255
257 bool setDeemphasisRate(PCM1681DeemphasisRate rate, bool apply = true) {
258 reg_map[SRST_REG] = (uint8_t)((reg_map[SRST_REG] & ~0x18) |
259 (((uint8_t)rate << 3) & 0x18));
260 return apply ? writeReg(SRST_REG, reg_map[SRST_REG]) : true;
261 }
262
264 bool setDeemphasisEnabled(bool enable, bool apply = true) {
265 reg_map[SRST_REG] = (uint8_t)((reg_map[SRST_REG] & ~0x01) | (enable ? 1 : 0));
266 return apply ? writeReg(SRST_REG, reg_map[SRST_REG]) : true;
267 }
268
270 bool setFilterRollOff(PCM1681FilterRollOff roll_off, bool apply = true) {
271 reg_map[FMTx_REG] = (uint8_t)((reg_map[FMTx_REG] & ~0x20) |
272 (((uint8_t)roll_off << 5) & 0x20));
273 return apply ? writeReg(FMTx_REG, reg_map[FMTx_REG]) : true;
274 }
275
277 bool setAttenuationScale(PCM1681AttenuationScale scale, bool apply = true) {
278 reg_map[DAMS_REG] = (uint8_t)((reg_map[DAMS_REG] & ~0x80) |
279 (((uint8_t)scale << 7) & 0x80));
280 return apply ? writeReg(DAMS_REG, reg_map[DAMS_REG]) : true;
281 }
282
286 bool rc = true;
287 for (uint8_t reg = 0; reg < N_REGISTERS; reg++) {
288 if (!isWriteable(reg)) continue;
289 rc &= writeReg(reg, reg_map[reg]);
290 }
291 return rc;
292 }
293
294 protected:
295 uint8_t reg_map[N_REGISTERS] = {0};
296
297 static bool isAccessible(uint8_t reg) { return reg != REG_0 && reg != REG_15; }
298
299 static bool isWriteable(uint8_t reg) {
300 return isAccessible(reg) && reg != REG_14;
301 }
302
303 static uint8_t attenuationReg(uint8_t channel) {
304 switch (channel) {
305 case 7:
306 return AT7x_REG;
307 case 8:
308 return AT8x_REG;
309 default:
310 return channel; // AT1x_REG .. AT6x_REG == 1..6
311 }
312 }
313
314 void updateBit(uint8_t reg, uint8_t pos, bool value) {
315 if (value) {
316 reg_map[reg] |= (uint8_t)(1U << pos);
317 } else {
318 reg_map[reg] &= (uint8_t)~(1U << pos);
319 }
320 }
321};
322
323} // namespace audio_driver
Header only C++ driver for the PCM1681 8-channel audio DAC.
Definition PCM1681.h:55
bool setDeemphasisRate(PCM1681DeemphasisRate rate, bool apply=true)
Configure the digital de-emphasis filter sample rate.
Definition PCM1681.h:257
bool setDacEnabled(uint8_t channel, bool enable, bool apply=true)
Enable or disable the DAC output of a single channel (used for start_output / stop_output).
Definition PCM1681.h:217
bool begin(uint32_t sample_rate, uint8_t bits)
Initialize the codec: reset the local register shadow to the factory defaults, configure the DAI form...
Definition PCM1681.h:95
static uint8_t attenuationReg(uint8_t channel)
Definition PCM1681.h:303
bool setFormat(PCM1681Format format, bool apply=true)
Configure the digital audio interface format.
Definition PCM1681.h:250
static constexpr int N_CHANNELS
Definition PCM1681.h:57
bool setDeemphasisEnabled(bool enable, bool apply=true)
Enable or disable the digital de-emphasis filter.
Definition PCM1681.h:264
uint8_t reg_map[N_REGISTERS]
Definition PCM1681.h:295
void updateBit(uint8_t reg, uint8_t pos, bool value)
Definition PCM1681.h:314
bool setMute(bool mute) override
Mute or unmute all 8 channels.
Definition PCM1681.h:201
static bool isWriteable(uint8_t reg)
Definition PCM1681.h:299
bool setVolume(uint8_t volume)
Set the volume (attenuation) for all 8 channels (0..100)
Definition PCM1681.h:168
bool setFilterRollOff(PCM1681FilterRollOff roll_off, bool apply=true)
Configure the digital filter roll-off characteristic.
Definition PCM1681.h:270
Reg
Definition PCM1681.h:61
@ REG_15
factory use only - not accessible
Definition PCM1681.h:77
@ MUTx_REG
Definition PCM1681.h:69
@ AT3x_REG
Definition PCM1681.h:65
@ DACx_REG
Definition PCM1681.h:70
@ SRST_REG
also ZREV/DREV/DMFx/DMC
Definition PCM1681.h:72
@ AT6x_REG
Definition PCM1681.h:68
@ FLTx_REG
also OVER_REG
Definition PCM1681.h:74
@ MUT_OR_REG
Definition PCM1681.h:80
@ DAMS_REG
also AZROx
Definition PCM1681.h:75
@ AT7x_REG
Definition PCM1681.h:78
@ REVx_REG
Definition PCM1681.h:73
@ AT2x_REG
Definition PCM1681.h:64
@ DAC_OR_REG
Definition PCM1681.h:81
@ AT1x_REG
Definition PCM1681.h:63
@ FMTx_REG
also FLT_REG (shares same register)
Definition PCM1681.h:71
@ AT5x_REG
Definition PCM1681.h:67
@ REG_14
read only - not writeable
Definition PCM1681.h:76
@ REG_0
Factory use only - not accessible.
Definition PCM1681.h:62
@ AT4x_REG
Definition PCM1681.h:66
@ AT8x_REG
Definition PCM1681.h:79
static constexpr int N_REGISTERS
Definition PCM1681.h:58
bool setVolume(uint8_t channel, uint8_t volume, bool apply=true)
Set the volume (attenuation) of a single output channel.
Definition PCM1681.h:148
static bool isAccessible(uint8_t reg)
Definition PCM1681.h:297
PCM1681()
Definition PCM1681.h:84
bool begin(uint32_t sample_rate, uint8_t bits, codec_mode_t mode, i2s_format_t fmt, bool is_master, uint8_t channels) override
Initializes the codec.
Definition PCM1681.h:101
bool setAttenuationScale(PCM1681AttenuationScale scale, bool apply=true)
Configure the attenuation scale (fine 0.5dB / wide 1.0dB steps)
Definition PCM1681.h:277
bool applyProperties()
Definition PCM1681.h:285
bool begin(PCM1681Format format=PCM1681Format::I2S_16_24)
Definition PCM1681.h:110
bool setDacEnabled(bool enable)
Enable or disable the DAC output of all channels.
Definition PCM1681.h:236
bool setMute(uint8_t channel, bool mute, bool apply=true)
Mute or unmute a single output channel.
Definition PCM1681.h:183
Common parent class for codec drivers that have been ported from the Zephyr RTOS audio driver impleme...
Definition ZephyrDriverCommon.h:22
uint8_t i2c_addr
Definition ZephyrDriverCommon.h:87
bool writeReg(uint8_t reg, uint8_t value)
Writes a single byte to an 8 bit register address.
Definition ZephyrDriverCommon.h:94
Namespace for audio driver components.
Definition AudioBoard.h:5
PCM1681Format
Digital audio interface format (PCM1681_FMTx_REG field)
Definition PCM1681.h:17
codec_mode_t
Definition DriverCommon.h:290
PCM1681FilterRollOff
Digital filter roll-off (PCM1681_FLT_REG)
Definition PCM1681.h:36
PCM1681DeemphasisRate
De-emphasis sample rate selection (PCM1681_DMFx_REG field)
Definition PCM1681.h:29
i2s_format_t
Definition DriverCommon.h:250
PCM1681AttenuationScale
Output attenuation scale (PCM1681_DAMS_REG)
Definition PCM1681.h:42