I2 S
目录
I2S
Inter-IC Sount Bus(I2S)是飞利浦半导体公司(现为恩智浦半导体公司)针对数字音频设备之间的音频数据传输而制定的一种总线标准。 在飞利浦公司的I2S标准中,既规定了硬件接口规范,也规定了数字音频数据的格式。
背景介绍
数字音频技术
现实生活中的声音是通过一定介质传播的连续的波,它可以由周期和振幅两个重要指标描述。正常人可以听到的声音频率范围为20Hz~20KHz。 现实存在的声音是模拟量,这对声音保存和长距离传输造成很大的困难,一般的做法是把模拟量转成对应的数字量保存,在需要还原声音的地方再把数字量的转成模拟量输出。
模拟量转成数字量过程,一般可以分为三个过程,分别为采样、量化、编码。 用一个比源声音频率高的采样信号去量化源声音,记录每个采样点的值,最后如果把所有采样点数值连接起来与源声音曲线是互相吻合的, 只是它不是连续的。在图中两条蓝色虚线距离就是采样信号的周期,即对应一个采样频率(FS), 可以想象得到采样频率越高最后得到的结果就与源声音越吻合,但此时采样数据量越越大,一般使用44.1KHz采样频率即可得到高保真的声音。 每条蓝色虚线长度决定着该时刻源声音的量化值,该量化值有另外一个概念与之挂钩,就是量化位数。量化位数表示每个采样点用多少位表示数据范围, 常用有16bit、24bit或32bit,位数越高最后还原得到的音质越好,数据量也会越大。
音频编解码器
因为声音采样需要处理,因此有专门的编解码器。我写这篇笔记学习时使用的时INMP441,平台是stm32f407。INMP441是一款高性能、低功耗、数字输出、全指向MEMS麦克风,带有底部接口。完整的INMP441解决方案包括MEMS传感器、信号调理、模数转换器、防混叠滤波器、电源管理以及行业标准的24位I²S接口。I²S接口允许INMP441直接连接到数字处理器,如DSP和微控制器,无需在系统中使用音频编解码器。关于INMP441的其他特性可参考数据手册。
I2S总线接口
I2S总线接口有3个主要信号,但只能实现数据半双工传输,后来为实现全双工传输有些设备增加了扩展数据引脚。STM32f4xx系列控制器支持扩展的I2S总线接口,即可实现全双工。
-
SD(Serial Data):串行数据线, 用于发送或接收两个时分复用的数据通道上的数据(仅半双工模式),如果是全双工模式,该信号仅用于发送数据。
-
WS(Word Select):字段选择线, 也称帧时钟(LRC)线,表明当前传输数据的声道,不同标准有不同的定义。WS线的频率等于采样频率(FS)。
-
CK(Serial Clock):串行时钟线, 也称位时钟(BCLK),是主模式下的串行时钟输出以及从模式下的串行时 钟输入,数字音频的每一位数据都对应有一个CK脉冲,它的频率为:2*采样频率*量化位数,2代表左右两个通道数据。
-
ext_SD(extend Serial Data): 扩展串行数据线,用于全双工传输的数据接收。
另外,有时为使系统间更好地同步,还要传输一个主时钟(MCK),STM32F4xx系列控制器固定输出为256* FS。
音频数据传输协议标准
随着技术的发展,在统一的I2S硬件接口下,出现了多种不同的数据格式,可分为左对齐(MSB)标准、右对齐(LSB)标准、I2S Philips标准。 另外,STM32F4xx系列控制器还支持PCM(脉冲编码调)音频传输协议。下面以STM32F4xx系列控制器资源解释这四个传输协议。
STM32f4xx系列控制器I2S的数据寄存器只有16bit,并且左右声道数据一般是紧邻传输,为正确得到左右两个声道数据,需要软件控制数据对应通道数据写入或读取。 另外,音频数据的量化位数可能不同,控制器支持16bit、24bit和32bit三种数据长度,因为数据寄存器是16bit的, 所以对于24bit和32bit数据长度需要发送两个。为此,可以产生四种数据和帧格式组合:
- 将16位数据封装在16位帧中
- 将16位数据封装在32位帧中
- 将24位数据封装在32位帧中
- 将32位数据封装在32位帧中
当使用32位数据包中的16位数据时,前16位(MSB)为有效位,16位LSB被强制清零,无需任何软件操作或DMA请求(只需一个读/写操作)。 如果程序使用DMA传输(一般都会用),则24位和32位数据帧需要对数据寄存器执行两次DMA操作。24位的数据帧,硬件会将8位非有效位扩展到带有0位的32位。对于 所有数据格式和通信标准而言,始终会先发送最高有效位(MSB优先)。
I2S Philips标准
使用WS信号来指示当前正在发送的数据所属的通道,为0时表示左通道数据。该信号从当前通道数据的第一个位(MSB)之前的一个时钟开始有效。 发送方在时钟信号(CK)的下降沿改变数据,接收方在上升沿读取数据。WS信号也在SCK的下降沿变化。下图为24bit数据封装在32bit帧传输波形。 正如之前所说,WS线频率对于采样频率FS,一个WS线周期包括发送左声道和右声道数据,在图中实际需要64个CK周期来完成一次传输。

还有

上图表示:
- 发送方在时钟信号 (CK) 的下降沿改变数据,接收方在上升沿读取数据。WS 信号也在 CK 的下降沿变化。
相应的寄存器读写

MSB(左对齐)标准
此标准同时生成 WS 信号和第一个数据位(即 MSBit)。

发送方在时钟信号的下降沿改变数据;接收方在上升沿读取数据。
LSB(右对齐)标准
该标准与 MSB 对齐标准类似(对于 16 位和 32 位全精度帧格式,没有任何不同)。

PCM标准
PCM即脉冲编码调制,模拟语音信号经过采样量化以及一定数据排列就是PCM了。WS不再作为声道数据选择。它有两种模式, 短帧模式和长帧模式,以WS信号高电平保持时间为判别依据,长帧模式保持13个CK周期,短帧模式只保持1个CK周期,可以通过相关寄存器位选择。 如果有多通道数据是在一个WS周期内传输完成的,传完左声道数据就紧跟发送右声道数据。
I2S 功能框图

功能引脚
I2S的SD映射到SPI的MOSI引脚,ext_SD映射到SPI的MISO引脚,WS映射到SPI的NSS引脚,CK映射到SPI的SCK引脚。MCK是I2S专用引脚, 用于主模式下输出时钟或在从模式下输入时钟。I2S时钟发生器可以由控制器内部时钟源分频产生,亦可采用CKIN引脚输入时钟分频得到, 一般使用内部时钟源即可。
数据寄存器
I2S有一个与SPI共用的SPI数据寄存器(SPI_DR),有效长度为16bit,用于I2S数据发送和接收,它实际由三个部分组成,一个移位寄存器、 一个发送缓冲区和一个接收缓冲区,当处于发送模式时,向SPI_DR写入数据先保存在发送缓冲区,总线自动把发送缓冲区内容转入到移位寄存器中进行传输; 在接收模式下,实际接收到的数据先填充移位寄存器,然后自动转入接收缓冲区,软件读取SPI_DR时自动从接收缓冲区内读取。I2S是挂载在APB1总线上的。
逻辑控制
I2S的逻辑控制通过设置相关寄存器位实现,比如通过配置SPI_I2S配置寄存器(SPI_I2SCFGR)的相关位可以实现选择I2S和SPI模式切换、 选择I2S工作在主模式还是从模式并且选择是发送还是接收、选择I2S标准、传输数据长度等等。SPI控制寄存器2(SPI_CR2)可用于设置相关中断和DMA请求使能, I2S有5个中断事件,分别为发送缓冲区为空、接收缓冲区非空、上溢错误、下溢错误和帧错误。SPI状态寄存器(SPI_SR)用于指示当前I2S状态。
时钟发生器
I2S比特率用来确定I2S数据线上的数据流和I2S时钟信号频率。I2S比特率=每个通道的位数×通道数×音频采样频率。(传输一位的频率)


要实现高品质的音频性能,I2SxCLK 时钟源可为 PLLI2S 输出(通过 R 分频系数)或外部时钟(映射到 I2S_CKIN 引脚)。
SPI_I2S预分频器寄存器(SPI_I2SPR)的MCKOE位用于设置MCK引脚时钟输出使能;ODD位设置预分频器的奇数因子,实际分频值=I2SDIV*2+ODD;I2SDIV为8位线性分频器,不可设置为0或1。
音频采样频率可能是 192 kHz、96 kHz 或 48 kHz。为达到所需频率,需要根据以下公式对线性分频器进行编程:
输出主时钟(SPI_I2SPR 寄存器中的 MCKOE 置 1)时:
当使能MCK时钟输出,即MCKOE=1时,采样频率计算如下: $$ FS = I2SxCLK/[(16\times 2)\times ((2\times I2SDIV)+ODD)\times 8)](通道帧宽度为16bit时) \ FS = I2SxCLK/[(32\times 2)\times ((2\times I2SDIV)+ODD)\times 4)](通道帧宽度为32bit时) $$ 当禁止MCK时钟输出,即MCKOE=0时,采样频率计算如下: $$ FS = I2SxCLK/[(16\times 2)\times ((2\times I2SDIV)+ODD))](通道帧宽度为16bit时) \ FS = I2SxCLK/[(32\times 2)\times ((2\times I2SDIV)+ODD))](通道帧宽度为32bit时) $$ MCK引脚输出的是串行时钟(SCK),而不是主时钟
关系:
-
MCK频率 = 采样率 × 帧宽度 × 2(左右声道)
-
SCK频率 = 采样率 × 帧宽度 × 2 × 每个采样的位数(通道帧为32位时每个采样64位;通道帧为16位时每个采样32位)
所以需要额外分频来生成正确的MCK输出频率
实操
在CubeMX左侧边栏中的Multimedia选择I2S2

- 这里使用麦克风INMP441,因此是主机接收。注意,INMP441是单声道麦克风。
- 根据模块的数据手册,选择I2S Philips格式
- 数据帧宽度也是根据手册来的。INMP441是24位左对齐(MSE)帧格式,因此选择32 Bits(也可以选择24 Bits)
- 采样频率根据需求以及手册范围,通常16KHz
- 时钟极性CPOL是指时钟线空闲时候的电平状态。根据I2S Philips,设置为Low
声道选择
如果仅接入一个麦克风,可用把对应L/R接地(左声道输出)或者接VCC(右声道输出)。
而STM32F4手册里面有这么一句话:
一个完整帧表示先进行左通道数据发送再进行右通道数据发送。不存在仅发送左通道的部分帧。
因此,需要跳过另一声道的帧。(读出来全是0)
滤波
不能使用低通滤波,声音本来就是高频信号。
大小端(Endianness)与DMA数据宽度对齐的问题
一开始,我使用16位单元的缓冲区uint16_t buf[],除了需要调整一下采样率对应关系外,一切正常。
因为接受的音频实际上是24位的,所以直接使用32位单元的缓冲区,然后DMA设置半字就好了,这样应该也能获取正常的数据。结果就掉进了坑里。
注意,INMP441/I2S 协议:发送数据是 MSB 先行(高位在前)。而STM32 内存读取:是 小端模式 (Little-Endian),即低地址存低位数据。
换句话说,第一个写入接收数据寄存器的那16位,也就是音频信息的高位,被写入了我们分配的32位缓冲区的低位;而第二个写入接收数据寄存器的那16位,也就是音频信息的低位,被写入了我们分配的32位缓冲区的高位。于是声音信息完全混乱。
解决方法也简单,交换一下高低16位就行了,然后再右移8位得到24位数据。