Skip to content

Commit 840e94e

Browse files
committed
Fix starved audio on RP2
Switch to one control DMA channel and one data channel instead of using background tasks to reset the read address of the DMA. When the background task is starved, the DMA reads into other memory because readaddr isn't reset. So, use a control channel to toggle between the buffers by resetting the read address.
1 parent 6b95609 commit 840e94e

5 files changed

Lines changed: 131 additions & 108 deletions

File tree

ports/raspberrypi/audio_dma.c

Lines changed: 101 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ static size_t audio_dma_convert_samples(audio_dma_t *dma, uint8_t *input, uint32
118118

119119
// buffer_idx is 0 or 1.
120120
static void audio_dma_load_next_block(audio_dma_t *dma, size_t buffer_idx) {
121-
assert(dma->channel[buffer_idx] < NUM_DMA_CHANNELS);
122-
size_t dma_channel = dma->channel[buffer_idx];
121+
assert(dma->data_channel < NUM_DMA_CHANNELS);
123122

124123
audioio_get_buffer_result_t get_buffer_result;
125124
uint8_t *sample_buffer;
@@ -141,22 +140,20 @@ static void audio_dma_load_next_block(audio_dma_t *dma, size_t buffer_idx) {
141140
dma, sample_buffer, sample_buffer_length,
142141
dma->buffer[buffer_idx], dma->buffer_length[buffer_idx]);
143142

144-
dma_channel_set_read_addr(dma_channel, dma->buffer[buffer_idx], false /* trigger */);
145-
dma_channel_set_trans_count(dma_channel, output_length_used / dma->output_size, false /* trigger */);
143+
// We're setting this early. It gets loaded when the buffer we're filling is triggered.
144+
dma_channel_set_trans_count(dma->data_channel, output_length_used / dma->output_size, false /* trigger */);
146145

147146
if (get_buffer_result == GET_BUFFER_DONE) {
148147
if (dma->loop) {
149148
audiosample_reset_buffer(dma->sample, dma->single_channel_output, dma->audio_channel);
150149
} else {
151150
// Set channel trigger to ourselves so we don't keep going.
152-
dma_channel_hw_t *c = &dma_hw->ch[dma_channel];
151+
dma_channel_hw_t *c = &dma_hw->ch[dma->data_channel];
153152
c->al1_ctrl =
154153
(c->al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) |
155-
(dma_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
154+
(dma->data_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
156155

157-
if (output_length_used == 0 &&
158-
!dma_channel_is_busy(dma->channel[0]) &&
159-
!dma_channel_is_busy(dma->channel[1])) {
156+
if (output_length_used == 0 && !dma_channel_is_busy(dma->data_channel)) {
160157
// No data has been read, and both DMA channels have now finished, so it's safe to stop.
161158
audio_dma_stop(dma);
162159
}
@@ -180,19 +177,19 @@ audio_dma_result audio_dma_setup_playback(
180177

181178
// Use two DMA channels to play because the DMA can't wrap to itself without the
182179
// buffer being power of two aligned.
183-
int dma_channel_0_maybe = dma_claim_unused_channel(false);
184-
if (dma_channel_0_maybe < 0) {
180+
int control_channel_maybe = dma_claim_unused_channel(false);
181+
if (control_channel_maybe < 0) {
185182
return AUDIO_DMA_DMA_BUSY;
186183
}
187184

188-
int dma_channel_1_maybe = dma_claim_unused_channel(false);
189-
if (dma_channel_1_maybe < 0) {
190-
dma_channel_unclaim((uint)dma_channel_0_maybe);
185+
int data_channel_maybe = dma_claim_unused_channel(false);
186+
if (data_channel_maybe < 0) {
187+
dma_channel_unclaim((uint)control_channel_maybe);
191188
return AUDIO_DMA_DMA_BUSY;
192189
}
193190

194-
dma->channel[0] = (uint8_t)dma_channel_0_maybe;
195-
dma->channel[1] = (uint8_t)dma_channel_1_maybe;
191+
dma->control_channel = (uint8_t)control_channel_maybe;
192+
dma->data_channel = (uint8_t)data_channel_maybe;
196193

197194
dma->sample = sample;
198195
dma->loop = loop;
@@ -262,24 +259,20 @@ audio_dma_result audio_dma_setup_playback(
262259
dma_size = DMA_SIZE_32;
263260
}
264261

265-
for (size_t i = 0; i < 2; i++) {
266-
dma_channel_config c = dma_channel_get_default_config(dma->channel[i]);
267-
channel_config_set_transfer_data_size(&c, dma_size);
268-
channel_config_set_dreq(&c, dma_trigger_source);
269-
channel_config_set_read_increment(&c, true);
270-
channel_config_set_write_increment(&c, false);
262+
// Setup the data channel
263+
dma_channel_config c = dma_channel_get_default_config(dma->data_channel);
264+
channel_config_set_transfer_data_size(&c, dma_size);
265+
channel_config_set_dreq(&c, dma_trigger_source);
266+
channel_config_set_read_increment(&c, true);
267+
channel_config_set_write_increment(&c, false);
271268

272-
// Chain to the other channel by default.
273-
channel_config_set_chain_to(&c, dma->channel[(i + 1) % 2]);
274-
dma_channel_set_config(dma->channel[i], &c, false /* trigger */);
275-
276-
dma_channel_set_write_addr(dma->channel[i], (void *)output_register_address, false /* trigger */);
277-
}
269+
channel_config_set_chain_to(&c, dma->control_channel);
270+
dma_channel_set_config(dma->data_channel, &c, false /* trigger */);
271+
dma_channel_set_write_addr(dma->data_channel, (void *)output_register_address, false /* trigger */);
278272

279273
// We keep the audio_dma_t for internal use and the sample as a root pointer because it
280274
// contains the audiodma structure.
281-
MP_STATE_PORT(playing_audio)[dma->channel[0]] = dma;
282-
MP_STATE_PORT(playing_audio)[dma->channel[1]] = dma;
275+
MP_STATE_PORT(playing_audio)[dma->data_channel] = dma;
283276

284277
// Load the first two blocks up front.
285278
audio_dma_load_next_block(dma, 0);
@@ -293,44 +286,49 @@ audio_dma_result audio_dma_setup_playback(
293286
}
294287
}
295288

289+
c = dma_channel_get_default_config(dma->control_channel);
290+
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
291+
channel_config_set_dreq(&c, 0x3f); // dma as fast as possible
292+
channel_config_set_read_increment(&c, true);
293+
channel_config_set_write_increment(&c, false);
294+
if (single_buffer) {
295+
// Wrap every 4 bytes, aka one word/transaction.
296+
channel_config_set_ring(&c, false, 2);
297+
} else {
298+
// Wrap every 16 bytes, aka two words/transactions.
299+
channel_config_set_ring(&c, false, 3);
300+
}
301+
channel_config_set_chain_to(&c, dma->control_channel); // Chain to ourselves so we stop.
302+
dma_channel_configure(dma->control_channel, &c,
303+
&dma_hw->ch[dma->data_channel].al3_read_addr_trig, // write address
304+
dma->buffer, // read address
305+
1, // transaction count
306+
false); // trigger
307+
296308
// Special case the DMA for a single buffer. It's commonly used for a single wave length of sound
297309
// and may be short. Therefore, we use DMA chaining to loop quickly without involving interrupts.
298310
// On the RP2040 we chain by having a second DMA writing to the config registers of the first.
299311
// Read and write addresses change with DMA so we need to reset the read address back to the
300312
// start of the sample.
301-
if (single_buffer) {
302-
dma_channel_config c = dma_channel_get_default_config(dma->channel[1]);
303-
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
304-
channel_config_set_dreq(&c, 0x3f); // dma as fast as possible
305-
channel_config_set_read_increment(&c, false);
306-
channel_config_set_write_increment(&c, false);
307-
channel_config_set_chain_to(&c, dma->channel[1]); // Chain to ourselves so we stop.
308-
dma_channel_configure(dma->channel[1], &c,
309-
&dma_hw->ch[dma->channel[0]].al3_read_addr_trig, // write address
310-
&dma->buffer[0], // read address
311-
1, // transaction count
312-
false); // trigger
313-
} else {
313+
if (!single_buffer) {
314314
// Enable our DMA channels on DMA_IRQ_0 to the CPU. This will wake us up when
315315
// we're WFI.
316-
dma_hw->inte0 |= (1 << dma->channel[0]) | (1 << dma->channel[1]);
316+
dma_hw->inte0 |= 1 << dma->data_channel;
317317
irq_set_mask_enabled(1 << DMA_IRQ_0, true);
318318
}
319319

320320
dma->playing_in_progress = true;
321-
dma_channel_start(dma->channel[0]);
321+
dma->next_buffer = 0;
322+
dma_channel_start(dma->control_channel);
322323

323324
return AUDIO_DMA_OK;
324325
}
325326

326327
void audio_dma_stop(audio_dma_t *dma) {
327328
// Disable our interrupts.
328329
uint32_t channel_mask = 0;
329-
if (dma->channel[0] < NUM_DMA_CHANNELS) {
330-
channel_mask |= 1 << dma->channel[0];
331-
}
332-
if (dma->channel[1] < NUM_DMA_CHANNELS) {
333-
channel_mask |= 1 << dma->channel[1];
330+
if (dma->data_channel < NUM_DMA_CHANNELS) {
331+
channel_mask |= 1 << dma->data_channel;
334332
}
335333
dma_hw->inte0 &= ~channel_mask;
336334
if (!dma_hw->inte0) {
@@ -341,57 +339,51 @@ void audio_dma_stop(audio_dma_t *dma) {
341339
// playing_audio.
342340
RUN_BACKGROUND_TASKS;
343341

344-
for (size_t i = 0; i < 2; i++) {
345-
size_t channel = dma->channel[i];
346-
if (channel == NUM_DMA_CHANNELS) {
347-
// Channel not in use.
348-
continue;
349-
}
342+
dma_channel_config c = dma_channel_get_default_config(dma->data_channel);
343+
channel_config_set_enable(&c, false);
344+
dma_channel_set_config(dma->data_channel, &c, false /* trigger */);
345+
dma_channel_set_config(dma->control_channel, &c, false /* trigger */);
346+
347+
if (dma_channel_is_busy(dma->data_channel)) {
348+
dma_channel_abort(dma->data_channel);
349+
}
350+
if (dma_channel_is_busy(dma->control_channel)) {
351+
dma_channel_abort(dma->control_channel);
352+
}
350353

351-
dma_channel_config c = dma_channel_get_default_config(dma->channel[i]);
352-
channel_config_set_enable(&c, false);
353-
dma_channel_set_config(channel, &c, false /* trigger */);
354+
dma_channel_set_read_addr(dma->data_channel, NULL, false /* trigger */);
355+
dma_channel_set_write_addr(dma->data_channel, NULL, false /* trigger */);
356+
dma_channel_set_trans_count(dma->data_channel, 0, false /* trigger */);
357+
dma_channel_unclaim(dma->data_channel);
354358

355-
if (dma_channel_is_busy(channel)) {
356-
dma_channel_abort(channel);
357-
}
359+
dma_channel_set_read_addr(dma->control_channel, NULL, false /* trigger */);
360+
dma_channel_set_write_addr(dma->control_channel, NULL, false /* trigger */);
361+
dma_channel_set_trans_count(dma->control_channel, 0, false /* trigger */);
362+
dma_channel_unclaim(dma->control_channel);
358363

359-
dma_channel_set_read_addr(channel, NULL, false /* trigger */);
360-
dma_channel_set_write_addr(channel, NULL, false /* trigger */);
361-
dma_channel_set_trans_count(channel, 0, false /* trigger */);
362-
dma_channel_unclaim(channel);
363-
MP_STATE_PORT(playing_audio)[channel] = NULL;
364-
dma->channel[i] = NUM_DMA_CHANNELS;
365-
}
364+
MP_STATE_PORT(playing_audio)[dma->data_channel] = NULL;
365+
dma->data_channel = NUM_DMA_CHANNELS;
366+
dma->control_channel = NUM_DMA_CHANNELS;
366367
dma->playing_in_progress = false;
367368

368369
// Hold onto our buffers.
369370
}
370371

371-
// To pause we simply stop the DMA. It is the responsibility of the output peripheral
372-
// to hold the previous value.
372+
// To pause we simply stop the data DMA channel. It is the responsibility of the
373+
// output peripheral to hold the previous value.
373374
void audio_dma_pause(audio_dma_t *dma) {
374-
dma_hw->ch[dma->channel[0]].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
375-
dma_hw->ch[dma->channel[1]].al1_ctrl &= ~DMA_CH1_CTRL_TRIG_EN_BITS;
375+
dma_hw->ch[dma->data_channel].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS;
376376
}
377377

378378
void audio_dma_resume(audio_dma_t *dma) {
379-
// Always re-enable the non-busy channel first so it's ready to continue when the busy channel
380-
// finishes and chains to it. (An interrupt could make the time between enables long.)
381-
if (dma_channel_is_busy(dma->channel[0])) {
382-
dma_hw->ch[dma->channel[1]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS;
383-
dma_hw->ch[dma->channel[0]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
384-
} else {
385-
dma_hw->ch[dma->channel[0]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
386-
dma_hw->ch[dma->channel[1]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS;
387-
}
379+
dma_hw->ch[dma->data_channel].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS;
388380
}
389381

390382
bool audio_dma_get_paused(audio_dma_t *dma) {
391-
if (dma->channel[0] >= NUM_DMA_CHANNELS) {
383+
if (dma->data_channel >= NUM_DMA_CHANNELS) {
392384
return false;
393385
}
394-
uint32_t control = dma_hw->ch[dma->channel[0]].ctrl_trig;
386+
uint32_t control = dma_hw->ch[dma->data_channel].ctrl_trig;
395387

396388
return (control & DMA_CH0_CTRL_TRIG_EN_BITS) == 0;
397389
}
@@ -418,14 +410,24 @@ void audio_dma_unpause_mask(uint32_t channel_mask) {
418410
}
419411

420412
void audio_dma_init(audio_dma_t *dma) {
413+
// We allocate four pointers worth so that we can align to a 8 byte boundary.
414+
dma->read_addr_buffer = port_malloc(4 * sizeof(uint32_t *), true);
415+
mp_printf(&mp_plat_print, "read_addr_buffer: %p\n", dma->read_addr_buffer);
416+
if ((size_t)dma->read_addr_buffer % 8 == 4) {
417+
// Pointer math! So, + 1 is + sizeof(uint32_t *).
418+
dma->buffer = dma->read_addr_buffer + 1;
419+
} else {
420+
dma->buffer = dma->read_addr_buffer;
421+
}
422+
mp_printf(&mp_plat_print, "buffer: %p\n", dma->buffer);
421423
dma->buffer[0] = NULL;
422424
dma->buffer[1] = NULL;
423425

424426
dma->buffer_length[0] = 0;
425427
dma->buffer_length[1] = 0;
426428

427-
dma->channel[0] = NUM_DMA_CHANNELS;
428-
dma->channel[1] = NUM_DMA_CHANNELS;
429+
dma->data_channel = NUM_DMA_CHANNELS;
430+
dma->control_channel = NUM_DMA_CHANNELS;
429431
}
430432

431433
void audio_dma_deinit(audio_dma_t *dma) {
@@ -436,10 +438,14 @@ void audio_dma_deinit(audio_dma_t *dma) {
436438
port_free(dma->buffer[1]);
437439
dma->buffer[1] = NULL;
438440
dma->buffer_length[1] = 0;
441+
442+
port_free(dma->read_addr_buffer);
443+
dma->read_addr_buffer = NULL;
444+
dma->buffer = NULL;
439445
}
440446

441447
bool audio_dma_get_playing(audio_dma_t *dma) {
442-
if (dma->channel[0] == NUM_DMA_CHANNELS) {
448+
if (dma->data_channel == NUM_DMA_CHANNELS) {
443449
return false;
444450
}
445451
return dma->playing_in_progress;
@@ -455,25 +461,13 @@ static void dma_callback_fun(void *arg) {
455461
return;
456462
}
457463

464+
gpio_put(6, true);
458465
common_hal_mcu_disable_interrupts();
459-
uint32_t channels_to_load_mask = dma->channels_to_load_mask;
460-
dma->channels_to_load_mask = 0;
466+
uint8_t next_buffer = dma->next_buffer;
461467
common_hal_mcu_enable_interrupts();
462468

463-
// Load the blocks for the requested channels.
464-
uint32_t channel = 0;
465-
while (channels_to_load_mask) {
466-
if (channels_to_load_mask & 1) {
467-
if (dma->channel[0] == channel) {
468-
audio_dma_load_next_block(dma, 0);
469-
}
470-
if (dma->channel[1] == channel) {
471-
audio_dma_load_next_block(dma, 1);
472-
}
473-
}
474-
channels_to_load_mask >>= 1;
475-
channel++;
476-
}
469+
audio_dma_load_next_block(dma, next_buffer);
470+
gpio_put(6, false);
477471
}
478472

479473
void __not_in_flash_func(isr_dma_0)(void) {
@@ -488,10 +482,12 @@ void __not_in_flash_func(isr_dma_0)(void) {
488482
// affected PIO continuous write more than audio.
489483
dma_hw->ints0 = mask;
490484
if (MP_STATE_PORT(playing_audio)[i] != NULL) {
485+
gpio_put(45, true);
491486
audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i];
492-
// Record all channels whose DMA has completed; they need loading.
493-
dma->channels_to_load_mask |= mask;
487+
// Next buffer is the one we just completed playing and can now load.
488+
dma->next_buffer = dma->next_buffer % 2;
494489
background_callback_add(&dma->callback, dma_callback_fun, (void *)dma);
490+
gpio_put(45, false);
495491
}
496492
if (MP_STATE_PORT(background_pio_read)[i] != NULL) {
497493
rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio_read)[i];

ports/raspberrypi/audio_dma.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ typedef enum {
2020

2121
typedef struct {
2222
mp_obj_t sample;
23-
uint8_t *buffer[2]; // Allocated through port_malloc so they are dma-able
23+
uint8_t **read_addr_buffer;
24+
uint8_t **buffer; // Allocated through port_malloc so they are dma-able. 8 byte aligned pointer into read_addr_buffer
2425
size_t buffer_length[2];
25-
uint32_t channels_to_load_mask;
2626
uint32_t output_register_address;
2727
background_callback_t callback;
28-
uint8_t channel[2];
28+
uint8_t control_channel;
29+
uint8_t data_channel;
2930
uint8_t audio_channel;
31+
uint8_t next_buffer;
3032
uint8_t output_size;
3133
uint8_t sample_spacing;
3234
uint8_t output_resolution; // in bits

ports/raspberrypi/boards/adafruit_fruit_jam/board.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@
1717
#define I2S_RESET_PIN_NUMBER 22
1818

1919
bool board_reset_pin_number(uint8_t pin_number) {
20+
if (pin_number == 45) {
21+
return true;
22+
}
23+
if (pin_number == 6) {
24+
return true;
25+
}
26+
if (pin_number == 7) {
27+
return true;
28+
}
2029
#if defined(DEFAULT_USB_HOST_5V_POWER)
2130
if (pin_number == DEFAULT_USB_HOST_5V_POWER->number) {
2231
// doing this (rather than gpio_init) in this specific order ensures no

ports/raspberrypi/supervisor/port.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,18 @@ safe_mode_t port_init(void) {
398398
return SAFE_MODE_USER;
399399
}
400400

401+
gpio_init(6);
402+
gpio_put(6, false);
403+
gpio_set_dir(6, GPIO_OUT);
404+
405+
gpio_init(7);
406+
gpio_put(7, false);
407+
gpio_set_dir(7, GPIO_OUT);
408+
409+
gpio_init(45);
410+
gpio_put(45, false);
411+
gpio_set_dir(45, GPIO_OUT);
412+
401413
return SAFE_MODE_NONE;
402414
}
403415

0 commit comments

Comments
 (0)