一. 前言

本文分享基于【富芮坤FR3068x-C】开发板实现基于micrpython的本地音频播放器。完全按照产品化的项目进行,考虑可测试可调式可移植可维护性,完成一个完整的项目。

代码见:https://gitee.com/qinyunti/fr3068-e-c-micropython.git

视频见:

【【富芮坤FR3068x-C】基于REPL MicroPython实现本地音乐播放】 https://www.bilibili.com/video/BV1aPCMYsEyf/?share_source=copy_web&vd_source=30f88a61ba48d80acfe41f622b10a844


基于REPL MicroPython实现本地音乐播放

二. 前期技术准备

详见网站文章


图片1.png
图片2.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps15.jpg

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps16.jpg

框图如下

包括实现基于fifo的uart驱动给micropython,shell,文件传输等提供好用高效的串口读写接口。

Shell的实现,实现了大量的测试调试命令集,文件操作命令集,音频播放命令集等,

Micropython基于mdk的移植,实现pyb模块,LED和AUDIO设备等

SPI的驱动测试BUG修改,FLASH读写驱动重写,FATFS适配测试调试。

DAC驱动调试包括示波器测试波形等,DAC的ping-pong发送驱动,基于FIFO状态机机的播放调度,消息队列和其他任务交互。

以及基础组件,FIFO实现,X.YMODEM实现,WAV解析,MD5计算等。


图片3.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps17.jpg


三. 音频播放设计

3.1 Wav格式解析

见微信公众号文章

基于DWC2的USB驱动开发-UAC之WAV-PCM音频文件格式详解


解析代码见代码wav_decode.c/h



3.2 架构设计

ping-pong发送架构

启动时先填满硬件FIFO,在硬件FIFO半满时产生中断,中断回调中填入新的一半数据。


图片4.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps18.jpg

FIFO流实现


上述DAC半满中断中,需要获取新的待发送数据写入硬件FIFO,这个操作必须快速,所以这里不能直接去读音频文件,而是通过一层软件FIFO来实现。

任务中读音频文件,写入软件FIFO,中断中从软件FIFO中取数写入硬件FIFO。


图片5.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps19.jpg

处理状态机

为了方便管理音频的播放,启停,音频播放任务按照状态机设置,

通过消息队列往该任务发送控制。

默认进入空闲状态,收到play消息,进入play状态,读取文件,写入软件FIFO。

播放完或者收到stop消息停止,进入空闲状态。


图片6.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps20.jpg

断流问题

参考公众号文章第四小节介绍

es8388音频芯片驱动之六:ES8388+UAC的录音播放实例分享


即半满中断回调从软件FIFO取数,以及任务往软件FIFO写数,之前可能存在临界状态。比如前者可能时间是

999uS,1ms后者可能是

1.1ms, 999us

那么可能存在前一次取数时间间隔小于写入使劲间隔,导致本次取数失败断流,这是因为两者平均速度有微小偏差导致,这个偏差抖动会导致经常性的断流。

解决办法是,先让软件FIFO中有多笔数据时,才开始取数,这样之后每次都能取到数,因为这个小的波动被FIFO中积蓄的数据消除掉。


3.3 音频驱动

详见网站上文章,这里不再介绍,可以先输出正弦波等进行测试,确保输出正确。

四. Shell下音频播放测试

详见视频演示

准备wav文件

下载MP3测试文件,我这里假设是leiqiao.mp3。

下载ffmpeg。


在当前文件夹下,命令行下运行命令:

ffmpeg/ffmpeg.exe -i leiqiao.mp3 -ac 1 -ar 16000 -acodec pcm_s16le -ss 00:00:05 -t 00:00:30 leiqiao.wav


其中-i后面为输入文件

-ac后面1表示输出1通道

-ar后面16000表示采样率16k

-acodec表示数据格式pcm_s16le表示 pcm有符号16位小端

-ss表示截取开始时间

-t表示截取时间长度

16k.wav是输出文件名。

这里有三个测试文件放在了源码目录下


图片7.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps21.jpg


导入文件

通过xmodem导入wav文件到开发板


图片8.png
图片9.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps22.jpg

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps23.jpg



启动播放


图片10.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps24.jpg


dacplay 文件名

停止播放

dacstop


静音控制

dacvolume 音量

音量设置

dacpa 0/1


五.绑定microplay 音频播放模块


py\genhdr\moduledefs.h中之前LED示例中已经注册模块pyb_module,

我们在

Src\py_port\modpyb.c中

pyb_module_globals_table下添加

{ MP_ROM_QSTR(MP_QSTR_AUDIO), MP_ROM_PTR(&pyb_audio_type) },

即注册pyb下的audio。


图片11.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps25.jpg


实现代码见audio.c和audio.h

audio.c中实现

主要绑定实现以下接口,mute,volume,play,stop


图片12.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps26.jpg


六.Micropython下音频播放测试

详细效果见视频演示

Shell环境中输入micropython进入python环境,

import pyb

audio = pyb.AUDIO(1) 这里注意ID从1开始只有一个实例

开始播放audio.play("2:/leiqiao.wav")

提前结束播放audio.stop()


图片13.png

file:///C:\Users\qinyunti\AppData\Local\Temp\ksohtml22964\wps27.jpg



mute测试

audio.mute(1)  静音

audio.mute(0)   不静音


设置音量测试

audio.volume(1)可以听到声音变小


退出python环境 按组合按键ctrl+d


七. 总结

以上分享了基于【富芮坤FR3068x-C】开发板实现基于micrpython的本地音频播放器。

可见富芮坤FR3068x-C开发板资源丰富,性能不错,尤其针对音频解决方案集成度高,使用直接PWM-DAC输出播放音频效果也非常不错,从演示视频可以看到,播放效果非常好几乎无杂音,完全不需要外置音频芯片可以满足大部分应用,是低成本高集成度的解决方案。在音频应用领域可以优先考虑该方案。