From 07ede3ede40f3580699de1fc72148391ca3a4d13 Mon Sep 17 00:00:00 2001 From: richardclli Date: Thu, 18 Jun 2026 16:56:30 +0800 Subject: [PATCH 1/2] fix(pl18): audio sluggishness from DAC underrun during flash erase Restore DAC DMA underrun interrupt handler (DMAUDRIE1) removed in 6d6c449c12. When audio buffers starve during flash erase, the underrun ISR stops DMA within ~31us instead of letting circular DMA replay stale data indefinitely. Add RTOS yield to flash_wait_for_not_busy() so the audio task gets CPU time during long flash erases (45-400ms), reducing starvation at the source. --- .../targets/common/arm/stm32/audio_dac_driver.cpp | 15 +++++++++++++-- radio/src/targets/common/arm/stm32/spi_flash.cpp | 4 ++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp index 9be32e8b07a..795bf3fc6d5 100644 --- a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp +++ b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp @@ -203,10 +203,12 @@ void dacInit() // use TIM6 TRGO as trigger (TSEL1 = TSEL2 = 000) // enable DAC & channel 1 trigger - AUDIO_DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1; + AUDIO_DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1 | DAC_CR_DMAUDRIE1; #endif NVIC_EnableIRQ(AUDIO_DMA_Stream_IRQn); NVIC_SetPriority(AUDIO_DMA_Stream_IRQn, 7); + NVIC_EnableIRQ(AUDIO_TIM_IRQn); + NVIC_SetPriority(AUDIO_TIM_IRQn, 7); } #if defined(AUDIO_MUTE_GPIO) @@ -299,7 +301,7 @@ void audioConsumeCurrentBuffer() AUDIO_DAC->SR = DAC_SR_DMAUDR1; // enable DAC - AUDIO_DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1; + AUDIO_DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1 | DAC_CR_DMAUDRIE1; #endif } else { #if defined(AUDIO_MUTE_GPIO) @@ -325,6 +327,15 @@ void audioEnd() NVIC_DisableIRQ(AUDIO_DMA_Stream_IRQn); } +extern "C" void AUDIO_TIM_IRQHandler() +{ + DEBUG_INTERRUPT(INT_AUDIO); + if (AUDIO_DAC->SR & DAC_SR_DMAUDR1) { + AUDIO_DAC->CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAUDRIE1); + AUDIO_DAC->SR = DAC_SR_DMAUDR1; + } +} + extern "C" void AUDIO_DMA_Stream_IRQHandler() { #if defined(STM32H5) || defined(STM32H7) || defined(STM32H7RS) diff --git a/radio/src/targets/common/arm/stm32/spi_flash.cpp b/radio/src/targets/common/arm/stm32/spi_flash.cpp index c14a6532580..7e50f93e533 100644 --- a/radio/src/targets/common/arm/stm32/spi_flash.cpp +++ b/radio/src/targets/common/arm/stm32/spi_flash.cpp @@ -24,6 +24,7 @@ #include "stm32_gpio.h" #include "hal.h" +#include "rtos.h" #define CS_HIGH() stm32_spi_unselect(&_flash_spi) #define CS_LOW() stm32_spi_select(&_flash_spi) @@ -147,6 +148,9 @@ static void flash_wait_for_not_busy() uint8_t status; do { flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1); + if (status & 0x01) { + RTOS_WAIT_MS(1); + } } while (status & 0x01); } From 18347c552e163245d2e40a6b23492a1d5b3be6a1 Mon Sep 17 00:00:00 2001 From: richardclli Date: Thu, 18 Jun 2026 17:11:12 +0800 Subject: [PATCH 2/2] fix(build): guard RTOS includes in spi_flash.cpp for bootloader build spi_flash.cpp is compiled for both bootloader and main firmware. The bootloader does not link FreeRTOS, so RTOS_WAIT_MS(1) causes undefined reference to vTaskDelay. Guard with BOOT and use bare-metal delay_ms(1) for the bootloader instead. --- radio/src/targets/common/arm/stm32/spi_flash.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/radio/src/targets/common/arm/stm32/spi_flash.cpp b/radio/src/targets/common/arm/stm32/spi_flash.cpp index 7e50f93e533..abe1d8b81eb 100644 --- a/radio/src/targets/common/arm/stm32/spi_flash.cpp +++ b/radio/src/targets/common/arm/stm32/spi_flash.cpp @@ -24,7 +24,9 @@ #include "stm32_gpio.h" #include "hal.h" +#if !defined(BOOT) #include "rtos.h" +#endif #define CS_HIGH() stm32_spi_unselect(&_flash_spi) #define CS_LOW() stm32_spi_select(&_flash_spi) @@ -149,7 +151,11 @@ static void flash_wait_for_not_busy() do { flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1); if (status & 0x01) { +#if !defined(BOOT) RTOS_WAIT_MS(1); +#else + delay_ms(1); +#endif } } while (status & 0x01); }