1. 项目概述
在嵌入式系统开发中,与外设的通信是核心任务之一。I2C和SSI作为两种经典的同步串行通信协议,因其硬件连接简单、协议成熟稳定,被广泛应用于连接各类传感器、存储器、音频编解码器等低速外设。对于刚接触底层驱动的开发者来说,面对芯片手册中繁杂的寄存器描述和流程图,常常感到无从下手。本文将以Freescale(现NXP)的MC9328MX1微控制器为例,抛开抽象的理论,直接深入到寄存器操作层面,手把手拆解I2C和SSI接口的编程流程。我会结合自己多年调试这类接口的经验,不仅告诉你寄存器该怎么配置,更会解释为什么这么配置,以及在实操中会遇到哪些“坑”,如何避开它们。无论你是正在调试一个I2C温度传感器,还是试图让SSI接口的音频芯片发出声音,这篇文章都能为你提供从寄存器位操作到完整通信流程的清晰路径和实战心得。
2. I2C接口编程:从寄存器到通信状态机
I2C协议的精髓在于其简洁的两线制(SDA, SCL)和基于状态机的通信流程。在MC9328MX1上,所有的状态感知和控制都通过一组特定的寄存器完成。理解这些寄存器,就相当于拿到了驾驭I2C总线协议的钥匙。
2.1 核心寄存器解析:I2DR与状态控制
I2C模块的寄存器不少,但最核心、最需要透彻理解的是I2C数据I/O寄存器(I2DR)和I2C状态寄存器(I2SR)。数据流转和状态判断都围绕它们展开。
I2C数据I/O寄存器(I2DR)的地址是0x00217010。这个寄存器看似简单,只有低8位(Bit 7-0)是有效数据位D,高24位保留。但它的行为模式却随着I2C模块的工作模式(主发送、主接收、从设备)而动态变化,这是最容易出错的地方。
- 在主发送模式下:当你需要发送一个字节的数据(包括从设备地址)时,你将该字节写入I2DR。硬件会在适当的时机(即在接收到从设备的应答位ACK后)自动将这个字节的数据移位到SDA线上。这里有个关键细节:写入操作本身并不会立即启动发送,它只是将数据放入“发送缓冲区”。真正的发送启动,依赖于你之前是否正确发出了START信号以及总线状态。
- 在主接收模式下:这是最容易混淆的一点。当I2C模块处于主接收模式时,最后一次成功接收到的数据字节会保存在I2DR中。你需要读取I2DR来获取这个数据。更重要的是,读取I2DR这个动作本身,会触发硬件自动生成用于接收下一个数据字节的时钟脉冲。如果你在接收流程中忘记读取I2DR,总线时钟SCL将会被拉低,通信会挂起。许多通信超时错误都源于此。
- 在从设备模式下:其行为与主模式类似,同样遵循“写I2DR以发送,读I2DR以接收并继续”的规则,只不过收发的主导权在于主设备。
I2C状态寄存器(I2SR)则是整个通信过程的“眼睛”。你需要持续查询或通过中断响应它的状态位。几个关键位必须烂熟于心:
- IBB (I2C Bus Busy):总线忙标志。为1表示总线正被占用(在START之后,STOP之前)。在发起通信前,必须检查此位是否为0。
- IAAS (I2C Addressed as a Slave):被寻址为从设备。当从设备检测到自己的地址与总线上广播的地址匹配时,硬件将此位置1。这是从设备中断服务程序首先要判断的条件。
- ICF (Data Transfer):数据转移完成。当一个字节(8位数据+1位ACK/NACK)的传输完成时,此位被置1。清除此位的方式因模式而异:在接收模式下,通过读取I2DR来清除;在发送模式下,通过写入下一个要发送的数据到I2DR来清除。这个机制保证了数据传输的节拍。
- IIF (I2C Interrupt):中断标志。当一次字节传输完成(ICF=1)且中断使能时,此位置1。必须在中断服务程序开头手动清除此位。
- RXAK (Received Acknowledge):接收到的应答位。0表示收到了ACK(应答),1表示收到了NACK(非应答)。主设备在发送完一个字节(包括地址字节)后,需要检查此位以确认从设备是否响应。
- SRW (Slave Read/Write):从设备读/写标志。仅在从设备被寻址(IAAS=1)时有效,指示主设备接下来希望读(1)还是写(0)从设备。
实操心得:状态寄存器的读取与副作用读取I2SR寄存器以查询状态是常规操作,但要注意,有些状态位(如ICF)的清除依赖于特定的操作(读/写I2DR),而不是直接写I2SR。在编写中断服务程序时,一个标准的顺序是:1) 读取I2SR保存状态;2) 根据状态判断进入哪个处理分支;3) 在分支内,通过执行相应的数据操作(读/写I2DR)来清除ICF,并最终手动清除IIF。顺序错误可能导致中断标志无法正确清除,陷入重复中断或丢失中断。
2.2 主设备通信流程全解析
让我们跟随一次完整的I2C主设备读写过程,看看上述寄存器是如何协同工作的。假设我们要向一个从设备(地址0x50)的寄存器0x00写入一个字节数据0xAB。
2.2.1 初始化与START信号生成
在操作总线之前,必须对I2C模块进行初始化。这个过程是静态的,通常在上电或模块使能时执行一次。
- 配置时钟频率:通过I2C频率分频寄存器(IFDR)的
IC字段设置SCL时钟频率。MC9328MX1的I2C时钟源于IP总线时钟,需要通过分频得到符合I2C标准(通常100kHz或400kHz)的SCL。你需要根据系统主频计算分频值。例如,若IP总线时钟为60MHz,要得到约100kHz的SCL,分频系数应为60M / (2 * 100k) = 300。需查阅手册找到最接近的预设分频值。 - 写入自身从地址:如果你的MCU也可能作为从设备被访问,需要在I2C地址寄存器(IADR)中写入自身的7位从地址。纯主设备模式下,此步骤非必须,但建议配置。
- 使能I2C模块:设置I2C控制寄存器(I2CR)的
IEN位为1。 - 配置工作模式:在I2CR中,设置
MTX位为1(主发送模式),IIEN位为1(使能中断,如果采用中断方式)。一个至关重要的检查:在使能I2C模块(IEN=1)前,必须确认IBB位为0(总线空闲)。如果IBB=1,说明总线上可能有异常未结束的通信。此时,一个可靠的做法是:先向I2CR写入一个值,其MSTA位为0(从模式)、MTX位为1,然后向I2DR写入任意值,最后生成一个STOP信号(设置I2CR的MSTA位为0),以强制总线恢复空闲状态。
初始化完成后,生成START信号。START信号的生成是由硬件自动完成的,其触发条件是:在总线空闲(IBB=0)时,将I2CR的MSTA位由0设置为1。软件上,这通常是一条“读-改-写”I2CR寄存器的指令。一旦MSTA置1,硬件会立即在SDA和SCL线上产生START条件,并将IBB置1。
紧接着,你需要发送从设备地址字节。这个字节由7位地址和1位方向位(R/W#)组成。对于写操作,方向位为0。因此,地址0x50的写操作字节是(0x50 << 1) | 0x00 = 0xA0。你将这个字节写入I2DR。硬件会自动在START信号后,将这个地址字节发送出去。
2.2.2 数据收发与中断处理
写入地址字节后,I2C模块开始串行发送。发送完这8位地址和1位方向位后,硬件会等待从设备的ACK。一旦收到ACK(RXAK=0),ICF和IIF位会被置1,如果中断已使能,则会触发中断。
在中断服务程序中(或轮询模式下检测到IIF=1):
- 清除IIF:首先手动清除中断标志位
IIF(向I2SR的对应位写1清零,具体操作需查��册,有些架构是写1清零,有些是读操作后自动清零,MC9328MX1通常是写1清零)。 - 检查状态:读取I2SR,检查
RXAK。如果RXAK=1,说明从设备无应答,通常意味着地址错误或从设备不存在,此时应生成STOP信号(MSTA=0)并结束传输。 - 处理数据:如果
RXAK=0(地址应答成功),且这是地址周期后的第一个中断,此时主设备仍处于发送模式(MTX=1)。接下来我们要发送寄存器地址0x00。清除ICF标志的方法是在发送模式下写入下一个数据到I2DR。所以,我们向I2DR写入0x00。这个操作会清除ICF,并启动第二个字节(寄存器地址)的发送。 - 后续字节:第二个字节发送完毕,再次进入中断。流程类似:清
IIF,查RXAK(应为0),然后向I2DR写入要发送的数据0xAB,启动第三个字节的发送。 - 结束传输:第三个字节(数据0xAB)发送完成后,进入中断。此时所有数据已发送完毕,主设备需要生成STOP信号来释放总线。生成STOP信号的方法是:将I2CR的
MSTA位由1清零。在清零MSTA前,确保最后一个字节的ICF已因写入新数据(或后续操作)而清除。通常,在最后一个数据字节写入I2DR后,在等待其发送完成的中断里,直接清除MSTA位即可。硬件会自动在SDA和SCL线上产生STOP条件,并将IBB清零。
对于主接收模式,流程的关键区别在于模式切换和终止通信的方式。例如,从设备地址0x50的寄存器0x00读取一个字节:
- 发送START,发送地址字节(0xA0,写方向)以选中从设备。
- 发送要读取的寄存器地址(0x00)。
- 发送重复START(Repeated START)。这不是一个STOP后再START,而是在不释放总线的情况下,再次发出START条件。软件操作是:在发送完寄存器地址后,保持
MSTA=1不变,重新向I2DR写入新的地址字节,但这次方向位为1(读操作),即(0x50 << 1) | 0x01 = 0xA1。硬件会自动生成Repeated START信号。 - 写入读地址后,需要将主设备切换为接收模式,即清除I2CR的
MTX位(设为0)。这个操作必须在地址周期中断中,在读取第一个数据字节之前完成。 - 切换为接收模式后,为了启动时钟接收第一个数据字节,需要执行一次对I2DR的“哑读”(Dummy Read)。这个读操作并不关心读回的数据(此时I2DR里可能是无效值),但其副作用是触发硬件生成时钟并开始接收数据。
- 第一个数据字节接收完成后,进入中断。此时,有效数据已存入I2DR。读取I2DR获取数据,这个读操作同时清除了
ICF,并自动启动了下一个字节的接收(如果你需要接收多个字节)。 - 在接收倒数第二个字节之前,主设备需要通知从设备“这是最后一个字节”。做法是:在读取倒数第二个字节之前,将I2CR的
TXAK位设置为1。这告诉硬件,在下一个字节接收完成后,将不发送ACK(即发送NACK)。 - 读取倒数第二个字节(此时已发送NACK预告)。
- 读取最后一个字节。由于上一步已预告NACK,从设备在发送完这个字节后,会释放SDA线。
- 主设备生成STOP信号(
MSTA=0)释放总线。
避坑指南:主接收模式的时序陷阱
- 模式切换时机:从发送模式(
MTX=1)切换到接收模式(MTX=0)必须在地址周期中断中,在读取任何数据之前完成。如果在发送读地址后忘记切换,硬件会继续尝试以发送模式驱动SDA线,导致总线冲突。- “哑读”的必要性:切换到接收模式后,必须有一次读I2DR的操作来“启动”接收引擎。很多新手会等待
ICF置位后再去读,结果发现ICF永远不置位,总线卡死。记住,在接收模式下,是“读操作”触发时钟和接收动作,而不是反过来。- NACK的发送:
TXAK位控制的是主设备在接收字节后,反馈给从设备的ACK/NACK。TXAK=1表示接下来主设备将反馈NACK。因此,你需要在接收倒数第二个字节之前就设置TXAK=1,这样在接收最后一个字节之后,硬件才会自动发出NACK。如果你在接收最后一个字节之后才设置,就来不及了。
2.3 从设备模式与仲裁丢失处理
当MC9328MX1作为从设备时,其核心是响应主设备的寻址。初始化流程与主设备类似,但通常将I2CR的MSTA位设为0(从模式),并使能中断(IIEN=1)。
从设备的中断服务程序逻辑:
- 读取I2SR,检查
IAAS位。如果IAAS=1,表示自己被寻址。 - 根据
SRW位判断主设备的意图:SRW=1表示主设备要读(从设备需发送数据),SRW=0表示主设备要写(从设备需接收数据)。 - 根据
SRW设置MTX位,以匹配接下来的数据传输方向。 - 写I2CR(任何值)以清除
IAAS位。此操作是必须的。 - 如果是从发送模式(
MTX=1),则向I2DR写入第一个要发送的数据字节。 - 如果是从接收模式(
MTX=0),则执行一次对I2DR的“哑读”,以释放SCL线,允许主设备继续发送数据。
在从发送模式下,每次发送完一个字节,都需要检查RXAK位。如果RXAK=1,表示主接收器已发送NACK,意图终止传输。此时,从设备应切换为接收模式(MTX=0),并执行一次哑读,以释放总线让主设备发送STOP信号。
仲裁丢失发生在多主系统中,当两个或以上主设备同时发起传输时。硬件会自动处理仲裁过程,失败的一方会检测到IAL(Arbitration Lost)位被置1,并且其MSTA位会被硬件自动清零(变为从模式),同时产生中断。在仲裁丢失中断服务程序中,软件必须检测并清除IAL位,然后根据应用逻辑决定是否重试。
3. SSI接口编程:时钟、帧同步与数据流
SSI(同步串行接口)是一个比I2C更灵活、更强大的全双工同步串行接口,常用于音频、通信等领域。MC9328MX1提供两个完全相同的SSI模块(SSI1和SSI2),支持I2S、左对齐、右对齐等多种数据格式。
3.1 SSI架构与引脚配置
SSI模块的核心是一个高度可配置的时钟和数据引擎。理解其结构,关键在于区分几组时钟和信号:
- 位时钟(Serial Bit Clock):用于同步每个数据位的传输,由SSI_TXCLK(发送)和SSI_RXCLK(接收)引脚输入或输出。
- 字时钟(Word Clock):内部信号,用于计数一个数据字(8/10/12/16位)的传输完成。
- 帧同步时钟(Frame Sync Clock):用于标识一个数据帧(包含多个字)的开始,由SSI_TXFS和SSI_RXFS引脚输入或输出。
- 系统时钟(SYS_CLK/PerCLK3):SSI模块的输入工作时钟,在同步主模式下,可以输出到SSI_RXCLK引脚供外部设备使用。
SSI的发送和接收部分相对独立,各有自己的时钟控制寄存器(STCCR/SRCCR)、配置寄存器(STCR/SRCR)和数据路径。这种独立性允许发送和接收使用不同速率、不同格式的时钟,实现复杂的全双工通信。
引脚复用配置是SSI驱动的第一个难点。MC9328MX1的SSI1信号可以映射到Port B或Port C,SSI2只能映射到Port C。配置涉及三个寄存器组:
- GPIO在使用寄存器(GIUS_x):清除对应位,表示该引脚用于外设功能而非GPIO。
- GPIO通用目的寄存器(GPR_x):设置对应位,选择备用功能(Alternate Function);清除对应位,选择主要功能(Primary Function)。对于SSI1,Port C是主要功能,Port B是备用功能。
- 功能复用控制寄存器(FMCR):这个位于系统控制模块的寄存器,决定SSI1的输入信号(如RXCLK, RXFS, RXDAT)是来自Port B还是Port C。
以配置SSI1使用Port C引脚为例,代码示例如下:
// 假设寄存器地址已定义 // 1. 配置Port C相关引脚为外设功能(非GPIO) GIUS_C &= ~((1<<8) | (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3)); // 清除PTC[8:3]的GIUS位 // 2. 配置Port C相关引脚为主要功能 GPR_C &= ~((1<<8) | (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3)); // 清除PTC[8:3]的GPR位 // 3. 在FMCR中,选择SSI1信号来自Port C (Primary) FMCR &= ~((1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3)); // 清除FMCR[7:3]位 // 4. (可选)禁用上拉电阻,使引脚为三态,避免冲突 PUEN_C &= ~((1<<8) | (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3));注意事项:引脚方向对于纯输出引脚(如SSI_TXDAT),只需要配置GIUS和GPR。对于输入或双向引脚(如SSI_RXDAT, SSI_RXCLK, SSI_RXFS),必须通过FMCR正确选择信号源。配置错误会导致无法接收到信号。
3.2 时钟生成与配置详解
SSI的时钟链是理解其速率配置的核心。如图30-4和30-5所示,时钟生成涉及多级分频。
- 输入时钟:SSI模块的源头是
PerCLK3(系统PLL分频后的外设时钟3)。 - 预分频器:由
PSR(预分频范围)和PM[7:0](预分频模数)控制。PSR选择除以1或8,PM是一个7位分频器(1-256)。这一级产生位时钟的基础频率。- 位时钟频率 =
PerCLK3 / [(PSR?8:1) * (PM+1)]
- 位时钟频率 =
- 字分频器:由
WL[1:0]控制,根据字长进行分频(÷8, ÷10, ÷12, ÷16)。这一级产生字时钟。- 字时钟频率 = 位时钟频率 / 字长
- 帧分频器:由
DC[4:0]控制,分频范围1-32。这一级产生帧同步时钟。- 帧同步频率 = 字时钟频率 / (DC+1)
例如,目标音频采样率为48kHz,字长16位(即每声道每帧1个字),PerCLK3为12.288MHz。
- 我们需要位时钟 = 采样率 * 字长 * 2(I2S格式下,左右声道各16位,共32位时钟周期)= 48k * 32 = 1.536 MHz。
- 计算分频:
PerCLK3 / 位时钟 = 12.288M / 1.536M = 8。 - 设置
PSR=0(÷1),则需PM+1=8,即PM=7。 WL设置为16位(WL=11b)。- 对于单声道或每帧一字,
DC=0(分频比1)。
配置代码体现在SSI发送时钟控制寄存器(STCCR)中:
// 假设STCCR地址为0x00218014 // PSR=0, PM=7, DC=0, WL=3 (16位) STCCR = (0 << 15) | (7 << 8) | (0 << 3) | (3 << 0);接收时钟控制寄存器(SRCCR)的配置通常与STCCR相同,以实现同步。
工作模式选择通过SSI控制/状态寄存器(SCSR)的I2S_MODE位和配置寄存器(STCR/SRCR)的SCKD,SCKD,SSCRE,NET,SYN等位控制。常见模式:
- 正常模式(非I2S):
I2S_MODE=00。使用独立的发送/接收帧同步和时钟。 - I2S模式:
I2S_MODE=01或10。时钟和帧同步有特定相位关系,常用于音频。 - 网络模式:
NET=1。支持时分复用,多个设备共享总线,用于多声道音频。 - 门控时钟模式:
SCKD=1。时钟仅在数据传输时有效,节省功耗。 - 同步模式:
SYN=1。发送和接收部分使用相同的位时钟和帧同步。
3.3 数据寄存器、FIFO与传输控制
SSI的数据流核心是发送数据寄存器(STX)、**接收数据寄存器(SRX)**以及其背后的FIFO和移位寄存器。
SSI发送数据寄存器(STX)是用户写入待发送数据的入口。关键在于理解其与发送FIFO和**发送移位寄存器(TXSR)**的关系:
- 当发送FIFO使能(
TFEN=1)时,STX是FIFO的入口。这是一个8x16位的FIFO。你连续写入STX的数据会依次压入FIFO。当移位寄存器TXSR为空时,FIFO中的第一个数据会自动加载到TXSR中,并在时钟和帧同步的控制下,通过SSI_TXDAT引脚移位输出。 - 当发送FIFO禁用(
TFEN=0)时,STX直接与TXSR对接。你必须等待TXSR为空(通过状态位TDE判断)后才能写入下一个数据,否则数据会丢失。
数据移位方向与位序由TXBIT0和TSHFD位控制(见表30-4)。这决定了数据字节在总线上的发送顺序(MSB first还是LSB first),必须与对接的设备协议匹配。例如,I2S协议要求MSB first。
接收端逻辑类似,数据从SSI_RXDAT引脚移入接收移位寄存器(RXSR),填满一个字后,自动存入接收FIFO(如果使能),用户从**接收数据寄存器(SRX)**读取数据。
控制流程通常采用中断方式:
- 使能发送中断(
TIE=1)和/或接收中断(RIE=1)。 - 发送时,检查发送FIFO空(
TFE)或发送数据空(TDE)标志,将数据写入STX。 - 接收时,检查接收FIFO就绪(
RFF)标志,从SRX读取数据。 - 在中断服务程序中,根据中断标志进行相应的数据填充或读取操作。
一个典型的SSI发送初始化与数据传输代码框架如下:
// 1. 引脚配置(如前所述) // 2. 禁用SSI (SSI_EN=0),配置时钟寄存器STCCR/SRCCR SCSR &= ~(1<<0); // 清除SSI_EN STCCR = ...; // 配置发送时钟 SRCCR = ...; // 配置接收时钟 // 3. 配置发送/接收控制寄存器STCR/SRCR(模式、字长、使能FIFO等) STCR = (1<<13) | // TFEN: 使能发送FIFO (1<<9) | // TIE: 使能发送中断 (0<<8) | // TSHFD: 正常移位顺序 (0<<7) | // TXBIT0: MSB first ... ; SRCR = ...; // 配置接收 // 4. 使能SSI模块 SCSR |= (1<<0); // 设置SSI_EN // 5. 在发送中断服务程序或主循环中填充数据 void SSI1_TX_IRQHandler(void) { if (SCSR & (1<<2)) { // 检查TFE位(发送FIFO空)或TDE位 // 如果FIFO未满,填充数据 if (!(SCSR & (1<<1))) { // 检查TUE位(发送FIFO未满) STX = next_audio_sample; // 写入数据到发送寄存器 } } // ... 清除中断标志等 }4. 调试技巧与常见问题排查
无论是I2C还是SSI,调试底层串行通信,逻辑分析仪或示波器是必不可少的工具。它们能让你直观地看到总线上的时序波形,这是排查问题的终极手段。
4.1 I2C常见问题与排查
总线死锁,SCL被拉低
- 现象:通信无响应,用示波器测量SCL线,发现被持续拉低。
- 原因:从设备在传输中异常(如程序跑飞),或主设备在接收模式下未及时读取I2DR。
- 排查:检查从设备电源、复位信号。检查主设备程序,确保在接收模式下,启动接收前执行了“哑读”,并在每次接收中断后读取了I2DR。
- 应急恢复:尝试软件生成STOP信号(即使
MSTA=0也写STOP条件)。如果无效,可能需要短暂关闭I2C模块再重新初始化,或者触发从设备的硬件复位。
从设备无应答(NACK)
- 现象:主设备发送地址字节后,读取
RXAK为1。 - 排查:
- 核对从设备7位地址是否正确,注意左移一位后加R/W位。
- 测量从设备的电源电压是否正常。
- 检查上拉电阻。I2C总线需要上拉(通常4.7kΩ),确保SDA和SCL线能被正确拉高。
- 用示波器看START信号后的地址字节波形,确认数据位和时钟边沿关系是否符合I2C规格。
- 确认从设备是否处于可寻址状态(例如,某些EEPROM需要内部写周期结束)。
- 现象:主设备发送地址字节后,读取
通信速度慢或不稳定
- 现象:通信时好时坏,或速度远低于预期。
- 排查:
- 检查IFDR的分频配置,计算实际SCL频率。
- 检查总线电容。长导线、过多设备会导致总线电容过大,上升沿变缓,可能违反时序要求。可尝试减小上拉电阻值(如改为2.2kΩ),但需注意驱动能力。
- 检查是否有电气干扰。确保SDA/SCL走线远离噪���源。
4.2 SSI常见问题与排查
无声或数据错乱
- 现象:音频系统无输出,或输出是噪音。
- 排查:
- 时钟与同步:用示波器同时测量位时钟(SCLK)、帧同步(FS)和数据(SD)线。确认时钟频率是否正确,帧同步信号是否在数据开始前有效,数据位是否在时钟的正确边沿(上升沿或下降沿,由配置决定)变化。
- 数据格式:确认
TXBIT0和TSHFD设置的数据位序(MSB/LSB first)与音频编解码器要求一致。确认字长(WL)匹配。 - FIFO与中断:如果使用中断,确认中断使能位和中断服务程序是否正确清除中断标志。检查是否因为FIFO下溢(发送端数据供给不足)或上溢(接收端数据读取不及时)导致错误。可以尝试禁用FIFO,采用查询
TDE/RDF标志的方式传输,简化问题。 - 主从模式:确认主从配置。如果MCU是主设备(产生时钟和帧同步),
SCKD和TFSD等方向位应设置为输出。如果是从设备,应设置为输入。
只有单声道或数据对齐错误
- 现象:播放立体声音频,只有一个声道有声,或声音失真。
- 排查:
- I2S模式:在I2S模式下,左右声道数据是交替发送的,帧同步信号(WS)指示左(0)或右(1)声道。确认发送的数据流是严格按照L, R, L, R...的顺序。
- 数据对齐:对于16位音频数据,存放在16位寄存器中,但SSI可能配置为发送32位(左右声道各16位)。确保你的数据在寄存器中的位置正确。有时需要将16位数据左移或右移以适应寄存器的位置。
- 网络模式与时间槽:如果使用网络模式(
NET=1),需要正确配置时间槽寄存器(STSR),指定哪些时间槽是有效的。配置错误会导致数据发送到错误的“槽位”,从而对应到错误的声道。
引脚配置错误
- 现象:完全无时钟或数据信号。
- 排查:这是最基础也最容易犯的错误。反复检查
GIUS,GPR,FMCR寄存器的配置,确保每个SSI信号对应的引脚已被正确设置为外设功能,并且方向(输入/输出)正确。特别是对于SSI2,其信号只在Port C的备用功能上,GPR_C的对应位必须置1。