@@ -165,7 +165,9 @@ static void audio_dma_load_next_block(audio_dma_t *dma, size_t buffer_idx) {
165
165
}
166
166
}
167
167
// 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
+ }
169
171
dma -> dma_result = AUDIO_DMA_OK ;
170
172
}
171
173
@@ -301,6 +303,8 @@ audio_dma_result audio_dma_setup_playback(
301
303
MP_STATE_PORT (playing_audio )[dma -> channel [0 ]] = dma ;
302
304
MP_STATE_PORT (playing_audio )[dma -> channel [1 ]] = dma ;
303
305
306
+ dma -> paused = false;
307
+
304
308
// Load the first two blocks up front.
305
309
audio_dma_load_next_block (dma , 0 );
306
310
if (dma -> dma_result != AUDIO_DMA_OK ) {
@@ -331,6 +335,8 @@ audio_dma_result audio_dma_setup_playback(
331
335
1 , // transaction count
332
336
false); // trigger
333
337
} 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 ]);
334
340
// Enable our DMA channels on DMA_IRQ_0 to the CPU. This will wake us up when
335
341
// we're WFI.
336
342
dma_hw -> inte0 |= (1 << dma -> channel [0 ]) | (1 << dma -> channel [1 ]);
@@ -344,6 +350,8 @@ audio_dma_result audio_dma_setup_playback(
344
350
}
345
351
346
352
void audio_dma_stop (audio_dma_t * dma ) {
353
+ dma -> paused = true;
354
+
347
355
// Disable our interrupts.
348
356
uint32_t channel_mask = 0 ;
349
357
if (dma -> channel [0 ] < NUM_DMA_CHANNELS ) {
@@ -363,12 +371,13 @@ void audio_dma_stop(audio_dma_t *dma) {
363
371
364
372
for (size_t i = 0 ; i < 2 ; i ++ ) {
365
373
size_t channel = dma -> channel [i ];
374
+ dma -> channel [i ] = NUM_DMA_CHANNELS ;
366
375
if (channel == NUM_DMA_CHANNELS ) {
367
376
// Channel not in use.
368
377
continue ;
369
378
}
370
379
371
- dma_channel_config c = dma_channel_get_default_config (dma -> channel [ i ] );
380
+ dma_channel_config c = dma_channel_get_default_config (channel );
372
381
channel_config_set_enable (& c , false);
373
382
dma_channel_set_config (channel , & c , false /* trigger */ );
374
383
@@ -381,7 +390,6 @@ void audio_dma_stop(audio_dma_t *dma) {
381
390
dma_channel_set_trans_count (channel , 0 , false /* trigger */ );
382
391
dma_channel_unclaim (channel );
383
392
MP_STATE_PORT (playing_audio )[channel ] = NULL ;
384
- dma -> channel [i ] = NUM_DMA_CHANNELS ;
385
393
}
386
394
dma -> playing_in_progress = false;
387
395
@@ -393,6 +401,7 @@ void audio_dma_stop(audio_dma_t *dma) {
393
401
void audio_dma_pause (audio_dma_t * dma ) {
394
402
dma_hw -> ch [dma -> channel [0 ]].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS ;
395
403
dma_hw -> ch [dma -> channel [1 ]].al1_ctrl &= ~DMA_CH1_CTRL_TRIG_EN_BITS ;
404
+ dma -> paused = true;
396
405
}
397
406
398
407
void audio_dma_resume (audio_dma_t * dma ) {
@@ -405,15 +414,14 @@ void audio_dma_resume(audio_dma_t *dma) {
405
414
dma_hw -> ch [dma -> channel [0 ]].al1_ctrl |= DMA_CH0_CTRL_TRIG_EN_BITS ;
406
415
dma_hw -> ch [dma -> channel [1 ]].al1_ctrl |= DMA_CH1_CTRL_TRIG_EN_BITS ;
407
416
}
417
+ dma -> paused = false;
408
418
}
409
419
410
420
bool audio_dma_get_paused (audio_dma_t * dma ) {
411
421
if (dma -> channel [0 ] >= NUM_DMA_CHANNELS ) {
412
422
return false;
413
423
}
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 ;
417
425
}
418
426
419
427
uint32_t audio_dma_pause_all (void ) {
@@ -446,6 +454,9 @@ void audio_dma_init(audio_dma_t *dma) {
446
454
447
455
dma -> channel [0 ] = NUM_DMA_CHANNELS ;
448
456
dma -> channel [1 ] = NUM_DMA_CHANNELS ;
457
+
458
+ dma -> playing_in_progress = false;
459
+ dma -> paused = false;
449
460
}
450
461
451
462
void audio_dma_deinit (audio_dma_t * dma ) {
@@ -486,37 +497,38 @@ bool audio_dma_get_playing(audio_dma_t *dma) {
486
497
// NOTE(dhalbert): I successfully printed from here while debugging.
487
498
// So it's possible, but be careful.
488
499
static 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.
489
502
audio_dma_t * dma = arg ;
490
503
if (dma == NULL ) {
491
504
return ;
492
505
}
493
506
494
507
common_hal_mcu_disable_interrupts ();
495
508
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.
496
511
dma -> channels_to_load_mask = 0 ;
497
512
common_hal_mcu_enable_interrupts ();
498
513
499
- // Load the blocks for the requested channels.
500
- uint32_t channel = 0 ;
514
+ uint8_t first_filled_channel = NUM_DMA_CHANNELS ;
501
515
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 ++ ;
515
520
}
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 );
520
532
}
521
533
}
522
534
@@ -537,6 +549,7 @@ void __not_in_flash_func(isr_dma_0)(void) {
537
549
dma -> channels_to_load_mask |= mask ;
538
550
// Disable the channel so that we don't play it without filling it.
539
551
dma_hw -> ch [i ].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS ;
552
+ // This is a noop if the callback is already queued.
540
553
background_callback_add (& dma -> callback , dma_callback_fun , (void * )dma );
541
554
}
542
555
if (MP_STATE_PORT (background_pio_read )[i ] != NULL ) {
0 commit comments