Menu Close

uart 通讯协议中增加checksum

在uart 通讯中,为保证长距离通讯的可靠性,会在数据包通讯协议中, 增加checksum。主要是用于在接收端增加检测。在uart通讯中,对于字节传输是否正确,通常使用奇偶校验来验证数据的正确性。 在通讯中,使用CRC 或者checksum 来保证数据包的完整性。 原因是数据正确,不等于数据包完整性。本文中使用checksum来保证数据包传输正确性。checksum校验方法简单,算法逻辑比较小,在很多协议中都有相关的应用。缺点是不能有效的判断包长的错误。举例: data0 + data1 + data2 + checksum  和 data0 + data1 + data2 + 0/8’hff + 0/8’hff  + checksum

 

1.  Uart中增加checksum

  1. 上一篇文章的基础上,数据包格式增加了8bit的checksum,checksum 作为工程的可选项(parameter)。整个工程代码中,只有rx_app 模块内部有变动,端口信号都未变化,其余模块与fifo的版本保持不变。
  2. 产品定义:length比实际发送数据字节数长的数据包,丢弃处理;length比实际发送数据字节数端的数据包,截取有效字节,当作正确包处理。当有校验和时包长length大于等于4可当作正确包接收。
  3. checksum 算法为:

sum[15:0] = length + pkg_type + pkg_dev + data0 + data1 + data2 + …. datan

while (sum[15:8]) sum = sum[7:0] + sum[15:8]

sum = ~sum;

  • 组织架构设计

 

  • 模块功能概述
    1. 其他模块与之前的项目相同
    2. rx_app

与之前的版本比较:rx_app 模块内部分为主从状态机,主状态机主要负责读fifo,从状态机主要负责对读出的数据进行解析和校验。使得整个模块设计层次更清晰,错误查找更容易。

主状态机流程图:

从状态机流程图:

 

        1. 代码详解

端口信号解释:

sys_clk:时钟域模块传递进来的系统复位信号

rx_pkg_plus:rx_fifo传递的单脉冲信号,表示rx_fifo已经写入一个完整数据包

rx_fifo_dout:从rx_fifo读出的数据

rx_fifo_rd :读rx_fifo 使能,当rx_fifo写入一个完整包开始读

pkg_type:从设备地址,表示计算机准备对那个设备进行操作

pkg_op:读/写 控制字

pkg_data:计算机写入到fpga的数据

pkg_valid:传递给应用层的数据和命令有效信号

rst:时钟域模块传递进来的系统复位信号

状态机详解:

主状态机:

  • 初始化:rst信号对状态机初始化
  • 状态0:如果rx_fifo中已经写入一个完整的数据包,给读使能,同时给从状态开始指示信号,跳转到状态1
  • 状态1:无操作,等待一个时钟周期
  • 状态2:判断读出数据最高,为低表示fifo读空,跳转到状态3
  • 状态3:给从状态机数据读完标志,等待从状态捕获到此标志后返回一个chk_end信号跳转到状态4
  • 状态4:给出一个读完一个数据包标志rx_pkg_minus,判断从状态机校验结果,有错则此包丢弃,无错则给出数据有效指示跳转到状态5(等一个时钟确保0状态准确拿到 packets_count 的值)
  • 状态5:变量清0,跳转到状态0

从状态机:(需要注意从状态机与主状态机的衔接,保证fifo读出的每一笔数据不丢失)

初始化:主状态机发送的!rx_start信号 作为状态复位信号

  • 状态0: 根据parameter参数值判断是否需要checksum,如果需要checksum则跳转到状态1,否则跳转到状态12

//=============================1-8 处理带checksum的数据

  • 状态1:判断读出的数据最高位是否为高,为高表示数据有效,为高且长度字节的数据大于等于4,表示数据包长度正常,接收低8bit,对读出的低8bit进行校验和计算,跳转到状态2;如果读出为高但低8bit数据的值小于3,表示数据包长度有问题,则跳转到状态14(数据包错误处理状态);如果最高位为低,表示读出数据无效,数据包或者写入有问题,跳转到状态14。
  • 状态2-状态4:判断读出数据最高位是否为高,为高表示数据有效,接收低8bit有效数据,并对读出数据进行校验和计算。最高位为低表示数据无效,跳转到状态14。
  • 状态5:判断读出最高位是否为高,为高表示数据有效,再判断包长与实际接收数据计数对比,如果包长等于实际接收数据,表示实际发送的数据比包长值长,截取前面有效字节,调整到状态8对fifo中剩余字节进行校验和。最高bit为高但是包长值大于实际接收计数,表示数据未接收完毕,继续停留再状态5接收数据并做校验和。由于最后一笔数据是校验和,所以不能直接放入pkg_data,需要临时变量接收;如果发现读出的最高bit为低,表示fifo读空,且包长与实际接收计数相等,表示数据包正确,跳转到状态6,如果为低但是包长值比实际接收的长,说明实际写入FIFO 数据比包长值短,当作错误包处理,调整到状态20。
  • 状态6:判断checksum高8bit是否为0,不为0 表示有进位位,需要继续计算,直到无进位位则将校验和取反跳转到状态7
  • 状态7:如果校验和结果为0,表示数据接收正确,调整到状态21,否则给出校验和错误指示,跳转到状态20。
  • 状态8:判断读出数据最高bit是否为低,为低表示数据读完,调整到状态6。否则继续停留在8状态,对读出的数据进行校验和。

//===========================12-15(处理不带checksum 的数据)

  • 状态12:状态1:判断读出的数据最高位是否为高,为高表示数据有效,为高且长度字节的数据大于等于3,表示数据包长度正常,接收低8bit。跳转到状态13;如果读出为高但低8bit数据的值小于3,表示数据包长度有问题,则跳转到状态20(数据包错误处理状态);如果最高位为低,表示读出数据无效,数据包或者写入有问题,跳转到状态20。
  • 状态13-状态14:判断读出数据最高位是否为高,为高表示数据有效,接收低8bit有效数据,调整到状态15。最高位为低表示数据无效,跳转到状态20。
  • 状态15:判断读出最高位是否为高,为高表示数据有效,再判断包长与实际接收数据计    数对比,如果包长等于实际接收数据,表示实际发送的数据比包长值长,截取前面有效字节,调整到状态21。最高bit为高但是包长值大于实际接收计数,表示数据未接收完毕,继续停留在状态15接收数据;如果发现读出的最高bit为低,表示fifo读空,且包长与实际接收数据计数相等,表示数据包正确,跳转到状态21,如果为低但是包长值比实际接收的长,说明实际写入FIFO 数据比包长值短,当作错误处理,此包丢弃,调整到状态20.
  • 状态20:无操作,作为一个错误指示状态,直接跳转到状态21。
  • 状态21:变量清0,如果接收到主状态机的数据读取完成信号,反馈一个chk_end。停留在状态21,等待下一次主状态机对从状态机复位。

仿真下板调试详情

length比实际发送数据字节数长的数据包,丢弃处理;length比实际发送数据字节数短的数据包,截取有效字节,当作正确包处理。当有校验和时包长length大于等于3可当作正确包接收,包长不包括最后的checksum。从仿真以及下板12种情况结果看,设计与调试结果一致。

仿真测试数据:

040102F8;060001aabb92;050001aabb93(包长未包含校验和字节)

 

下板测试数据:

无校验和:

  • 030102 (正确包),040001aa (正确包), 050001aabb (正确包);
  • 03010200 (包长比实际字节短–截取),
  • 050001aa33cc (包长比实际字节短–截取);
  • 040102 (包长比实际字节长–错误包),
  • 040001 (包长比实际字节长–错误包),
  • 050001aa (包长比实际字节长–错误包);
  • 030102 (正确包), 060001aabbcc (正确包);060001345678 (正确包);

 

有校验和:

  • 030102F9(包长低于4–无效);
  • 040001aa50(截取);
  • 0400011234B4  (包长比实际字节短,校验和正确);
  • 040001123495 (包长比实际字节短,校验和错误–无效);
  • 06000112E6(包长比实际字节长–无效);
  • 040102F8 (正确包),050001aa4F (正确包), 060001aabb92 (正确包);
  • 04010200F8 (截取),0501021234b1 (截取),0600015678cc5d (截取);
  • 050102F7 (错误包)050001aa44 (校验和错误), 060001aabb93 (校验和错误);

调试分类:

 

Quartus 工程:

 

Posted in FPGA, FPGA 教材教案, Verilog, 教材与教案, 文章

发表回复

相关链接