1. 项目概述:为什么需要深入理解SHI?
在嵌入式音频处理系统,尤其是像Freescale(现NXP)DSP56720/56721这样的多核音频处理器中,处理器与外部主控芯片(如MCU、FPGA或其他DSP)之间的高效、可靠通信是系统设计的基石。串行主机接口(Serial Host Interface, SHI)正是为此而生的关键外设。它不是简单的串口,而是一个集成了内存映射访问、中断驱动、DMA支持,并兼容I2C和SPI双协议的高度可编程通信引擎。对于从事音频算法开发、嵌入式系统固件编写或硬件驱动的工程师而言,仅仅知道如何配置几个寄存器是远远不够的。你必须透彻理解其内部架构、数据流、中断机制以及各种模式下的时序细节,才能写出稳定、高效且能应对复杂场景(如高优先级音频中断下的数据通信)的驱动代码。否则,通信丢包、时序错乱、系统死锁等问题将层出不穷。本文将以DSP56720/56721的SHI模块为蓝本,结合手册原理与实战经验,为你彻底拆解其架构与编程模型。
2. SHI内部架构与核心设计思想
2.1 内存映射:DSP视角下的SHI
SHI最核心的设计思想是内存映射。DSP内核将SHI视为X数据存储器空间中的一个外设。这意味着,DSP可以使用访问内存的普通指令(如MOVE)和寻址模式来读写SHI的控制与数据寄存器。手册中给出的寄存器地址(如HCSR在$FFFF91)就是其在DSP内存空间中的“门牌号”。
为什么选择内存映射?
- 编程简化:开发者无需学习特殊的I/O指令,统一了内存与I/O的访问方式,降低了编程复杂度。
- 效率提升:
MOVEP指令的存在是关键。这条指令允许在接口和内存之间直接传输数据,而无需经过中间寄存器中转,这对于需要批量传输音频数据块的场景至关重要,能显著减少指令周期。 - DMA集成:由于SHI寄存器在统一的内存地址空间中,DMA控制器可以像搬运一块内存数据一样,自动服务SHI的发送(HTX)和接收(HRX FIFO)数据路径。这实现了数据搬运与DSP核心计算的完全解耦,是保证实时音频处理不被打断的“法宝”。
从图10-1的框图可以看出,SHI内部是一个精巧的双总线结构:一边通过DSP全局数据总线与核心及DMA相连,另一边通过移位寄存器(IOSR)和引脚控制逻辑与外部串行总线(I2C/SPI)对接。中间的控制器逻辑则是协调双方、生成时钟、处理协议和中断的“大脑”。
2.2 双模式与时钟生成策略
SHI支持主模式(Master)和从模式(Slave),并通过HMST位进行切换。这个选择决定了谁是通信时序的发起者。
- 主模式(HMST=1):SHI主动生成串行时钟(SCK/SCL)。此时,内部的可编程波特率发生器开始工作。它由系统时钟(FSYS)经过一个复杂的分频链(包括HRS预分频和HDM[7:0]主分频)产生所需的串行时钟。工程师必须根据目标波特率和系统时钟频率,精确计算分频系数,这是配置的第一步,也是容易出错的一步。
- 从模式(HMST=0):SHI接收外部主设备提供的时钟。此时,内部的时钟发生器通常被禁用(I2C模式下若HCKFR=1则例外)。SHI的引脚逻辑会采样外部时钟,并据此同步内部的数据移位操作。
> 注意:模式切换的黄金法则在改变HMST位(或HI2C、HCKFR等关键模式位)之前,务必先将SHI置于“个体复位”状态(即清除HEN位)。这是因为SHI的引脚功能、内部状态机在不同模式下差异巨大。带电切换模式可能导致引脚冲突、总线锁死或不可预测的行为。这是一个手册强调但实践中仍常被忽略的要点。
3. 核心寄存器详解与编程模型
SHI的编程模型清晰地分为主机侧和DSP侧。主机侧(外部MCU)通过标准的I2C或SPI协议与SHI的IOSR交互。而DSP侧则通过一组内存映射寄存器来控制和监控整个通信过程。理解每个寄存器的位定义是编程的基础。
3.1 数据通路寄存器:HTX、HRX与IOSR
主机发送数据寄存器(HTX):
- 作用:DSP向主机发送数据的“发射井”。这是一个24位宽的只写寄存器。
- 工作流程:DSP或DMA将数据写入HTX。写入操作会清除“发送数据寄存器空(HTDE)”状态位。数据随后会被转移到内部的**输入/输出移位寄存器(IOSR)**中,在串行时钟的节拍下,逐位从MOSI(SPI主)或SDA(I2C)引脚发送出去。当数据从HTX转移到IOSR后,HTDE位会被重新置1,表示可以写入下一个数据。
- 数据对齐:根据HM[1:0]设置的8/16/24位模式,只有IOSR的高位部分会被使用。例如在8位模式下,只发送HTX[23:16]这8位。编程时必须注意数据在HTX中的对齐方式,错误的对齐会导致主机收到错误数据。
主机接收数据FIFO(HRX):
- 作用:DSP从主机接收数据的“缓冲池”。这是一个10字深、24位宽的先进先出(FIFO)队列,只读。
- 工作流程:来自主机的串行数据通过MISO(SPI从)或SDA(I2C)引脚移入IOSR。当一个完整的数据字(根据HM[1:0]确定长度)接收完毕后,该数据会被自动压入HRX FIFO。DSP或DMA可以从中读取数据。每读取一个字,FIFO指针前移。
- FIFO深度策略:HFIFO位控制FIFO深度。当HFIFO=0时,FIFO仅1级(相当于一个普通寄存器);当HFIFO=1时,启用10级深度。在高速或实时性要求高的数据流中,务必启用10级FIFO。这为DSP响应中断、处理数据提供了宝贵的缓冲时间,能有效避免因DSP暂时繁忙导致的接收溢出(Overrun)错误。
输入/输出移位寄存器(IOSR):
- 关键认知:IOSR是SHI内部真正的“搬运工”,但它对程序员不可见,无法直接访问。它负责在并行数据(与HTX/HRX交互)和串行比特流(与外部引脚交互)之间进行转换。理解它的存在有助于你想象数据是如何一位一位地被“推”出去或“拉”进来的。
3.2 控制与状态寄存器(HCSR):SHI的“控制面板”
HCSR是配置SHI工作模式和获取其运行状态的核心。下面挑几个实战中至关重要的位进行深度解析:
- HEN(位0):SHI总开关。0=个体复位(所有状态位复位,引脚高阻),1=使能。使能前必须确保时钟、模式等配置已正确完成。
- HI2C(位1):协议选择。0=SPI,1=I2C。切换前请遵循“个体复位”法则。
- HM[1:0](位3-2):数据字长。00=8位,01=16位,10=24位。此位只能在SHI空闲(HBUSY=0)时修改。在传输过程中修改会导致数据帧错误。
- HMST(位6):主从模式选择。决定了SCK/SCL引脚的方向和时钟源。
- HTIE & HRIE[1:0](位11, 13-12):中断使能位。这是实现高效异步通信的关键。
HTIE:发送中断使能。当HTDE=1(发送寄存器空)且HTUE=0(无下溢错误)时,触发发送数据中断。HRIE[1:0]:接收中断使能。这是一个组合配置(见表10-6)。常用配置是01(HRNE=1时中断,即FIFO非空)或11(HRFF=1时中断,即FIFO满)。在音频流传输中,我通常配置为01。因为“FIFO非空”就中断,可以让DSP更及时地取走数据,保持FIFO低水位,为突发数据留出缓冲空间。如果等“FIFO满”再中断,延迟可能过大,在高速流下容易溢出。
- 状态位(HTDE, HRNE, HRFF, HROE, HTUE, HBER):这些只读位是驱动程序进行决策的依据。例如,在查询方式下,程序需要循环检查HTDE是否为1才能写入下一个数据;在中断服务程序(ISR)中,也需要检查这些位来确定中断原因(是正常发送完成还是发生了错误)。
3.3 时钟控制寄存器(HCKR)与噪声滤波
HCKR寄存器负责配置SHI的时钟特性,尤其在主模式下至关重要。
- CPOL & CPHA(位1-0):SPI通信的“相位与极性”。这两个位定义了数据采样和驱动的时钟边沿关系,必须与通信对端设备严格匹配。共有4种组合(CPOL, CPHA):(0,0), (0,1), (1,0), (1,1)。图10-6的时序图是理解它们的金钥匙。简单来说,CPOL决定时钟空闲电平(0=低,1=高),CPHA决定数据采样的边沿(0=第一个边沿采样,1=第二个边沿采样)。在项目初期,与硬件工程师确认外设芯片要求的SPI模式是第一步。
- HRS & HDM[7:0](位2, 10-3):波特率分频器。串行时钟频率
SCK = FSYS / (Prescaler * (HDM+1)),其中Prescaler在HRS=0时为8,HRS=1时为1。计算时需确保最终的SCK频率在芯片支持的范围和外部设备要求的范围内。 - HFM[1:0](位13-12):噪声滤波模式。这是一个非常实用但常被忽略的功能。在电气环境嘈杂(如电机附近、长线缆)的应用中,SCK和DATA线上的毛刺可能导致数据错误。HFM提供了三级滤波(极窄、窄、宽)来抑制特定宽度的尖峰脉冲。代价是它会引入延迟,从而限制最高通信速率。在干净的环境下,应设置为00(旁路)以获得最高速度。在典型的I2C总线应用中,手册推荐使用
11(宽滤波)以增强抗噪性并符合I2C规范。
> 实操心得:配置HCKR的步骤
- 根据系统时钟
FSYS和目标波特率,结合手册公式计算HRS和HDM[7:0]的值。通常会有多个解,选择一个即可。 - 根据外设确定
CPOL和CPHA。 - 评估环境噪声,决定
HFM[1:0]。如果不确定,在调试阶段可以先设为11(最抗噪)确保通信稳定,待系统稳定后再尝试优化为00以提高速率。 - 重要:在修改了
HFM[1:0]、HI2C或CPOL后,如果滤波器未旁路(即HFM[1:0] != 00),必须等待至少10倍于可容忍尖峰宽度的时间,才能置位HEN使能SHI。例如选择宽滤波(容忍100ns尖峰),则需等待至少1μs。这是为了让滤波器电路稳定。
4. 中断与DMA编程实战
轮询(Polling)方式简单但效率低下,会白白消耗DSP的运算能力。在音频DSP中,核心资源极其宝贵,必须采用中断或DMA来释放CPU。
4.1 中断向量与优先级管理
SHI提供了多达6个独立的向量化中断(见表10-1),这意味着不同的事件会跳转到不同的中断服务程序入口,无需在ISR内部再去判断中断源,减少了延迟。
中断优先级由硬件固定(见表10-2):
- 总线错误(最高)
- 接收溢出错误
- 发送下溢错误
- 接收FIFO满
- 发送数据(HTX空)
- 接收FIFO非空(最低)
这个优先级顺序设计得很合理:错误处理拥有最高优先级,其次是“缓冲区快满了”的告警,最后才是常规的“有数据待处理”通知。在编写ISR时,尤其是接收FIFO满中断服务程序,处理速度一定要快,要尽快将数据从HRX FIFO中搬走,否则可能连续触发溢出错误。
4.2 中断服务程序(ISR)编写要点
以“接收FIFO非空”中断(向量地址VBA:$0044)为例,一个稳健的ISR应该:
; 假设使用DSP56720汇编,此处为示例框架 SHI_RX_ISR: ; 1. 现场保护 (入栈) ... ; 2. 读取HCSR,确认中断源(虽然向量化,但谨慎起见可读状态) movep x:$FFFF91, x0 ; 读取HCSR到寄存器x0 ; 3. 检查是否有错误发生(如HROE接收溢出) jclr #21, x0, _no_rx_error ; 检查HROE位 ; 处理接收溢出错误:记录日志、清空FIFO、恢复通信等 ... _no_rx_error: ; 4. 循环读取HRX FIFO,直到其为空(HRNE=0) _rx_loop: btst #16, x0 ; 测试HRNE位(假设x0中仍是HCSR,实际需重新读取) jcc _rx_done ; 如果HRNE=0,跳转完成 movep x:$FFFF94, y0 ; 从HRX FIFO读取数据到y0 ; 处理数据y0,例如存入音频缓冲区 ... movep x:$FFFF91, x0 ; 重新读取HCSR,更新HRNE状态 jmp _rx_loop _rx_done: ; 5. 现场恢复 (出栈) ... rti ; 中断返回> 关键陷阱:中断屏蔽延迟手册在HBIE、HTIE、HRIE的说明中特别警告:清除中断使能位(屏蔽中断)后,需要经过一个指令周期延迟才能真正生效。这意味着,如果你在ISR末尾才清除中断使能,然后立即执行RTI返回,可能有一个短暂的时间窗口,新的中断请求又来了,但未被屏蔽,导致中断重入,引发栈溢出或数据错乱。解决方案:在长ISR中,如果需要提前屏蔽本中断,应在清除中断使能位(如bsclr #12, x:$FFFF91)和RTI指令之间,插入至少一条其他无关指令(如nop),以确保屏蔽生效。
4.3 DMA传输配置
对于大批量、规律的数据传输(如连续收发音频采样块),使用DMA是最高效的方式。SHI可以与DMA控制器联动,在HTX空或HRX非空时触发DMA请求,由DMA自动在SHI寄存器和内存缓冲区之间搬运数据,完全解放DSP核心。
配置DMA服务SHI发送的步骤:
- 配置DMA通道的源地址为内存中的音频数据缓冲区地址。
- 配置DMA通道的目的地址为SHI的HTX寄存器地址(
$FFFF93)。 - 配置DMA传输计数为需要发送的数据字数。
- 配置DMA的触发源为“SHI发送数据”请求(即HTX空事件)。
- 使能DMA通道和SHI的发送功能。
- DSP核心只需在DMA传输完成中断中,准备下一个数据缓冲区即可。
使用DMA的显著优势:
- 零CPU开销:数据传输过程无需CPU干预。
- 确定性:DMA传输的时序是硬件保证的,避免了软件ISR因其他高优先级任务导致的抖动。
- 双缓冲支持:可以轻松实现“乒乓缓冲”,一个缓冲区被DMA使用的同时,CPU处理另一个缓冲区,实现无缝数据流。
5. I2C与SPI模式下的特殊考量
5.1 SPI模式下的时序与从机选择
在SPI从机模式(HMST=0)下,SS(从机选择)引脚的行为至关重要,且受CPHA影响:
- CPHA=0:SS引脚必须在每个字传输之间先取消断言(拉高),再重新断言(拉低)。数据在SS断言后的第一个时钟边沿被捕获。这意味着,如果外部主机在连续传输多个字时没有操作SS引脚,传输会出错。HTX寄存器中的数据,只有在SS取消断言后才会被加载到IOSR中。
- CPHA=1:SS引脚可以在多个字传输期间保持断言(低电平)。数据在第一个时钟边沿被捕获。HTX寄存器中的数据在SS断言且IOSR为空时,会立即加载。
> 避坑指南:SPI从机模式下的HTUE错误发送下溢错误(HTUE)在SPI从机模式下容易发生。当外部主机开始读取下一个字时,如果SHI内部的IOSR和HTX寄存器都为空(即DSP没有及时提供新数据),HTUE位就会被置位。根据CPHA的不同,触发时刻也不同。避免HTUE的关键是确保在主机发起读取前,DSP已经将数据写入HTX。在CPHA=0模式下,可以利用SS引脚在字间的跳变作为“数据就绪”的同步信号来触发DSP写入。
5.2 I2C模式下的地址识别与时钟拉伸
I2C模式(HI2C=1)更为复杂,因为它是一个多主多从的协议。
从机地址(HSAR):SHI的7位I2C从机地址由HSAR寄存器中的HA[6:3]、HA1位,以及外部引脚HA0和HA2共同组成。这提供了硬件配置地址的灵活性。SHI也会响应通用呼叫地址(0x00)。
时钟拉伸(Clock Stretching)与HCKFR位:这是I2C从机的一个高级功能。当SHI作为从机接收器(主机写数据)时,如果HRX FIFO已满;或作为从机发送器(主机读数据)时,如果HTX为空,SHI可以通过拉低SCL线来“拉伸”时钟,暂停总线,直到自己准备好。
HCKFR=1:启用时钟拉伸。SHI在未准备好时会主动拉低SCL。此时,SHI内部的时钟发生器必须被编程为产生与外部主机时钟相同(或0.75-1倍)的频率,否则会出错。这要求你大致知道主机的时钟速率。HCKFR=0:禁用时钟拉伸。如果主机在SHI未准备好时强行通信,会导致溢出(Overrun)或下溢(Underrun)错误(HROE或HTUE置位)。- 实战建议:在不确定主机行为或追求最大兼容性时,可以启用时钟拉伸(HCKFR=1),并为SHI配置一个接近主机频率的时钟。在追求最高速率且能保证DSP及时响应时,可以禁用拉伸,但必须做好错误处理。
HIDLE位(仅I2C主模式):这是一个用于控制I2C总线“起停”和“应答”的巧妙设计。
- 设置HIDLE位,然后写入HTX,会先产生一个STOP条件,再产生一个START条件,并将HTX数据的高8位作为从机地址字节发送。这用于开始一次新的I2C会话。
- HIDLE位还控制接收应答(ACK/NACK)。
HIDLE=0发送ACK(0),HIDLE=1发送NACK(1)。在主机读取多个字节后,通常在最后一个字节发送NACK,接着发送STOP条件来结束读取。
6. 常见问题排查与调试技巧
在实际开发中,SHI通信失败是常态。以下是一个基于症状的排查清单:
| 症状 | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
| 完全无通信 | 1. SHI未使能(HEN=0) 2. 时钟配置错误(主模式) 3. 模式/协议选择错误(HI2C, HMST) 4. 引脚复用冲突 | 1. 检查HCSR的HEN位是否为1。 2. 主模式下,用示波器测量SCK/SCL引脚是否有时钟输出。检查HCKR的HRS、HDM计算是否正确,FSYS时钟是否正常。 3. 确认HI2C位与外部设备协议一致,HMST位与主从角色一致。 4. 检查芯片的引脚控制寄存器,确保SHI功能已映射到正确的物理引脚。 |
| SPI模式下数据错位 | CPOL/CPHA配置不匹配 | 用逻辑分析仪同时抓取SCK、MOSI、MISO、SS信号,对照图10-6,检查数据采样边沿与时钟相位关系是否与对端设备要求一致。调整CPOL和CPHA位。 |
| I2C模式下无应答 | 1. 从机地址不匹配 2. 总线上下拉电阻缺失或阻值不当 3. 时钟速率过快 | 1. 确认主机发送的地址与SHI的HSAR寄存器及HA0/HA2引脚配置的地址完全一致。 2. I2C总线需要上拉电阻(通常4.7kΩ)。用示波器检查SDA/SCL在高电平时是否能被拉到接近VDD。 3. 降低I2C时钟频率(调整主机或从机的分频器)。 |
| 偶尔数据错误或丢失 | 1. 噪声干扰 2. FIFO溢出/下溢 3. 中断响应不及时 | 1. 尝试启用HCKR中的噪声滤波器(HFM[1:0]),从“宽滤波”模式开始测试。 2. 检查HCSR中的HROE(接收溢出)或HTUE(发送下溢)位是否被置位。如果频繁发生,考虑:启用10级FIFO(HFIFO=1)、提高中断优先级、优化ISR效率或使用DMA。 3. 在中断服务程序中加入超时或错误状态检查,并确保及时清除了中断标志。 |
| DMA传输不启动 | 1. DMA触发源配置错误 2. SHI中断未正确使能以触发DMA请求 3. DMA通道未使能 | 1. 确认DMA通道的触发源配置为“SHI发送请求”或“SHI接收请求”。 2. 虽然DMA传输不依赖CPU中断,但SHI内部需要产生DMA请求。确保HTIE或HRIE(根据传输方向)可能不需要使能,但SHI到DMA控制器的请求通路是硬件连接的,需检查相关全局使能位。 3. 检查DMA通道控制寄存器的使能位。 |
调试必备工具:
- 逻辑分析仪:这是调试任何串行通信的首选。连接SCK/SCL、数据线和SS(SPI),可以清晰看到每一位的时序、数据内容、起始停止条件,是定位CPOL/CPHA问题、I2C地址问题的利器。
- 示波器:用于观察时钟信号质量、噪声毛刺,检查上拉电平是否到位。
- 芯片仿真器/调试器:可以实时查看和修改SHI的各个寄存器值,单步执行代码,观察中断触发和DMA传输状态。
最后,分享一个我个人在调试复杂SHI通信时的习惯:编写一个简单的“寄存器诊断”函数。这个函数将SHI所有关键寄存器(HCSR, HCKR, HSAR, HRX, HTX)的值通过其他简单接口(如另一个UART)打印出来。当通信异常时,首先调用这个函数,将寄存器的实际状态与预期配置进行对比,往往能快速定位是配置错误、状态机卡死还是数据传输问题。磨刀不误砍柴工,深入理解SHI的每一处细节,才能在面对棘手的嵌入式通信问题时游刃有余。