ST意法半导体
直播中

七上八下

9年用户 905经验值
私信 关注
[问答]

求助,关于STM32 PDM转PCM库的使用问题求解

我在使用STM32WBA55G-DK1板子调试SAI接口,SAI连接了一个数字麦克风,数字麦克风提供的是PDM信号,ST提供了一个PDM2PCM库进行转换,但是我的工程发现转换出来的PCM数据都是0,为了验证是不是我的PDM数据有问题,我从这个官方提供这个板子的Demo工程里获取SAI获取的PDM数据保存在一个数组中, 在我自己的工程中对这个数组进行PDM转PCM,结果还是为0。
为了对比我的工程与官方工程的差异,不断精简官方代码和我的工程代码,最后只剩下在main函数中初始化串口1作为log输出,直接调用PDM2PCM库进行初始化以及转换,结果仍然有差异,我都不知道为何会造成这种情况。
下面是我的代码
#define PDM_SAMPLES_AT_EACH_CALL 20#define AUDIO_REC_BUFFER_SIZE   (PDM_SAMPLES_AT_EACH_CALL * 8 * 2)#define AUDIO_PLAY_BUFFER_SIZE  (PDM_SAMPLES_AT_EACH_CALL * 4)#define AUDIO_HIGH_PASS_TAP     2122358088/* USER CODE END PM *//* Private variables ---------------------------------------------------------*/UART_HandleTypeDef huart1;/* USER CODE BEGIN PV */uint8_t   RecordBuff[AUDIO_REC_BUFFER_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x96, 0x65, 0x9A, 0x5A, 0x36, 0xCA, 0x95, 0xA5, 0x69, 0x66, 0x0D, 0x73, 0x4E, 0x99, 0x6A, 0x9A, 0x93, 0xA9, 0xA6, 0x95,0x23, 0x67, 0x96, 0x99, 0xA5, 0x99, 0x69, 0x96, 0x65, 0xA6, 0xA6, 0x55, 0x66, 0x26, 0x8F, 0x99, 0x59, 0xA6, 0x69, 0x5A, 0xE5, 0x30, 0x67, 0x93, 0xA9, 0x66, 0x66, 0x23, 0x67, 0x96, 0x65, 0x9A,0xA6, 0x8D, 0xC9, 0x95, 0x59, 0xA6, 0xA6, 0x35, 0x9C, 0x69, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x96, 0x59, 0xA6, 0x69, 0x5A, 0xA3, 0x5C, 0x59, 0x9A, 0x69, 0x96, 0x65, 0xC9, 0x59,};uint16_t  PlaybackBuff[AUDIO_PLAY_BUFFER_SIZE];static PDM_Filter_Handler_t PDM_FilterHandler;static PDM_Filter_Config_t PDM_FilterConfig;int main(void){  /* USER CODE BEGIN 1 */  uint32_t ret;  uint16_t loop;  /* USER CODE END 1 */  /* MCU Configuration--------------------------------------------------------*/  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */  HAL_Init();  /* USER CODE BEGIN Init */  /* USER CODE END Init */  /* Configure the system clock */  SystemClock_Config();  /* USER CODE BEGIN SysInit */  /* USER CODE END SysInit */  /* Initialize all configured peripherals */  MX_GPIO_Init();  MX_USART1_UART_Init();  /* USER CODE BEGIN 2 */  printf("Hello Worldrn");  __HAL_RCC_CRC_CLK_ENABLE();  /* Init PDM filters */  PDM_FilterHandler.bit_order  = PDM_FILTER_BIT_ORDER_MSB;  PDM_FilterHandler.endianness = PDM_FILTER_ENDIANNESS_LE;  PDM_FilterHandler.high_pass_tap = AUDIO_HIGH_PASS_TAP;  PDM_FilterHandler.out_ptr_channels = 1;  PDM_FilterHandler.in_ptr_channels  = 1;  ret = PDM_Filter_Init((PDM_Filter_Handler_t *)(&PDM_FilterHandler));  if (ret != 0) {      printf("PDM_Filter_Init ret:%drn", ret);  }  /* PDM lib config phase */  PDM_FilterConfig.mic_gain = 24;  PDM_FilterConfig.output_samples_number = PDM_SAMPLES_AT_EACH_CALL;  PDM_FilterConfig.decimation_factor = PDM_FILTER_DEC_FACTOR_64;  ret = PDM_Filter_setConfig((PDM_Filter_Handler_t *)&PDM_FilterHandler, &PDM_FilterConfig);  if (ret != 0) {      printf("PDM_Filter_setConfig ret:%drn", ret);    }    for (loop = 0; loop < AUDIO_REC_BUFFER_SIZE / 2; loop++) {        printf("%02X  ", RecordBuff[loop]);        if (loop % 32 == 31) {            printf("n");        }    }    if (loop % 32 != 0) {        printf("n");    }    memset(PlaybackBuff, 0, sizeof(PlaybackBuff));    //hcrc.Instance->CR = CRC_CR_RESET;    ret = PDM_Filter(RecordBuff, PlaybackBuff, &PDM_FilterHandler);    if (ret != 0) {        printf("PDM_Filter Fail, ret:%xn", ret);    }    for (loop = 0; loop < PDM_SAMPLES_AT_EACH_CALL; loop++) {        printf("%04X  ", RecordBuff[loop]);            if (loop % 32 == 31) {                printf("n");            }    }    if (loop % 32 != 0) {        printf("n");    }  /* USER CODE END 2 */  /* Infinite loop */  /* USER CODE BEGIN WHILE */  while (1)  {    /* USER CODE END WHILE */    /* USER CODE BEGIN 3 */  }  /* USER CODE END 3 */}以下是官方的工程中精简后的代码
#define PDM_SAMPLES_AT_EACH_CALL 20#define AUDIO_REC_BUFFER_SIZE   (PDM_SAMPLES_AT_EACH_CALL * 8 * 2)#define AUDIO_PLAY_BUFFER_SIZE  (PDM_SAMPLES_AT_EACH_CALL * 4)#define AUDIO_HIGH_PASS_TAP     2122358088static uint8_t RecordBuff[AUDIO_REC_BUFFER_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x96, 0x65, 0x9A, 0x5A, 0x36, 0xCA, 0x95, 0xA5, 0x69, 0x66, 0x0D, 0x73, 0x4E, 0x99, 0x6A, 0x9A, 0x93, 0xA9, 0xA6, 0x95,0x23, 0x67, 0x96, 0x99, 0xA5, 0x99, 0x69, 0x96, 0x65, 0xA6, 0xA6, 0x55, 0x66, 0x26, 0x8F, 0x99, 0x59, 0xA6, 0x69, 0x5A, 0xE5, 0x30, 0x67, 0x93, 0xA9, 0x66, 0x66, 0x23, 0x67, 0x96, 0x65, 0x9A,0xA6, 0x8D, 0xC9, 0x95, 0x59, 0xA6, 0xA6, 0x35, 0x9C, 0x69, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x96, 0x59, 0xA6, 0x69, 0x5A, 0xA3, 0x5C, 0x59, 0x9A, 0x69, 0x96, 0x65, 0xC9, 0x59,};static uint16_t  PlaybackBuff[AUDIO_PLAY_BUFFER_SIZE];static PDM_Filter_Handler_t            PDM_FilterHandler;static PDM_Filter_Config_t             PDM_FilterConfig;int main(void){    uint32_t ret, loop;  /* STM32WBAxx HAL library initialization:       - Systick timer is configured by default as source of time base, but user             can eventually implement his proper time base source (a general purpose             timer for example or other time source), keeping in mind that Time base             duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and             handled in milliseconds basis.       - Set NVIC Group Priority to 4       - Low Level Initialization     */  HAL_Init();  /* Configure the System clock to have a frequency of 100 MHz */  SystemClock_Config();  /* Add your application code here     */  MX_USART1_UART_Init();  printf("Hello Worldrn");  __HAL_RCC_CRC_CLK_ENABLE();    /* Init PDM filters */    PDM_FilterHandler.bit_order  = PDM_FILTER_BIT_ORDER_MSB;    PDM_FilterHandler.endianness = PDM_FILTER_ENDIANNESS_LE;    PDM_FilterHandler.high_pass_tap = AUDIO_HIGH_PASS_TAP;    PDM_FilterHandler.out_ptr_channels = 1;    PDM_FilterHandler.in_ptr_channels  = 1;    ret = PDM_Filter_Init((PDM_Filter_Handler_t *)(&PDM_FilterHandler));    if (ret != 0) {        printf("PDM_Filter_Init ret:%drn", ret);    }    /* PDM lib config phase */    PDM_FilterConfig.mic_gain = 24;    PDM_FilterConfig.output_samples_number = PDM_SAMPLES_AT_EACH_CALL;    PDM_FilterConfig.decimation_factor = PDM_FILTER_DEC_FACTOR_64;    ret = PDM_Filter_setConfig((PDM_Filter_Handler_t *)&PDM_FilterHandler, &PDM_FilterConfig);    if (ret != 0) {        printf("PDM_Filter_Init ret:%drn", ret);    }    printf("PDMrn");    for (loop = 0; loop < AUDIO_REC_BUFFER_SIZE / 2; loop++) {      printf("0x%02X, ", RecordBuff[loop]);      if (loop % 32 == 31) {        printf("rn");      }    }    if (loop % 32 != 0) {      printf("rn");    }    /* Store values on Play buff */    ret = PDM_Filter(&RecordBuff[0], &PlaybackBuff[0], &PDM_FilterHandler);    printf("PCM ret:%drn", ret);    for (loop = 0; loop < PDM_SAMPLES_AT_EACH_CALL; loop++) {      printf("0x%04X, ", PlaybackBuff[loop]);      if (loop % 32 == 31) {        printf("rn");      }    }    if (loop % 32 != 0) {      printf("rn");    }  /* Infinite loop */  while (1)  {  }}数据源都是数组,且数据相同。PDM_Filter的配置也相同。使用的PDM2PCM库也都是libPDMFilter_CM33_GCC_wc32.a,也同样是一块板子。不知道为何会有这样的差异

回帖(2)

孟佳

2025-3-15 16:50:26
1.试试用官方例程的文件去一个个替换你原本工程的文件对比,有可能库有一定修改。
2.观察编译输出的各个关键变量的地址,看看是否存在4字节对齐问题
举报

郭大

2025-3-21 17:54:21

针对您在使用STM32WBA55G-DK1的PDM2PCM库时遇到的问题,以下是逐步排查和解决方案:




1. 确认库的版本和兼容性



  • 检查库版本:确保使用的PDM2PCM库版本与STM32WBA系列完全兼容。部分库可能需要针对特定芯片调整配置。

  • 参考官方文档:查阅STM32CubeWBA的文档,确认库支持的配置和依赖项。




2. 验证初始化参数



  • 参数对比:将您的初始化代码与官方Demo中的PDM_Filter_Init参数逐字段对比:
    PDM_Filter_Init(&PDMHandle);
    // 示例参数(需替换为实际值)
    PDMHandle.DecimationFactor = 64;     // 抽取因子
    PDMHandle.OutputBitDepth = 16;       // 输出位深(16或32)
    PDMHandle.InternalBitDepth = 24;     // 内部处理位深
    PDMHandle.HighPassToggle = ENABLE;  // 高通滤波器使能

  • 关键参数:确保DecimationFactor与麦克风的PDM时钟频率和输出PCM采样率匹配。




3. 输入数据格式验证



  • 位序对齐:确认PDM数据的位序(MSB或LSB)与库的配置一致。例如:
    // 若麦克风输出是MSB在前,而库默认LSB,需调整
    PDMHandle.InputDataMSB = 1;  // 1表示MSB在前

  • 数据长度:输入PDM数据的长度必须是DecimationFactor的整数倍(如64的倍数)。




4. 缓冲区管理



  • 内存对齐:确保输入/输出缓冲区按库的要求对齐(如4字节对齐):
    // 使用__attribute__((aligned(4)))确保对齐
    uint8_t pdmBuffer[512] __attribute__((aligned(4)));
    int16_t pcmBuffer[128] __attribute__((aligned(4)));

  • 缓冲区大小:输入缓冲区大小应满足PDM2PCM库的最小样本数要求。




5. 时钟与中断配置



  • SAI时钟:确认SAI接口的时钟源和分频配置与官方Demo一致,尤其是SAIx_CLK的频率。

  • 中断处理:如果库依赖DMA或中断,确保相关中断使能并配置优先级:
    HAL_NVIC_SetPriority(SAIx_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SAIx_IRQn);




6. 调试与日志



  • 输出中间数据:在调用PDM_Filter前后打印输入和输出缓冲区的原始数据:
    printf("PDM Data: ");
    for(int i=0; i PDM_Filter(&PDMHandle, pdmBuffer, pcmBuffer, &pcmSize);
    printf("PCM Data: ");
    for(int i=0; i

  • 检查返回值:确认PDM_Filter函数的返回值是否为成功状态(如PDM_OK)。




7. 对比工程配置



  • 编译选项:检查工程是否启用浮点运算(若库依赖FPU),确保-mfloat-abi=hard-mfpu=fpv4-sp-d16正确设置。

  • 链接库路径:确认PDM2PCM库文件(如libPDMFilter.a)的路径正确,且头文件包含无误。




8. 使用调试器跟踪



  • 单步调试:在调试模式下逐行跟踪PDM_Filter函数,观察中间变量(如滤波器状态、计算过程中的临时值)是否异常。

  • 断点设置:在库的关键函数(如卷积计算、滤波器更新)设置断点,确认数据流是否正常。




9. 尝试最小化测试



  • 仅保留核心功能:在main函数中仅初始化PDM2PCM库和SAI,直接硬编码一段已知有效的PDM数据(如官方Demo中的数组)进行转换:
    uint8_t testPDM[] = {0x55, 0xAA, ...};  // 官方Demo中的PDM数据
    int16_t testPCM[128];
    PDM_Filter(&PDMHandle, testPDM, testPCM, 128);




10. 联系ST支持



  • 提交案例:若问题仍未解决,通过ST官网提交技术支持请求,附上工程代码、配置截图和调试日志。




通过以上步骤,应能定位到PDM转PCM失败的根本原因。常见问题多集中在参数配置、数据对齐或硬件外设初始化疏漏。建议优先对比官方Demo的配置,逐步替换关键模块以缩小问题范围。

举报

更多回帖

×
20
完善资料,
赚取积分