一、硬件介绍
1、产品特点
STM32H747I-DISCO开发板基于Arm的STM32H747XIH6微控制器拥有Cortex-M7内核(带双精度浮点单元,运行频率高达 480 MHz) 和 Cortex-M4内核(带单精度浮点单元,运行频率高达 240 MHz)的双核性能,板载配备2MB的Flash存储器和1MB的RAM、4英寸TFT LCD触摸显示屏(480x800) 具有MIPI DSI接口等;


规格参数

24 MHz 晶振(X1),用于USB OTG HS PHY 和摄像头模块;
25 MHz 晶振(X2),用于主时钟发生器和以太网 PHY;
32.768 kHz 晶体(X3),用于RTC;
25 MHz 晶振(X4),仅用于STLINK-V3E;
硬件框图

2、功能引脚示意图 / 原理图
主要原理图

二、功能配置
1、数字MEMS麦克风
硬件介绍
STM32H747I-DISCO板上的U21(MP34DT05-A) 是一款MEMS数字全向麦克风,默认通过PDM(脉冲密度调制)输出;
麦克风(配置对应焊桥)也可以连接到U12(WM8994ECS/R,音频编解码器),音频编解码器为麦克风提供PDM时钟;
特性
单电源电压;低功耗;AOP:122.5 dBSPL;64db 信噪比;全向性灵敏度:-26 dBFS ±3 dB 的灵敏度;PDM 输出;
SAI 接口
SAI 接口是一种串行音频接口,具有灵活性高、配置多样等特点,可支持多种音频协议;可配置为支持 I2S 标准、LSB 或 MSB 对齐、PCM / DSP等协议,将音频模块配置为发送器时,SAI 接口可提供 SPDIF 输出;
MP34DT05-A 输出 1-bit PDM流,时钟频率通常为 1.024 MHz ~ 3.072 MHz; DFSDM 内部数字滤波器进行抽取,输出多比特 PCM;
抽取因子和对应的频率


硬件引脚连接
CLK → 连接到 STM32 的 PE2 (SAI4_CK1);
DOUT → 连接到 STM32 的 PC1 (SAI4_D1);


原理图


2、创建工程
1、工程配置
打开 STM32CubeMX ,选择创建 STM32H747I-DISCO 模板,进行相关配置;




配置SAI接口
48kHz单声道16bits
Data Size: 16 bits Slot Size: 16 bits Frame Length: 16 bits (1通道 × 16位 = 16位)


配置SAI时钟
PDM_CLK = 64× 采样率 = 64 × 48kHz = 3.072MHz
PDM_CLK = SAI_CLK / (2*(Mckdiv+1)) = 50Mhz / (2(7+1)) = 50 / 16 = 3.125Mhz ;


2、安装 PDM2PCM库
PDM2PCM库具有从数字麦克风抽取和滤除脉冲密度调制(PDM)流的功能,用于将其转换为脉冲编码调制(PCM)信号输出流; PCM输出流以16位分辨率实现,默认用16 kHz的PCM 采样率。
需开启 CRC;


安装 PDM2PCM库 :
PDM 转 PCM 需要 抽取,典型抽取因子为 64 (即每 64 个 PDM 比特 → 1 个 PCM 样点)
所需 PDM 比特数 = output_samples_number × 抽取因子 ; 所需 PDM 字节数 = (output_samples_number × 64 + 7) / 8 ≈ output_samples_number × 8
如果是 125 个 PCM 样点 ,并且抽取率为 64
则需要提供 125 × 64 = 8000 个 PDM bits
即 1000 字节 PDM 数据(8000 ÷ 8 = 1000)


PDM2PCM库 接口
通过pdm2pcm_glo.h 头文件和lib库文件 libPDMFilter_CM7_Keil_wc16.lib,使用PDM2PCM库;
运行流程图


三、代码编写
效果:通过板载MEMS麦克风采集外部的音频数据,并进行播放;
音频流配置为:48 kHz, 16-bit
主要相关代码
main.c:
#include "main.h"
static void SystemClock_Config(void);
static void Display_DemoDescription(void);
static void MPU_Config(void);
static void CPU_CACHE_Enable(void);
int main(void)
{
MPU_Config();
CPU_CACHE_Enable();
HAL_Init();
SystemClock_Config();
AudioRecord(); // 采集 + 播放
while (1)
{
HAL_Delay(500);
}
}
AudioRecord.c:
#define PCM_BLOCK_BYTES (AUDIO_IN_PDM_BUFFER_SIZE / 4)
extern AUDIO_ErrorTypeDef AUDIO_Start(uint32_t audio_start_address, uint32_t audio_file_size);
#define AUDIO_FREQUENCY 48000U //48Khz
#define AUDIO_IN_PDM_BUFFER_SIZE (uint32_t)(128*AUDIO_FREQUENCY/16000*2)
#define RECORD_BUFFER_SIZE 4096
static uint32_t AudioFreq[9] = {8000 ,11025, 16000, 22050, 32000, 44100, 48000, 96000, 192000};
ALIGN_32BYTES (uint16_t RecPlayback[2*RECORD_BUFFER_SIZE]);
ALIGN_32BYTES (uint16_t PlaybackBuffer[2*RECORD_BUFFER_SIZE]);
uint32_t VolumeLevel = 80;
uint32_t InState = 0;
uint32_t OutState = 0;
uint32_t *AudioFreq_ptr;
uint16_t playbackBuf[RECORD_BUFFER_SIZE*2];
BSP_AUDIO_Init_t AudioInInit;
BSP_AUDIO_Init_t AudioOutInit;
uint32_t playbackPtr;
uint32_t AudioBufferOffset;
typedef enum {
BUFFER_OFFSET_NONE = 0,
BUFFER_OFFSET_HALF,
BUFFER_OFFSET_FULL,
}BUFFER_StateTypeDef;
void AudioRecord(void)
{
uint32_t channel_nbr = 1;
uint32_t x_size, y_size;
AudioFreq_ptr = AudioFreq + 6; // 48Khz
AudioOutInit.Device = AUDIO_OUT_DEVICE_AUTO;
AudioOutInit.ChannelsNbr = channel_nbr;
AudioOutInit.SampleRate = *AudioFreq_ptr;
AudioOutInit.BitsPerSample = AUDIO_RESOLUTION_16B; // 16bits
AudioOutInit.Volume = VolumeLevel;
AudioInInit.Device = AUDIO_IN_DEVICE_DIGITAL_MIC;
AudioInInit.ChannelsNbr = channel_nbr;
AudioInInit.SampleRate = *AudioFreq_ptr;
AudioInInit.BitsPerSample = AUDIO_RESOLUTION_16B;
AudioInInit.Volume = VolumeLevel;
BSP_AUDIO_IN_Init(1, &AudioInInit);
BSP_AUDIO_IN_GetState(1, &InState);
BSP_AUDIO_OUT_Init(0, &AudioOutInit);
BSP_AUDIO_OUT_SetDevice(0, AUDIO_OUT_DEVICE_HEADPHONE);
BSP_AUDIO_IN_RecordPDM(1, (uint8_t*)&recordPDMBuf, 2*AUDIO_IN_PDM_BUFFER_SIZE);//采集
BSP_AUDIO_OUT_Play(0, (uint8_t*)&RecPlayback[0], 2*RECORD_BUFFER_SIZE);//播放
while (1)
{
HAL_Delay(100);
}
}
我要赚赏金
