1. 项目概述与SSI接口核心价值
如果你在嵌入式系统,特别是数字信号处理领域摸爬滚打过几年,一定会对“同步串行接口”这个词又爱又恨。爱的是它那简洁的硬件连接和高效的时序控制,恨的是手册里那些密密麻麻的寄存器位和看似复杂的模式配置。今天,我们就来彻底拆解Motorola(现NXP)DSP56002这颗经典DSP芯片上的SSI接口,尤其是它的“网络模式”。这不是一篇照本宣科的数据手册翻译,而是我结合多年实际项目经验,从电路板调试到代码烧录,一步步踩坑总结出来的实战指南。
SSI本质上是一种基于时钟同步的串行通信协议。与UART那种需要双方约定波特率的异步方式不同,SSI通信双方共享同一个时钟信号(SCK),数据在时钟的上升沿或下降沿被采样,从根本上杜绝了因时钟频率微小偏差导致的累积误差。这使得SSI能在更高的速率下稳定工作,非常适合连接ADC、DAC、音频编解码器以及构建多DSP协同处理系统。DSP56002的SSI模块强大之处在于其高度可配置性:你可以选择8、12、16或24位的字长,使用连续时钟或门控时钟,配置独立的收发时钟源,甚至利用其“网络模式”轻松构建时分复用(TDM)总线。理解并驾驭这些模式,是让DSP56002在数字音频处理、电信多路复用等场景中发挥性能的关键。
2. SSI网络模式深度解析:从理论到寄存器配置
2.1 网络模式与普通模式的核心差异
很多工程师第一次接触SSI时,都是从“普通模式”入手的。在普通模式下,每次帧同步信号有效,SSI就传输一个字(Word),然后等待下一个帧同步。这就像公共汽车每站只上下一个乘客,简单直接。但当你需要连接多个设备,比如构建一个多通道音频采集系统,让多个ADC芯片或编解码器共享同一组数据线时,普通模式就显得力不从心了。
这时,“网络模式”就该登场了。你可以把网络模式想象成一列有多节车厢的火车。一个帧同步周期(一帧)被划分成多个“时间槽”,每个时间槽都可以独立传输一个字。DSP56002允许你通过CRA寄存器的DC[4:0]位域,将一帧划分为2到32个时间槽。例如,在一个8通道的音频系统中,你可以设置DC=7(即8个时间槽),让每个时间槽对应一个音频通道的数据。主设备(通常是产生时钟和帧同步的DSP)在每个时间槽都可以选择发送数据或保持高阻,而从设备则在指定的时间槽监听总线并接收属于自己的数据。
这种机制的实现,依赖于SSI状态寄存器(SSISR)中的两个关键状态位:TFS(发送帧同步)和RFS(接收帧同步)。在网络模式下,只有在一个帧的第一个时间槽期间,这两个标志位才会被置位。你的中断服务程序可以通过检查TFS/RFS是否为1,来判断当前是否是一个新帧的开始,从而重置你的时间槽计数器,确保收发双方对“当前是第几个通道”这一认知始终保持同步。
2.2 控制寄存器配置实战拆解
纸上谈兵终觉浅,我们直接来看代码。要让SSI工作在网络模式,需要对两个控制寄存器进行精细配置。下面这个配置示例,目标是建立一个16位字长、8个时间槽、使用内部生成时钟和帧同步的同步网络主节点。
; SSI控制寄存器A (CRA) - 地址 X:$FFEC
; 配置时钟和帧结构
MOVEP #$401F, X:CRA ; 写入CRA
这行代码向CRA写入了
$401F
。我们来逐位拆解:
- PSR (位15) : 0。选择预分频器范围,0表示旁路除以8的预分频器,使用基础分频。
- WL1, WL0 (位14-13) : 01。这表示选择16位字长(00=8位,01=12位,10=16位,11=24位)。必须根据你外设的数据宽度来设置。
-
DC4-DC0 (位12-8)
: 0 0001。这是帧率分频器控制,在网络模式下它定义了“每帧的时间槽数减一”。
00001是1,意味着时间槽数 = 1 + 1 = 2。如果你想设置8个时间槽,这里应该是00111(即7),对应的立即数是$40?7,需要根据PM值计算完整数值。 -
PM7-PM0 (位7-0)
: 0001 1111 (0x1F)。这是预分频器模数值。串行位时钟频率由系统主频(fosc)、PSR、PM共同决定,公式为:
f_bit = fosc / (4 * (7*PSR + 1) * (PM + 1))。假设fosc=40MHz,PSR=0,PM=31,则f_bit = 40MHz / (4 * 1 * 32) = 312.5 kHz。每个时间槽传输16位,则帧率约为19.5kHz,适合音频应用。
; SSI控制寄存器B (CRB) - 地址 X:$FFED
; 配置操作模式、时钟源和引脚功能
MOVEP #$5B34, X:CRB ; 写入CRB
写入
$5B34
到CRB:
- RIE/TIE (位15,14) : 0, 1。接收中断禁用,发送中断使能。在网络模式下,我们通常用中断来及时响应每个时间槽的数据准备。
- RE/TE (位13,12) : 1, 1。接收器和发送器使能。
- MOD (位11) : 1。这是关键!置1选择网络模式。
- GCK (位10) : 0。选择连续时钟模式。帧同步是一个独立的信号。
- SYN (位9) : 1。选择同步模式,即发送器和接收器使用相同的时钟和帧同步信号。
- FSL1, FSL0 (位8,7) : 0, 0。选择字长帧同步(帧同步脉冲宽度与一个字传输时间等宽)。也可以选择位长帧同步(一个时钟周期宽)。
- SHFD (位6) : 1。移位方向,1表示LSB先发送/接收。有些编解码器是MSB在先,需要根据数据手册调整。
- SCKD (位5) : 1。时钟源方向,1表示SCK引脚为输出(内部时钟)。
- SCD2 (位4) : 1。SC2引脚方向,1表示输出。在同步模式下,SC2用作帧同步输出。
- SCD1, SCD0 (位3,2) : 1, 1。SC1和SC0引脚方向,1表示输出。在同步模式下,它们被配置为标志输出引脚,可以用来做片选等控制信号。
- OF1, OF0 (位1,0) : 0, 0。输出标志的初始值。
关键经验 :配置SSI时,务必遵循“先静态配置,后动态使能”的原则。即先完整配置好CRA和CRB的所有参数,最后再通过写PCC寄存器将对应引脚功能从GPIO切换到SSI,并解除中断屏蔽。如果顺序颠倒,SSI可能会在未正确配置的情况下开始工作,产生错误的时钟或损坏数据。
2.3 网络模式下的数据收发机制与状态机
理解了寄存器配置,我们来看看数据是如何在网络模式下流动的。这背后是一个精妙的状态机在运作。
发送流程 :
- 使能发送器(TE=1)后,SSI会等待下一个帧同步信号的开始(第一个时间槽)。
- 在第一个时间槽开始时,如果TX寄存器中有数据(TDE=0),则该数据被加载到发送移位寄存器,并开始逐位在STD引脚上移出。同时,TDE标志被置1,如果TIE=1,则产生发送中断。
-
你的中断服务程序(ISR)必须在当前字发送完成、下一个时间槽开始之前,做出决定:
- 写入新数据到TX寄存器 :数据将在下一个时间槽被发送。这会清除TDE。
- 写入任意值到时间槽寄存器(TSR) :这不会发送有效数据,但会清除TDE,并使STD引脚在下一个时间槽保持高阻态。这允许总线上其他设备在该时间槽发送数据,是实现TDM总线仲裁的关键。
- 不进行任何写操作 :TDE保持为1。当下一个时间槽开始时,发送移位寄存器为空,会触发发送下溢错误(TUE=1),并且上一个时间槽的数据会被 重新发送 。这通常是你需要避免的。
- 在每个时间槽开始时,输出标志(OF1/OF0)会更新为CRB中OF1/OF0位的值。你可以提前在ISR中修改OF1/OF0,从而让标志信号与数据严格同步地输出到SC1/SC0引脚,用于控制外部多路器或作为通道标识。
接收流程 :
- 使能接收器(RE=1)后,SSI同样等待帧同步开始。
- 在每个时间槽,数据都会从SRD引脚移入接收移位寄存器,无论该数据是否意图发给本机。
- 当一个字的最后一位移入后,数据被锁存到RX寄存器,RDF标志置1,如果RIE=1则产生接收中断。
- 你的接收ISR 必须 在下一个字完全移入之前(即下一个RDF置位前),从RX寄存器读取数据。否则,会发生接收过载错误(ROE=1),新数据将丢失。
- 在ISR中,你需要根据内部维护的“时间槽计数器”来判断当前数据是否属于自己。如果属于自己,则存储;否则,可以简单地读取RX然后丢弃,以清除RDF,避免过载错误。
一个常见的陷阱 :时间槽的识别。发送和接收中断发生在数据 开始处理 的时刻,而非结束的时刻。例如,当你在时间槽N的发送中断中写入TX,这个数据实际上是为时间槽N+1准备的。你的软件时间槽计数器必须与这个硬件流水线行为保持一致。通常的做法是,在中断中根据TFS/RFS判断帧头,然后使用一个模运算(与DC设置的值匹配)的计数器来跟踪当前时间槽索引。
3. 实战代码剖析:构建一个双通道TDM收发系统
理论说得再多,不如一行代码。我们基于手册中的图6-78和图6-79示例,构建一个更完整、更健壮的双通道(左/右声道)TDM收发系统。假设主DSP负责产生时钟和帧同步,并在时间槽1发送右声道数据,时间槽2发送左声道数据(或接收)。
3.1 发送端程序详解与优化
发送端的关键是维护时间槽索引,并在正确的时间槽发送正确的数据,同时管理好标志位。
; ******************************
; SSI TDM 发送器初始化与主循环
; 目标:在时间槽1发右声道,时间槽2发左声道
; 使用标志位SC0区分通道 (0=左,1=右)
; ******************************
; --- 常量与寄存器定义 ---
IPR EQU $FFFF
CRA EQU $FFEC
CRB EQU $FFED
PCC EQU $FFE1
TX EQU $FFEF
TSR EQU $FFEE ; 时间槽寄存器,写入即禁用该槽发送
SSISR EQU $FFEE
PCDDR EQU $FFE3
RIGHT_BUF EQU $1000 ; 右声道数据缓冲区基址
LEFT_BUF EQU $1100 ; 左声道数据缓冲区基址
BUFFER_SIZE EQU 256 ; 缓冲区大小(样本数)
SLOT_COUNT EQU 2 ; 每帧时间槽数,必须与CRA.DC设置匹配
ORG P:$40 ; 主程序起始
START
MOVEP #$3000, X:IPR ; 设置SSI中断优先级
MOVE #RIGHT_BUF, R0 ; R0 -> 右声道数据指针
MOVE #LEFT_BUF, R1 ; R1 -> 左声道数据指针
MOVE #BUFFER_SIZE-1, M0 ; 设置缓冲区模值,实现环形缓冲
MOVE #BUFFER_SIZE-1, M1
; 初始化SSI控制寄存器A
; WL1,WL0=10 (16位), DC=1 (2 time slots), PM=31 (312.5kHz @40MHz)
MOVEP #$411F, X:CRA ; PSR=0, WL=16b, DC=1, PM=31
; 初始化SSI控制寄存器B
; MOD=1(网络), GCK=0(连续时钟), SYN=1(同步), SCKD=1(内部时钟输出)
; SCD2=1(帧同步输出), SCD1/0=1(标志输出), TIE&TE=1
MOVEP #$5B34, X:CRB ; 具体值需根据OF1/OF0初始值调整
; 配置PC3-PC8为SSI功能,PC2-PC0保持GPIO(假设用于其他用途)
MOVEP #$01F8, X:PCC ; CC8-CC3 = 1
ANDI #$FC, MR ; 全局中断使能 (I1,I0 = 0)
MOVEP X:(R0)+, X:TX ; 预加载第一个数据(右声道)
BSET #0, X:CRB ; 设置OF0=1,标识第一个数据为右声道
MAIN_LOOP
; 此处可进行其他DSP算法处理
; 发送由SSI中断异步处理
JMP MAIN_LOOP
; --- 发送中断服务程序 (向量地址 P:$0010) ---
ORG P:$0010
JSR SSI_TX_ISR
RTI
SSI_TX_ISR
; 关键:判断是否为帧开始
JCLR #2, X:SSISR, NOT_FRAME_START ; 测试TFS位
; 是帧开始,重置时间槽计数器
MOVE #0, X:SLOT_INDEX
JMP HANDLE_SLOT
NOT_FRAME_START
; 不是帧开始,递增时间槽计数器
MOVE X:SLOT_INDEX, A
ADD #1, A
AND #(SLOT_COUNT-1), A ; 模运算,防止溢出
MOVE A, X:SLOT_INDEX
HANDLE_SLOT
; 根据当前时间槽索引决定动作
MOVE X:SLOT_INDEX, A
CMP #0, A ; 时间槽0 (实际发送的是预加载的数据)
JEQ IS_SLOT0
CMP #1, A ; 时间槽1
JEQ IS_SLOT1
IS_SLOT0 ; 处理时间槽0(例如:右声道)
; 为下一个时间槽0(即下一帧的右声道)准备数据
MOVEP X:(R0)+, X:TX ; 从右缓冲区取数,发送到下一帧的槽0
BSET #0, X:CRB ; 设置OF0=1,标识为右声道数据
RTI
IS_SLOT1 ; 处理时间槽1(例如:左声道)
; 为下一个时间槽1(即下一帧的左声道)准备数据
MOVEP X:(R1)+, X:TX ; 从左缓冲区取数,发送到下一帧的槽1
BCLR #0, X:CRB ; 清除OF0=0,标识为左声道数据
RTI
; --- 变量定义 ---
ORG X:$0
SLOT_INDEX DC 0 ; 当前时间槽索引
代码精要解析与避坑指南 :
-
流水线意识
:中断中
MOVEP X:(R0)+, X:TX写入的数据,并不是在当前时间槽发送,而是在 下一个同类时间槽 发送。这是SSI双缓冲机制(TX寄存器和发送移位寄存器)导致的。你的软件状态机必须超前一个时间槽。 -
模运算的重要性
:
AND #(SLOT_COUNT-1), A这行代码确保了时间槽计数器在0和1之间循环。如果DC设置的是8个时间槽,这里就应该AND #7。忘记模运算会导致索引溢出,通道映射完全混乱。 -
标志位同步
:我们通过
BSET/BCLR直接修改CRB中的OF0位。这个修改会立即生效,但输出到SC0引脚的变化,是与下一个时间槽的数据传输严格同步的。这为从设备提供了可靠的通道标识信号。 - 中断效率 :这是一个长中断(JSR)。对于高帧率系统,如果时间槽很多,中断开销可能成为瓶颈。此时可以考虑使用查询方式(Polling),在主循环中频繁检查TDE和TFS位,但这会增加CPU负载。需要根据系统实时性要求权衡。
3.2 接收端程序详解与数据对齐
接收端程序与发送端对称,但核心挑战在于数据对齐和过载预防。
; ******************************
; SSI TDM 接收器初始化与主循环
; 目标:根据SC0标志,在时间槽1收右声道,时间槽2收左声道
; ******************************
; --- 常量定义 (与发送端部分相同,略) ---
CRA EQU $FFEC
CRB EQU $FFED
PCC EQU $FFE1
RX EQU $FFEF
SSISR EQU $FFEE
RIGHT_BUF_RX EQU $1200 ; 接收右声道缓冲区
LEFT_BUF_RX EQU $1300
BUFFER_SIZE EQU 256
ORG P:$40
START_RX
MOVEP #$3000, X:IPR
MOVE #RIGHT_BUF_RX, R2
MOVE #LEFT_BUF_RX, R3
MOVE #BUFFER_SIZE-1, M2
MOVE #BUFFER_SIZE-1, M3
; 初始化CRA (必须与发送端严格一致!)
MOVEP #$411F, X:CRA ; 字长、时间槽数、时钟分频必须匹配
; 初始化CRB (同步模式,时钟和帧同步为输入)
; MOD=1, GCK=0, SYN=1, SCKD=0(外部时钟), SCD2=0(外部帧同步)
; SCD0=0(SC0配置为输入标志)
MOVEP #$AB00, X:CRB ; RIE&RE=1使能接收中断
MOVEP #$01F8, X:PCC ; 使能SSI引脚功能
ANDI #$FC, MR ; 使能中断
JMP * ; 等待接收中断
; --- 接收中断服务程序 (向量地址 P:$000C) ---
ORG P:$000C
JSR SSI_RX_ISR
RTI
SSI_RX_ISR
; 检查接收过载错误
JCLR #5, X:SSISR, NO_OVERRUN ; 检查ROE位
; 发生过载!处理错误:可以记录日志、重置缓冲区指针等
MOVE X:RX, A ; 必须读一次RX来清除ROE,即使数据可能已损坏
JMP ISR_EXIT
NO_OVERRUN
; 判断帧起始
JCLR #3, X:SSISR, NOT_RX_FRAME_START ; 检查RFS位
MOVE #0, X:RX_SLOT_INDEX
JMP PROCESS_DATA
NOT_RX_FRAME_START
MOVE X:RX_SLOT_INDEX, A
ADD #1, A
AND #(SLOT_COUNT-1), A ; 模运算
MOVE A, X:RX_SLOT_INDEX
PROCESS_DATA
; 根据SC0输入标志判断数据归属
JCLR #0, X:SSISR, IS_LEFT_CHANNEL ; 检查IF0位 (SC0输入的状态)
IS_RIGHT_CHANNEL ; IF0=1, 右声道数据
MOVEP X:RX, X:(R2)+ ; 存储右声道数据
JMP ISR_EXIT
IS_LEFT_CHANNEL ; IF0=0, 左声道数据
MOVEP X:RX, X:(R3)+ ; 存储左声道数据
ISR_EXIT
RTI
; --- 接收端变量 ---
ORG X:$10
RX_SLOT_INDEX DC 0
关键点与调试技巧 :
-
过载错误处理
:
ROE错误是网络模式接收中最常见的错误。它意味着CPU来不及在下一个字接收完成前读取RX寄存器。中断服务程序必须足够快。如果频繁发生ROE,你需要:优化ISR代码、降低数据速率、或者使用DMA(如果支持)。 务必在ISR开始处检查并清除ROE ,否则后续数据会持续丢失。 -
输入标志的采样
:
IF0位是在当前接收字的 第一位被采样时 锁存的SC0引脚状态,并在整个字接收期间保持不变。这保证了通道标识与数据的严格对应,即使SC0信号在传输中途发生变化。 - 配置一致性 :接收端的CRA配置(字长、时间槽数、时钟分频) 必须 与发送端完全一致。任何偏差都会导致数据错位和无法恢复的通信失败。最好的实践是将配置参数定义为共享的常量。
- 缓冲区管理 :示例使用了环形缓冲区。在实际系统中,你还需要维护“读指针”和“写指针”,并判断缓冲区是否满/空,以防止数据覆盖或读取无效数据。
4. 高级应用与疑难问题排查
4.1 按需模式与SPI兼容性
手册中提到的“按需模式”是网络模式的一个特例,通过设置DC[4:0]=0来实现。在这种模式下,没有固定的时间槽,数据传输由TX寄存器的写入事件触发。每次写入TX,SSI就会自动发送一个完整的字,并在字之间插入至少两个位时钟的间隔。这非常类似于SPI协议的主机模式。
配置要点 :
-
MOD=1(网络模式) -
DC4-DC0=0(按需模式) -
GCK=1(门控时钟)。时钟只在数据传输期间有效,这与SPI的CPOL/CPHA模式非常匹配。 -
SYN=0(异步模式)。通常,在按需全双工通信中,主设备产生发送时钟(SCK输出),从设备使用这个时钟同时进行收发,但帧同步可能需要独立(异步)。
这种模式非常适合与标准的SPI从设备(如存储器、传感器)通信。你需要额外用GPIO引脚来模拟SPI的片选信号(CS)。
4.2 常见问题排查速查表
在调试SSI网络时,以下问题最为常见:
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 完全无数据/时钟输出 |
1. PCC寄存器未正确配置,引脚仍为GPIO。
2. TE或RE未使能。 3. 全局中断屏蔽未打开,且采用中断方式。 |
1. 检查MOVEP #$01F8, X:PCC指令是否执行。
2. 检查CRB中TE和RE位是否为1。 3. 检查状态寄存器MR的I1、I0位,或确认查询方式下程序在检查TDE/RDF。 |
| 数据错位(如左右声道颠倒) |
1. 发送/接收端时间槽计数器未同步或模运算错误。
2. 输出/输入标志(OF0/IF0)使用错误。 3. SHFD移位方向设置与对方设备不匹配。 |
1. 在ISR中打印或通过LED显示时间槽索引,确认其按0,1,0,1...循环。
2. 用示波器同时观察SC0标志线和数据线,确认对应关系。 3. 确认双方SHFD位设置相同(通常MSB在先为0,LSB在先为1)。 |
| 随机数据错误或丢失 |
1. 接收过载(ROE)。
2. 发送下溢(TUE)。 3. 缓冲区指针管理错误导致数据被覆盖。 4. 电气问题(时钟抖动、信号完整性)。 |
1. 在接收ISR开头检查并记录ROE。
2. 在发送ISR开头检查TUE。 3. 加强缓冲区边界检查,加入满/空判断。 4. 用示波器检查SCK、帧同步和数据线的波形质量,确保建立/保持时间满足要求。 |
| 只能传输一帧数据 | 中断服务程序未正确更新TX寄存器或时间槽索引,导致后续时间槽TDE一直为1,触发TUE并重复发送旧数据。 | 确保 每个 时间槽的发送中断中,都执行了写TX或写TSR的操作,以清除TDE。 |
| 通信速率不对 | CRA中的PSR和PM计算错误。 |
复核公式
f_bit = fosc / (4 * (7*PSR + 1) * (PM + 1))
。使用示波器测量实际SCK频率。
|
4.3 系统集成与性能考量
当你将多个DSP56002通过SSI网络模式级联时(如图6-91的级联系统),就构成了一个强大的并行处理管道。数据从第一个DSP的SRD输入,经过处理后从STD输出到下一个DSP的SRD,如此接力。每个DSP可以处理特定的时间槽或执行特定的算法阶段。
设计此类系统时需注意 :
- 时钟偏移 :长距离或多节点级联时,时钟信号会产生偏移。尽量让主时钟源靠近所有从设备,或使用差分时钟信号。
- 帧同步恢复 :在环形或总线型网络中,每个节点都会引入一个时钟周期的延迟。需要在软件中补偿这个延迟,或者设计硬件电路来重新生成帧同步。
- 中断风暴 :如果系统有32个时间槽且帧率很高,每个DSP每秒可能面临数万次中断。评估CPU中断处理能力至关重要。对于高密度数据流,考虑使用DMA或降低中断频率(例如,每接收完一个完整的、多字的音频帧再产生一次中断)。
- 标志线的灵活运用 :SC0和SC1作为输入/输出标志,功能远超简单的通道选择。你可以用它们来传输控制命令(如“增益调整”、“滤波器系数更新”)、标识数据包类型(如“音频数据”、“配置数据”)、甚至实现简单的硬件流控。
最后,调试这样的系统,一个逻辑分析仪是必不可少的。要同时捕获SCK、帧同步、STD/SRD数据线以及关键的标志线,并设置触发条件为帧同步开始。通过观察多帧的数据波形,你可以清晰地看到每个时间槽的数据归属、标志状态,从而快速定位软件逻辑或硬件时序的问题。从理解每个寄存器位的含义,到构建一个稳定的多节点TDM网络,这个过程充满了挑战,但当你看到数据在多个处理器间流畅、同步地穿梭时,那种成就感是对工程师最好的回报。
334

被折叠的 条评论
为什么被折叠?



