Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
ART-Pi
DMA
sai音频接口
Art-Pi学习笔记10:优化多媒体扩展板的音频驱动添加录音功能
发布于 2021-07-07 11:31:10 浏览:3389
订阅该版
**开发板:** Art-Pi + 多媒体扩展板 **开发环境:** Rtthread studio **内核版本:** 4.0.3 **上一次的笔记** Art-Pi学习笔记9:如何使用art-pi的多媒体扩展板播放TF卡中的音乐文件 - RT-Thread问答社区 https://club.rt-thread.org/ask/article/2849.html **起因** 内容接上一次的笔记,自从实现了Art-Pi多媒体扩展板的音频播放功能之后,就一直心心念扩展板上的麦克风是不是也能顺利的用起来。毕竟有现成的软件包wavrecord可以使用,不用白不用啊。没想到一下子就跳进了一个大坑。 首先来看看扩展板的原理图 共有两个MIC信号连接到WM8988的输入引脚上。分别是通过耳机插口的输入,以及板载的极柱体麦克风。经过WM8988采集后进行ADC转换,最后以PCM格式的数据流从PCM接口输出。既然上一次笔记中已经实现了WM8988的音频播放,那说明PCM接口的驱动是完善的,开通录音功能应该是水到渠成,易如反掌啊! ![image.png](https://oss-club.rt-thread.org/uploads/20210707/15e64e84c6204b35493967297473a355.png.webp) 实践证明,大意了! 打开art-pi的声音驱动文件drv_sound.c,看看sound0设备的注册信息是“只读” ![image.png](https://oss-club.rt-thread.org/uploads/20210707/b899e21e792be4d31e3de7a2f4fd031d.png.webp) 再看看另一块号称也是rtthread开发板的潘多拉。除了drv_sound.c文件,还有一个drv_mic.c文件。也就是说,麦克风是由另一个文件来驱动的。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/cba4277d2ee37ee94097fbf17dff492a.png) 没事,本着stm32一家亲,外加rtthread设备管理的独门秘方,移植咯!驾轻就熟的打开cubemx进行外设配置,代码生成,拷贝到项目里面,编译,一顿操作猛如虎,结果不能用。完蛋! ![image.png](https://oss-club.rt-thread.org/uploads/20210707/458e74ab8a88baa744be57ecede2f7fa.png.webp) 这可咋整?过度依赖cubemx的开发是不行的,这次使用到的外设是SAI,之前没有玩过的,还是要从头开始,学习外设的使用。这时候就需要请出葵花宝典了,《STM32H743参考手册中文版.pdf》 **关于SAI的介绍** ![image.png](https://oss-club.rt-thread.org/uploads/20210707/874e39a34a4e04ba609374fb5d7f08fc.png.webp) 简单来说就是一个专门用来接音频外设的一个接口。具体的说明这里就不再复述,直接奔着功能配置去。 首先,我们要实现的功能是,播放音频文件和接收麦克风数据,这就需要对两个音频流进行处理,需要用到SAIx_A和SAIx_B。从框图上来看,这两个模块是相互独立的,拥有各自的专用引脚,也就是说可以组成全双工工作模式,互不影响。当然,也可以相互协作,组成主从模式,共用部分引脚。同样不会影响性能。在art-pi上使用的就是共用引脚模式,FS,SCK,MCLK引脚共用。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/9461989b5a212c507f3443e8955ba818.png.webp) **配置GPIO** 首先就是引脚的配置,这里要对原有引脚配置做一些修改。原来的PG10引脚只是配置成普通的IO。现在改成SAI2的功能复用引脚,作为PCM数据流输入引脚。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/c56b2ab1bf5802640da97f69c26b5c4e.png.webp) **配置SAI2_A** 接下来就是要对SAI进行功能配置了。Art-pi使用了SAI2,在drv_sound.h中有两个外设的地址宏定义 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/93a73a0d0b150f74e603e0c0bcc4f618.png) 而且在drv_sound.c文件的一开始就定义了使用SAI2。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/6dca3b0ae398df4886d2360b0c42e048.png) 通过电路原理图又可以知道,使用SAI2_A模块作为输出,SAI2_B模块作为输入。而且两者共用部分引脚。因此我们在功能规划上应该这样规划: 1.SAI2_A作为主发送模块,使用DMA传送数据,存储器到外设。 2.SAI2_B作为从接收模块,使用DMA传送数据,外设到存储器。 先看看SAI2_A的功能配置,这里修改了drv_sound.c中原来的配置,参考的是H750水星开发板。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/6b967b4f8493e772cf32988b7bd9dcef.png.webp) 接下来是DMA的配置,这里使用DMA2_Stream3。H7系列的DMA和其他系列有所不同,增加了一个DMAMUX的配置,这是什么东东? ![image.png](https://oss-club.rt-thread.org/uploads/20210707/e697d552d142e6640f1a2fdf020abc20.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/9eb8a64b2d35a59edad3c870e3d25f0c.png.webp) 我们使用的dma2需要通过配置DMAMUX1的映射。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/d51f9862fd6a88c75d3396b13b378c09.png.webp) 弄清楚原理就开始上代码了。其中关于DMAMUX1的配置已经红框标识出来了。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/b1862fb7a3c171e53d053b3c0766afeb.png.webp) DMA中断中处理的事情 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/861b75a7a94a7305f29204c87943349b.png) 然后呢,是如何实现音乐的播放和停止的呢,其实就是使能和禁止DMA数据流就可以了。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/0257b8659080e8f3564c8bd5fd8cb284.png.webp) **通过对SAI2_A代码的理解,整个处理流程就比较清晰了。 1.初始化硬件接口 2.初始化SAI2_A作为主发送器 3.初始化DMAMUX1映射接口,初始化DMA2_Stream3,并开启中断 4.播放音乐的时候,开启DMA传送流。 5.停止音乐的时候,禁止DMA传送流。** **配置SAI2_B** 上面的部分是对原有drv_sound.c关于SAI2_A的理解以及修改一些函数达到优化的目的。接下来重点来了,按此流程来初始化SAI2_B,并注册一个新的设备mic0. 首先,宏定义buffer大小,已经构造一个结构体_stm32_record。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/c35f6e3dd5f78885b7eaacc6541f4660.png) 接下来需要写四个函数,这四个函数都是应用层通过audio组件来操作硬件设备的接口。由于SAIB是作为从接收器,因此对于时钟的配置,通道配置,采样数据位数的配置这些参数都是通过调用SAIA的配置函数来实现的。而且经过实验,目前采集效果比较好的一组参数就是:采样率44100,通道2,位数16位。其他参数都有杂音,具体原因还不清除,程序有待完善。因此这里锁定配置参数。 这里需要重点说明一下void SAIB_samplerate_set(rt_uint32_t freq)函数,在配置完采样率之后,需要打开SAI2A的DMA数据流,因为这样总线上才会产生FS,CLK同步信号。然后使能SAI2B的DMA和音频模块。如果这里不使能SAI2A的DMA数据流,会因为总线上没有FS,CLK信号而无法采集到音频数据流,也就没办法进入DMA接收中断。这里很重要,我在这个坑里泡了很久,最后用逻辑分析仪抓引脚信号才发现的。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/6745141d768e12fdf305eafcc40f9cd2.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/189298395f7116e66589892c48dc806b.png) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/c29761369abc52ce4f72f3de6c358f3f.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/3e7ac7baf74f7e3eae0bdc848a75c7c2.png) 接下来就是SAI2B的功能配置和DMA配置,这里选了DMA2_Stream2。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/cc7a5f57efb89a92eabfbf2d935d97f5.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/0f6895fa0bb2841494981a4c262b1711.png.webp) 注意因为我们使用了双缓冲机制,因此在DMA2_Stream2中断中,需要判断是哪一个FIFO满了,我们要从相应的FIFO中获取数据,一开始没注意这个问题,总是从同一个FIFO中获取数据,结果只取到一组数据,而另一组满了。造成溢出错误中断。别问我为什么知道,因为我快成玩泥坑的小猪佩奇了。 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/90a875b2a93f17d29946f95ae20adb5b.png.webp) 然后就是仿造着前面SAI2_A中的两个与audio组件对接的函数的样式,写两个函数作为mic设备与audio组件对接。 分别是函数static rt_err_t stm32_record_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps) 和函数static rt_err_t stm32_record_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps) 然后就是初始化入口函数,数据流传送开始函数,数据流传送停止函数等 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/51d40d5064aa4dfa4d22394bbe525778.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/c8388b3b70086c4d099c25bb3e756741.png.webp) 上述这些都基本照抄SAI2_A中相应的函数,改一下名称而已。 接下来就是mic0设备的初始化函数了。没想到又是一个大坑,具体如下图所示: ![image.png](https://oss-club.rt-thread.org/uploads/20210707/5cfb55fe3a1ac7b0d1ce3156414e202e.png.webp) 通过上述配置就完成了SAI2_B的初始化配置,并注册位mic0设备,而且对接到audio组件,方便应用层去调用。代码烧录进去之后,发现录到的是杂音,这又是为啥呢?原来WM8988的初始化还有问题没有解决。原来WM8988有两路输入,两路输出,可以通过配置寄存器实现多种输入和输出的组合。 **配置WM8988** ![image.png](https://oss-club.rt-thread.org/uploads/20210707/429ee19515c80a82472ef5d646a50a16.png.webp) 好吧,继续爬寄存器。 这里我修改了原来的配置,将wm8988的功能配置如下: 1.只使用一路输出,固定将输出指向LOUT1,就是对应于多媒体扩展板上的audio插口。Lineout插口暂时不用了。 2.只使用一路输入,固定使用INPUT1,对应于多媒体扩展板上的极柱体麦克风。 配置代码如下: ![image.png](https://oss-club.rt-thread.org/uploads/20210707/0748aa2bbd0e36ec14e3fa4ea9fe8625.png.webp) 好了,最后看一下settings的配置 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/b1047c61f71f0fdb0be55f9e0e685dea.png) ![image.png](https://oss-club.rt-thread.org/uploads/20210707/6cbc56187c9eddff0371554dea54bb17.png) **功能验证** 插TF卡,开机,连接调试终端,通过终端输入命令 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/8b4366e26890935a0b81eca2d8835005.png.webp) 结束录音 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/346c1bc7976f15b40ee3f2cc1fd96b12.png) 通过ls命令查看 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/af5cbd23fda4895f180ef788003175bf.png) 插上耳机,通过wavplay命令来播放刚刚的录音文件 ![image.png](https://oss-club.rt-thread.org/uploads/20210707/adcb39f759bac2990a6a581e4c05797d.png.webp) **NICE!** **总结** 初步实现了多媒体扩展板的录音功能。虽然还不够完美,程序有待完善,但是从中还是学到了不少知识。 1. DMAMUX和DMA的联系 2. SAI外设的功能配置和使用 3. WM8988的功能配置和使用 在此将内容分享出来,希望能给小伙伴们一个参考。也希望更多的小伙伴能加入到代码的完善中来,一起学习一起进步。 **相关文章:** [Art-Pi学习笔记10:优化多媒体扩展板的音频驱动添加录音功能](https://club.rt-thread.org/ask/article/2872.html) [Art-Pi学习笔记9:如何使用art-pi的多媒体扩展板播放TF卡中的音乐文件](https://club.rt-thread.org/ask/article/2849.html) [Art-Pi学习笔记9:如何为Art-pi的内部flash设置读保护](https://club.rt-thread.org/ask/article/2568.html) [Art_Pi学习笔记8:使用AHT10温湿度模块](https://club.rt-thread.org/ask/article/2543.html) [Art_Pi学习笔记7:自己添加硬件定时器设备HWTIMER](https://club.rt-thread.org/ask/article/2492.html) [Art_Pi学习笔记6:驱动PWM输出](https://club.rt-thread.org/ask/article/2483.html) [Art-Pi学习笔记5_4:在littlevgl中显示二维码](https://club.rt-thread.org/ask/article/2698.html) [Art-Pi学习笔记5_3:在littlevgl软件包中显示中文字体](https://club.rt-thread.org/ask/article/2695.html) [Art_Pi学习笔记5.2:LVGL模拟器安装在VS2019上的避坑指南](https://club.rt-thread.org/ask/article/2470.html) [Art_Pi学习笔记5.1:优化LVGL软件包提高刷屏的速度](https://club.rt-thread.org/ask/article/2464.html) [Art_Pi学习笔记5:移植LittleVGL2RTT软件包驱动多媒体扩展屏](https://club.rt-thread.org/ask/article/2434.html) [Art_Pi学习笔记4:驱动多媒体扩展版的LCD和触摸功能](https://club.rt-thread.org/ask/article/2436.html) [Art_Pi学习笔记3:学习驱动wifi模块AP6212](https://club.rt-thread.org/ask/article/2429.html) [Art_Pi学习笔记2:驱动片外SPI_FLASH_W25Q128](https://club.rt-thread.org/ask/article/2423.html) [Art-Pi学习笔记1:驱动SDIO和USB设备做TF读卡器](https://club.rt-thread.org/ask/article/2417.html)
10
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
adaphoto
这家伙很懒,什么也没写!
文章
25
回答
44
被采纳
5
关注TA
发私信
相关文章
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
stm32L4 lpuart1DMA下不能打开的问题
4
UART驱动开启DMA后编译报错,UART DMA配置中加入了没有定义的域
5
UART DMA 设计问题
6
UART DMA 拆包问题
7
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
8
串口接收使用方式问题
9
在studio中打开串口的DMA后,编译出错
10
官方DMA串口例程,使用时数据打印错误
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
12
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
7
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部