我怎样才能改进我的代码,以免出现计时错误?
How can I improve my code so I don't get timing errors?
我正在编写代码与 this DAC 接口以产生正弦波。我有一个正弦 LUT,它可以很好地生成值,还有一个 DAC 控制器。控制器将 CS 拉低,逐位输入 16 位整数,并在 16 次计数后将 CS 脉冲拉高。当它发出脉冲时,它还会向 sin LUT 发送一个使能脉冲以再计数一个数。这段代码似乎不能很好地工作,因为我的输出出现峰值。这是因为时钟在 CS 应该为高电平时读取为低电平(图 1),导致 DAC 读取 17 位(换句话说,将当前数字的 MSB 读取为前一个数字的 LSB),这导致尴尬尖峰(图 2)。
我如何更好地组织此代码,以便将 运行 进入此计时问题的风险降至最低?
module DAC_Control(
input [15:0]data_in,
input counter_enable,
input clk,
input rst,
output data_out,
output reg cs,
output reg enable
);
//bit counter
reg [3:0] bit_counter;
//to help with shifting
reg [15:0] shifter;
//shifter
always @(posedge (clk)) begin
if (rst) begin
bit_counter <= 4'b0;
shifter <= 0;
end
else if (counter_enable == 1) begin
shifter <= data_in;
bit_counter <= 4'b0;
end
else begin
shifter <= shifter << 1; // shifting
bit_counter <= bit_counter + 1'b1; // counter
end
end
reg cs_hold;
always @(posedge (clk)) begin
if (rst) begin
enable <= 1'b0;
cs <= 1'b1;
end
else if (bit_counter == 4'b1110) begin
enable <= 1'b1;
cs <= 1'b0;
end
else if (bit_counter == 4'b1111) begin
enable <= 1'b0;
cs <= 1'b1;
end
else if (cs_hold == 1) begin
enable <= 1'b0;
cs <= 1'b1;
end
else begin
enable <= 1'b0; // generate enable signals
cs <= 1'b0;
end
end
assign data_out = shifter[15];
endmodule
图1.黄色是DIN,蓝色是CS,绿色是时钟
图 2. DAC 的输出
DAC 正在使用上升沿对数据进行采样:
http://www.analog.com/media/en/technical-documentation/data-sheets/AD5541A.pdf
Serial Data Input. This device accepts 16-bit words. Data is clocked into the serial input register on the rising edge of SCLK.
您可能想尝试在 clk 的下降沿生成 data_out 和 cs。
我不知道您的 FPGA 来自哪个供应商,但是,大多数都有时序限制,允许您定义时钟和数据之间的关系。他们使用虚拟时钟的想法。把它想象成有一个外部时钟,你可以说出时钟之间的差异是什么。如果时钟直接从 FPGA 生成,而不是从某些外部源生成,我认为您可以将一些 CLK 值设置为 0。
通过设置这些类型的约束,您可以使数据输出相对于 clk 移动,并且它将是 "consistent and controlled"。
+----------+ +--------+
| FPGA |----Data_out--->| DAC |
+----------+ +--------+
CLKs /\ CLKd /\
| |
+-------sys_clk--------+
这是使用 SDC 为输出计时的 Altera 设备的解决方案。
#specify the maximum external clock delay to the FPGA
set CLKs_max 0.200
#specify the minimum external clock delay to the FPGA
set CLKs_min 0.100
#specify the maximum external clock delay to the external device
set CLKd_max 0.200
#specify the minimum external clock delay to the external device
set CLKd_min 0.100
#specify the maximum setup time of the external device
set tSU 0.125
#specify the minimum setup time of the external device
set tH 0.100
#specify the maximum board delay
set BD_max 0.180
#specify the minimum board delay
set BD_min 0.120
#create a clock 10ns
create_clock -period 10 -name sys_clk [get_ports sys_clk]
#create the associated virtual input clock
create_clock -period 10 -name virt_sys_clk
#create the output maximum delay for the data output from the FPGA that
#accounts for all delays specified
set_output_delay -clock virt_sys_clk \
-max [expr $CLKs_max + $BD_max + $tSU - $CLKd_min] \
[get_ports {data_out[*]}]
#create the output minimum delay for the data output from the FPGA that
#accounts for all delays specified
set_output_delay -clock virt_sys_clk \
-min [expr $CLKs_min + $BD_min - $tH - $CLKd_max] \
[get_ports {data_out[*]}]
或者,如果您不能通过约束来控制数据和时钟之间的关系,这似乎很俗气(如果是这样,请告诉我供应商,这样我就可以远离他们),您可以使情况变得更好按照上一个答案的建议,将您的姿势更改为否定。请记住,这在构建之间可能是灵活的,因为输出可能不会按照您想要的方式受到限制。
我正在编写代码与 this DAC 接口以产生正弦波。我有一个正弦 LUT,它可以很好地生成值,还有一个 DAC 控制器。控制器将 CS 拉低,逐位输入 16 位整数,并在 16 次计数后将 CS 脉冲拉高。当它发出脉冲时,它还会向 sin LUT 发送一个使能脉冲以再计数一个数。这段代码似乎不能很好地工作,因为我的输出出现峰值。这是因为时钟在 CS 应该为高电平时读取为低电平(图 1),导致 DAC 读取 17 位(换句话说,将当前数字的 MSB 读取为前一个数字的 LSB),这导致尴尬尖峰(图 2)。
我如何更好地组织此代码,以便将 运行 进入此计时问题的风险降至最低?
module DAC_Control(
input [15:0]data_in,
input counter_enable,
input clk,
input rst,
output data_out,
output reg cs,
output reg enable
);
//bit counter
reg [3:0] bit_counter;
//to help with shifting
reg [15:0] shifter;
//shifter
always @(posedge (clk)) begin
if (rst) begin
bit_counter <= 4'b0;
shifter <= 0;
end
else if (counter_enable == 1) begin
shifter <= data_in;
bit_counter <= 4'b0;
end
else begin
shifter <= shifter << 1; // shifting
bit_counter <= bit_counter + 1'b1; // counter
end
end
reg cs_hold;
always @(posedge (clk)) begin
if (rst) begin
enable <= 1'b0;
cs <= 1'b1;
end
else if (bit_counter == 4'b1110) begin
enable <= 1'b1;
cs <= 1'b0;
end
else if (bit_counter == 4'b1111) begin
enable <= 1'b0;
cs <= 1'b1;
end
else if (cs_hold == 1) begin
enable <= 1'b0;
cs <= 1'b1;
end
else begin
enable <= 1'b0; // generate enable signals
cs <= 1'b0;
end
end
assign data_out = shifter[15];
endmodule
图1.黄色是DIN,蓝色是CS,绿色是时钟
图 2. DAC 的输出
DAC 正在使用上升沿对数据进行采样:
http://www.analog.com/media/en/technical-documentation/data-sheets/AD5541A.pdf
Serial Data Input. This device accepts 16-bit words. Data is clocked into the serial input register on the rising edge of SCLK.
您可能想尝试在 clk 的下降沿生成 data_out 和 cs。
我不知道您的 FPGA 来自哪个供应商,但是,大多数都有时序限制,允许您定义时钟和数据之间的关系。他们使用虚拟时钟的想法。把它想象成有一个外部时钟,你可以说出时钟之间的差异是什么。如果时钟直接从 FPGA 生成,而不是从某些外部源生成,我认为您可以将一些 CLK 值设置为 0。
通过设置这些类型的约束,您可以使数据输出相对于 clk 移动,并且它将是 "consistent and controlled"。
+----------+ +--------+
| FPGA |----Data_out--->| DAC |
+----------+ +--------+
CLKs /\ CLKd /\
| |
+-------sys_clk--------+
这是使用 SDC 为输出计时的 Altera 设备的解决方案。
#specify the maximum external clock delay to the FPGA
set CLKs_max 0.200
#specify the minimum external clock delay to the FPGA
set CLKs_min 0.100
#specify the maximum external clock delay to the external device
set CLKd_max 0.200
#specify the minimum external clock delay to the external device
set CLKd_min 0.100
#specify the maximum setup time of the external device
set tSU 0.125
#specify the minimum setup time of the external device
set tH 0.100
#specify the maximum board delay
set BD_max 0.180
#specify the minimum board delay
set BD_min 0.120
#create a clock 10ns
create_clock -period 10 -name sys_clk [get_ports sys_clk]
#create the associated virtual input clock
create_clock -period 10 -name virt_sys_clk
#create the output maximum delay for the data output from the FPGA that
#accounts for all delays specified
set_output_delay -clock virt_sys_clk \
-max [expr $CLKs_max + $BD_max + $tSU - $CLKd_min] \
[get_ports {data_out[*]}]
#create the output minimum delay for the data output from the FPGA that
#accounts for all delays specified
set_output_delay -clock virt_sys_clk \
-min [expr $CLKs_min + $BD_min - $tH - $CLKd_max] \
[get_ports {data_out[*]}]
或者,如果您不能通过约束来控制数据和时钟之间的关系,这似乎很俗气(如果是这样,请告诉我供应商,这样我就可以远离他们),您可以使情况变得更好按照上一个答案的建议,将您的姿势更改为否定。请记住,这在构建之间可能是灵活的,因为输出可能不会按照您想要的方式受到限制。