FSI协议详解:嵌入式高可靠通信的帧类型、SPI兼容与链路建立
1. FSI协议:嵌入式通信的“瑞士军刀”
在嵌入式系统里,通信协议就像是设备之间的“语言”。选对了语言,沟通就高效可靠;选错了,轻则数据错乱,重则系统瘫痪。今天要聊的FSI(Flexible Serial Interface),就是德州仪器(TI)在其AM26x系列等处理器中集成的一把通信“瑞士军刀”。它不像SPI、I2C那样广为人知,但在需要高可靠性、强抗干扰能力的工业现场,比如电机驱动、数字电源、隔离通信这些场合,FSI往往是藏在芯片深处的秘密武器。
FSI的核心价值,在于它把很多通信的“脏活累活”交给了硬件。你想做CRC校验确保数据没错?硬件自动算好了。担心线上有干扰导致帧不完整?硬件有看门狗盯着。甚至你想做ECC纠错,它也能帮上忙。更妙的是,它还能“伪装”成SPI,跟市面上大量的标准SPI从设备对话,这种灵活性大大拓宽了其应用场景。但手册上的描述往往偏重寄存器位定义,缺乏一个连贯的、从“为什么”到“怎么做”的工程视角。我结合自己的踩坑经验,把FSI里最核心的帧类型设计、SPI兼容模式的弯弯绕绕,以及最让人头疼的链路建立过程,掰开揉碎了讲清楚。无论你是在评估选型,还是正在调试FSI通信,这篇文章都能帮你避开我当年走过的弯路。
2. 帧类型详解:不只是传数据那么简单
FSI的通信基础是“帧”。你可以把它理解成一封信,信封上要有地址、邮票、邮戳,信封里才是信纸(数据)。FSI硬件定义了好几种“信封”格式,每种格式用途不同,这就是帧类型。理解帧类型,是理解FSI一切高级特性的起点。
2.1 帧类型总览与设计哲学
FSI协议用4比特(4-bit Frame Code)来标识帧类型,这决定了整帧的结构和行为。手册里的表格是冰冷的,我们需要理解其背后的设计意图。
| 帧类型 | 4比特代码 | 核心用途与设计考量 |
|---|---|---|
| PING | 0000 | 链路心跳与状态探测。这是最简单的帧,不含数据域和CRC。它的核心目的是周期性“打招呼”,确认对方还在线。硬件可以自动发送,极大减轻CPU负担,用于实现通信线缆断裂或对方设备宕机的检测(Line Break Detect)。 |
| ERROR | 1111 | 紧急事件或自定义信令。虽然叫“错误帧”,但硬件不对其内容做任何限定。你可以用它报告错误,也可以当成一个最高优先级的硬件中断信号来用,通知对端有紧急事务需要处理。 |
| DATA_1_WORD | 0100 | 传输16比特数据。适用于传输状态字、控制命令等小数据包,开销小,效率高。 |
| DATA_2_WORD | 0101 | 传输32比特数据。最常用的数据帧之一,适合传输一个32位浮点数或两个16位ADC采样值。 |
| DATA_4_WORD | 0110 | 传输64比特数据。用于传输双精度浮点数或更复杂的数据结构。 |
| DATA_6_WORD | 0111 | 传输96比特数据。特定场景下使用,例如传输一组三相电机的电流、电压值。 |
| DATA_N_WORD | 0011 | 传输可变长度数据(1-16字)。灵活性最高,数据长度由软件在TX_FRAME_CTRL.N_WORDS寄存器中定义。关键点:发送端和接收端的N值必须配置一致,否则会引发帧同步错误。 |
| Reserved | 0001, 0010, 1000-1110 | 保留未来扩展。切勿使用,否则兼容性无法保证。 |
注意:
DATA_N_WORD帧的灵活性是有代价的。它要求通信双方在初始化阶段就必须通过其他方式(如固定的启动配置、或先通过固定长度帧协商)来同步N的值。如果双方N值配置不同,接收方会因期待的数据字数不符而产生帧错误或CRC错误,导致链路无法建立。在点对点固定应用中,建议优先使用固定长度的数据帧(如DATA_2_WORD),更为可靠。
2.2 PING帧:链路的“脉搏”
PING帧的结构最为精简:[Idle][Preamble][SOF][Frame Type=0000][Frame Tag][EOF][Postamble][Idle]。其中,帧类型固定为0000,帧标签(Frame Tag)由软件定义,通常用不同标签区分定时器自动发送的PING和软件手动触发的PING。
它的工作逻辑是双向的:
- 发送方:可以配置一个硬件定时器,周期性地自动发送PING帧,完全无需CPU干预。这就像心脏自主跳动,是检测链路存活性的根本机制。
- 接收方:配备了一个“PING看门狗”(Ping Watchdog)。这个看门狗设定一个时间窗口,如果在这个窗口内没有收到任何有效的PING帧,它就会触发中断,告知软件“链路可能已断开”。这个时间窗口的设定需要仔细计算,通常要略大于发送方PING周期的2倍,以避免因偶尔的时钟抖动或干扰产生误报。
实操心得:在噪声较大的工业环境中,不要仅仅依赖一两次PING超时就判定链路故障。我的做法是在软件层面做一个简单的滤波:连续3次PING看门狗超时中断,才执行链路断开的重置流程。同时,PING周期不宜设置过短,否则会占用过多总线带宽;也不宜过长,否则故障检测不及时。对于百微秒级通信周期的系统,将PING周期设为1-10毫秒是一个不错的起点。
2.3 ERROR帧:被名字耽误的硬件信号弹
ERROR帧的结构与PING帧完全一致,只是帧类型码为1111。它的“错误”之名容易让人误解。实际上,硬件只是提供了一个快速传递4比特标签(通过TX_FRAME_TAG_UDATA寄存器设置)的通道。接收方硬件能识别帧类型为1111,并立即将标签值存入RX_FRAME_TAG_UDATA寄存器,通常还会产生一个高优先级中断。
你可以把它用成:
- 紧急错误码:发送0x0表示过流,0x1表示过温,0x2表示通信校验异常等。
- 硬件事件触发器:发送特定标签,触发接收方执行某个预设动作,如切换控制模式、启动一段安全程序。
- 低延迟信令:由于没有数据域和CRC计算,ERROR帧的传输延迟是所有帧中最小的,可用于需要极快响应的同步信号。
配置要点:接收端需要使能ERROR帧中断,并在中断服务程序里第一时间读取RX_FRAME_TAG_UDATA寄存器来获取标签值,因为下一个帧可能会覆盖这个寄存器。
2.4 DATA帧:数据搬运的主力
DATA帧结构最复杂,包含了用户数据、数据字和CRC字节:[Idle][Preamble][SOF][Frame Type][User Data][Data Words][CRC][Frame Tag][EOF][Postamble][Idle]。
- 用户数据(User Data):一个8比特字段,用途完全由软件定义。常见的用法是存放数据包的序列号、子地址、或作为简单命令字。在启用ECC功能时,这个字段常被用来传递ECC校验值。
- 数据字(Data Words):每个字16比特,数量由帧类型决定。数据按字写入发送缓冲区,硬件会自动按序发出。
- CRC字节:硬件自动计算并附加在数据域之后。FSI采用CRC-8多项式0x07(
x^8 + x^2 + x + 1),计算范围涵盖用户数据域和所有数据字。接收方硬件会自动计算CRC并进行比对,结果通过状态寄存器或中断告知软件。
CRC计算顺序详解:这是容易出错的地方。手册的例子是:用户数据=0xAA,两个数据字分别为Data-0=0x2211, Data-1=0x4433。硬件计算CRC时,输入字节流顺序是:
- 0xAA (用户数据)
- 0x11 (Data-0的低字节)
- 0x22 (Data-0的高字节)
- 0x33 (Data-1的低字节)
- 0x44 (Data-1的高字节)
注意字节序:对于每个16位数据字,都是低字节在前,高字节在后(小端序)。如果你的MCU内存数据是大端序,在填充发送缓冲区前需要进行字节交换。
3. 高级特性与SPI兼容模式实战
FSI的强大不止于基础通信,其多通道、硬件ECC和SPI兼容能力,才是它在复杂系统中脱颖而出的关键。
3.1 多通道传输:提升带宽与抗噪
FSI支持在两条数据线(TXD0, TXD1)上并行传输,这类似于DDR内存的原理,在时钟频率不变的情况下,有效数据吞吐量翻倍。其比特分配规则非常规整:所有控制字段(SOF, Frame Type, Frame Tag, EOF)在双线上完全重复,而用户数据、数据字和CRC字段则按比特奇偶交错分配。
以8位用户数据u7u6u5u4u3u2u1u0为例:
- TXD0线发送:u7, u5, u3, u1 (奇数位)
- TXD1线发送:u6, u4, u2, u0 (偶数位)
数据字和CRC字段同理。这种设计保证了控制信号的鲁棒性(双线冗余),同时高效地并行化了数据载荷。
启用与配置:多通道模式通常通过TX_OPER_CTRL和RX_OPER_CTRL寄存器中的相关位使能。需要特别注意PCB布线,应尽量保证TXD0和TXD1到接收端的走线等长,以减少信号偏移(Skew)。FSI接收器内部有可编程的延迟调整单元(Skew Adjustment),可以用来补偿微小的走线长度差异,但这不能替代良好的硬件设计。
3.2 硬件ECC:为关键数据加把锁
CRC能检错,但ECC(Error Correction Code)能纠错。FSI内置的ECC模块(可选)可以计算并校验数据的纠错码,对于传输关键参数(如电机位置、电流环设定值)的场景,能极大提升系统的可靠性。
发送端ECC流程:
- 配置:设置
TX_OPER_CTRL_HI_ALT1_.ECC_SEL选择ECC数据宽度(16/32位)。 - 写入数据:将待发送数据同时写入发送缓冲区和
TX_ECC_DATA寄存器。 - 获取ECC值:读取
TX_ECC_VAL寄存器,得到硬件计算的8位ECC值。 - 嵌入ECC:将这个8位ECC值填入
TX_FRAME_TAG_UDATA.USER_DATA字段(用户数据域)。 - 发送:启动帧传输。
接收端ECC校验流程:
- 提取数据与ECC:接收完成后,将数据从接收缓冲区复制到
RX_ECC_DATA寄存器,将从帧中解析出的用户数据(即发送端传来的ECC值)复制到RX_ECC_VAL寄存器。 - 读取结果:读取
RX_ECC_LOG寄存器。- 如果值为0:无错误,
RX_ECC_SEC_DATA中的数据有效。 - 如果
SBE位为1:发生单比特错误,硬件已自动纠正,RX_ECC_SEC_DATA中是纠正后的数据。 - 如果
MBE位为1:发生多比特错误,无法纠正,RX_ECC_SEC_DATA中的数据无效,必须丢弃。
- 如果值为0:无错误,
重要提示:上述方法利用了用户数据域携带ECC值,适用于数据量不大的帧(如DATA_1_WORD, DATA_2_WORD)。如果你的数据负载很大,另一种更推荐的做法是:使用
DATA_N_WORD帧,预留其中一个数据字(例如最后一个字)专门存放ECC值。这样既不占用用户数据域,也能保护更长的数据。
3.3 SPI兼容模式:连接传统世界的桥梁
这是FSI最实用的特性之一。它允许FSI模块扮演SPI主机或从机的角色,与标准SPI设备通信。但这不是无损兼容,FSI在SPI模式下工作于一种“受限配置”。
SPI兼容模式的核心限制:
- 时钟边沿:数据在时钟上升沿发送,在下降沿采样(SPI Mode 0)。
- 字长:仅支持16位字长。
- 片选信号:FSI作为主机时,TXD1引脚被用作低有效的片选信号(
SPI_STE),在整帧传输期间保持低电平。 - 无前导/后导码:帧间所有信号线返回空闲状态。
- FSI不能作为SPI从机发送:因为FSI的TXCLK不能接受外部时钟源。
SPI帧结构变形:当FSI向标准SPI设备发送一帧数据时,SPI设备看到的是一个接一个的16位数据流。FSI需要将自身的帧结构“编码”到这个流中。例如,发送一个DATA_2_WORD帧,SPI从机端会收到4个16位字:
- SPI Word 0:
[SOF: 1001][Frame Type: 0100][User Data: 8 bits] - SPI Word 1: 数据字1 (16位)
- SPI Word 2: 数据字2 (16位)
- SPI Word 3:
[CRC: 8 bits][Frame Tag: 4 bits][EOF: 0110]
这意味着,与之通信的SPI从设备固件必须有能力解析这个封装格式,从中提取出SOF、帧类型、用户数据、CRC等字段。普通的SPI传感器或存储器芯片无法直接理解,因此此模式主要用于与另一个智能控制器(如另一颗MCU)的SPI接口通信,且对方软件需做相应适配。
3.4 三种SPI应用场景配置
根据FSI模块(TX/RX)的角色和连接方式,主要有三种应用模式。
模式一:FSI作为SPI主机(仅发送)
- 连接:FSI_TX作为SPI主机。
TXCLK接SPI_CLK,TXD0接SPI_SIMO(主机输出),TXD1接SPI_STE(片选)。 - 配置:在完成标准FSI TX初始化后,释放复位前,设置
TX_OPER_CTRL_LO_ALT2_.SPI_MODE = 1。 - 能力分析:
- FSI端优势:硬件自动完成CRC、帧检查。可配置PING看门狗检测链路中断。
- SPI从机端局限:所有高级特性(如CRC校验、链路中断检测)都需要在SPI从机的软件中实现,增加了其CPU开销。
模式二:FSI作为SPI从机(仅接收)
- 连接:FSI_RX作为SPI从机。
RXCLK接SPI_CLK,RXD0接SPI_SOMI(主机输入)。RXD1悬空,无需片选。 - 配置:在完成标准FSI RX初始化后,释放复位前,设置
RX_OPER_CTRL.SPI_MODE = 1。 - 能力分析:
- FSI端优势尽显:作为接收方,FSI的所有硬件优势得以保留。它能用硬件检测帧错误、CRC错误、ECC错误,并能通过帧看门狗检测突然终止的帧。其内部的毛刺抑制和偏移调整功能也能有效提升通信鲁棒性。
- 对SPI主机的要求:SPI主机需要在其发送的数据流中,按照FSI的帧格式进行编码,嵌入SOF、帧类型、CRC等信息。
模式三:FSI模拟全双工SPI主机(最复杂)
- 连接:使用一个FSI_TX模块和一个FSI_RX模块共同模拟一个全双工SPI主机。TX模块连接如前所述(提供CLK, MOSI, CS)。RX模块的
RXD0连接SPI从机的MISO线。时钟RXCLK可以选择内部环回(连接TXCLK)或外部连接。 - 配置:分别配置TX和RX模块的
SPI_MODE位。若使用内部时钟环回,还需设置RX_MAIN_CTRL_ALTC_.SPI_PAIRING = 1。 - 关键挑战:FSI的TX和RX模块在硬件上是独立的。发送模块无法直接知道接收模块收到了什么。因此,需要编写上层软件来协调两者,模拟出完整的SPI控制器行为。例如,在一次SPI传输后,软件需要主动去查询RX模块的接收缓冲区,才能获取从机返回的数据。这引入了额外的软件复杂性和延迟。
4. 通信链路建立:从混沌到同步
FSI通信链路建立,尤其是跨隔离芯片或独立上电的设备间建立链路,是一个精细活。核心矛盾在于:接收端随时准备采样,但必须正确识别出一个完整帧的起始点。这需要通过“刷新序列”来同步。
4.1 刷新序列:接收器的“清醒剂”
每次FSI接收模块软复位后,它都处于一种“混沌”状态,无法正确解析帧。此时,发送端必须发送一个特殊的“刷新序列”。这个序列的本质,是提供至少5个完整的接收时钟边沿,让接收器的内部状态机稳定下来,并清除任何残留的亚稳态。
刷新序列由两部分组成:
- 数据线切换:在时钟上升沿,两条数据线(TXD0, TXD1)同时产生一次电平翻转(例如从00变为11,再变回00)。
- 连续时钟脉冲:紧接着,提供至少5个连续的时钟脉冲。
重要替代方案:如果接收端连接的是一个标准SPI,那么从SPI发送一个数据字0xFFFF(即16个连续的‘1’)到FSI的RXD0,也能达到完全相同的刷新效果。因为0xFFFF的波形正好包含了数据线的切换和足够的时钟边沿。这在调试和兼容设计中非常有用。
4.2 点对点链路建立流程(无外部握手信号)
假设有两个设备:Device A(主)和Device B(从),通过FSI互联。它们不知道对方何时上电完成。以下是建立可靠链路的经典“握手”流程,完全通过FSI自有信号完成。
Device A(主设备)流程:
- 初始化:解除FSI TX和RX模块的复位,完成基本配置(波特率、帧类型等)。
- 使能接收中断:配置FSI RX中断,准备接收来自Device B的PING帧。
- 主动握手循环: a.发送刷新序列:确保Device B的接收器处于就绪状态。 b.发送标签为0的PING帧:这是一个“你在吗?”的询问。 c.等待并监听:启动一个超时计时器(例如10ms),同时等待接收中断。 d.判断响应: * 超时未收到任何帧:返回步骤a,重发。可加入重试次数限制。 * 收到有效PING帧,且帧标签为
0001:说明Device B已收到询问并回复了确认。握手成功,跳出循环。 * 收到其他帧:丢弃,返回步骤a。 - 发送确认:握手成功后,发送一个标签为
0001的PING帧给Device B,作为最终的链路就绪确认。
Device B(从设备)流程:
- 初始化:同Device A。
- 使能接收中断:准备接收来自Device A的PING帧。
- 被动等待与响应: a.等待接收中断。 b.判断帧:如果收到一个有效的PING帧,且帧标签为
0000(这是Device A的询问),则继续;否则丢弃,返回等待。 c.发送刷新序列:准备向Device A发送回复。 d.发送标签为1的PING帧:这是对“你在吗?”的肯定回复(“我在!”)。 e.等待确认:再次等待接收中断。期望收到一个标签为0001的PING帧(Device A的最终确认)。如果收到标签0000,可能是Device A的第二轮询问又到了,继续等待即可。 - 链路就绪:收到标签为
0001的确认帧后,链路建立完成。
这个流程利用了PING帧和帧标签,实现了一个简单的二次握手协议。其关键在于刷新序列的发送时机:每次准备向一个可能未同步的接收端发送有效帧之前,都应先发送刷新序列。在链路建立阶段,这个操作尤为重要。
5. 开发调试与常见问题排查
理论通了,上手调试才是见真章的时候。FSI的硬件特性丰富,也意味着配置点众多,容易踩坑。
5.1 寄存器保护机制:防止误操作的保险丝
FSI的关键控制寄存器受两级保护,这在多任务或复杂初始化流程中能避免灾难性误写。
- 寄存器密钥保护:对
TX_MAIN_CTRL、RX_MAIN_CTRL等核心控制寄存器进行写操作时,必须同时写入正确的密钥(Key)。例如,要设置CORE_RST位,需要写入0xA501,其中0xA500是密钥,0x0001是复位值。写错密钥,操作会被忽略。 - 控制寄存器锁:
TX_LOCK_CTRL和RX_LOCK_CTRL寄存器提供了一个总锁。一旦上锁(写入0xA501),所有受保护的寄存器都将无法写入,直到发生一次系统级复位(SYSRSn)或对FSI模块的外设软复位。这是一个不可逆的软件锁,主要用于产品出厂后的安全保护,调试阶段慎用。
5.2 调试器暂停与实时性处理
FSI模块一旦启动,其时钟和数据流是独立于CPU自由运行的。这意味着当你用调试器暂停CPU时,FSI的收发并不会停止。如果此时正好有数据帧在传输,可能会导致缓冲区溢出或状态机错乱。
如果你需要在调试时暂停FSI:
- 将调试器设置为实时仿真模式(Real-time Emulation Mode),这样它不会完全停止芯片时钟。
- 将FSI的中断标记为时间关键中断(在DBGIER寄存器中使能相应位)。
- 在FSI的中断服务程序(ISR)中,可以检查
DSTAT寄存器来判断中断是否发生在调试器暂停期间。 - 如果是在暂停期间触发的,可以在ISR中临时禁用FSI操作,并跳转到一个专门的调试处理代码段。
5.3 典型问题排查速查表
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 链路无法建立,接收方无任何中断 | 1. 物理连接问题(线缆、电平)。 2. 时钟配置错误(TXCLK频率与RXCLK不匹配)。 3. 未发送刷新序列。 | 1. 用示波器测量TXCLK、TXD0、TXD1信号,确认有波形输出,电平正确。 2. 核对发送端和接收端的时钟分频配置,确保波特率一致。 3.确保在发送任何有效帧(尤其是第一个PING帧)前,已发送完整的刷新序列。 |
| 能收到帧,但CRC持续错误 | 1. 发送/接收双方的数据长度(N_WORDS)或帧类型配置不一致。 2. 用户数据或数据填充顺序错误。 3. 多通道模式下,线路偏移严重。 | 1. 仔细检查TX_FRAME_CTRL和RX_OPER_CTRL中关于帧类型和数据长度的配置位。2. 确认数据写入发送缓冲区的字节序(小端序)。检查CRC计算涵盖的数据范围是否正确。 3. 测量双数据线的时序,利用接收端的偏移调整功能进行补偿。 |
| PING看门狗频繁误报 | 1. PING发送周期不稳定或中断堵塞。 2. 看门狗超时窗口设置过小。 3. 线路噪声导致PING帧偶尔出错。 | 1. 检查配置PING定时器的时钟源是否稳定,确保PING中断优先级足够高,不被长时间屏蔽。 2. 适当增大看门狗超时窗口,例如设置为PING周期的2.5-3倍。 3. 在软件层面增加滤波逻辑,如连续多次超时才判定为故障。 |
| SPI兼容模式下,标准SPI设备无法解析数据 | 1. SPI模式(时钟极性、相位)不匹配。 2. 标准SPI设备固件未按照FSI帧格式解析数据流。 3. 片选信号(TXD1)时序问题。 | 1. 确认FSI的SPI模式固定为CPOL=0, CPHA=0(上升沿采样)。 2.这是最常见原因:确认SPI从机的代码能够从连续的16位数据流中,正确提取出第1个字中的SOF、帧类型,以及最后一个字中的CRC和EOF。 3. 用示波器确认片选信号在整帧期间保持低电平,帧结束后拉高。 |
| 启用ECC后,数据校验总是不通过 | 1. 发送端和接收端ECC数据宽度配置不一致。 2. 用于计算ECC的源数据与发送的数据不一致。 3. 接收端提取ECC值(来自User Data)的源错误。 | 1. 核对TX_OPER_CTRL_HI_ALT1_.ECC_SEL和接收端对应配置位。2. 确保写入 TX_ECC_DATA寄存器的数据,与写入发送缓冲区的数据完全一致。3. 确认接收端是从 RX_FRAME_TAG_UDATA.USER_DATA中读取接收到的ECC值,而不是从其他地方。 |
| 多通道传输时数据错位 | 1. TXD0和TXD1走线长度差异过大。 2. 接收端未启用或未正确配置偏移调整。 | 1. 硬件上尽量保证双线等长。 2. 在接收端配置寄存器中,找到Skew Adjustment相关字段,尝试微调其中一条数据线的延迟(通常以时钟周期为单位),观察数据是否对齐。 |
调试FSI,示波器或逻辑分析仪是必不可少的。重点观察几个关键点:刷新序列的波形是否正确、SOF(1001)和EOF(0110)模式是否清晰、数据域是否完整、CRC字段是否存在。将实际波形与协议规定的帧结构逐位对比,大部分问题都能定位。最后,务必充分利用芯片厂商提供的驱动库或示例代码作为起点,它们通常已经处理好了许多底层的配置细节和时序问题,能让你事半功倍。
