fpga: x400: avoid false PPS rising edge on switching sources
Original-commit: d5876c82a02f7800141b74517d0b5461946de9fc
This commit is contained in:
+42
-32
@@ -100,30 +100,38 @@ module x4xx_pps_sync #(
|
||||
.out (pps_ext_brc)
|
||||
);
|
||||
|
||||
// Synchronize the select bits over to the reference clock as well. Note that this is
|
||||
// a vector, so we could have some invalid values creep through when changing.
|
||||
// See the note below as to why this is safe.
|
||||
wire [1:0] pps_select_brc;
|
||||
synchronizer #(
|
||||
.FALSE_PATH_TO_IN (1),
|
||||
.WIDTH (2)
|
||||
) synchronizer_pps_select (
|
||||
.clk (base_ref_clk),
|
||||
.rst (1'b0),
|
||||
.in (pps_select),
|
||||
.out (pps_select_brc)
|
||||
// Synchronize the select bits over to the reference clock using a handshake
|
||||
// to guarantee transfer of the complete pps_select signal.
|
||||
// Further include the LMK sync trigger to make sure both signals are aligned.
|
||||
reg [1:0] pps_select_brc;
|
||||
reg pll_sync_trigger_brc;
|
||||
wire pps_handshake_out_valid;
|
||||
wire [2:0] pps_handshake_out_data;
|
||||
handshake #(
|
||||
.WIDTH (3)
|
||||
) handshake_pps (
|
||||
.clk_a (ctrl_clk),
|
||||
.rst_a (1'b0),
|
||||
.valid_a (1'b1),
|
||||
.data_a ({pps_select, pll_sync_trigger}),
|
||||
.busy_a (),
|
||||
.clk_b (base_ref_clk),
|
||||
.valid_b (pps_handshake_out_valid),
|
||||
.data_b (pps_handshake_out_data)
|
||||
);
|
||||
always @(posedge base_ref_clk) begin
|
||||
if (pps_handshake_out_valid) begin
|
||||
{pps_select_brc, pll_sync_trigger_brc} <= pps_handshake_out_data;
|
||||
end
|
||||
end
|
||||
|
||||
// PPS MUX - selects internal or external PPS.
|
||||
reg pps_brc = 1'b0;
|
||||
// Generate the signal new_pps_selected to indicate a change in the PPS source.
|
||||
reg pps_brc = 1'b0;
|
||||
reg [1:0] pps_select_delayed_brc = 2'b00;
|
||||
reg new_pps_selected = 1'b0;
|
||||
always @(posedge base_ref_clk) begin
|
||||
// It is possible when the vector is being double-synchronized to the
|
||||
// reference clock domain that there could be multiple bits asserted
|
||||
// simultaneously. This is not problematic because the order of operations
|
||||
// in the following selection mux should take over and only one PPS should
|
||||
// win. This could result in glitches, but that is expected during ANY PPS
|
||||
// switchover since the switch is performed asynchronously to the PPS
|
||||
// signal.
|
||||
// generate PPS signal based on selected source
|
||||
case (pps_select_brc)
|
||||
PPS_INT_10MHZ: begin
|
||||
pps_brc <= pps_int_10mhz_brc;
|
||||
@@ -135,6 +143,16 @@ module x4xx_pps_sync #(
|
||||
pps_brc <= pps_ext_brc;
|
||||
end
|
||||
endcase
|
||||
|
||||
// Delay the select signal to compare with the current value
|
||||
pps_select_delayed_brc <= pps_select_brc;
|
||||
|
||||
// Indicate the first cycle of a newly selected PPS source
|
||||
if (pps_select_brc != pps_select_delayed_brc) begin
|
||||
new_pps_selected <= 1'b1;
|
||||
end else begin
|
||||
new_pps_selected <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// forward BRC based PPS to output
|
||||
@@ -146,23 +164,15 @@ module x4xx_pps_sync #(
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Detect rising edge of PPS
|
||||
// Ignore the first cycle after a new PPS source is selected as this might cause a change in the
|
||||
// PPS signal as the PPS sources are not aligned.
|
||||
// Skipping this switching cycle ensures the rising edge is detected from the selected PPS source.
|
||||
reg pps_brc_delayed;
|
||||
wire pps_rising_edge_brc;
|
||||
always @(posedge base_ref_clk) begin
|
||||
pps_brc_delayed <= pps_brc;
|
||||
end
|
||||
assign pps_rising_edge_brc = pps_brc & ~pps_brc_delayed;
|
||||
|
||||
// Transfer control signals to internal clock domain
|
||||
wire pll_sync_trigger_brc;
|
||||
synchronizer #(
|
||||
.FALSE_PATH_TO_IN (1)
|
||||
) synchronizer_sync_trigger (
|
||||
.clk (base_ref_clk),
|
||||
.rst (1'b0),
|
||||
.in (pll_sync_trigger),
|
||||
.out (pll_sync_trigger_brc)
|
||||
);
|
||||
assign pps_rising_edge_brc = pps_brc & ~pps_brc_delayed & ~new_pps_selected;
|
||||
|
||||
// There is no data coherency guaranteed by this synchronizer, but this is
|
||||
// not required. The information is derived in the same clock domain as the
|
||||
|
||||
Reference in New Issue
Block a user