You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F746G-Discovery音频采集程序卡在DMA中断无法退出

STM32F746G-Discovery WM8994 MEMS麦克风采集中断卡死问题

开发背景

在STM32F746G-Discovery开发板上开展音频采集开发,调用BSP库读取板载MEMS麦克风的音频数据,板卡搭载WM8994音频Codec,硬件连接可参考开发板官方原理图。

测试代码

核心工程代码如下:

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32746g_discovery_audio.h"
#include "wm8994.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define AUDIO_BLOCK_SIZE   ((uint32_t)0xFFFE)
#define AUDIO_NB_BLOCKS    ((uint32_t)4)
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

I2C_HandleTypeDef hi2c3;

SAI_HandleTypeDef hsai_BlockA2;
SAI_HandleTypeDef hsai_BlockB2;
DMA_HandleTypeDef hdma_sai2_b;
DMA_HandleTypeDef hdma_sai2_a;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_SAI2_Init(void);
static void MX_I2C3_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
void BSP_AUDIO_IN_TransferComplete_CallBack(void);
void BSP_AUDIO_IN_HalfTransfer_CallBack(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint32_t  audio_rec_buffer_state;
/* USER CODE END 0 */

/**
  * @brief  程序入口
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    uint8_t res = 0;
    uint16_t  internal_buffer[AUDIO_BLOCK_SIZE];
    uint32_t bytesread = 0;
    /* USER CODE END 1 */

    /* 使能I-Cache---------------------------------------------------------*/
    SCB_EnableICache();

    /* 使能D-Cache---------------------------------------------------------*/
    SCB_EnableDCache();

    /* MCU配置--------------------------------------------------------*/
    HAL_Init();

    /* 系统时钟配置 */
    SystemClock_Config();
    PeriphCommonClock_Config();

    /* 初始化所有配置的外设 */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_SAI2_Init();
    MX_I2C3_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    audio_rec_buffer_state = BUFFER_OFFSET_NONE;
    res = BSP_AUDIO_IN_Init(INPUT_DEVICE_DIGITAL_MICROPHONE_2, 35, AUDIO_FREQUENCY_44K);

    if(!res) {
        res = BSP_AUDIO_IN_Record(internal_buffer, AUDIO_BLOCK_SIZE);
        for (int block_number = 0; block_number < AUDIO_NB_BLOCKS; ++block_number) {
            while(audio_rec_buffer_state != BUFFER_OFFSET_HALF);
            audio_rec_buffer_state = BUFFER_OFFSET_NONE;
            while(audio_rec_buffer_state != BUFFER_OFFSET_FULL);
            audio_rec_buffer_state = BUFFER_OFFSET_NONE;
        }
        BSP_AUDIO_IN_Stop(CODEC_PDWN_SW);
        BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_HEADPHONE, 35, AUDIO_FREQUENCY_44K);
        BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
        res = BSP_AUDIO_OUT_Play(internal_buffer, AUDIO_BLOCK_SIZE);
        BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
    }
    /* USER CODE END 2 */

    /* 死循环 */
    while (1)
    {
    }
}

// 回调函数
void BSP_AUDIO_IN_TransferComplete_CallBack(void)
{
  audio_rec_buffer_state = BUFFER_OFFSET_FULL;
  return;
}

void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
{
  audio_rec_buffer_state = BUFFER_OFFSET_HALF;
  return;
}

故障现象

调试时程序进入DMA中断函数后无法正常退出,涉及的中断处理函数如下:

void DMA2_Stream7_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream7_IRQn 0 */

  /* USER CODE END DMA2_Stream7_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_sai2_b);
  /* USER CODE BEGIN DMA2_Stream7_IRQn 1 */

  /* USER CODE END DMA2_Stream7_IRQn 1 */
}

故障排查与解决方法

按优先级从高到低排查以下问题:

  • 栈溢出故障(最高概率):代码中internal_buffer定义在main函数的局部变量区,单块大小为0xFFFE个uint16_t,总大小约128KB。STM32F7默认主栈大小通常配置为4KB~16KB,该数组直接占满栈空间并破坏栈内的返回地址、其他变量内存,DMA写入数据时触发内存访问错误,导致中断卡死。
    解决方法:将internal_buffer定义为全局变量,或增加static修饰将其分配到静态存储区,禁止将KB级以上的大数组定义为局部变量放在栈上。
  • D-Cache一致性故障:代码中开启了D-Cache,DMA传输直接操作SRAM物理地址,CPU访问的是Cache缓存数据,二者数据不同步会导致DMA传输异常、内存访问错误。
    解决方法:将音频缓冲区分配到DTCM RAM(该区域不经过Cache),或配置缓冲区所在SRAM区域为非Cache属性,也可以在每次半传输、全传输中断触发时,调用SCB_InvalidateDCache_by_Addr对缓冲区对应地址范围做Cache无效操作。
  • 重复初始化外设导致配置冲突:代码中先通过CubeMX生成的MX_SAI2_Init、MX_DMA_Init、MX_I2C3_Init初始化了音频相关外设,之后调用的BSP_AUDIO_IN_Init接口本身也会重新初始化I2C、SAI、DMA外设并配置中断,两次初始化的参数(比如DMA数据宽度、SAI音频槽、时钟源、中断优先级)如果冲突,会导致DMA传输错误,反复触发中断无法退出。
    解决方法:二选一做初始化,要么完全依赖BSP库的初始化接口,删除自己生成的SAI、DMA、I2C初始化代码;要么自己实现完整的音频底层驱动,不要混用BSP库的音频接口。
  • DMA错误标志未清除:调试时可查看中断触发时hdma_sai2_b的ErrorCode成员值,如果存在FIFO错误、传输错误、直接模式错误标志,说明DMA配置和SAI外设的数据宽度、地址增量模式不匹配,对应修正参数即可。

额外逻辑问题:当前代码中录音完成后调用BSP_AUDIO_OUT_Play立刻调用BSP_AUDIO_OUT_Stop是错误的,播放接口为异步非阻塞接口,调用后会立刻返回,不会等待播放完成,直接Stop会导致音频完全无法输出,需要等播放完成回调触发后再执行停止操作。

内容的提问来源于stack exchange,提问作者akoluaciklinux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:21:37