项目场景:
CPLD开发板介绍:有一个FPGA芯片与RAM芯片,现在内容是由开发板A对串口发送过来的数据进行曼彻斯特编码,之后将编码数据输出到引脚,通过杜邦线输送到另一个开发板B,开发板B进行曼彻斯特译码。
开发软件:quartus II 语言:Verilog
问题描述
目前曼彻斯特编码数据一切正常,主要思路就是先产生一个合适的采样时钟,其中采样时钟通过分频手段。其中编码逻辑部分是参考CSDN曼彻斯特编码以及译码原理 ,但是线上仿真总是最理想的情况,实际运转中存在一定的偏差。
进行曼彻斯特译码中,首先通过时钟clk_bps_en(该时钟是通过分频产生的,其频率是串口波特率的2倍,即9600*2)将一个2位的数组将保存数据的前两位数据。然后通过clk_bps_en产生一个两倍的flag2采样时钟,该时钟就是下面译码的参考时钟。
主要问题
采样时钟flag2与编码后的数据之间的相位差总是随机的,又或者说两者之间的相位差在一个固定的周期内不断变化,当两者相位差超过了某个阈值后,采样时钟flag2在上升沿取值的时候会发生偏差,也就导致后续的取值都发生错误,但是当这个相位差小于这个阈值后,取值又回到正常。
现象
所以现在的实验现象是:一段时间译码正确,一段时间译码错误,然后一直这样循环。
译码代码Verilog
//该代码主要负责接受曼彻斯特编码 并进行解码 解码后的数据在28pin 展示
//顶部函数
module top_fpga(
input clk,
input rst_n,
input rxd, //译码数据来源
output data_dis,//查看其他数据接口
output data_clk,//同上
output reg flag2,//译码时钟
output reg data_code//译码结束后的输出接口
);
//译码数据定义
reg [1:0] temp; //存储1-01 0-10
reg flag1=0;//开始译码标志
reg fail=0;//如果译码出错则为1
wire clk_bps_en;//基础分频时钟
//编码时钟配置clk_bps_en
precise_divider//分频模块
#(
//DEVIDE_CNT = 85.89934592 * fo @50M
//DEVIDE_CNT = 42.94967296 * fo @100M
.DEVIDE_CNT(32'd1649267) //9600Hz * 2
)u_precise_divider_0
(
//global clock
.clk(clk),
.rst_n(rst_n),
//user interface
//.divide_clk()
.divide_clken(clk_bps_en)
);
//确定什么时候开始译码
always @ (posedge clk_bps_en)
begin
temp <= {rxd,temp[1]};
if(temp == 2'b00 || temp == 2'b11)
begin
flag1 <= 1;//开始译码标志
end
end
//产生一个基于基础分频时钟2倍的译码时钟flag2
always @ (negedge clk_bps_en)
begin
if(flag1 == 1)
begin
flag2 <= ~flag2;
end
end
//进行译码
always @ (posedge flag2)
begin
if(temp == 2'b10)
begin
data_code <= 0;
fail <= 0;
end
else if(temp == 2'b01)
begin
data_code <= 1;
fail <= 0;
end
else if(temp == 2'b00 || temp ==2'b11)
begin
data_code <= 0;
fail <= 1;
end
end
assign data_dis=temp;//查看temp存储的数据
endmodule
//分频部分函数
较为简单不予展示
原因分析:
上面ch1是flag2 译码时钟,ch2是译码数据来源,通过不断stop观察到ch1与ch2之间的相位差随机,一会ch1的上升沿与下面对齐,一会ch1的上升沿在ch2的中间等等,
示波器实际看到的波形
解决方案:
想过几个解决思路:
解决思路(1)
由于flag2与译码数据来源都是基于分频时钟clk_bps_en进行工作的,所以这两个算是一个同时钟域信号(对吗?)
这个思路就是通过锁相环PLL固定flag2与译码数据信号之间的相位差,进而避免相位差随机造成的取值差错问题。但是试了一下没有成功,可能是我的代码不正确。
解决思路(2)
在一个就是通过不断译码标志,因为译码标志就是连续检测到"11"或者"00",通过这个标志不断对flag2进行修改,如果更正的这段时间<出错的这段时间,这就实现了避开错误。但是没有实现,新手小白不太会写逻辑= =