STM32的新片子的音频外设叫SAI了,S就是Serial,A就是Audio,I就是Interface,还是挺好记的.究竟新在哪里,就是支持音频各种了,但是实际上用到的,还不是I2S.为了不要让大家蒙圈,我总结下我理解的经验,SAI配置其实非常简单.
看下图,初始化,才4个寄存器:
我们要拆分难点,首先,回想下SPI协议,要用硬件SPI来发东西,要想从机能收到信息,需要做哪些配置:
- 打开SPI外设时钟
- 修改引脚复用
- 设置SPI分频,模式等等
- 发数据
是的,看起来非常简单,SAI也是一样,要打开外设时钟,修改引脚复用,设置时钟,发数据,就这么就完成了.但是音频跟SPI的最明显区别是什么?
- 音频是不断流的,SPI发完可以休息.
- 音频是没CS的,他CS相当于左右声道,都有用.
- 音频他频率跟SPI不一样,通常不是整数的.
首先第一,我们要用DMA的双缓冲,或者DMA的半传输中断不断填Buffer,才能做到不断流.这是DMA的作用.也就是你要学习SAI,先学DMA吧.是用半空还是双Buffer,看你的器件设计了.注意Buffer还不能太小,不然在你填Buffer过程,另一个Buffer就完成发送了.
音频的CS,就是左右声道,都是硬件控制的,不担心之.
因为频率原因,所以他不是从总线分频,而是有自己的PLL,多么奢侈.不过就算是这样,STM32的SAI一样做不到完全标准频率.
在SAI上,还有几个让人蒙圈的概念,slot和frame.为了方便理解,我用最通俗方式讲,但不是最科学.我们把slot等效为byte,一byte就是一个声道的数据,一frame就是一次完整的表达,比如2声道的音乐,那么需要2byte(slot)才能构成一次传输,也就是1frame,8声道就是8个byte(slot)构成一个frame了,这下好理解啦吧.
但是此处byte不一定是8bit,如果是32bit音乐,这个byte就是32bit,是16bit音乐,这个byte就是16bit,32bit的立体声,一次frame要传64bit的数据.slot的长度相当于SPI的发送位数.而frame,就是多个slot构成,想象成一个SPI要公平给多个不同设备发送数据.那么只能来回切CS.一个设备CS高有效,一个CS低有效.
之前说过SAI时钟跟别的时钟不同,那么他就有他的独立时钟发生器.他的名字就叫PLLSAI,对就是SAI专用的.复习一下I2S,I2S有四条线(精简情况3条,不是此时讨论的.),为了方便讨论,我代入192KHz的音频fs来说,而MCLK引脚,要256倍fs,也就是要49.152MHz,我们PLL就是要配到这个频率,然后输出到MCLK引脚.
这下,我们PLLSAI就克服了,当49.152MHz时候,分频0,就是192k音频了.
那么,那4个寄存器呢?分别是CR1,CR2,FRCR,SLOTR,看名字CR就是控制寄存器,很好理解.因为SAI是支持输入音频的,所以寄存器也多了点.
先看看1号寄存器.
MCKDIV就是刚才说的要得到192K的音频,那么分频是0,记住分频是0哦,因为你要PLLSAI/256/分频 = 音频频率,而实际上不能设置为0,因为为0时候,ST为了不出现除0错误,输入0等于1,所以要设置成NODIV允许.如果要分,NODIV就禁止,然后设置分频数值.
DMAEN和SAIEN就是开关,这肯定在最后才打开他们.打开后就相当于SAI在工作了.
OUTDRIV就是是否开驱动,如果不开,那么只有SAIEN开了,驱动才有,否则驱动可以一直存在,一般选驱动一直在就行,因为经常变换fs时候,重写初始化要失能SAIEN,然后驱动丢了电平就不确定了.
MONO单声道双声道,很好理解.
SYSCEN设置,我们工作在I2S模式,仅仅输出时候不用设置同步,如果要同时输入输出,就是要同步,这样可以节省MCLK,CS(其实是声道选择),FSCLK三根,只要多一根线,当然同步是跟自己内部模块同步还是内部其他SAI同步分多钟情况.
CKSTR就像我们SPI的CPOL模式,我们一般设置为1,下降沿时候生成数据.也有可能有其他DAC不同,没见过.
LSBFIRST和我们SPI的MSB/LSB一样道理.
DS和我们SPI一次发多少Bit同样道理,我们发16bit,这里设置了slot还得设置,因为SAI还有一种叫slot不对齐模式(为什么要这么干?不明白)
PRTCFG是设置协议,类似SPI的摩托罗拉模式,TI模式,我们用的是I2S,是开源模式.
MODE是设置模式,跟SPI一样,是主机还是从机,只不过他多了方向,因为SAI一旦初始化,通信方向就确定.
我们每次变换fs,就是换歌,只需要换CR1寄存器的设置就行了,跟其他没关系.
接下来再看看二号配置寄存器:
只关心最后一个,就是FTH,系统一个一个Byte给东西是很累的,可以设置一个FIFO等级,FIFO低于这个阈值就告诉系统/DMA来给我丢一堆数据,数据量就塞满我FIFO为止.我们可以设成1/4空时候提醒,那么一次可以丢更多东西进去,设置为空有可能因为DMA仲裁不到总线,然后就GG.如果用主设备多,吃总线,那么可能FIFO还要调整.
接下来看FRCR寄存器:
FSOFF是帧t要不要偏移的决定位,明显我们帧不偏移.
FSPOL类似SPI的CPOH,设置FS的低有效还是高有效,根据实际来设置了,因为为0,低有效.
FSDEF配置帧起始信号,而I2S协议起始信号是SOF+通道识别号的,所以设置为1.
FSALL和FRL是互相制约关系,其中FRL是帧长度,比如要发32bit,那么这里设置31,设置的数值一定是基数,并且是2的倍数,最小是8,就是9bit音频,我们的slot长度16bit,两个声道,所以就是32bit,而FSALL是帧同步有效长度,一般设置为一半的FRL,也就是15.
最后最后,就是SLOT配置寄存器了.
SLOTEN,第一次看到EN这么长是吧,这个EN意思是使能多少个slot,我们有2声道,所以要2个slot,他这里最多配置16个slot,如果BIT0设置1,就是1个slot,BIT0+BIT1设置1就是2个slot,所有BIT设置就是16个slot.我们设置0x03,就是2个.
SLOTSZ是slot的size,01就是16bit,10就是32bit配置,如果要兼容32bit和16bit,就要设置成32bit配置.
NBSLOT就是要告诉他多少个slot,最少一个,1个时候填0,两个填1,我们都放立体声,填2,就算要放非立体声的时候,我们也可以左右声道放一样内容,做到单声道效果.不然除了改这里,还要改DAC配置呢.
FBOFF跟之前的FSOFF差不多意思,不过这里偏移的是slot,之前是偏移帧,我们都不需要,设置为0就行.
为什么音频调试让人感到困难,主要克服问题,不要断流,DAC和I2S都要正确才能发生.所以感觉可能比较难.不能拆开调试.