异步HDLC协议与MPC866 SCC控制器实现详解
1. 异步HDLC协议核心原理与MPC866 SCC控制器概述
在嵌入式通信和工业控制领域,数据链路层的可靠传输是系统稳定性的基石。异步HDLC协议,作为高级数据链路控制协议在异步串行链路上的实现,因其结构清晰、可靠性高而被广泛应用于PPP拨号、IrDA红外通信以及各类专有串行总线中。与同步HDLC不同,异步HDLC工作在起止式异步串行接口上,需要在字节流中识别帧的边界,这带来了独特的挑战,例如如何区分数据字节和帧标志,以及如何处理传输错误。
MPC866 PowerQUICC处理器集成的SCC控制器,其异步HDLC模式正是为解决这些挑战而设计的硬件加速引擎。它并非一个简单的UART,而是一个集成了协议处理状态机的智能外设,能够自动完成帧的封装、透明性编码、CRC计算与校验,以及错误检测,将CPU从繁重的比特级协议处理中解放出来。理解其工作原理,对于设计高可靠、高效率的串行通信系统至关重要。本文将从一个嵌入式开发者的视角,深入拆解异步HDLC的协议细节,并详细剖析如何在MPC866的SCC控制器上实现它,包括寄存器配置、缓冲区管理以及实际编程中的避坑指南。
2. 异步HDLC帧结构与透明性编码机制深度解析
2.1 帧结构:从字节流中识别消息边界
异步HDLC的帧结构是其可靠性的基础。一个完整的帧由以下几个字段顺序构成:
- BOF:帧开始标志,固定为
0x7E。接收方通过扫描此字符来定位帧的起始位置。 - Address:地址字段,通常为8位。关键点在于:MPC866的SCC硬件不处理此字段。它既不会在发送时自动添加,也不会在接收时解析或过滤。这意味着地址字段必须由软件(CPU核心)包含在发送缓冲区中,并在接收后由软件进行解析。这种设计提供了灵活性,可以支持扩展寻址,但也要求开发者心中有数。
- Control:控制字段,同样为8位。与地址字段类似,SCC硬件对其“视而不见”,所有生成和解析工作均由软件负责。这常用于承载帧类型(信息帧、监控帧、无编号帧)和序列号。
- Information:信息字段,长度可变(M * 8位),是实际要传输的用户数据。
- FCS:帧校验序列,16位CRC-CCITT。这是硬件的核心功能之一,SCC会在发送时自动计算并附加,在接收时自动校验。其多项式为
x^16 + x^12 + x^5 + 1,初始值为0xFFFF。 - EOF:帧结束标志,同样为
0x7E。在PPP中,一个结束标志可以同时作为下一个帧的开始标志。
这种“标志位定界”的方法简单有效,但引出了一个根本问题:如果用户数据中恰好包含了0x7E这个字节,接收方就会错误地认为帧提前结束了。这就是“透明性”问题。
2.2 透明性编码:RFC 1549与字符填充
为了解决上述问题,异步HDLC采用了基于RFC 1549的“字符填充”或“字节填充”机制。MPC866的SCC控制器在硬件层面实现了该算法。
发送端(Transmitter Transparency Encoding): 发送器在将数据移出发送FIFO之前,会逐个字节进行检查。如果满足以下任一条件,则触发转义序列:
- 该字节是标志字符:对于PPP是
0x7E,对于IrLAP是0xC0或0xC1。 - 该字节是控制转义字符:
0x7D。 - 该字节是需要映射的控制字符:值在
0x00至0x1F之间,且在发送控制字符表TXCTL_TBL中对应的位被置1。
当触发时,发送器不会直接发送原字节,而是发送一个两字节的序列:
- 首先发送控制转义字符
0x7D。 - 然后发送原字节与
0x20进行异或(XOR)后的结果。
例如,数据中有一个0x7E(标志位)需要发送:
- 原字节:
0x7E - 异或
0x20后:0x7E ^ 0x20 = 0x5E - 线上实际发送的序列:
0x7D,0x5E
这样,接收方只要看到0x7D,就知道下一个字节是经过转义的,将其与0x20再次异或即可恢复原始数据。0x7D本身也需要被转义,其转义序列为0x7D, 0x5D。
接收端(Receiver Transparency Decoding): 接收器的解码流程是逆向的。它维护一个XOR_NEXT状态位。当收到一个字节时:
- 如果
XOR_NEXT为真,则将该字节与0x20异或,结果写入缓冲区,然后将XOR_NEXT清零。 - 如果收到
0x7D,则设置XOR_NEXT为真,并丢弃该0x7D字节。 - 如果收到
0x7E(结束标志),则结束当前帧的处理。 - 如果收到的字符值小于
0x20,且其在接收控制字符表RXCTL_TBL中对应的位被置1,则该字符会被直接丢弃(通常用于处理流控字符如XON/XOFF)。 - 其他字符直接写入缓冲区。
关键配置:控制字符表TXCTL_TBL和RXCTL_TBL是两个32位的寄存器(各4字节),每一位对应一个ASCII控制字符(0x00-0x1F)。TXCTL_TBL的某位为1,表示发送时该字符需要被转义;RXCTL_TBL的某位为1,表示接收时该字符应被丢弃。这为协议提供了额外的灵活性。例如,在有些环境中,你可能希望将0x11(XON)和0x13(XOFF)在链路上透明传输(不触发软件流控),那么就需要在TXCTL_TBL中设置对应的位。
实操心得:
TXCTL_TBL和RXCTL_TBL的初始化极易被忽略。对于大多数PPP应用,这两个表通常初始化为0,因为PPP协议本身不依赖这些控制字符。但对于需要处理特殊控制字符或与老旧设备对接的场景,正确配置这两个表是保证数据完整性的关键。务必根据你的实际协议规范来设置。
3. MPC866 SCC控制器异步HDLC模式实现详解
3.1 核心工作流程:DMA与缓冲区描述符
MPC866的SCC控制器通过CPM(通信处理器模块)与系统内存交互,其核心是缓冲区描述符机制。这是一种高效的DMA描述符,让SCC能够以极少的CPU干预进行数据收发。
发送流程:
- CPU准备数据:将待发送的完整帧数据(包括地址、控制字段)填入一个或多个内存缓冲区,并设置好对应的TxBD链表。
- 设置TxBD就绪:将第一个TxBD的
R(Ready)位置1。SCC的发送器会周期性地(或立即)轮询TxBD表。 - SCC自动处理:SCC从
TBASE指向的TxBD开始,找到R=1的缓冲区,读取数据指针和长度,开始发送。发送过程中,硬件自动添加BOF标志,对数据进行透明性编码,计算并附加FCS,最后添加EOF标志。 - 通知CPU:当一个缓冲区发送完成,SCC会清除该BD的
R位,如果该BD的I(Interrupt)位为1,则触发发送缓冲区中断(SCCE[TXB])。如果这是帧的最后一个缓冲区(L=1),则会在帧尾标志开始发送时触发中断。 - 循环/停止:如果当前BD的
W(Wrap)位为1,则发送完成后,SCC会跳回TBASE指向的BD链表头部继续查找;否则继续查找下一个BD。
接收流程:
- CPU准备空缓冲区:初始化一系列
E(Empty)位为1的RxBD,构成接收链表。 - SCC等待帧开始:接收器在串行线上搜索一个或多个连续的BOF标志(
0x7E)。 - 数据填充:检测到BOF后,SCC找到下一个
E=1的RxBD,开始将解码后的数据(已去除转义)填入对应的缓冲区。 - 缓冲区管理与帧结束:当一个缓冲区填满,或检测到EOF标志、 abort序列、或任何错误(如CD丢失、溢出)时,SCC会关闭当前缓冲区(清除
E位,设置L位如果是帧尾,并更新状态位)。 - 通知CPU:当RxBD被关闭,且其
I位为1,或接收帧数达到RFTHR阈值时,SCC会触发接收帧中断(SCCE[RXF])。CPU在中断服务程序中,读取Data Length和状态位,处理接收到的数据,然后将该BD的E位置1,交还给SCC循环使用。
3.2 关键寄存器配置与初始化步骤
配置SCC进入异步HDLC模式是一个精细的过程,错一步都可能导致通信失败。以下是基于手册的初始化流程精炼与解读:
步骤1-4:基础环境搭建
- 初始化SDCR:设置系统DMA配置寄存器,通常使用复位默认值即可,除非有特殊的内存访问需求。
- 配置端口:在NMSI模式下,配置端口A和C的相应引脚功能,将TXD、RXD、CTS、RTS、CD等信号映射到正确的物理引脚上。
- 配置波特率发生器:为SCC通道分配一个BRG,并设置其分频比,以产生所需的波特率时钟。注意:异步HDLC模式下,
GSMR_L[TDCR/RDCR]必须设置为10(16倍)或11(32倍)时钟模式,以提供足够的采样率。 - 配置SICR:在SICR寄存器中,将上一步配置的BRG时钟路由到目标SCC,并选择是使用NMSI引脚还是通过TSA连接。
步骤5-14:协议参数与缓冲区设置5.设置RBASE和TBASE:在SCC的参数RAM区域,将这两个指针分别指向你定义的RxBD和TxBD链表在内存中的起始地址。地址必须对齐。 6.发送初始化命令:向CPCR发送INIT TX AND RX PARAMETERS命令,将SCC参数RAM中所有协议相关参数复位。 7.配置RFCR和TFCR:设置接收和发送功能码寄存器,通常配置为正常操作、摩托罗拉字节序。 8.设置MRBLR:定义接收缓冲区的最大长度。所有RxBD指向的缓冲区长度不应超过此值。 9.配置CRC参数:将C_MASK写为0x0000F0B8,C_PRES写为0x0000FFFF。这是CRC-CCITT算法的标准初始值和掩码,切勿更改。 10.清零ZERO寄存器:这是一个历史遗留寄存器,按手册要求清零即可。 11.设置RFTHR:接收帧阈值。当SCC累积接收到这么多帧后,才触发一次SCCE[RXF]中断。设置为1表示每收到一帧就中断一次;设置更大值可以降低中断频率,提高吞吐量,但会增加延迟。 12.配置控制字符表:根据你的协议需求,初始化TXCTL_TBL和RXCTL_TBL。对于纯PPP,通常全部置零。 13.初始化所有RxBD:将链表中的所有RxBD的E位置1,W位仅在最后一个BD设置,Data Length和Buffer Pointer指向有效的内存缓冲区。 14.初始化所有TxBD:将所有TxBD的R位置0,W位同样仅在最后一个BD设置。
步骤15-20:使能控制器15.清除SCCE:向SCCE写入0xFFFF以清除所有可能悬挂的事件位。 16.配置SCCM:根据你的中断处理需求,使能相应的事件中断位。例如,使能RXF和TXB用于数据收发中断,使能TXE和RXF中的错误位用于错误处理。 17.配置GSMR_H:重点设置RFW=1(启用低延迟操作,这对字符型协议很重要),并根据需要设置IRP(仅SCC2用于IrDA)。 18.配置GSMR_L:将MODE设置为0b0110以选择异步HDLC模式。此时先不要使能ENR和ENT。 19.配置PSMR:异步HDLC模式寄存器。关键设置是CHLN=0b11(8位数据),FLC位根据是否需要硬件流控(CTS/RTS)来设置。 20.使能收发器:最后,在GSMR_L中置位ENT和ENR,启动发送和接收器。
避坑指南:初始化顺序至关重要。一个常见的错误是在参数(如
RBASE)尚未配置正确时,就使能了接收器(ENR)。这会导致SCC立即开始从错误的内存地址读取BD,进而引发总线错误或系统锁定。务必遵循“先静态配置,后动态使能”的原则。
3.3 错误处理与命令控制
异步HDLC控制器提供了丰富的错误检测和恢复机制。
发送错误:
- CTS丢失:在发送过程中,如果CTS信号无效,SCC会停止发送当前缓冲区,设置
SCCE[TXE]和当前TxBD的CT位。发送将在收到RESTART TRANSMIT命令后,从下一个TxBD继续。 - STOP TRANSMIT命令:当软件发出此命令,SCC会立即发送Abort序列(
0x7D+0x7E),然后发送空闲字符(0xFF),并停止发送。这用于紧急停止或重新排序缓冲区。之后必须发RESTART TRANSMIT来恢复。
接收错误:
- 溢出:接收FIFO(SCC1为32字节,其他为16字节)已满,但CPM无法及时将数据写入内存。当前帧被丢弃,
RxBD[OV]被设置。 - CD丢失:载波检测信号在帧接收过程中消失。这是最高优先级的错误,帧立即被终止,
RxBD[CD]被设置。 - Abort序列:收到
0x7D+0x7E序列。当前帧被丢弃,RxBD[AB]被设置。 - CRC错误:帧的CRC校验失败。CRC值仍会被写入缓冲区末尾,但
RxBD[CR]被设置。 - Break序列:接收到Break字符。
RxBD[BRK]被设置。
关键命令:
STOP TRANSMIT/RESTART TRANSMIT:用于控制发送流程。ENTER HUNT MODE:强制接收器关闭当前RxBD(如果正在使用),并重新进入搜索标志位(Hunt)模式。这在需要软件复位接收状态时非常有用。INIT RX/TX PARAMETERS:初始化参数RAM。必须在收发器禁用时执行。
4. 异步HDLC模式下的编程实践与疑难排查
4.1 缓冲区描述符管理与数据组织
高效管理BD链表是发挥SCC性能的关键。以下是一个典型的数据结构定义示例(用C语言描述):
typedef struct bd { uint16_t status; // 状态控制字 uint16_t length; // 数据长度 uint8_t *buffer; // 数据缓冲区指针 } BD_t; // 发送BD链表 (示例,通常需要4字节对齐) BD_t txBdTable[4] __attribute__((aligned(4))); // 接收BD链表 BD_t rxBdTable[8] __attribute__((aligned(4))); // 数据缓冲区 uint8_t txDataBuffers[4][256]; uint8_t rxDataBuffers[8][256];初始化BD链表的要点:
- 链表成环:将最后一个BD的
W(Wrap)位置1,并将其buffer指针指向下一个有效数据缓冲区(通常是第一个缓冲区),形成环形链表。确保链表不会在中间断裂。 - 缓冲区对齐:虽然手册未强制要求,但将BD表和缓冲区放在非缓存(Cache-inhibited)内存区域,或确保在DMA操作前进行缓存回写(flush),可以避免一致性问题。
- 长度计算:对于发送,
length是你想发送的用户数据长度(包括地址和控制字段)。SCC会自动添加BOF、FCS和EOF。对于接收,length是缓冲区的大小。当帧接收完成后,SCC会在此BD的length字段中更新实际接收到的字节数(包括CRC字节)。
4.2 中断服务程序处理流程
中断处理是数据吞吐的核心。通常使能SCCE[RXF](帧接收)和SCCE[TXB](缓冲区发送完成)中断。
接收中断处理流程:
- 读取
SCCE寄存器,判断中断源。 - 如果是
RXF,则遍历RxBD链表,寻找E=0的BD(表示已满)。 - 读取该BD的
status字段,检查错误位(OV,CD,CR,AB,BRK)。根据错误类型进行相应处理(如重发、丢弃、日志记录)。 - 读取
length字段,从buffer中拷贝数据。注意:length包含2字节的CRC。软件需要根据status中的CR位决定是否信任这些数据。 - 处理数据后,必须将该BD重新“归还”给SCC:将
status中的错误标志位清零(如果需要),然后将E位置1。如果使用了连续模式(CM=1),则E位在无错误时不会自动清零,需要软件在特定时机处理。 - 清除
SCCE[RXF]位(写1清零)。
发送中断处理流程:
- 如果是
TXB,表示一个TxBD已发送完成(其R位已被硬件清零)。 - 软件可以检查该BD的状态,确认是否发送成功(如
CT位)。 - 回收该BD对应的缓冲区,用于装载新的发送数据。
- 如果需要继续发送,准备好数据后,将新的TxBD的
R位置1。 - 清除
SCCE[TXB]位。
4.3 常见问题与排查技巧实录
在实际调试中,以下问题最为常见:
问题1:完全收不到数据,或数据全是乱码。
- 排查思路:
- 物理层:首先用示波器或逻辑分析仪检查TXD、RXD引脚是否有波形,波特率是否正确。确认硬件连接无误。
- 时钟配置:检查BRG的时钟源和分频设置,确保
GSMR_L[TDCR/RDCR]设置为16x或32x模式。这是异步模式必须的。 - 引脚复用:确认端口A/C的引脚复用寄存器是否正确配置,将SCC功能映射到了正确的物理引脚。
- 缓冲区描述符:使用调试器检查
RBASE和TBASE指向的地址是否正确,BD链表是否完整闭环,初始BD的E(接收)或R(发送)位是否已正确设置。 - 中断与轮询:如果使用中断,确认中断控制器已正确配置,并且SCCM寄存器中已使能相应中断位。也可以先尝试轮询方式,检查
SCCE和BD状态位的变化。
问题2:能收到数据,但帧不完整,或频繁出现CRC错误。
- 排查思路:
- 透明性编码:检查发送和接收双方的控制字符表
TXCTL_TBL/RXCTL_TBL配置是否一致。如果不一致,转义/解转义过程会错位,导致CRC失败。 - 数据包含标志位:如果你的数据中确实包含
0x7E,但TXCTL_TBL未配置为对其转义,那么接收方会将其误认为帧结束。确保需要转义的字符已被正确映射。 - 缓冲区大小与帧长:检查
MRBLR是否设置过小。如果接收帧长度超过MRBLR,SCC会使用多个BD来接收,但若BD链表耗尽(所有BD的E位都为0),会导致SCCE[BSY]置位,帧被丢弃。确保接收BD链表足够长,或使用CM模式。 - 时钟稳定性:异步通信对时钟精度要求较高。时钟偏差过大会导致采样错误,产生帧错误或字节错误,进而引发CRC错误。检查时钟源精度。
- 透明性编码:检查发送和接收双方的控制字符表
问题3:发送过程中,CTS流控不生效。
- 排查思路:
- PSMR寄存器:确认
PSMR[FLC]位已设置为1,启用了异步流控功能。 - CTS引脚配置:确认CTS对应的端口C引脚已正确配置为CTS输入功能,而非通用I/O。
- 信号极性:确认CTS信号的硬件连接和有效电平。CTS为低电平有效,当CTS无效时,发送器应在当前字符发送完后停止。
- PSMR寄存器:确认
问题4:使用连续模式时,缓冲区数据被覆盖。
- 核心要点:连续模式是为了实现零拷贝或极高吞吐量而设计的。当RxBD的
CM位为1时,即使帧接收完成且无错误,SCC也不会自动清除该BD的E位。这意味着下次接收会直接覆盖这个缓冲区。软件必须在数据被覆盖前,将有效数据取走。通常需要在RXF中断中,不仅处理数据,还要在确认数据已安全保存后,手动将BD的E位置1(如果还需要继续使用该BD)或切换到下一个BD。这是一个高级特性,使用不当极易导致数据丢失。
问题5:IrDA模式无法工作。
- 关键检查点:
- 仅限SCC2:红外编码解码器硬件仅在SCC2上可用。
- GSMR_L2[SIR]位:必须置1以激活红外编解码器。
- GSMR_H2[IRP]位:根据红外接收器的硬件设计,设置正确的接收极性。
- BOF/EOF字符:在参数RAM中,
BOF应初始化为0xC0,EOF初始化为0xC1,以匹配IrLAP协议。 - 时钟模式:IrDA通常要求
GSMR_L[TDCR/RDCR]设置为16x时钟模式。
通过系统地理解协议原理、硬件机制,并掌握这些实战调试技巧,你就能驾驭MPC866的异步HDLC控制器,构建出稳定高效的串行通信链路。记住,数据手册是你的第一参考资料,但在遇到问题时,结合逻辑分析仪抓取线上的实际数据流,与软件状态进行对比分析,往往是定位复杂问题的终极手段。
