From b4be2317cbe1c343f76494b72f11349e8ce073b3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 26 Jun 2023 10:33:41 -0500 Subject: [PATCH] rp2040: Avoid screeches due to audio underflow during flash writes By pausing audio during flash writes, the worst screeching of #8121 is avoided. I don't consider this a full fix, but it greatly improves the by far most common scenario in which the problem occurs. Tested on rp2040 prop feather with a midi synth playing arpeggios. When writing to the flash e.g., with ``` dd bs=512 count=32 if=/dev/zero of=/media/jepler/CIRCUITPY/boop ``` the audio goes "tap tap tap tap" during the flash write instead of the squawking. This isn't a 100% fix; it will still glitch out, including during USB enumeration which must be taking a long time without servicing background tasks. Add a delay if not usb-connected at startup ameliorates this greatly. --- ports/raspberrypi/audio_dma.c | 21 +++++++++++++++++++ ports/raspberrypi/audio_dma.h | 3 +++ ports/raspberrypi/supervisor/internal_flash.c | 4 ++++ 3 files changed, 28 insertions(+) diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index 612fbbde4c..3b7ef5ec44 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -388,6 +388,27 @@ bool audio_dma_get_paused(audio_dma_t *dma) { return (control & DMA_CH0_CTRL_TRIG_EN_BITS) == 0; } +uint32_t audio_dma_pause_all(void) { + uint32_t result = 0; + for (size_t channel = 0; channel < NUM_DMA_CHANNELS; channel++) { + audio_dma_t *dma = MP_STATE_PORT(playing_audio)[channel]; + if (dma != NULL && !audio_dma_get_paused(dma)) { + audio_dma_pause(dma); + result |= (1 << channel); + } + } + return result; +} + +void audio_dma_unpause_cookie(uint32_t cookie) { + for (size_t channel = 0; channel < NUM_DMA_CHANNELS; channel++) { + audio_dma_t *dma = MP_STATE_PORT(playing_audio)[channel]; + if (dma != NULL && (cookie & (1 << channel))) { + audio_dma_resume(dma); + } + } +} + void audio_dma_init(audio_dma_t *dma) { dma->buffer[0] = NULL; dma->buffer[1] = NULL; diff --git a/ports/raspberrypi/audio_dma.h b/ports/raspberrypi/audio_dma.h index ae9a07a604..91d692f8ac 100644 --- a/ports/raspberrypi/audio_dma.h +++ b/ports/raspberrypi/audio_dma.h @@ -89,4 +89,7 @@ void audio_dma_pause(audio_dma_t *dma); void audio_dma_resume(audio_dma_t *dma); bool audio_dma_get_paused(audio_dma_t *dma); +uint32_t audio_dma_pause_all(void); +void audio_dma_unpause_cookie(uint32_t cookie); + #endif // MICROPY_INCLUDED_RASPBERRYPI_AUDIO_DMA_OUT_H diff --git a/ports/raspberrypi/supervisor/internal_flash.c b/ports/raspberrypi/supervisor/internal_flash.c index 9216f1ebe2..b0b89d38f1 100644 --- a/ports/raspberrypi/supervisor/internal_flash.c +++ b/ports/raspberrypi/supervisor/internal_flash.c @@ -39,6 +39,7 @@ #include "lib/oofatfs/ff.h" #include "shared-bindings/microcontroller/__init__.h" +#include "audio_dma.h" #include "supervisor/flash.h" #include "supervisor/usb.h" @@ -97,9 +98,12 @@ void port_internal_flash_flush(void) { } // Make sure we don't have an interrupt while we do flash operations. common_hal_mcu_disable_interrupts(); + // and audio DMA must be paused as well + uint32_t cookie = audio_dma_pause_all(); flash_range_erase(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, SECTOR_SIZE); flash_range_program(CIRCUITPY_CIRCUITPY_DRIVE_START_ADDR + _cache_lba, _cache, SECTOR_SIZE); _cache_lba = NO_CACHE; + audio_dma_unpause_cookie(cookie); common_hal_mcu_enable_interrupts(); }