MPC866异步HDLC协议硬件配置与实战解析
1. 异步HDLC协议与MPC866 PowerQUICC从原理到实战配置在嵌入式通信领域尤其是在工业控制、网络设备和早期的无线数据模块中异步HDLC协议扮演着数据链路层“可靠信使”的角色。它不像我们熟悉的TCP/IP那样复杂但恰恰是这种简洁、高效的帧结构让它能在资源受限的微控制器上为串行链路提供稳定的数据封装、错误校验和流量控制。我第一次接触异步HDLC是在一个老旧的路由器固件升级项目中当时为了解析其调试串口输出的私有协议帧不得不深入研究手册那段经历让我深刻体会到理解硬件如何实现协议远比单纯调用API要扎实得多。今天我们就以经典的MPC866 PowerQUICC处理器为例彻底拆解其SCC控制器对异步HDLC协议的硬件支持。这不仅仅是阅读数据手册更是理解如何让一块芯片的串口从简单的字节收发器变身成为一个能自动组帧、验错、处理特殊字符的智能通信引擎。无论你是在维护遗留系统还是在设计新的串行通信模块掌握这些底层配置细节都能让你在调试时心里有底在设计时游刃有余。2. 异步HDLC协议核心原理与帧结构拆解在深入MPC866的寄存器之前我们必须先搞清楚异步HDLC协议到底在干什么。你可以把它想象成邮寄一封实体信信封标志位告诉邮局信从哪里开始、到哪里结束信纸数据是你的内容而信封上的校验码CRC则确保信在途中没有被篡改或损坏。2.1 帧结构通信的基本单元一个标准的异步HDLC帧其结构非常规整如下图所示-------------------------------------------------------- | 标志 | 地址 | 控制 | 信息字段 | 帧校验序列 | 标志 | | (8位) | (8位) | (8位) | (可变) | (16位) | (8位) | --------------------------------------------------------标志字段 (Flag, 0x7E)这是帧的定界符就像信封的封口。一个帧以0x7E开始也以0x7E结束。连续的帧之间可以共享一个标志位。接收方通过搜索0x7E来识别帧的开始和结束。地址字段 (Address)在点对点通信中这个字段通常用于标识次要站地址但在许多简单应用中如PPP协议它常被固定为0xFF广播地址。关键点在于MPC866的SCC硬件在异步HDLC模式下不自动生成也不解析此字段。这意味着如果你需要地址字段必须由你的软件核心将其作为数据的一部分放入发送缓冲区接收时也需要从缓冲区中自行提取和判断。控制字段 (Control)用于区分帧的类型信息帧、监控帧、无编号帧。和地址字段一样MPC866的硬件不处理此字段需要软件介入。信息字段 (Information)这才是你要传输的实际有效数据长度可变。帧校验序列 (FCS)这是帧的“指纹”使用CRC-CCITT多项式x^16 x^12 x^5 1对整个帧从地址字段开始到信息字段结束不包括标志位和本身进行计算。MPC866的硬件会自动在发送时生成并附加FCS在接收时进行校验并将结果通过缓冲描述符BD的状态位告知软件。注意这里容易产生一个误解认为“异步HDLC”的“异步”是指像UART那样的起止式异步通信。其实不然。这里的“异步”是相对于HDLC协议本身的同步比特流传输而言。异步HDLC是在异步字符链路如RS-232上承载HDLC帧其物理层是异步的有起始位、停止位但数据链路层的帧处理逻辑是同步且规整的。MPC866的SCC正是为了适配这种“物理层异步链路层同步”的混合模式而设计的。2.2 透明传输与字符填充解决“标志位冲突”难题既然0x7E是标志位那么如果我要传输的数据里恰好就有一个字节是0x7E接收方岂不是会误认为帧结束了这就是所谓的“标志位冲突”问题。异步HDLC的解决方案是“透明传输”或“字节填充”。其规则是对于发送方在将数据放入物理链路之前需要扫描整个帧不包括头尾的标志位。一旦发现以下三种字符之一就进行“转义”标志字符0x7E。转义字符本身0x7D。任何值在0x00-0x1F之间的控制字符如果该字符在“控制字符表”中被映射。转义的方法是先发送一个转义字符0x7D然后发送原字符与0x20进行异或XOR后的结果。例如数据0x7E会被转换成0x7D, 0x5E因为 0x7E XOR 0x20 0x5E。数据0x7D会被转换成0x7D, 0x5D因为 0x7D XOR 0x20 0x5D。接收方则执行相反的过程当收到0x7D时它知道下一个字节是经过转义的于是丢弃0x7D并将下一个字节与0x20异或恢复出原始数据再进行CRC计算和存储。MPC866的妙处这套复杂的扫描、替换、恢复逻辑完全由SCC控制器的微码硬件实现无需CPU介入。你只需要在参数RAM中配置好转义字符ESC通常为0x7D和控制字符映射表TXCTL_TBL/RXCTL_TBL硬件就会自动完成“填充”和“去填充”极大减轻了CPU负担。2.3 CRC校验数据的守护神CRC校验是确保数据完整性的核心。MPC866的异步HDLC控制器固定使用16位的CRC-CCITT。这里有一个至关重要的细节CRC计算是在“透明编码”之前和“透明解码”之后进行的。发送时硬件对原始的地址、控制、信息字段即你放入缓冲区的原始数据计算CRC然后将计算结果FCS附加在信息字段之后。最后才对整个“原始数据FCS”这个块进行透明编码如果需要再加上头尾的标志位发送出去。接收时硬件识别出标志位后对接收到的字节流进行透明解码恢复出原始数据流然后用这个恢复后的数据流来计算CRC并与接收到的FCS字段进行比较。这样做的好处是无论线路上因为转义增加了多少字节CRC校验的始终是用户数据的原貌保证了校验的准确性。CRC计算的结果正确或错误会体现在接收缓冲描述符RxBD的CR位中。3. MPC866 SCC异步HDLC模式硬件架构详解理解了协议我们再看MPC866如何用硬件来实现它。SCCSerial Communication Controller是PowerQUICC系列处理器的通信利器一个MPC866最多有4个SCC每个都可以独立配置为UART、HDLC、BISYNC等多种协议模式。当配置为异步HDLC模式时它就变成了一个高度自动化的帧处理器。3.1 核心工作流程DMA与缓冲描述符BD的共舞SCC异步HDLC模式高效的核心在于其与CPM通信处理器模块的DMA控制器以及“缓冲描述符”机制的紧密配合。这避免了每个字节都产生CPU中断的传统低效模式。发送流程软件准备你在内存中设置好一个“发送缓冲描述符TxBD”链表。每个TxBD包含一个指向实际数据缓冲区的指针、数据长度以及控制状态位如R-就绪、L-帧末。硬件接管当你设置好第一个TxBD的R1并使能发送器后SCC的DMA引擎便开始工作。自动处理DMA从内存中取出数据SCC硬件自动为这批数据添加CRC、进行透明编码、在头尾加上标志位然后通过串口发送出去。状态回写一帧或一个缓冲区发送完成后硬件会自动清除该TxBD的R位表示完成并根据设置可能生中断通过I位控制。软件通过轮询或中断感知发送完成然后可以回收或准备下一个缓冲区。接收流程软件准备同样你预先初始化一个“接收缓冲描述符RxBD”链表并将它们的E空位设为1表示缓冲区空闲可供硬件使用。硬件监听使能接收器后SCC开始监视串口数据线寻找标志位0x7E。自动填充发现帧起始后DMA引擎自动将解码后的数据写入当前E1的RxBD所指向的缓冲区。帧结束处理当收到结束标志或检测到错误如CRC错误、载波丢失时硬件会设置该RxBD的L最后一帧位更新数据长度包含CRC字节清除E位并可能产生中断。软件处理软件检查E0的RxBD读取数据注意缓冲区里包含了原始的地址、控制、信息字段以及硬件附加的CRC字节进行业务逻辑处理然后重新将该BD的E置1放回接收池。实操心得理解BD的“所有权”切换是关键。当E1或R1时BD和对应的缓冲区“属于”硬件软件绝不能修改。只有当硬件将其清零后所有权才交还给软件。在多任务或中断环境中访问这些共享数据结构时必须做好同步否则会导致数据损坏或系统锁死。3.2 关键寄存器与参数RAM配置解析要让SCC跑起来除了BD更重要的是正确初始化一堆寄存器和参数RAM。手册里的表格很多我们抓重点看。1. 协议特定参数RAM (SCC Parameter RAM)这是配置协议行为的核心区域基址由SCC编号决定如SCC1为IMMR 0x3C00。对于异步HDLC必须关注以下字段偏移量名称宽度描述与初始化值0x34C_MASK字CRC常数。必须初始化为 0x0000_F0B8。这是CRC-CCITT多项式对应的常数值。0x38C_PRES字CRC预设值。必须初始化为 0x0000_FFFF。这是CRC计算的初始值。0x3CBOF半字开始标志字符。PPP协议设为0x7EIrLAPIrDA协议设为0xC0。0x3EEOF半字结束标志字符。PPP协议设为0x7EIrLAP协议设为0xC1。0x40ESC半字转义字符。PPP和IrLAP均设为0x7D。0x4ARFTHR半字接收帧阈值。设置收到多少帧后触发SCCE[RXF]中断。设为1表示每收一帧都中断设为N则可以积累N帧再中断减轻CPU负担。0x50TXCTL_TBL字发送控制字符表。一个32位的位图每一位对应一个ASCII控制字符0x00-0x1F。如果某位为1则对应的字符在发送时会被透明编码即使它不是0x7E或0x7D。通常初始化为0。0x54RXCTL_TBL字接收控制字符表。同样是一个32位位图。如果某位为1则接收到的对应字符将在解码前被丢弃被认为是链路层填充不属于用户数据。通常初始化为0。0x58NOF半字发送帧起始标志的数量。值为n表示发送n1个连续的开始标志。通常设为0即发送一个开始标志。2. 通用SCC模式寄存器 (GSMR)这个寄存器配置SCC的全局工作模式。GSMR_L[MODE]必须设置为0b0110以选择异步HDLC模式。GSMR_L[TDCR/RDCR]发送/接收时钟分频率。对于异步HDLC必须选择8x、16x或32x模式。通常设置为相同的值且16x是最常见和稳定的选择。注意IrLAP模式不能使用8x和32x。GSMR_H[RFW]对于异步HDLC这类面向字符的协议建议设置为1启用低延迟操作。这会将Rx FIFO宽度设为8位让每个字符都能被及时处理避免因等待凑齐32位数据而引入延迟。GSMR_H[TFL]发送FIFO阈值。当设置为1时可以防止在发送STOP TRANSMIT命令后FIFO中残留的字符被发出。在需要精确控制发送中止的场景下有用。3. 异步HDLC模式寄存器 (PSMR)此寄存器在异步HDLC模式下有特定含义。PSMR[FLC]流控制位。设置为1时启用CTS硬件流控。当CTS信号无效时发送器会在当前字符发送完毕后停止发送空闲字符直到CTS恢复有效。这可以防止接收端缓冲区溢出。PSMR[CHLN]必须设置为0b11表示字符长度为8位。这是异步HDLC模式下的固定要求。4. 数据同步寄存器 (DSR)在异步HDLC模式下此寄存器被保留应保持其复位值0x7E7E不变。3.3 命令与错误处理机制SCC通过CPM命令寄存器CPCR接收命令通过事件寄存器SCCE报告状态和错误。关键命令STOP TRANSMIT立即中止当前帧的发送。硬件会发送一个“中止序列”对于PPP是0x7D 0x7E然后停止发送数据。在修改TxBD表或当前发送指针TBPTR之前必须先发此命令。RESTART TRANSMIT在STOP TRANSMIT或发生发送错误后使用此命令重新启动发送器从当前TBPTR指向的BD继续发送。ENTER HUNT MODE强制接收器关闭当前RxBD如果正在使用并进入“狩猎”模式重新寻找下一个帧的开始标志。这在链路同步丢失时非常有用。INIT TX/RX PARAMETERS初始化发送/接收参数RAM。必须在发送器/接收器禁用时执行。错误处理硬件能检测多种错误并通过设置BD状态位和SCCE寄存器位来报告。发送错误主要是CTS Lost。如果在帧发送过程中CTS信号丢失当前缓冲区发送会被停止TxBD[CT]和SCCE[TXE]被置位。接收错误种类较多Overrun接收FIFO溢出。数据丢失RxBD[OV]置位。CD Lost载波检测丢失。这是最高优先级的错误RxBD[CD]置位。CRC ErrorCRC校验失败。RxBD[CR]置位。注意CRC校验字节仍然会被写入缓冲区。Abort Sequence收到中止序列。RxBD[AB]置位。Break Sequence收到Break信号。RxBD[BRK]置位。注意事项错误发生后硬件通常会关闭当前缓冲区设置L位并清除E位。软件在中断服务程序或轮询中必须检查这些错误位并做出相应处理例如重发帧、记录错误日志或重置链路。特别要注意在连续模式CM1下除非发生错误否则硬件不会自动清除BD的E/R位这允许缓冲区被重复使用但软件需要更精细地管理缓冲区状态。4. 异步HDLC模式完整配置与编程实战理论说再多不如一行代码。下面我们以一个典型的SCC1配置为例展示如何将其初始化为异步HDLC模式以PPP协议为例。假设使用NMSI非复用串行接口模式波特率由BRG1提供。4.1 初始化步骤详解以下是基于手册25.17节的编程示例展开的详细步骤和代码片段以C语言伪代码为例// 步骤1: 初始化SDMA配置寄存器SDCR。这通常在上电初始化CPM时完成一次。 // 示例设置SDCR为推荐值如总线仲裁优先级等。 MEMORY_MAPPED_REG(SDCR) 0x0000; // 步骤2: 配置端口引脚。将SCC1对应的TXD、RXD、CTS、RTS、CD引脚配置为复用功能。 // 假设TXD对应PA12RXD对应PA13CTS对应PC8RTS对应PC9CD对应PC10。 // 设置PAPAR端口A引脚分配寄存器和PADIR方向寄存器。 PAPAR | (112) | (113); // PA12, PA13 用作 SCC1 的 TXD, RXD PADIR ~((112) | (113)); // 配置为输出(TXD)/输入(RXD)具体看手册 PCPAR | (18) | (19) | (110); // PC8,9,10 用作 SCC1 的 CTS, RTS, CD PCDIR ~(18); // PC8 (CTS) 输入 PCDIR | (19); // PC9 (RTS) 输出 PCDIR ~(110); // PC10 (CD) 输入 // 步骤3: 配置波特率发生器BRG1。 // 假设系统时钟为50MHz目标波特率为115200使用16倍采样率。 // BRG分频数 (系统时钟 / (16 * 波特率)) - 1 // BRG分频数 (50,000,000 / (16 * 115200)) - 1 ≈ 26.1 -1 25.1取整为25。 BRGC1 25; // 设置BRG1的分频器 // 步骤4: 配置串行接口配置寄存器(SICR)将BRG1时钟路由到SCC1并选择NMSI模式。 // 具体位域需参考手册假设SICR中SCC1的时钟源选择位域为[20:23]。 SICR ~(0xF 20); // 清零相关位 SICR | (0x1 20); // 设置SCC1使用BRG1作为时钟源并选择NMSI模式 // 步骤5: 在SCC1的参数RAM中设置RBASE和TBASE指向RxBD和TxBD表的起始地址。 // 假设我们在内存中定义了结构体数组 scc1_rxbd_table[] 和 scc1_txbd_table[]。 SCC1_PRAM-RBASE (uint32_t)scc1_rxbd_table; SCC1_PRAM-TBASE (uint32_t)scc1_txbd_table; // 步骤6: 向CPCR发出 INIT TX AND RX PARAMETERS 命令初始化SCC1的收发参数RAM。 cpcr_command(CPM_CR_SCC1, CPM_CR_INIT_TX_RX_PARAMS); // 步骤7: 配置RFCR和TFCR接收/发送功能码寄存器。通常设置为默认值0x18表示32位总线正常操作。 SCC1_PRAM-RFCR 0x18; SCC1_PRAM-TFCR 0x18; // 步骤8: 设置MRBLR最大接收缓冲区长度。例如设置为256字节。 SCC1_PRAM-MRBLR 256; // 步骤9: 设置CRC常数和预设值。 SCC1_PRAM-C_MASK 0x0000F0B8; SCC1_PRAM-C_PRES 0x0000FFFF; // 步骤10: 清零ZERO寄存器保留字段按手册要求清零。 SCC1_PRAM-ZERO 0; // 步骤11: 设置接收帧阈值RFTHR。例如设置为1每收到一帧就产生RXF中断。 SCC1_PRAM-RFTHR 1; // 步骤12: 配置控制字符表。对于标准PPP通常不需要映射额外控制字符设为0。 SCC1_PRAM-TXCTL_TBL 0x00000000; SCC1_PRAM-RXCTL_TBL 0x00000000; // 步骤13: 初始化所有RxBD。 for(int i0; iRX_BD_NUM; i) { scc1_rxbd_table[i].cstatus BD_SC_EMPTY; // E1, 缓冲区空 scc1_rxbd_table[i].length 0; scc1_rxbd_table[i].buffer (uint8_t*)rx_buffer[i][0]; scc1_rxbd_table[i].cstatus | (i (RX_BD_NUM-1)) ? BD_SC_WRAP : 0; // 最后一个BD设置Wrap位 } // 步骤14: 初始化所有TxBD。 for(int i0; iTX_BD_NUM; i) { scc1_txbd_table[i].cstatus 0; // R0, 未就绪 scc1_txbd_table[i].length 0; scc1_txbd_table[i].buffer (uint8_t*)tx_buffer[i][0]; scc1_txbd_table[i].cstatus | (i (TX_BD_NUM-1)) ? BD_SC_WRAP : 0; } // 步骤15: 清除SCC1事件寄存器(SCCE)通过写1清除所有可能置位的位。 SCCE1 0xFFFF; // 步骤16: 配置SCC1掩码寄存器(SCCM)使能所需的中断。例如使能接收帧(RXF)和发送缓冲区(TXB)中断。 SCCM1 SCCE_RXF | SCCE_TXB; // 只使能这两个中断 // 步骤17: 配置GSMR_H。 uint16_t gsmr_h 0; gsmr_h | GSMRH_RFW; // 启用低延迟接收模式 // 其他位如TFL发送FIFO阈值等根据需求设置 GSMR1_H gsmr_h; // 步骤18: 配置GSMR_L选择异步HDLC模式但先不打开收发器。 uint16_t gsmr_l 0; gsmr_l | GSMR_L_MODE_ASYNC_HDLC; // 模式设为0b0110 gsmr_l | GSMR_L_TDCR_BRG16 | GSMR_L_RDCR_BRG16; // 时钟分频设为16x // 注意此时 GSMR_L[ENR] 和 GSMR_L[ENT] 应为0关闭收发 GSMR1_L gsmr_l; // 步骤19: 配置PSMR。 uint16_t psmr 0; psmr | PSMR_FLC; // 启用CTS硬件流控如果需要 psmr | PSMR_CL_8; // 字符长度必须为8位 (0b11) PSMR1 psmr; // 步骤20: 最后在GSMR_L中使能发送器和接收器。 gsmr_l GSMR1_L; gsmr_l | GSMR_L_ENT | GSMR_L_ENR; // 使能发送和接收 GSMR1_L gsmr_l;4.2 数据收发操作示例初始化完成后数据的收发就围绕着BD链表进行。发送一帧数据// 1. 找到一个状态为 R0 的TxBD表示空闲 int tx_index find_ready_txbd(); // 自定义函数遍历TxBD表 if (tx_index -1) { /* 错误无空闲发送缓冲区 */ } // 2. 将数据拷贝到该BD关联的缓冲区 memcpy(tx_bd_table[tx_index].buffer, data_to_send, data_len); // 3. 设置BD的数据长度和状态位 tx_bd_table[tx_index].length data_len; tx_bd_table[tx_index].cstatus BD_SC_READY | BD_SC_LAST; // R1, L1假设一帧一个BD // 4. 如果发送器之前因无数据而空闲设置好BD后它会自动开始发送。 // 如果需要可以检查SCCE[TXB]中断或轮询BD的R位是否被硬件清零来判断发送完成。接收数据中断方式// SCC1的RXF中断服务例程 void scc1_rx_isr(void) { // 1. 清除中断标志写1清除 uint16_t events SCCE1; SCCE1 events; // 写回检测到的事件位以清除它们 // 2. 处理所有 E0 的RxBD volatile rxbd_t *bd scc1_rxbd_table[0]; int processed 0; while (!(bd-cstatus BD_SC_EMPTY)) { // 3. 检查接收状态 uint16_t status bd-cstatus; int len bd-length; // 长度包含了CRC字节 if (status BD_SC_LAST) { // 这是一个完整的帧或因为错误而关闭的帧 if (status (BD_SC_CR | BD_SC_OV | BD_SC_CD | BD_SC_AB | BD_SC_BRK)) { // 处理接收错误 handle_rx_error(status); } else { // 成功接收一帧处理数据。注意缓冲区数据包含2字节CRC。 process_received_frame(bd-buffer, len - 2); // 减去CRC字节 } } else { // 这是一个多BD帧的中间部分可能需要拼接异步HDLC通常一帧一BD但协议支持多BD } // 4. 回收BD清除状态只保留WRAP位重新标记为空闲 bd-cstatus BD_SC_EMPTY | (bd-cstatus BD_SC_WRAP); bd-length 0; // 5. 指向下一个BD如果当前BD是WRAP硬件会自动跳回RBASE我们软件遍历也需模拟 if (bd-cstatus BD_SC_WRAP) { bd scc1_rxbd_table[0]; } else { bd; } processed; } // 6. 如果处理了BD可能需要重新使能接收中断如果之前因为缓冲区用尽而关闭 if (processed 0) { // 通常不需要额外操作因为回收BD设置E1后硬件会自动继续使用它们。 } }5. 疑难排查与实战经验分享即使按照手册一步步配置在实际调试中还是会遇到各种问题。下面是我在多年项目中总结的一些常见坑点和排查技巧。5.1 常见问题速查表现象可能原因排查步骤完全无法收发1. SCC模式未正确设置。2. 时钟未正确路由或分频错误。3. 引脚复用未配置。4. 收发器未使能GSMR_L[ENT/ENR]。1. 确认GSMR_L[MODE]0b0110。2. 检查SICR时钟源选择用示波器测量SCC的接收时钟RCLK引脚。3. 核对PAPAR/PCPAR寄存器配置。4. 确认GSMR_L[ENT]和GSMR_L[ENR]已置位。能发不能收或反之1. 单向的引脚配置错误。2. 对应的BD链表未初始化或初始化错误。3. RFTHR设置过大未达到中断阈值。4. 对方设备问题。1. 检查TXD/RXD引脚方向配置。2. 确认RBASE/TBASE指向有效内存且初始BD的E1或R1。3. 尝试将RFTHR设为1并检查SCCE[RXF]是否置位。4. 环回测试短接TXD和RXD自发自收。接收数据错乱或CRC错误1. 波特率不匹配。2. 双方控制字符表TXCTL_TBL/RXCTL_TBL配置不一致。3. 物理链路噪声大。4. 缓冲区溢出OV错误。1. 精确计算并核对BRG分频值。2. 确认双方对0x00-0x1F范围内字符的处理方式一致。3. 检查硬件连接尝试降低波特率。4. 检查RxBD[OV]位增大缓冲区或优化DMA/CPU性能。发送中止或控不生效1.STOP TRANSMIT命令使用时机不当。2. PSMR[FLC]未使能或CTS/RTS引脚未正确配置/连接。3. 对方设备不支持流控。1. 确保在修改TxBD表或TBPTR前发STOP TRANSMIT修改后发RESTART TRANSMIT。2. 确认PSMR[FLC]1并检查CTS/RTS引脚的电平变化。3. 与对方确认流控协议。中断无法产生1. SCCM寄存器未使能相应中断位。2. CPM中断控制器未配置。3. BD的I位未设置。4. 中断服务程序未正确清除SCCE位。1. 核对SCCM值。2. 检查CPM的CICR和SIMASK寄存器。3. 对于发送设置TxBD的I位对于接收RFTHR和RxBD的I位共同控制。4. 必须在ISR中写1清除SCCE中已发生的事件位。5.2 深度避坑指南“幽灵字符”与控制字符表最隐蔽的问题之一是控制字符表。如果你的应用需要传输二进制数据且数据中可能包含0x00-0x1F的值务必确认TXCTL_TBL和RXCTL_TBL的设置。如果发送方映射了某个字符位设为1而接收方没有接收方会将其作为普通数据接收但该字符在发送时已被转义导致数据不一致和CRC错误。最佳实践除非协议明确要求否则将这两个表都初始化为0。BD链表的“Wrap”位陷阱BD表中的最后一个描述符其WWrap位必须设置为1。这告诉DMA控制器“这是链表末尾下一个回到开头”。如果你忘记设置或者链表中间某个BD误设了W位DMA会在错误的位置继续读写导致内存越界系统崩溃。初始化BD表时务必仔细检查循环的最后一个BD。CRC校验字节的处理接收时硬件会把2字节的CRC也写入缓冲区并更新Data Length。很多新手在计算接收数据长度时会直接使用这个长度导致多处理了2个不属于应用层的字节。务必记得应用数据长度 RxBD[Data Length] - 2。连续模式CM位的慎用TxBD和RxBD都有CM位。当CM1时硬件在完成一帧后不会自动清除R/E位允许软件重用同一个缓冲区而不更新BD指针。这能提升性能但管理更复杂。如果你在CM1时修改了缓冲区内容必须确保在硬件再次使用它之前完成修改否则会引发数据竞争。对于大多数应用从CM0开始更安全。IrDA模式仅SCC2的特殊配置如果使用SCC2进行IrDA通信除了设置BOF0xC0和EOF0xC1还必须设置GSMR_L[SIR]1以激活红外编解码器并且TDCR/RDCR只能选择16x模式不能是8x或32x。红外极性GSMR_H[IRP]也需要根据实际硬件连接调整。调试这类底层驱动逻辑分析仪或带协议分析功能的示波器是神器。直接抓取TXD/RXD引脚上的波形可以看到真实的标志位、转义序列和数据流能与软件中打印的缓冲区内容进行比对快速定位是硬件配置问题、数据问题还是软件处理逻辑问题。