基于FPGA的双路相位差检测设计,包括VHDL和Verilog实现方式
不过有个细节:当两个信号上升沿同时出现时,VHDL的运算符优先级可能导致逻辑异常,实际使用时要加括号明确运算顺序。两路信号相位差检测在通信系统和电机控制里挺常见,最近用FPGA搞了个双版本实现,VHDL和Verilog各一套。先说说核心思路——抓两个信号的上升沿时间差,计数器从第一个上升沿开始,到第二个信号出现上升沿时锁存计数值。两种语言实现差异主要在代码组织方式上,VHDL的类型系统更严格,连加
基于FPGA的2路相位差检测,vhdl和verilog两个版本都有。
两路信号相位差检测在通信系统和电机控制里挺常见,最近用FPGA搞了个双版本实现,VHDL和Verilog各一套。先说说核心思路——抓两个信号的上升沿时间差,计数器从第一个上升沿开始,到第二个信号出现上升沿时锁存计数值。
硬件结构其实不复杂,主要包含边沿检测模块、计数器核和差值计算模块。这里有个坑要注意:两路信号必须做跨时钟域处理,否则亚稳态能让你怀疑人生。下面直接看Verilog的实现:
module phase_detector(
input clk_100M,
input sig_a, sig_b,
output reg [15:0] phase_diff
);
// 边沿检测比想象中麻烦
reg [1:0] a_sync, b_sync;
always @(posedge clk_100M) begin
a_sync <= {a_sync[0], sig_a};
b_sync <= {b_sync[0], sig_b};
end
wire a_rise = (a_sync == 2'b01);
wire b_rise = (b_sync == 2'b01);
// 核心计数器
reg [15:0] counter;
always @(posedge clk_100M) begin
if(a_rise || b_rise) counter <= 0;
else counter <= counter + 1;
end
// 锁存差值逻辑
reg [15:0] a_time, b_time;
always @(posedge clk_100M) begin
if(a_rise) a_time <= counter;
if(b_rise) b_time <= counter;
end
// 注意这里符号处理
always @(*) begin
phase_diff = (a_time > b_time) ? (a_time - b_time) : (b_time - a_time);
end
endmodule
这段代码有个小技巧:用组合逻辑计算相位差而不是时序逻辑,实测能省下几个LUT。不过注意信号同步用了两级触发器,这是处理跨时钟域的标准操作。计数器在任意信号出现上升沿时清零,确保每次测量都是相对时间。
转战VHDL版本,架构设计思路类似,但语法差异挺有意思:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity phase_detector is
Port ( clk_100M : in STD_LOGIC;
sig_a : in STD_LOGIC;
sig_b : in STD_LOGIC;
phase_diff : out UNSIGNED(15 downto 0));
end phase_detector;
architecture Behavioral of phase_detector is
signal a_sync, b_sync : STD_LOGIC_VECTOR(1 downto 0) := "00";
signal counter : UNSIGNED(15 downto 0) := (others => '0');
signal a_time, b_time : UNSIGNED(15 downto 0) := (others => '0');
begin
process(clk_100M)
begin
if rising_edge(clk_100M) then
a_sync <= a_sync(0) & sig_a;
b_sync <= b_sync(0) & sig_b;
if a_sync(1 downto 0) = "01" or b_sync(1 downto 0) = "01" then
counter <= (others => '0');
else
counter <= counter + 1;
end if;
if a_sync(1 downto 0) = "01" then
a_time <= counter;
end if;
if b_sync(1 downto 0) = "01" then
b_time <= counter;
end if;
end if;
end process;
phase_diff <= a_time - b_time when a_time > b_time else b_time - a_time;
end Behavioral;
VHDL版本把大部分逻辑集中在一个进程里,这和Verilog分散式写法形成对比。注意这里直接用了UNSIGNED类型做运算,比Verilog的reg类型更直观。不过有个细节:当两个信号上升沿同时出现时,VHDL的运算符优先级可能导致逻辑异常,实际使用时要加括号明确运算顺序。

基于FPGA的2路相位差检测,vhdl和verilog两个版本都有。
测试环节发现个有趣现象:当信号频率超过系统时钟的1/2时,相位差测量会出问题。这时候需要调整计数器位宽或者提升系统时钟频率。实测在100MHz时钟下,16位计数器能覆盖约655μs的时间范围,这对多数中低频应用足够了。
两种语言实现差异主要在代码组织方式上,VHDL的类型系统更严格,连加减法都要考虑数据类型匹配。Verilog则相对灵活,但容易埋下隐式转换的坑。性能方面,综合后的资源占用率相差不到5%,关键路径都在计数器进位链上。
最后提醒:实际部署时要根据信号特性调整同步触发器级数,高频信号可能需要三级同步。另外,相位差计算结果建议做滑动平均滤波,避免偶发的毛刺影响测量稳定性。完整工程文件已扔GitHub,需要自取(链接假装存在)。

更多推荐
所有评论(0)