Skip to content

Commit e172e15

Browse files
authored
Merge pull request adafruit#10182 from dhalbert/audioout-fixes
Disallow identical AudioOut channel pins. Work around ESP-IDF ESP32-S2 bug that swaps DAC channels randomly.
2 parents 81d96ac + 725f8f1 commit e172e15

File tree

3 files changed

+51
-47
lines changed

3 files changed

+51
-47
lines changed

ports/atmel-samd/common-hal/audioio/AudioOut.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ static void ramp_value(uint16_t start, uint16_t end) {
7979
// Caller validates that pins are free.
8080
void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self,
8181
const mcu_pin_obj_t *left_channel, const mcu_pin_obj_t *right_channel, uint16_t quiescent_value) {
82+
83+
// The case of left_channel == right_channel is already disallowed in shared-bindings.
84+
8285
#ifdef SAM_D5X_E5X
8386
bool dac_clock_enabled = hri_mclk_get_APBDMASK_DAC_bit(MCLK);
8487
#endif
@@ -107,10 +110,6 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self,
107110
if (right_channel != NULL && right_channel != &pin_PA02 && right_channel != &pin_PA05) {
108111
raise_ValueError_invalid_pin_name(MP_QSTR_right_channel);
109112
}
110-
if (right_channel == left_channel) {
111-
mp_raise_ValueError_varg(MP_ERROR_TEXT("%q and %q must be different"),
112-
MP_QSTR_left_channel, MP_QSTR_right_channel);
113-
}
114113
claim_pin(left_channel);
115114
if (right_channel != NULL) {
116115
claim_pin(right_channel);

ports/espressif/common-hal/audioio/AudioOut.c

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
#include "driver/dac_continuous.h"
1313

14-
1514
#if defined(CONFIG_IDF_TARGET_ESP32)
1615
#define pin_CHANNEL_0 pin_GPIO25
1716
#define pin_CHANNEL_1 pin_GPIO26
@@ -304,6 +303,32 @@ static audioout_sample_convert_func_t audioout_get_samples_convert_func(
304303
}
305304
}
306305

306+
static void audioio_audioout_start(audioio_audioout_obj_t *self) {
307+
esp_err_t ret;
308+
309+
self->playing = true;
310+
self->paused = false;
311+
312+
ret = dac_continuous_start_async_writing(self->handle);
313+
if (ret != ESP_OK) {
314+
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to start async audio"));
315+
}
316+
}
317+
318+
static void audioio_audioout_stop(audioio_audioout_obj_t *self, bool full_stop) {
319+
dac_continuous_stop_async_writing(self->handle);
320+
if (full_stop) {
321+
self->get_buffer_index = 0;
322+
self->put_buffer_index = 0;
323+
self->sample_buffer = NULL;
324+
self->sample = NULL;
325+
self->playing = false;
326+
self->paused = false;
327+
} else {
328+
self->paused = true;
329+
}
330+
}
331+
307332
static bool audioout_fill_buffer(audioio_audioout_obj_t *self) {
308333
if (!self->playing) {
309334
return false;
@@ -342,7 +367,7 @@ static bool audioout_fill_buffer(audioio_audioout_obj_t *self) {
342367
&raw_sample_buf, &raw_sample_buf_size);
343368

344369
if (get_buffer_result == GET_BUFFER_ERROR) {
345-
common_hal_audioio_audioout_stop(self);
370+
audioio_audioout_stop(self, true);
346371
return false;
347372
}
348373

@@ -390,7 +415,7 @@ static bool audioout_fill_buffer(audioio_audioout_obj_t *self) {
390415
} else {
391416
// TODO: figure out if it is ok to call this here or do we need
392417
// to somehow wait for all of the samples to be flushed
393-
common_hal_audioio_audioout_stop(self);
418+
audioio_audioout_stop(self, true);
394419
return false;
395420
}
396421
}
@@ -492,24 +517,15 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self,
492517
self->paused = false;
493518
self->freq_hz = DEFAULT_SAMPLE_RATE;
494519

495-
/* espressif has two dac channels and it can support true stereo or
496-
* outputting the same signal to both channels (dual mono).
497-
* if different pins are supplied for left and right then use true stereo.
498-
* if the same pin is supplied for left and right then use dual mono.
499-
*/
520+
// The case of left_channel == right_channel is already disallowed in shared-bindings.
521+
500522
if ((left_channel_pin == &pin_CHANNEL_0 &&
501523
right_channel_pin == &pin_CHANNEL_1) ||
502524
(left_channel_pin == &pin_CHANNEL_1 &&
503525
right_channel_pin == &pin_CHANNEL_0)) {
504526
self->channel_mask = DAC_CHANNEL_MASK_ALL;
505527
self->num_channels = 2;
506528
self->channel_mode = DAC_CHANNEL_MODE_ALTER;
507-
} else if ((left_channel_pin == &pin_CHANNEL_0 ||
508-
left_channel_pin == &pin_CHANNEL_1) &&
509-
right_channel_pin == left_channel_pin) {
510-
self->channel_mask = DAC_CHANNEL_MASK_ALL;
511-
self->num_channels = 1;
512-
self->channel_mode = DAC_CHANNEL_MODE_SIMUL;
513529
} else if (left_channel_pin == &pin_CHANNEL_0 &&
514530
right_channel_pin == NULL) {
515531
self->channel_mask = DAC_CHANNEL_MASK_CH0;
@@ -550,32 +566,6 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) {
550566
_active_handle = NULL;
551567
}
552568

553-
static void audioio_audioout_start(audioio_audioout_obj_t *self) {
554-
esp_err_t ret;
555-
556-
self->playing = true;
557-
self->paused = false;
558-
559-
ret = dac_continuous_start_async_writing(self->handle);
560-
if (ret != ESP_OK) {
561-
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to start async audio"));
562-
}
563-
}
564-
565-
static void audioio_audioout_stop(audioio_audioout_obj_t *self, bool full_stop) {
566-
dac_continuous_stop_async_writing(self->handle);
567-
if (full_stop) {
568-
self->get_buffer_index = 0;
569-
self->put_buffer_index = 0;
570-
self->sample_buffer = NULL;
571-
self->sample = NULL;
572-
self->playing = false;
573-
self->paused = false;
574-
} else {
575-
self->paused = true;
576-
}
577-
}
578-
579569
void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
580570
mp_obj_t sample, bool loop) {
581571

@@ -597,7 +587,11 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
597587
self->looping = loop;
598588
freq_hz = audiosample_get_sample_rate(self->sample);
599589

600-
if (freq_hz != self->freq_hz) {
590+
// Workaround: always reset the DAC completely between plays,
591+
// due to a bug that causes the left and right channels to be swapped randomly.
592+
// See https://github.com/espressif/esp-idf/issues/11425
593+
// TODO: Remove the `true` when this issue is fixed.
594+
if (true || freq_hz != self->freq_hz) {
601595
common_hal_audioio_audioout_deinit(self);
602596
self->freq_hz = freq_hz;
603597
audioout_init(self);

shared-bindings/audioio/AudioOut.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@
2828
//| """Create a AudioOut object associated with the given pin(s). This allows you to
2929
//| play audio signals out on the given pin(s).
3030
//|
31-
//| :param ~microcontroller.Pin left_channel: The pin to output the left channel to
32-
//| :param ~microcontroller.Pin right_channel: The pin to output the right channel to
31+
//| :param ~microcontroller.Pin left_channel: Output left channel data to this pin
32+
//| :param ~microcontroller.Pin right_channel: Output right channel data to this pin. May be ``None``.
3333
//| :param int quiescent_value: The output value when no signal is present. Samples should start
3434
//| and end with this value to prevent audible popping.
3535
//|
36+
//| .. note:: On ESP32 and ESP32-S2, the DAC channels are usually designated
37+
//| as ``DAC_1`` (right stereo channel) and DAC_2 (left stereo channel).
38+
//| These pins are sometimes labelled as ``A0`` and ``A1``, but they may be assigned
39+
//| in either order. Check your board's pinout to verify which pin is which channel.
40+
//|
3641
//| Simple 8ksps 440 Hz sin wave::
3742
//|
3843
//| import audiocore
@@ -90,6 +95,12 @@ static mp_obj_t audioio_audioout_make_new(const mp_obj_type_t *type, size_t n_ar
9095
const mcu_pin_obj_t *right_channel_pin =
9196
validate_obj_is_free_pin_or_none(args[ARG_right_channel].u_obj, MP_QSTR_right_channel);
9297

98+
// Can't use the same pin for both left and right channels.
99+
if (left_channel_pin == right_channel_pin) {
100+
mp_raise_ValueError_varg(MP_ERROR_TEXT("%q and %q must be different"),
101+
MP_QSTR_left_channel, MP_QSTR_right_channel);
102+
}
103+
93104
// create AudioOut object from the given pin
94105
audioio_audioout_obj_t *self = mp_obj_malloc_with_finaliser(audioio_audioout_obj_t, &audioio_audioout_type);
95106
common_hal_audioio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy