如何在Verilog中生成延迟以进行综合?

5

我希望设计一个Verilog代码来实现16*2 LCD的接口。在LCD中,我们需要给"命令"或"数据"时,必须给LCD的使能引脚一个"高到低脉冲",也就是说:

**E=1;
Delay();//Must be 450ns wide delay
E=0;**

我在 Verilog 合成中感到困惑,因为#符号不允许使用,那么我该如何在这里设置延迟呢?下面是我的代码,请帮助我解决延迟问题。

             ///////////////////////////////////////////////////////////////////////////////////
             ////////////////////LCD Interfacing with Xilinx FPGA///////////////////////////////
             ////////////////////Important code for 16*2/1 LCDs///////////////////////////////// 
             //////////////////Coder-Shrikant Vaishnav(M.Tech VLSI)/////////////////////////////
             ///////////////////////////////////////////////////////////////////////////////////

 module lcd_fpgashri(output reg [7:0]data,output reg enb,output reg rs,output reg rw ,input CLK);
        reg [15:0]hold;
        reg [13:0]count=0;
        //Code Starts from here like C's Main......
        always@(posedge CLK)
        begin
        count=count+1; //For Delay

       //For LCD Initialization   
        lcd_cmd(8'b00111000);
        lcd_cmd(8'b00000001);
        lcd_cmd(8'b00000110);
        lcd_cmd(8'b00001100);

       //This is a String "SHRI" that I want to display
        lcd_data(8'b01010011);//S
        lcd_data(8'b01001000);//H
        lcd_data(8'b01010010);//R
        lcd_data(8'b01001001);//I
        end


        //Task For Command

       task lcd_cmd(input reg [7:0]value); 
          begin
         data=value;
         rs=1'b0;
         rw=1'b0;
         enb=1'b1;        //sending high to low pulse
         hold=count[13]; //This is the place where I try to design delay
         enb=1'b0;
        end
        endtask


   //Task for Data      

    task lcd_data(input reg [7:0]value1);
        begin
         data=value1;
         rs=1'b1;
         rw=1'b0;
         enb=1'b1;        //sending high to low pulse  
         hold=count[13]; //This is the place where I try to design delay
         enb=1'b0;
        end 
        endtask


        endmodule

在你编写任何HDL之前,请观看这个视频:http://www.youtube.com/watch?v=rdAPXzxeaxs - Jean
3个回答

7

根据你的代码,你似乎陷入了软件编程思维的困境,如果你想真正描述HDL中的控制器,你需要做出很大的改变。

不幸的是,你不能像你写程序那样在“例程”中插入任意延迟。

当你编写软件程序时,编写类似于下面的程序是完全合理的:

doA();
doB();
doC();

每行按顺序逐个执行的方式在HDL中不可行。你需要跳出任务思维,开始考虑时钟和状态机。
请记住,当你有一个总是块(always block)时,整个块在每个时钟周期上都并行执行。 当你在总是块中有像这样的语句时:
    lcd_cmd(8'b00111000);
    lcd_cmd(8'b00000001);
    lcd_cmd(8'b00000110);
    lcd_cmd(8'b00001100);

这对你没有好处,因为所有四个操作都在时钟的正沿同时执行,而不是按顺序执行。你需要做的是创建一个状态机,使其在时钟周期内前进并执行一个操作。

如果我尝试以顺序方式复制这四个lcd_cmd,它可能看起来像这样。

always @(posedge clk)
    case(state_f)
       `RESET: begin
           state_f <= `INIT_STEP_1;
           data = 8'b00111000;
       end
       `INIT_STEP_1: begin
           state_f <= `INIT_STEP_2;
           data = 8'b00000001;
       end
       `INIT_STEP_2: begin
           state_f <= `INIT_STEP_3;
           data = 8'b00000110;
       end
       `INIT_STEP_3: begin
           state_f <= `INIT_STEP_4;
           data =8'b00111000;
       end
       `INIT_STEP_4: begin
           state_f <= ???; //go to some new state
           data = 8'b00000110;
       end
    endcase
end

现在,通过这段代码,您可以在四个时钟周期内向前推进四个状态,因此您可以开始看到如何处理在每个时钟周期上推进的事件序列。
这个答案并没有像你想要的那样有“延迟”。但是,您可以想象一个状态机,在设置数据后,移动到DELAY状态,在那里您可以设置一个计数器,倒计时足够的时钟周期以满足您的时间要求,然后再进入下一个状态。

+1 是因为这些之间没有“延迟”,正如您所希望的那样。但是为什么要使用阻塞赋值来分配数据呢? - Jean
你说得对,它可能应该是非阻塞的,我只是随便写了一些伪代码,没有充分校对它。 - Tim
先生,我们在“顺序块”即“Begin-End”中编写的所有内容都是按顺序执行的……所以我认为它是按顺序执行的……如果我错了,请告诉我。 - Shrikant Vaishnav
块内的语句按顺序评估,但这些评估之间没有固有的延迟。在测试台中,您可以在这些语句中插入固定的延迟,但它们不能被综合。您必须开始从硬件的角度思考,而不是软件的角度。 - user1619508
先生,但我仍然不知道如何生成延迟。根据Tim先生在数字设计中,延迟是通过使用“计数器”来生成的,但我不知道如何为计数器编写代码......我的意思是我可以像这样放置语句“N<=N+1;”在同一个always块中吗?这让我非常困惑...... - Shrikant Vaishnav
Tim的代码中不需要计数器。它每个时钟周期发送一次命令。时钟的周期是在每个命令之间获得的延迟。 - Jean

2

最好的引入延迟的方法是使用计数器,就像Tim所提到的那样。 根据你的时钟周期,找出需要等待多少个时钟周期才能获得所需的延迟时间(这里是450纳秒)。

假设计算得出需要等待的时钟周期数为count。在这种情况下,以下代码片段可以让你获得所需的延迟时间。但是,你可能需要根据自己的目的修改逻辑。

always @ (posedge clk) begin
  if (N == count) begin
    N <= 0;
    E = ~E;
  end else begin
    N <= N +1;    
  end 
end

确保将N和E初始化为零。


先生,我对在您的代码中使用“计数器”来生成“延迟”感到困惑。我知道计数器用于生成延迟,但不知道如何根据要求使用它......我的意思是为什么您使用if和else条件像一个触发器一样,以及为什么您使用“E”.....我的意思是为什么您不直接使用always,并在其中放置“N<=N+1;”.... - Shrikant Vaishnav
1
当你只使用 "just always" 时,会有延迟,但是你怎样将其纳入你的逻辑中呢? 在这里,“E”可以被视为逻辑的使能/时钟使能。 因此,每次计数达到即达到所需延迟时,使能/时钟使能会切换。 我使用了 "E",因为在您的需求中您已经提到了它。请参见下文。 E=0 <延迟> E=1 - Vineeth VS
先生,我可以这样使用吗?假设1个计数=1纳秒,那么对于450纳秒,我需要450个计数,那么根据您的意见,这种方式是否总是有效的?@(posedge clk)begin "mylogic" count<=count+1; if(count==450)begin disable end end....... - Shrikant Vaishnav

0
检查您的FPGA板的时钟频率,并相应地初始化计数器。例如,如果您想在具有50MHz时钟频率的FPGA板上延迟1秒,则必须编写一个计数器代码,该计数器从0计数到49999999。将terminalCLK用作设计的clk。延迟的时钟输入将为您的设计添加延迟。伪代码如下:
module counter(count,terminalCLK,clk)
parameter n = 26, N = 50000000;
input clk;
output reg [n-1:0] count;
output reg terminalCLK;
always@(posedge clk)
begin
  count <= count + 1;
  if (count <= N/2)
      terminalCLK <= ~terminalCLk;
  if (count == N)
      terminalCLK <= ~terminalCLk;
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接