1. 概述
本文主要记录下音频播放实现过程中遇到的问题。音频文件存储在外部FLASH中,SPI+DMA读取到MCU中,然后进行DAC转换后输入到NS4165B音频功率放大器(数据手册)。第一次接触音频,遇到很多零碎问题,有些问题很基础,主要是学习单片机时不够扎实,统一记录在这里。
先贴三篇参考的文章,都是此方案的实现:
基于STM32的DAC实现音频波形的输出
STM32F103使用TIM DMA DAC实现播放WAV音乐
基于STM32F103C8T6片内Flash的音频播放(DAC通道)
通过这三篇文章,有了一个整体的概念。
2. 音频采样率
2.1 定时器触发周期
DAC使用定时器作为触发源,参考的三篇文章,对定时器的周期设置描述比较少。定时器的周期应该设置多少呢?
定时器计时时间到,进行一次DAC转换,所以应该与音频的采样速率相同。
更多时候是采用DAC,使用I2S通信,可以直接设置音频采样率:
而定时器,则需要自己计算下预分频和计数值:
仿真查看系统时钟0x44AA200 = 72M,修改为预分频12M,再750计数,正好是16K
使用正弦进行测试,每一小段正好为16K
2.2 音频文件的格式
在音频文件的头信息中,包括了单双声道、采样速率等信息。
从第45字节开始,才是采样的音频数据:
具体描述如下:
扩展链接:
1.多媒体文件格式(五):PCM / WAV 格式。
2.PCM音频数据。
3. DAC的左对齐和右对齐
以往ADC也好,DAC也好,以往都是用右对齐,也没关注过左对齐有什么用,使用上有什么区别。
3.1 为什么要使用左对齐
在8位单片机中,超过8位的数据,就要占用H和L两个寄存器。左、右对齐,就对应了H存放高八位和L存放低八位。当对转换精度要求不高时,通过设置左对齐,只读H寄存器取高八位,加快速度。
而在32位单片机,寄存器基本是16位和32位,都是读取一次寄存器,并不存在上述的只读一次H加快速度了。那么左对齐是不是就没用了呢?在这里恰巧用到了左对齐。
参考链接:ADC数据存储:左对齐和右对齐。
3.2 左对齐数据的读写
最常用的是右对齐,数据寄存器如下:
使用时直接对寄存器进行读取即可。而左对齐数据寄存器如下:
设置为左对齐模式,在数据处理时需要进行处理。若寄存器里左对齐的数据值X,则X>>4才是实际的数据。
单片机是按照地址进行读写,并不会因为我们设置了左右对齐,直接将我们的数据放到有效位。
3.3 音频数据的使用
3.3.1 16bit数据和12位DAC的失真问题
我的音频文件是16位,而DAC是12位,那么就要对16位数据进行取舍,所以转换音频数据的高12位。
这个时候如果使用右对齐,需要对每一个音频数据进行移位操作,因为音频数据很大,是比较浪费时间的。那么使用左对齐,就不必进行移位,直接赋值音频数据就可以了。
经过这样处理后,有明显噪音。将音频重新采样为8bit后,能够正常播放,怀疑是16bit忽略低4位导致的。但实际并不是,这个失真是相对使用16位DAC,而使用精度较差的DAC,高精度采样数据,并不会失真,反而可能会更好。这一点,可以通过简单计算理解:
- 假设参考电压3V,实际电压2V,计算12位DAC和16位DAC的采样值。
- 然后忽略16位采样值的低四位,也就是>> 4,与12位DAC的采样值对比。
3.3.2 音频数据的符号位处理
上一小节提到16bit有杂音,改为8bit重新对音频采样,就可以正常播放了。这是因为16位音频数据是有符号的,在使用DAC进行转换时,需要考虑去除符号位。
STM32F103.12位DAC输出16位WAV语音文件
简单的程序将int16_t数组转换为uint16_t
4. 单双声道的理解
单双声道 – DMA每传输一次,地址偏移size,所以配置中size改为字
下一次传输的地址将是前一次传输的地址递增 1个数据宽度、2个数据宽度或 4个数据宽度
【STM32】 DMA原理,步骤超细详解,一文看懂DMA
5. DMA无法进入中断
调试DMA+TIM+DAC实现音频输出,发现无法进入DMA中断,芯片为国民技术N32G45。
一定要先使能DMA通道中断,再使能DMA通道。
6. 测试播放效果
直接播放flash存放的开机音乐等,噪音较大,且波形不是规律的,不易分析。
6.1 测试单音
直接测试flash内的音频,无法播放可能有很多原因。可以先测试单音:通过调整正弦的频率,让喇叭发出不同的声音。
在1 2 3 4 5 6 7的在声乐中的的频率各是多少?帖子中,得到以下频率:
A:440Hz a:880Hz
B:493.88Hz b:987.76Hz
C∶523.25Hz c:1046.50Hz
D: 587.33Hz d:1174.66Hz
E∶659.25Hz e:1318.51Hz
F∶698.46Hz f:1396.92Hz
G∶783.99Hz g:1567.98Hz
再看正弦数组:
一个正弦周期是32个采样点,那么要发哪个声音,就用频率 * 32得到DAC用作触发的定时器频率。定时器预分频为12M,所以再用12M/频率,就得到计数值。
A * 32 12M/(A * 32) a * 32 12M/(a * 32)
A:440Hz a:880Hz 14080 852 28160 426.13
B:493.88Hz b:987.76Hz 15804.16 759 31608 379.65
C∶523.25Hz c:1046.50Hz 16744 716.67 33488 358.33
D: 587.33Hz d:1174.66Hz 18794.56 638.48 37589 319.24
E∶659.25Hz e:1318.51Hz 21096 568.82 42192 284.41
F∶698.46Hz f:1396.92Hz 22350.72 536.91 44701 268.45
G∶783.99Hz g:1567.98Hz 25087.68 478.31 50175 239.16
只要传入计数值即可:
6.2 测试播放人声
为了能够容易感受到调试过程中声音的变化效果,需要使用人声。
在线文字转语音,语音合成,真人语音合成-在线工具
生成后将数据放到const数组即可进行测试。文章来源:https://www.toymoban.com/news/detail-420705.html
7. 音频文件制作
自己选一个音乐片段,生成音频文件:Goldwave生成wave音频数据。文章来源地址https://www.toymoban.com/news/detail-420705.html
到了这里,关于DAC+DMA+TIM实现音频播放问题记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!