@@ -165,7 +165,9 @@ static void audio_dma_load_next_block(audio_dma_t *dma, size_t buffer_idx) {
165165 }
166166 }
167167 // Enable the channel so that it can be played.
168- dma_hw -> ch [dma_channel ].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS ;
168+ if (!dma -> paused ) {
169+ dma_hw -> ch [dma_channel ].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS ;
170+ }
169171 dma -> dma_result = AUDIO_DMA_OK ;
170172}
171173
@@ -301,6 +303,8 @@ audio_dma_result audio_dma_setup_playback(
301303 MP_STATE_PORT (playing_audio )[dma -> channel [0 ]] = dma ;
302304 MP_STATE_PORT (playing_audio )[dma -> channel [1 ]] = dma ;
303305
306+ dma -> paused = false;
307+
304308 // Load the first two blocks up front.
305309 audio_dma_load_next_block (dma , 0 );
306310 if (dma -> dma_result != AUDIO_DMA_OK ) {
@@ -331,6 +335,8 @@ audio_dma_result audio_dma_setup_playback(
331335 1 , // transaction count
332336 false); // trigger
333337 } else {
338+ // Clear any latent interrupts so that we don't immediately disable channels.
339+ dma_hw -> ints0 |= (1 << dma -> channel [0 ]) | (1 << dma -> channel [1 ]);
334340 // Enable our DMA channels on DMA_IRQ_0 to the CPU. This will wake us up when
335341 // we're WFI.
336342 dma_hw -> inte0 |= (1 << dma -> channel [0 ]) | (1 << dma -> channel [1 ]);
@@ -344,6 +350,8 @@ audio_dma_result audio_dma_setup_playback(
344350}
345351
346352void audio_dma_stop (audio_dma_t * dma ) {
353+ dma -> paused = true;
354+
347355 // Disable our interrupts.
348356 uint32_t channel_mask = 0 ;
349357 if (dma -> channel [0 ] < NUM_DMA_CHANNELS ) {
@@ -363,12 +371,13 @@ void audio_dma_stop(audio_dma_t *dma) {
363371
364372 for (size_t i = 0 ; i < 2 ; i ++ ) {
365373 size_t channel = dma -> channel [i ];
374+ dma -> channel [i ] = NUM_DMA_CHANNELS ;
366375 if (channel == NUM_DMA_CHANNELS ) {
367376 // Channel not in use.
368377 continue ;
369378 }
370379
371- dma_channel_config c = dma_channel_get_default_config (dma -> channel [ i ] );
380+ dma_channel_config c = dma_channel_get_default_config (channel );
372381 channel_config_set_enable (& c , false);
373382 dma_channel_set_config (channel , & c , false /* trigger */ );
374383
@@ -381,7 +390,6 @@ void audio_dma_stop(audio_dma_t *dma) {
381390 dma_channel_set_trans_count (channel , 0 , false /* trigger */ );
382391 dma_channel_unclaim (channel );
383392 MP_STATE_PORT (playing_audio )[channel ] = NULL ;
384- dma -> channel [i ] = NUM_DMA_CHANNELS ;
385393 }
386394 dma -> playing_in_progress = false;
387395
@@ -393,6 +401,7 @@ void audio_dma_stop(audio_dma_t *dma) {
393401void audio_dma_pause (audio_dma_t * dma ) {
394402 dma_hw -> ch [dma -> channel [0 ]].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS ;
395403 dma_hw -> ch [dma -> channel [1 ]].al1_ctrl &= ~DMA_CH1_CTRL_TRIG_EN_BITS ;
404+ dma -> paused = true;
396405}
397406
398407void audio_dma_resume (audio_dma_t * dma ) {
@@ -405,15 +414,14 @@ void audio_dma_resume(audio_dma_t *dma) {
405414 dma_hw -> ch [dma -> channel [0 ]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS ;
406415 dma_hw -> ch [dma -> channel [1 ]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS ;
407416 }
417+ dma -> paused = false;
408418}
409419
410420bool audio_dma_get_paused (audio_dma_t * dma ) {
411421 if (dma -> channel [0 ] >= NUM_DMA_CHANNELS ) {
412422 return false;
413423 }
414- uint32_t control = dma_hw -> ch [dma -> channel [0 ]].ctrl_trig ;
415-
416- return (control & DMA_CH0_CTRL_TRIG_EN_BITS ) == 0 ;
424+ return dma -> playing_in_progress && dma -> paused ;
417425}
418426
419427uint32_t audio_dma_pause_all (void ) {
@@ -446,6 +454,9 @@ void audio_dma_init(audio_dma_t *dma) {
446454
447455 dma -> channel [0 ] = NUM_DMA_CHANNELS ;
448456 dma -> channel [1 ] = NUM_DMA_CHANNELS ;
457+
458+ dma -> playing_in_progress = false;
459+ dma -> paused = false;
449460}
450461
451462void audio_dma_deinit (audio_dma_t * dma ) {
@@ -486,37 +497,38 @@ bool audio_dma_get_playing(audio_dma_t *dma) {
486497// NOTE(dhalbert): I successfully printed from here while debugging.
487498// So it's possible, but be careful.
488499static void dma_callback_fun (void * arg ) {
500+ // Any audio interrupts that happen below will requeue the background task
501+ // after updating channels_to_load_mask.
489502 audio_dma_t * dma = arg ;
490503 if (dma == NULL ) {
491504 return ;
492505 }
493506
494507 common_hal_mcu_disable_interrupts ();
495508 uint32_t channels_to_load_mask = dma -> channels_to_load_mask ;
509+ // This can be 0 if the background task was queued between the call to
510+ // dma_callback_fun and the above read of channels_to_load_mask.
496511 dma -> channels_to_load_mask = 0 ;
497512 common_hal_mcu_enable_interrupts ();
498513
499- // Load the blocks for the requested channels.
500- uint32_t channel = 0 ;
514+ uint8_t first_filled_channel = NUM_DMA_CHANNELS ;
501515 size_t filled_count = 0 ;
502- while (channels_to_load_mask ) {
503- if (channels_to_load_mask & 1 ) {
504- if (dma -> channel [0 ] == channel ) {
505- audio_dma_load_next_block (dma , 0 );
506- filled_count ++ ;
507- }
508- if (dma -> channel [1 ] == channel ) {
509- audio_dma_load_next_block (dma , 1 );
510- filled_count ++ ;
511- }
512- }
513- channels_to_load_mask >>= 1 ;
514- channel ++ ;
516+ if (dma -> channel [0 ] != NUM_DMA_CHANNELS && (channels_to_load_mask & (1 << dma -> channel [0 ]))) {
517+ audio_dma_load_next_block (dma , 0 );
518+ first_filled_channel = dma -> channel [0 ];
519+ filled_count ++ ;
515520 }
516- // If we had to fill both buffers, then we missed the trigger from the other
517- // buffer. So restart the DMA.
518- if (filled_count == 2 ) {
519- dma_channel_start (dma -> channel [0 ]);
521+ if (dma -> channel [1 ] != NUM_DMA_CHANNELS && (channels_to_load_mask & (1 << dma -> channel [1 ]))) {
522+ audio_dma_load_next_block (dma , 1 );
523+ first_filled_channel = dma -> channel [1 ];
524+ filled_count ++ ;
525+ }
526+
527+ // Restart if the other channel has been queued while we were filling the first or we filled two
528+ // now. (Two get filled if the second buffer completes while the first is waiting in the
529+ // background task queue.)
530+ if (first_filled_channel != NUM_DMA_CHANNELS && (dma -> channels_to_load_mask != 0 || filled_count == 2 )) {
531+ dma_channel_start (first_filled_channel );
520532 }
521533}
522534
@@ -537,6 +549,7 @@ void __not_in_flash_func(isr_dma_0)(void) {
537549 dma -> channels_to_load_mask |= mask ;
538550 // Disable the channel so that we don't play it without filling it.
539551 dma_hw -> ch [i ].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS ;
552+ // This is a noop if the callback is already queued.
540553 background_callback_add (& dma -> callback , dma_callback_fun , (void * )dma );
541554 }
542555 if (MP_STATE_PORT (background_pio_read )[i ] != NULL ) {
0 commit comments