verilog - 独立的 Nexys 4 个时钟随着时间的推移而去同步

标签 verilog hardware hdl

我们正在开发一个程序,需要两个设备上的同步时钟来测量超声信号的传播时间。

问题是,当我们综合程序并在两个独立的 Nexys4 FPGA 上测试它时,距离往往会随着时间的推移而减小 (0.13 cm/s)。这个比率是恒定的,并且总是在减少,导致我们认为问题出在代码中。

当我们仅在一台 Nexys 4 中综合该程序时,随着时间的推移,并没有看到任何减少。

我们有一个用于监听信号的模块(每个从站 3 个信号,3 个从站),称为 dataListener:信号 SendCommand 是 UART 模块的控制信号,该模块将方向和命令发送到 SRF02 超声波,该模块正是两种设备上的操作相同。

module dataListener(
    input mclk,
    input clkSync,
    input reset,
    input rxDataRdy,
    output wire[7:0] command,
    output reg[7:0] direction,
    output reg read,
    output reg sendCommand,
     output reg dataChanged,
     output reg [1:0] slave,
     output reg [1:0] sensor
    );

parameter dir0 = 8'd0;
parameter dir1 = 8'd3;
parameter dir2 = 8'd6;

parameter rangingCommand = 8'd87;
parameter readCommand = 8'd94;

//parameter clkTime = 0.000000001; // 1ns Simulation // 10ns FPGA
//parameter windowTime = 0.08; // 80 ms
//parameter listenTime = 0.07; // 70ms
parameter windowCyclesDuration = 8000000;
parameter listenCyclesDuration = 7000000;

reg [54:0] windowCounter;
reg emitSent;
reg readSent;

reg slave1;
reg slave2;
reg slave3;

assign command = emitSent ?  readCommand : rangingCommand;
///////////////////////////////////////////////////////////////////

always @(posedge mclk) begin

    if( reset )begin
        sensor <= 2'b0;
        windowCounter <= 55'b0;
        emitSent <= 0;
        readSent <= 0;
          slave <=0;
    end else begin
          if( clkSync ) begin

            if( windowCounter >= windowCyclesDuration )begin //Window ended
                windowCounter <= 55'b0; //resetCounter
                emitSent <= 0;
                readSent <= 0;
                if( sensor == 2'd2 )begin
                        sensor <= 2'b0;
                        if(slave == 2'd2)
                            slave <= 2'b0;
                        else
                            slave <= slave+1'b1;
                end else begin
                    sensor <= sensor + 1'b1;
                end       
            end else begin
                windowCounter <= windowCounter + 1'b1;  //Window in process
                if(!emitSent)begin
                    sendCommand <= 1;         
                end
                else if( (windowCounter >= listenCyclesDuration) && !readSent)begin //listen done, time to send the read command
                    sendCommand <= 1;         
                end           
            end

            if(sendCommand)begin
                sendCommand <= 0; //Shut down "sendCommand" signal.
                if(!emitSent)
                    emitSent <= 1;
                else
                    readSent <= 1;
            end
        end
        /// Process incoming data 
        if( rxDataRdy )begin
            read <= 1;  
        end else if( read )begin
            read <= 0;

        end 
    end
end

//////////////////////////////////////////////////////////////////
always @( sensor ) begin
    case(sensor)
        2'd0: begin
            direction <= dir0;
        end
        2'd1: begin
            direction <= dir1;
        end
        2'd2: begin
            direction <= dir2;
        end
        default: begin
            direction <= dir0;
        end
    endcase
end

endmodule

从设备上发送命令的模块:

module slave(
     input mclk,
    input clkSync,
     input reset,
     output [7:0] command,
    output [7:0] direction,
     output reg sendCommand,
     output inWindow
    );

parameter numSlave = 2'b0;          //Between 0-2
parameter dir=8'd0;                 //Depends on the slaves direction
parameter comm=8'd92;

assign command = comm;
assign direction = dir;

parameter windowCyclesDuration = 8000000;

reg [54:0] windowCounter;
reg [1:0] sensor, slave;
reg commandSent;
assign inWindow = (slave == numSlave);

always @(posedge mclk) begin

    if( reset )begin
        windowCounter <= 55'b0;
          sendCommand <=0;
          commandSent <= 1; 
          slave <= 2'b0;
          sensor <= 2'b0;
   end else begin
          if( clkSync ) begin
            if( windowCounter >= windowCyclesDuration )begin //Window ended
                windowCounter <= 55'b0; //resetCounter
                     commandSent <= 0; 
                if( sensor == 2'd2 )begin
                        sensor <= 2'b0;
                        if(slave == 2'd2)
                            slave <= 2'b0;
                        else
                            slave <= slave + 1'b1;
                end else begin
                     sensor <= sensor + 1'b1;
                end       
            end else begin
                    windowCounter <= windowCounter + 1'b1;  //Window in process
                    if( inWindow && !commandSent)begin //im in my window and command not sent yet
                        sendCommand <= 1;//send when a new window is about to begin
                        commandSent <= 1;
                    end
            end 

                if(sendCommand)begin
                    sendCommand <= 0; //Shut down "sendCommand" signal.
                end
          end       
    end
end

endmodule

信号clkSync仅在两个设备“同步”时激活,这种情况仅在通过电缆开始运行时发生,然后将电缆移除以允许移动。

这是主站的同步模块:

module SyncM(
    input mclk,
    input reset,
    input response1,
    input response2,
    input response3,
    output reg call1,
     output reg call2,
     output reg call3,
    output reg clkSync,
     output reg slave1,
     output reg slave2,
     output reg slave3
     );



always @ (posedge mclk)   begin

    if(reset)begin
        clkSync <= 0;
        slave1 <= 0;
        slave2 <= 0;
        slave3 <= 0;
        call1 <= 0; 
        call2 <= 0;
        call3 <= 0;
    end else begin

        if( btn && !call1 )begin    
            call1 <= 1;
            call2 <= 1;
            call3 <= 1;
            clkSync <= 1;
        end

        if(response1)
                slave1 <= 1;

        if(response2)
                slave2 <= 1;

        if(response3)
                slave3 <= 1;
    end
end
endmodule

从机同步模块,call信号通过电缆从主机发送到从机。

`timescale 1ns / 1ps

module SyncS(
    input reset,
     input call,
    output reg clkSync,
    output reg response
    );


always @ (reset or call) begin

    if(reset) begin
        clkSync <= 0;
        response <= 0;        
    end else begin
        if (call) begin
            response <= 1;
            clkSync <= 1;
        end
  end
end
endmodule

最佳答案

我还没有理解你的所有代码。但是,问题似乎是,您依赖 FPGA 板上的外部振荡器。如果您使用两 block 板,两个振荡器将不会以完全相同的频率运行。因此,如果您在启动后仅补偿一次相移,则时钟将在一段时间后失去同步。这就是为什么它只适用于一 block 板。

有两种可能的解决方案:

  • 仅使用一个时钟源(振荡器)并将时钟转发到另一 block 板。

  • 定期补偿相移。

两种解决方案都需要两个板之间或多或少稳定的连接。

关于verilog - 独立的 Nexys 4 个时钟随着时间的推移而去同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34123361/

相关文章:

verilog - 如何在 Verilog 中编写具有可变端口数的模块

android - 用户空间应用程序如何控制 Android 中的硬件(位置/网络/Wifi)?

Verilog 中 Always block 内的递归

c# - 如何使用c#检查硬盘是Sata设备还是IDE设备

c - 如何直接与硬件交互?

verilog - Verilog 中的行为算法 (GCD) - 可能吗?

verilog - 在(系统)verilog 仿真中从命令行定义参数

verilog - LED 开关的简单 Verilog 示例?

verilog - verilog 中的二进制补码

verilog - 将可综合的初始值分配给 Verilog 中的寄存器