赞
踩
本文在stm32平台上,利用IIS协议和INMP441模块,实现了对于音频的采样,并通过串口将数据实时返回电脑
本文只是一个初学者的经验分享,希望为同样刚接触相关协议的朋友提供一些帮助,有错误的地方还请包涵
本文是在另一位大佬工作基础上的改进版,建议先阅读该文章
使用STM32的I2S协议读取麦克风INMP441-CSDN博客
在其中已经将IIS协议、工程基本配置讲的非常详细,一些基础的内容本文不再赘述
最后,本文附上了笔者使用的python上位机,里面实现了一些基础功能
需要提前说明的是,UART速率过慢,不适合用于音频到上位机的实时传输,本文仅处于初级开发阶段,因此未作深入。如果要做相关开发,可以采用IIS采集 - IIS发送,等等方法。
此外,不要使用性能过差的平台做音频相关的深度开发,内存、处理速度、接口资源都是问题。
IIS个三根通信相关的引脚,时钟SCK、帧选择WS、数据SD
帧选择信号WD控制左右声道,当WD=0时,设置为左声道的模块输出;WD=1时,右声道输出;帧的大小受IIS帧格式影响,如果是24bit data on 32 frame的格式,帧大小就是32bit,如果是16bit data on 16 bit frame格式,帧大小就是16bit;
在CUBEMX中的IIS配置界面,有一个参数Audio frequency,这个参数等于采样频率
那么有:
采样频率Fs = audio frequency
帧选择信号WS = Fs
时钟信号SCK = Fs * 2 * 帧大小,即一个采样周期里,左右声道各采集一帧
在IIS的采样频率为Fs = 8khz情况下,要实现音频数据的实时上传,需要满足两个条件:
假设使用USART上传,并且只采集单声道数据,对于INMP441的24位ADC数据,我们需要使用uint32型发送数据,那么数据产生速率为:
32 * 8000 = 256000 bit/s
UART发送一字节数据,最少需要1个开始位和1个停止位,那么UART串口波特率必须满足:
256000 / 8 * 10 = 320000 bit/s,
对于其他通讯协议,同理
HAL库处理中断需要绕很大一个圈子:
触发中断 - 进入DMA通道IRQ - 进入具体DMA连接IRQ - 各种判断 - 进入半完成/完成中断
这个过程非常耗时,再加上UART传输比较慢,很可能无法及时处理中断,如下图
这里就是处理速度过慢,即使用了双缓冲,也不得不抛弃一半的数据,只能达到4khz的数据回报率
对于问题1,我们提高串口波特率即可,对于本文所使用的STM32f103,可以在CUBEMX中观察到最大波特率范围,我们这里设置为360000bit/s
对于问题2,我们可以通过增大缓冲区的方式,将中断处理耗时平摊到每一次采集上。但如果还想给程序加上RTOS,或者临时去处理些其他任务,还是用更好的芯片吧
将缓冲区大小增加到512后,可以从图中看到,不再出现无法及时响应中断的问题,跑满了8khz
请结合之前贴出的文章阅读,这里只指出修改了的地方
首先,DMA传输方式用half word就可以了
程序中用增加半完成中断的方式做了双缓冲
- uint16_t dma_buffer[512];
- uint32_t val24[2][64];
- int val32[2][64];
- int cb_cnt=0;
- extern UART_HandleTypeDef huart1;
- /* USER CODE END PV */
-
- /* Private function prototypes -----------------------------------------------*/
- void SystemClock_Config(void);
- /* USER CODE BEGIN PFP */
-
- /* USER CODE END PFP */
-
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- //一组采样数据,左通道2个u16,右通道2个u16
- void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
- {
- if (hi2s == &hi2s2) {
- cb_cnt++;
- // 选择当前使用的缓冲区
- int offset = 0;
-
- for (int i = 0; i < 64; i++) {
- val24[0][i] = dma_buffer[offset + 4 * i];
- val24[0][i] = val24[0][i] << 8;
- val24[0][i] = val24[0][i] + (dma_buffer[offset + 4 * i + 1] >> 8);
-
- if (val24[0][i] & 0x800000) {
- val32[0][i] = 0xff000000 | val24[0][i];
- } else {
- val32[0][i] = val24[0][i];
- }
- }
-
- HAL_UART_Transmit(&huart1, (uint8_t*)&val32[0][0], 256, 0xff);
- }
- }
-
- void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
- {
- if (hi2s == &hi2s2) {
- cb_cnt++;
- // 选择当前使用的缓冲区
- int offset = 256;
-
- for (int i = 0; i < 64; i++) {
- val24[1][i] = dma_buffer[offset + 4 * i];
- val24[1][i] = val24[1][i] << 8;
- val24[1][i] = val24[1][i] + (dma_buffer[offset + 4 * i + 1] >> 8);
-
- if (val24[1][i] & 0x800000) {
- val32[1][i] = 0xff000000 | val24[1][i];
- } else {
- val32[1][i] = val24[1][i];
- }
- }
-
- HAL_UART_Transmit(&huart1, (uint8_t*)&val32[1][0], 256, 0xff);
- }
- }
最后,主函数中仅对DMA开启函数的调用做了一些修改
- int main(void)
- {
-
- /* USER CODE BEGIN 1 */
-
- /* 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_DMA_Init();
- MX_I2S2_Init();
- MX_USART1_UART_Init();
- /* USER CODE BEGIN 2 */
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- HAL_I2S_Receive_DMA(&hi2s2, (uint16_t*)dma_buffer, 512); // 双缓冲区,共512个16位数据
-
- while (1)
- {
- HAL_Delay(100);
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
注意,带上位机版本的stm32程序与前文中不同,请和上位机一同下载
上位机所需库:pyserial、wave、numpy、scipy(如果要做fft)
工程文件及功能:
server.py - 主程序,包括了菜单支持
SerialRec.py - 包含串口通讯类,在这里修改串口通讯参数
txt2wave.py - 将txt文件转换成音频,做了一个简单的高通滤波,不过没什么用
txt_fft_viewer.py / wav_fft_viewer - 两个用来观察频域的文件,不是很有用,真要做相关操作还是自己写吧
使用:
运行server.py,键盘根据提示输入,直到打开串口
串口参数可以在SerialRec.py里面修改全局变量,默认用的360000波特率
先使用功能1接收采样数据,接收数据量由 单片机完成中断中的停止条件 决定
最后的判断就是终止条件,这里设置调用半完成+完成中断共1000次,每次发送64次采样,即发送64000个采样数据,在8000hz采样率下,共发送8s
接收完毕后使用功能2将原始数据转换成整型
最后使用功能3将数据保存到txt文件,默认保存到txtEaxample文件夹下
txt2wave.py中,修改文件名,并按情况修改采样率,音量调节值,和高通滤波器截至频率
运行该文件,转换后的音频保存到waveExample下
8000hz采样率下的音质还是不错的
最后,贴出下载链接,偷懒就放百度网盘了
删除链接中的中文即可
链接:https://pan.baidu.co防m/s/1EY5Y_uJyCt吞V2BngGNeJH3A?pwd=ais2
提取码:ais2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。