UART串口环回测试中的校验位实战:从原理到FPGA实现 1. UART串口校验位的前世今生第一次接触UART串口通信时我被这个看似简单的协议难住了——为什么要有起始位、停止位还要加个莫名其妙的校验位直到在项目中遇到数据错乱的问题才真正理解校验位的重要性。校验位就像快递包裹上的防拆封条虽然增加了少许开销但能确保数据在传输过程中没有被调包。UART通信中最常用的校验方式有三种无校验None简单粗暴适合对可靠性要求不高的场景奇校验Odd确保数据位校验位中1的总数为奇数偶校验Even确保数据位校验位中1的总数为偶数举个生活中的例子假设我们要传输数字1011001奇校验原始数据有4个1偶数所以校验位补1使总数变为奇数偶校验原始数据已有偶数个1校验位补0保持偶数无校验直接忽略校验位在FPGA实现时奇偶校验的计算可以用一个巧妙的技巧——按位异或。Verilog中只需一行代码// 奇校验计算 assign odd_parity ~^data; // 偶校验计算 assign even_parity ^data;这个设计妙在哪儿呢异或运算本质上是在统计1的奇偶性——偶数个1异或结果为0奇数个则为1。所以偶校验直接取异或结果奇校验则取反。2. FPGA环回测试系统设计去年给某工业设备设计通信模块时我搭建了一个完整的UART环回测试系统。这个系统就像个回声测试仪——FPGA收到什么数据就原样发回去同时加入校验位验证机制。这种设计特别适合调试能快速定位是发送端、接收端还是传输线路的问题。2.1 系统架构设计整个系统包含三个关键模块UART发送模块uart_tx将并行数据转为串行波形自动添加校验位UART接收模块uart_rx解析串行数据校验位检查环回控制逻辑将接收数据实时转发给发送模块状态机设计是核心难点。以发送模块为例我采用了五段式状态机localparam IDLE 5b00001, // 空闲 START 5b00010, // 起始位 DATA 5b00100, // 数据位 CHECK 5b01000, // 校验位 STOP 5b10000; // 停止位每个状态对应特定的比特位数起始位固定1bit低电平数据位8bit可配置校验位1bit停止位固定1bit高电平2.2 波特率生成技巧在50MHz时钟下实现115200波特率需要计算分频系数parameter CLOCK 50_000_000; parameter MAX_BPS 115200; parameter MAX_1bit CLOCK/MAX_BPS; // 434个时钟周期实际调试中发现采样点设置在比特周期中间最稳定。我采用计数器过半触发的方式// 在接收模块中 always (posedge clk) begin if(cnt_baud (MAX_1bit 1)) // 计数器达到217时采样 rx_sample rx_input; end3. Verilog实现细节3.1 发送模块关键代码发送状态机的第三段处理输出逻辑特别重要always (*) begin case(cstate) IDLE : tx 1b1; START : tx 1b0; // 起始位 DATA : tx tx_data[cnt_bit]; CHECK : tx check_val; // 动态校验位 STOP : tx 1b1; // 停止位 default: tx 1b1; endcase end校验位生成逻辑支持三种模式assign check_val (CHECK_BIT Odd) ? ~^tx_data : (CHECK_BIT Even) ? ^tx_data : 1b1; // 无校验时固定高电平3.2 接收模块的智能校验接收端的数据有效性判断是难点。我的设计是assign rx_data_vld (CHECK_BIT None) ? data_done : (check_done (check_val rx_check)) ? 1 : 0;这里有个坑要注意校验比较必须等校验位采样完成check_done后才能进行。早期版本我漏了这个条件导致偶尔出现误判。4. 仿真与实测对比4.1 Modelsim仿真技巧搭建测试平台时我设计了三种测试场景正常传输校验位与数据匹配人为错误故意翻转校验位边界情况全0、全1数据测试以奇校验为例仿真波形应该看到数据01010101奇数个1→ 校验位0数据11010101偶数个1→ 校验位1// 测试用例片段 initial begin // 正常奇校验测试 tx_data 8b01010101; #100 tx_data_vld 1; #20 tx_data_vld 0; // 错误校验测试 #1000 force uart_rx.rx_check ~uart_rx.rx_check; // 人为制造错误 end4.2 串口助手实测用串口助手测试时要注意波特率必须严格匹配误差3%校验位设置要与FPGA代码一致建议先测试环回再对接真实设备常见问题排查表现象可能原因解决方法接收乱码波特率不匹配检查时钟分频计算校验错误模式设置不一致确认双方校验模式数据截断停止位不足增加停止位周期5. 工程优化经验在实际项目中我总结了几个优化点参数化设计将波特率、校验模式设为参数方便重用module uart_tx #( parameter CHECK_BIT None, parameter MAX_BPS 115200 )( // 端口声明 );亚稳态处理对异步的RX信号双寄存器同步always (posedge clk) begin rx_r1 rx; rx_r2 rx_r1; end assign rx_nege ~rx_r1 rx_r2; // 下降沿检测资源优化状态机采用独热码one-hot编码虽然多用触发器但解码简单最近一次升级中我增加了自动波特率检测功能。通过测量起始位宽度动态调整分频系数使模块能自适应不同设备。这个改进让我们的产品兼容性提升了40%。