Menu Close

曼彻斯特编码-参考代码(Verilog)

根据曼彻斯特码的编解码原理,使用verilog 语言设计曼彻斯特编码的PHY层逻辑。

相关的参考文章:

曼彻斯特编码介绍

曼彻斯特解码介绍

曼彻斯特解码-参考代码(Verilog)

 

本工程采用mvb 相关曼码通讯协议,其他曼码工程与之类似。 一般情况下,只需要修改起始定界符,终止定界符就可以应用到其他的曼码工程中去了。

曼码设计框图:

整个曼码模块由 phy_mcode.v phy_bt.v mcode_tx_phy.v mcode_rx_phy 四个文件组成。

顶层文件:phy_mcode.v 接口包括:

clk : 系统时钟, 当前使用的系统时钟为48M 时钟,mvb 的通讯速率是1.5M, 48M 系统时钟会非常方便分频。

reset: 对整个曼码模块进行复位。

mcode_tx: 曼码发送pin ,可连接到fpga pin 上 ,用于曼码的发送。

mcode_tx_de:曼码发送enable pin, 可连接到fpga pin 上, 用于曼码发送。(有时硬件设计会采用rs485,rs422等通讯方式,这时就需要这个pin 来控制) 不是必须的,根据用户的硬件方案选择使用。 这个信号会包含mcode_tx 信号,宽度(时间轴)会大于 mode_tx, 用来防止数据传输时丢失。

mcode_rx: 曼码接收到的串行数据。

mcode_rx_de: 曼码接收enable 线。 使用方法和发送类似。

tx_data: 8bit 数据 输入, 由fpga 内容逻辑产生,将这个数据发送给曼码模块, 曼码模块将数据以曼彻斯特编码方式串行输出的fpga pin 上。

tx_data_en: tx_data 的enable, 通知曼码模块,当前的tx_data 可以使用了。(48M单时钟周期)

tx_start_en: 通知曼码模块,发送起始定界符(48M单时钟周期)

tx_stop_en: 通知曼码模块,发送终止定界符(48M单时钟周期)

tx_busy: 在曼码数据发送期间(包括发送 起始定界符,终止定界符,正常的数据发送)一直为高电平,当发送结束,tx_busy 为低电平。这时fpga 系统软件可以发送下一个指令了(起始定界符,终止定界符,数据)。

rx_data: 从曼码phy 层得到的数据(将曼码解码得到的正常数据,可用于fpga 系统使用)

rx_rdy: 表示rx_data 已经正常接收到了(48M单时钟周期)

 

rx_eop: 表示 当前曼码包已经结束了(48M单时钟周期)

rx_data_err: 表示 当前曼码接收到的数据由错误。

rx_start_err: 表述 当前曼码接收的起始定界符错误。

 

顶层文件phy_mcode.v 代码:

注意:
//assign mcode_rx_de = ~mcode_tx_de;
assign mcode_rx_de = mcode_tx_de;
当前的工程是一个测试代码,也就是说发送的数据会被接收模块(mcode_rx_phy.v)立即接收到。对于mcode_rx_phy来说,
mcode_rx_de 是一个input 信号。这样方便在一个板子上做测试。但是在实际的工程中, 由于外部接口(硬件设计)有所不同,用户可以根据情况修改这个信号。


举例:在串行异步半双工通讯过程中, 往往是发送完数据后, 转为接收状态,接收完数据后(完整的接收包)后再次转为发送状态。(一般情况下的异步通讯)。
但是也不排除用户使用的是全双工的通讯方式, 用户在具体的使用(用户自己的项目中),可以根据情况,修改mcode_rx_de 的状态, 甚至可以修改input ,output等
状态来满足用户自己的需求。本文中mcode_rx_phy.v 只有在mcode_rx_de = 1 时,才接收曼码数据。

 

phy_bt.v 文件:
根据系统时钟分频,产生0.5BT 的波特率,用于曼码发送使用。 当前文件依照mvb 协议 产生3M (0.5BT) 波特率,其他的曼码协议,用户可以自行更改。
clk: 系统时钟 (48M)
clk_div:
分频系数, 本文中选择15. 3M = 48M / (15 + 1)
bt_3m_tick:
0.5BT 信号, 这时一个与48M 时钟同步的单沿信号,频率是3M
reset:
系统复位信号

用户可以根据自己协议的需要,更改相关的系统时钟和分频系数来满足客户的需求,本文是以mvb 为例的。

phy_bt.v 代码

 

mcode_tx_phy.v 文件:

接口信号

clk:  系统时钟 (48M)

bt_tick: 0.5BT 波特率(3M 频率, 48M时钟下的单沿信号)

mcode_tx: 定义与phy_mcode.v(上文中)的定义相同

mcode_tx_de: 定义与phy_mcode.v(上文中)的定义相同

tx_data: 定义与phy_mcode.v(上文中)的定义相同

tx_data_en: 定义与phy_mcode.v(上文中)的定义相同

tx_start_en: 定义与phy_mcode.v(上文中)的定义相同

tx_stop_en: 定义与phy_mcode.v(上文中)的定义相同

tx_busy: 定义与phy_mcode.v(上文中)的定义相同

reset: 模块复位信号

mcode_tx_phy.v 功能的使用流程:

  1. fpga 系统 给出 tx_start_en  (单沿信号) ,通知tx phy(mcode_tx_phy.v) 产生起始定界符
  2. 等待tx phy (mcode_tx_phy.v) tx_busy 信号 为一
  3. 等待tx_busy 信号为零, 发送tx_data 数据,同时产生tx_data_en(单沿信号)
  4. 等待tx phy (mcode_tx_phy.v) tx_busy 信号 为一
  5. 如果还有要发送的数据,跳转到3; 如果没有数据需要发送,等待tx_busy信号为零, 发送tx_stop_en(单沿信号)
  6. 等待tx phy (mcode_tx_phy.v) tx_busy 信号 为一
  7. 等待tx_busy 信号为零, 跳转到1 

到此一个完整的曼码包发送完毕。

mcode_tx_phy.v 代码:

 

其中:

wire [17:0] start_flag = {2’b10, 2’b10, 2’b10, 2’b10, 2’b00, 2’b11, 2’b10, 2’b00, 2’b11};   //起始定界符

wire [3:0] stop_flag = {2’b00, 2’b11};  //终止定界符

 

在tx_st 状态机中 :

状态0: 等待tx_start_en 信号,得到tx_start_en 信号后, 跳转到状态1

状态1: 产生mcode_tx_de = 1 , 但没有发送起始定界符,让长线传输中,线路上信号稳定一段时间(&cnt == 1) 256 个系统时钟周期,这里是测试例子,实际需要多少时间,用户可以根据协议修改。如果用户的协议中不需要mcode_tx_de 这个信号, 状态1 可以之间跳转到状态2

状态2: 发送起始定界符18bit (9对 数据 )

状态3: 根据情况准备发送数据还是发送终止定界符。 发送数据,将数据编码为曼码格式 ,跳转到状态4; 发送终止定界符,跳转到状态5

状态4: 发送数据,发送完成后跳转到状态3

状态5: 发送终止定界符,发送完成后,跳转到状态6

状态6: 延迟一段时间后,mcode_tx_de  = 0; 返回状态0

 

仿真波形为:

1: 发送tx_start_en

2: 发送数据1

3: 发送数据2

4: 发送数据3

5: 发送 tx_stop_en

mcode_tx 上显示的是完整一包的曼码波形。

 

Posted in FPGA, FPGA 教材教案, IP开发, RISC-V 外设, RISC-V架构, Verilog, 教材与教案, 文章