如何改进我的代码,以免出现时序错误?

时间:2016-08-17 18:40:30

标签: signals verilog fpga timing dac

我正在编写代码以与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,绿色为时钟

figure 1

图2. DAC的输出

figure 2

2 个答案:

答案 0 :(得分:2)

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。

答案 1 :(得分:2)

我不知道您的FPGA来自哪个供应商,但是,大多数都有时序限制,允许您定义时钟和数据之间的关系。他们使用虚拟时钟的想法。可以想象它有一个外部时钟,你可以说出时钟之间的差异。如果时钟是直接从FPGA生成的,而不是来自某些外部源,我认为你可以将一些CLKs值设置为0.

通过设置这些约束,您可以使数据输出相对于clk移动,并且它将“一致并受控”。

+----------+                +--------+
| 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[*]}]

或者,如果你不能用约束来控制数据和时钟之间的关系,这甚至建议看起来很俗气(如果是真的,请告诉我供应商这样我可以留下来)你可以通过以下方式改善情况通过将你的构成改为negedge来回答前一个答案的建议。请记住,从构建到构建,这可能是灵活的,因为输出可能不会以您想要的方式受到约束。