8000 Merge pull request #4958 from dhalbert/rp2040-audio-fixes · domdfcoding/circuitpython@c37f354 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit c37f354

Browse files
authored
Merge pull request adafruit#4958 from dhalbert/rp2040-audio-fixes
RP2040 PWMAudioOut: Release DMA channels after play has finished
2 parents 9190436 + d886e80 commit c37f354

File tree

20 files changed

+95
-91
lines changed

20 files changed

+95
-91
lines changed

ports/atmel-samd/audio_dma.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
131131
uint8_t *buffer;
132132
uint32_t buffer_length;
133133
audioio_get_buffer_result_t get_buffer_result =
134-
audiosample_get_buffer(dma->sample, dma->single_channel, dma->audio_channel,
134+
audiosample_get_buffer(dma->sample, dma->single_channel_output, dma->audio_channel,
135135
&buffer, &buffer_length);
136136

137137
DmacDescriptor *descriptor = dma->second_descriptor;
@@ -155,7 +155,7 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
155155
descriptor->SRCADDR.reg = ((uint32_t)output_buffer) + output_buffer_length;
156156
if (get_buffer_result == GET_BUFFER_DONE) {
157157
if (dma->loop) {
158-
audiosample_reset_buffer(dma->sample, dma->single_channel, dma->audio_channel);
158+
audiosample_reset_buffer(dma->sample, dma->single_channel_output, dma->audio_channel);
159159
} else {
160160
descriptor->DESCADDR.reg = 0;
161161
}
@@ -183,7 +183,7 @@ static void setup_audio_descriptor(DmacDescriptor *descriptor, uint8_t beat_size
183183
audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
184184
mp_obj_t sample,
185185
bool loop,
186-
bool single_channel,
186+
bool single_channel_output,
187187
uint8_t audio_channel,
188188
bool output_signed,
189189
uint32_t output_register_address,
@@ -195,20 +195,20 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
195195

196196
dma->sample = sample;
197197
dma->loop = loop;
198-
dma->single_channel = single_channel;
198+
dma->single_channel_output = single_channel_output;
199199
dma->audio_channel = audio_channel;
200200
dma->dma_channel = dma_channel;
201201
dma->signed_to_unsigned = false;
202202
dma->unsigned_to_signed = false;
203203
dma->second_descriptor = NULL;
204204
dma->spacing = 1;
205205
dma->first_descriptor_free = true;
206-
audiosample_reset_buffer(sample, single_channel, audio_channel);
206+
audiosample_reset_buffer(sample, single_channel_output, audio_channel);
207207

208208
bool single_buffer;
209209
bool samples_signed;
210210
uint32_t max_buffer_length;
211-
audiosample_get_buffer_structure(sample, single_channel, &single_buffer, &samples_signed,
211+
audiosample_get_buffer_structure(sample, single_channel_output, &single_buffer, &samples_signed,
212212
&max_buffer_length, &dma->spacing);
213213
uint8_t output_spacing = dma->spacing;
214214
if (output_signed != samples_signed) {
@@ -254,12 +254,12 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
254254
} else {
255255
dma->beat_size = 1;
256256
dma->bytes_per_sample = 1;
257-
if (single_channel) {
257+
if (single_channel_output) {
258258
output_register_address += 1;
259259
}
260260
}
261261
// Transfer both channels at once.
262-
if (!single_channel && audiosample_channel_count(sample) == 2) {
262+
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
263263
dma->beat_size *= 2;
264264
}
265265

ports/atmel-samd/audio_dma.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ typedef struct {
4242
uint8_t beat_size;
4343
uint8_t spacing;
4444
bool loop;
45-
bool single_channel;
45+
bool single_channel_output;
4646
bool signed_to_unsigned;
4747
bool unsigned_to_signed;
4848
bool first_buffer_free;
@@ -72,16 +72,16 @@ void dma_free_channel(uint8_t channel);
7272
// This sets everything up but doesn't start the timer.
7373
// Sample is the python object for the sample to play.
7474
// loop is true if we should loop the sample.
75-
// single_channel is true if we only output a single channel. When false, all channels will be
75+
// single_channel_output is true if we only output a single channel. When false, all channels will be
7676
// output.
77-
// audio_channel is the index of the channel to dma. single_channel must be false in this case.
77+
// audio_channel is the index of the channel to dma. single_channel_output must be false in this case.
7878
// output_signed is true if the dma'd data should be signed. False and it will be unsigned.
7979
// output_register_address is the address to copy data to.
8080
// dma_trigger_source is the DMA trigger source which cause another copy
8181
audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
8282
mp_obj_t sample,
8383
bool loop,
84-
bool single_channel,
84+
bool single_channel_output,
8585
uint8_t audio_channel,
8686
bool output_signed,
8787
uint32_t output_register_address,

ports/atmel-samd/boards/meowmeow/mpconfigboard.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ USB_MANUFACTURER = "Electronic Cats"
66
CHIP_VARIANT = SAMD21G18A
77
CHIP_FAMILY = samd21
88

9+
CIRCUITPY_PWMIO = 0
10+
911
INTERNAL_FLASH_FILESYSTEM = 1
1012
LONGINT_IMPL = NONE
1113
CIRCUITPY_FULL_BUILD = 0

ports/raspberrypi/audio_dma.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
129129
uint8_t *buffer;
130130
uint32_t buffer_length;
131131
get_buffer_result = audiosample_get_buffer(dma->sample,
132-
dma->single_channel, dma->audio_channel, &buffer, &buffer_length);
132+
dma->single_channel_output, dma->audio_channel, &buffer, &buffer_length);
133133

134134
if (get_buffer_result == GET_BUFFER_ERROR) {
135135
audio_dma_stop(dma);
@@ -148,7 +148,7 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
148148
dma_channel_set_read_addr(dma_channel, output_buffer, false /* trigger */);
149149
if (get_buffer_result == GET_BUFFER_DONE) {
150150
if (dma->loop) {
151-
audiosample_reset_buffer(dma->sample, dma->single_channel, dma->audio_channel);
151+
audiosample_reset_buffer(dma->sample, dma->single_channel_output, dma->audio_channel);
152152
} else {
153153
// Set channel trigger to ourselves so we don't keep going.
154154
dma_channel_hw_t *c = &dma_hw->ch[dma_channel];
@@ -161,13 +161,13 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
161161
audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
162162
mp_obj_t sample,
163163
bool loop,
164-
bool single_channel,
164+
bool single_channel_output,
165165
uint8_t audio_channel,
166166
bool output_signed,
167167
uint8_t output_resolution,
168168
uint32_t output_register_address,
169169
uint8_t dma_trigger_source) {
170-
// Use two DMA channels to because the DMA can't wrap to itself without the
170+
// Use two DMA channels to play because the DMA can't wrap to itself without the
171171
// buffer being power of two aligned.
172172
dma->channel[0] = dma_claim_unused_channel(false);
173173
dma->channel[1] = dma_claim_unused_channel(false);
@@ -180,7 +180,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
180180

181181
dma->sample = sample;
182182
dma->loop = loop;
183-
dma->single_channel = single_channel;
183+
dma->single_channel_output = single_channel_output;
184184
dma->audio_channel = audio_channel;
185185
dma->signed_to_unsigned = false;
186186
dma->unsigned_to_signed = false;
@@ -189,12 +189,12 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
189189
dma->first_channel_free = true;
190190
dma->output_resolution = output_resolution;
191191
dma->sample_resolution = audiosample_bits_per_sample(sample);
192-
audiosample_reset_buffer(sample, single_channel, audio_channel);
192+
audiosample_reset_buffer(sample, single_channel_output, audio_channel);
193193

194194
bool single_buffer;
195195
bool samples_signed;
196196
uint32_t max_buffer_length;
197-
audiosample_get_buffer_structure(sample, single_channel, &single_buffer, &samples_signed,
197+
audiosample_get_buffer_structure(sample, single_channel_output, &single_buffer, &samples_signed,
198198
&max_buffer_length, &dma->sample_spacing);
199199

200200
// Check to see if we have to scale the resolution up.
@@ -227,10 +227,9 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
227227
dma->output_size = 1;
228228
}
229229
// Transfer both channels at once.
230-
if (!single_channel && audiosample_channel_count(sample) == 2) {
230+
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
231231
dma->output_size *= 2;
232232
}
233-
234233
enum dma_channel_transfer_size dma_size = DMA_SIZE_8;
235234
if (dma->output_size == 2) {
236235
dma_size = DMA_SIZE_16;
@@ -324,20 +323,19 @@ void audio_dma_stop(audio_dma_t *dma) {
324323
// to hold the previous value.
325324
void audio_dma_pause(audio_dma_t *dma) {
326325
dma_hw->ch[dma->channel[0]].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
327-
dma_hw->ch[dma->channel[1]].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
326+
dma_hw->ch[dma->channel[1]].al1_ctrl &= ~DMA_CH1_CTRL_TRIG_EN_BITS;
328327
}
329328

330329
void audio_dma_resume(audio_dma_t *dma) {
331330
// Always re-enable the non-busy channel first so it's ready to continue when the busy channel
332331
// finishes and chains to it. (An interrupt could make the time between enables long.)
333-
size_t first = 0;
334-
size_t second = 1;
335332
if (dma_channel_is_busy(dma->channel[0])) {
336-
first = 1;
337-
second = 0;
333+
dma_hw->ch[dma->channel[1]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS;
334+
dma_hw->ch[dma->channel[0]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
335+
} else {
336+
dma_hw->ch[dma->channel[0]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
337+
dma_hw->ch[dma->channel[1]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS;
338338
}
339-
dma_hw->ch[dma->channel[first]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
340-
dma_hw->ch[dma->channel[second]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
341339
}
342340

343341
bool audio_dma_get_paused(audio_dma_t *dma) {
@@ -378,6 +376,8 @@ bool audio_dma_get_playing(audio_dma_t *dma) {
378376

379377
// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
380378
// background tasks such as this and causes a stack overflow.
379+
// NOTE(dhalbert): I successfully printed from here while debugging.
380+
// So it's possible, but be careful.
381381
STATIC void dma_callback_fun(void *arg) {
382382
audio_dma_t *dma = arg;
383383
if (dma == NULL) {

ports/raspberrypi/audio_dma.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ typedef struct {
3939
uint8_t output_size;
4040
uint8_t sample_spacing;
4141
bool loop;
42-
bool single_channel;
42+
bool single_channel_output;
4343
bool signed_to_unsigned;
4444
bool unsigned_to_signed;
4545
bool output_signed;
@@ -66,16 +66,16 @@ void audio_dma_reset(void);
6666
// This sets everything up but doesn't start the timer.
6767
// Sample is the python object for the sample to play.
6868
// loop is true if we should loop the sample.
69-
// single_channel is true if we only output a single channel. When false, all channels will be
69+
// single_channel_output is true if we only output a single channel. When false, all channels will be
7070
// output.
71-
// audio_channel is the index of the channel to dma. single_channel must be false in this case.
71+
// audio_channel is the index of the channel to dma. single_channel_output must be false in this case.
7272
// output_signed is true if the dma'd data should be signed. False and it will be unsigned.
7373
// output_register_address is the address to copy data to.
7474
// dma_trigger_source is the DMA trigger source which cause another copy
7575
audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
7676
mp_obj_t sample,
7777
bool loop,
78-
bool single_channel,
78+
bool single_channel_output,
7979
uint8_t audio_channel,
8080
bool output_signed,
8181
uint8_t output_resolution,

ports/raspberrypi/common-hal/audiobusio/I2SOut.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
/*
23
* This file is part of the MicroPython project, http://micropython.org/
34
*
@@ -36,10 +37,10 @@
3637
// We don't bit pack because we'll only have two at most. Its better to save code size instead.
3738
typedef struct {
3839
mp_obj_base_t base;
39-
bool left_justified;
4040
rp2pio_statemachine_obj_t state_machine;
41-
bool playing;
4241
audio_dma_t dma;
42+
bool left_justified;
43+
bool playing;
4344
} audiobusio_i2sout_obj_t;
4445

4546
void i2sout_reset(void);

ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,6 @@ void common_hal_audiopwmio_pwmaudioout_construct(audiopwmio_pwmaudioout_obj_t *s
9696
mp_raise_RuntimeError(translate("All timers in use"));
9797
}
9898

99-
claim_pin(left_channel);
100-
if (right_channel != NULL) {
101-
claim_pin(right_channel);
102-
}
103-
10499
audio_dma_init(&self->dma);
105100
self->pacing_timer = NUM_DMA_TIMERS;
106101

@@ -220,7 +215,10 @@ bool common_hal_audiopwmio_pwmaudioout_get_playing(audiopwmio_pwmaudioout_obj_t
220215
if (!playing && self->pacing_timer < NUM_DMA_TIMERS) {
221216
dma_hw->timer[self->pacing_timer] = 0;
222217
self->pacing_timer = NUM_DMA_TIMERS;
218+
219+
audio_dma_stop(&self->dma);
223220
}
221+
224222
return playing;
225223
}
226224

ports/raspberrypi/common-hal/pwmio/PWMOut.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
163163
self->variable_frequency = variable_frequency;
164164
self->duty_cycle = duty;
165165

166+
claim_pin(pin);
167+
166168
if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) {
167169
return PWMOUT_INVALID_FREQUENCY;
168170
}

shared-module/audiocore/RawSample.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,31 +67,31 @@ uint8_t common_hal_audioio_rawsample_get_channel_count(audioio_rawsample_obj_t *
6767
}
6868

6969
void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t *self,
70-
bool single_channel,
70+
bool single_channel_output,
7171
uint8_t channel) {
7272
}
7373

7474
audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t *self,
75-
bool single_channel,
75+
bool single_channel_output,
7676
uint8_t channel,
7777
uint8_t **buffer,
7878
uint32_t *buffer_length) {
7979
*buffer_length = self->len;
80-
if (single_channel) {
80+
if (single_channel_output) {
8181
*buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8);
8282
} else {
8383
*buffer = self->buffer;
8484
}
8585
return GET_BUFFER_DONE;
8686
}
8787

88-
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel,
88+
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel_output,
8989
bool *single_buffer, bool *samples_signed,
9090
uint32_t *max_buffer_length, uint8_t *spacing) {
9191
*single_buffer = true;
9292
*samples_signed = self->samples_signed;
9393
*max_buffer_length = self->len;
94-
if (single_channel) {
94+
if (single_channel_output) {
9595
*spacing = self->channel_count;
9696
} else {
9797
*spacing = 1;

shared-module/audiocore/RawSample.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ typedef struct {
4444

4545
// These are not available from Python because it may be called in an interrupt.
4646
void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t *self,
47-
bool single_channel,
47+
bool single_channel_output,
4848
uint8_t channel);
4949
audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t *self,
50-
bool single_channel,
50+
bool single_channel_output,
5151
uint8_t channel,
5252
uint8_t **buffer,
5353
uint32_t *buffer_length); // length in bytes
54-
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel,
54+
void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel_output,
5555
bool *single_buffer, bool *samples_signed,
5656
uint32_t *max_buffer_length, uint8_t *spacing);
5757

shared-module/audiocore/WaveFile.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ uint32_t audioio_wavefile_max_buffer_length(audioio_wavefile_obj_t *self) {
169169
}
170170

171171
void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t *self,
172-
bool single_channel,
172+
bool single_channel_output,
173173
uint8_t channel) {
174-
if (single_channel && channel == 1) {
174+
if (single_channel_output && channel == 1) {
175175
return;
176176
}
177177
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
@@ -184,11 +184,11 @@ void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t *self,
184184
}
185185

186186
audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t *self,
187-
bool single_channel,
187+
bool single_channel_output,
188188
uint8_t channel,
189189
uint8_t **buffer,
190190
uint32_t *buffer_length) {
191-
if (!single_channel) {
191+
if (!single_channel_output) {
192192
channel = 0;
193193
}
194194

@@ -265,13 +265,14 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t *
265265
return self->bytes_remaining == 0 ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA;
266266
}
267267

268-
void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t *self, bool single_channel,
268+
void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t *self, bool single_channel_output,
269269
bool *single_buffer, bool *samples_signed,
270270
uint32_t *max_buffer_length, uint8_t *spacing) {
271271
*single_buffer = false;
272+
// In WAV files, 8-bit samples are always unsigned, and larger samples are always signed.
272273
*samples_signed = self->bits_per_sample > 8;
273274
*max_buffer_length = 512;
274-
if (single_channel) {
275+
if (single_channel_output) {
275276
*spacing = self->channel_count;
276277
} else {
277278
*spacing = 1;

0 commit comments

Comments
 (0)
0