Skip to content

Commit 30a9346

Browse files
committed
samd: audio_dma: Track channel allocation
Previously, we depended on allocated channels to always be "dma_channel_enabled". However, (A) sometimes, many operations would take place between find_free_audio_dma_channel and audio_dma_enable_channel, and (B) some debugging I did led me to believe that "dma_channel_enabled" would become false when the hardware ended a scheduled DMA transaction, but while a CP object would still think it owned the DMA channel. ((B) is not documented in the datasheet and I am not 100% convinced that my debugging session was not simply missing where we were disabling the channel, but in either case, it shows a need to directly track allocated separately from enabled) Therefore, * Add audio_dma_{allocate,free}_channel. * audio_dma_free_channel implies audio_dma_disable_channel * track via a new array audio_dma_allocated[] * clear all allocated flags on soft-reboot * Convert find_free_audio_dma_channel to audio_dma_allocate_channel * use audio_dma_allocated[] instead of dma_channel_enabled() to check availability * remove find_free_audio_dma_channel * For each one, find a matching audio_dma_disable_channel to convert to audio_dma_free_channel Closes: adafruit#2058
1 parent 0b00787 commit 30a9346

File tree

3 files changed

+20
-7
lines changed

3 files changed

+20
-7
lines changed

ports/atmel-samd/audio_dma.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,24 @@ static audio_dma_t* audio_dma_state[AUDIO_DMA_CHANNEL_COUNT];
4242
// This cannot be in audio_dma_state because it's volatile.
4343
static volatile bool audio_dma_pending[AUDIO_DMA_CHANNEL_COUNT];
4444

45-
uint8_t find_free_audio_dma_channel(void) {
45+
static bool audio_dma_allocated[AUDIO_DMA_CHANNEL_COUNT];
46+
47+
uint8_t audio_dma_allocate_channel(void) {
4648
uint8_t channel;
4749
for (channel = 0; channel < AUDIO_DMA_CHANNEL_COUNT; channel++) {
48-
if (!dma_channel_enabled(channel)) {
50+
if (!audio_dma_allocated[channel]) {
51+
audio_dma_allocated[channel] = true;
4952
return channel;
5053
}
5154
}
52-
return channel;
55+
return channel; // i.e., return failure
56+
}
57+
58+
void audio_dma_free_channel(uint8_t channel) {
59+
assert(channel < AUDIO_DMA_CHANNEL_COUNT);
60+
assert(audio_dma_allocated[channel]);
61+
audio_dma_disable_channel(channel);
62+
audio_dma_allocated[channel] = false;
5363
}
5464

5565
void audio_dma_disable_channel(uint8_t channel) {
@@ -167,7 +177,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
167177
bool output_signed,
168178
uint32_t output_register_address,
169179
uint8_t dma_trigger_source) {
170-
uint8_t dma_channel = find_free_audio_dma_channel();
180+
uint8_t dma_channel = audio_dma_allocate_channel();
171181
if (dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
172182
return AUDIO_DMA_DMA_BUSY;
173183
}
@@ -278,6 +288,7 @@ void audio_dma_stop(audio_dma_t* dma) {
278288
disable_event_channel(dma->event_channel);
279289
MP_STATE_PORT(playing_audio)[channel] = NULL;
280290
audio_dma_state[channel] = NULL;
291+
audio_dma_free_channel(dma->dma_channel);
281292
}
282293
dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT;
283294
}
@@ -307,6 +318,7 @@ void audio_dma_reset(void) {
307318
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
308319
audio_dma_state[i] = NULL;
309320
audio_dma_pending[i] = false;
321+
audio_dma_allocated[i] = false;
310322
audio_dma_disable_channel(i);
311323
dma_descriptor(i)->BTCTRL.bit.VALID = false;
312324
MP_STATE_PORT(playing_audio)[i] = NULL;

ports/atmel-samd/audio_dma.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ uint8_t audiosample_channel_count(mp_obj_t sample_obj);
6464
void audio_dma_init(audio_dma_t* dma);
6565
void audio_dma_reset(void);
6666

67-
uint8_t find_free_audio_dma_channel(void);
67+
uint8_t audio_dma_allocate_channel(void);
68+
void audio_dma_free_channel(uint8_t channel);
6869

6970
// This sets everything up but doesn't start the timer.
7071
// Sample is the python object for the sample to play.

ports/atmel-samd/common-hal/audiobusio/PDMIn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) {
355355
// output_buffer_length is the number of slots, not the number of bytes.
356356
uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self,
357357
uint16_t* output_buffer, uint32_t output_buffer_length) {
358-
uint8_t dma_channel = find_free_audio_dma_channel();
358+
uint8_t dma_channel = audio_dma_allocate_channel();
359359
uint8_t event_channel = find_sync_event_channel();
360360
if (event_channel >= EVSYS_SYNCH_NUM) {
361361
mp_raise_RuntimeError(translate("All sync event channels in use"));
@@ -464,7 +464,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
464464
}
465465

466466
disable_event_channel(event_channel);
467-
audio_dma_disable_channel(dma_channel);
467+
audio_dma_free_channel(dma_channel);
468468
// Turn off serializer, but leave clock on, to avoid mic startup delay.
469469
i2s_set_serializer_enable(self->serializer, false);
470470

0 commit comments

Comments
 (0)