Commit 707d6aec authored by Andrey Filippov's avatar Andrey Filippov

started porting imu_logger.v - split original file into single-module ones

parent cbd7c464
/*******************************************************************************
* Module: buf_xclk_mclk16_393
* Date:2015-07-06
* Author: andrey
* Description: move data from xclk to mclk domain
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* buf_xclk_mclk16_393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* buf_xclk_mclk16_393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module buf_xclk_mclk16_393(
xclk, // posedge
mclk, // posedge
rst, // @posedge xclk
din,
din_stb,
dout,
dout_stb);
input xclk; // half frequency (80 MHz nominal)
input mclk; // system clock - frequency (160 MHz nominal)
input rst; // reset module
input [15:0] din;
input din_stb;
output [15:0] dout;
output dout_stb;
reg [1:0] wa;
reg [1:0] wa_mclk;
reg [1:0] wa_mclk_d;
reg rst_mclk;
reg [1:0] ra;
reg [1:0] ra_next;
reg inc_ra;
wire [15:0] pre_dout;
reg [15:0] dout;
reg dout_stb;
always @ (posedge xclk) begin
if (rst) wa[1:0] <= 2'h0;
else if (din_stb) wa[1:0] <={wa[0],~wa[1]};
end
always @ (posedge mclk) begin
wa_mclk[1:0] <= wa[1:0];
wa_mclk_d[1:0] <= wa_mclk[1:0];
rst_mclk<= rst;
if (rst_mclk) ra[1:0] <= 2'h0;
else ra[1:0] <= inc_ra?{ra[0],~ra[1]}:{ra[1],ra[0]};
if (rst_mclk) ra_next[1:0] <= 2'h1;
else ra_next[1:0] <= inc_ra?{~ra[1],~ra[0]}:{ra[0],~ra[1]};
inc_ra <= !rst && (ra[1:0]!=wa_mclk_d[1:0]) && (!inc_ra || (ra_next[1:0]!=wa_mclk_d[1:0]));
dout_stb <= inc_ra;
if (inc_ra) dout[15:0] <= pre_dout[15:0];
end
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(2))
i_fifo_4x16 (.D(din[15:0]),
.WE(din_stb),
.clk(xclk),
.AW(wa[1:0]),
.AR(ra[1:0]),
.QW(),
.QR(pre_dout[15:0]));
endmodule
endmodule
This diff is collapsed.
/*******************************************************************************
* Module: imu_exttime393
* Date:2015-07-06
* Author: andrey
* Description: get external timestamp (for image)
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* imu_exttime393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* imu_exttime393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
/*
logs frame synchronization data from other camera (same as frame sync)
*/
module imu_exttime393(
xclk, // half frequency (80 MHz nominal)
en, // enable module operation, if 0 - reset
trig, // external time stamp updated
usec, // microseconds from external timestamp (should not chnage after trig for 10 xclk)
sec, // seconds from external timestamp
ts, // timestamop request
rdy, // data ready
rd_stb, // data read strobe (increment address)
rdata); // data out (16 bits)
input xclk; // half frequency (80 MHz nominal)
input en; // enable
input trig; // external time stamp updated
input [19:0] usec; // microseconds from external timestamp
input [31:0] sec; // seconds from external timestamp
output ts; // timestamp request
output rdy; // encoded nmea data ready
input rd_stb;// encoded nmea data read strobe (increment address)
output [15:0] rdata; // encoded data (16 bits)
reg [ 4:0] raddr;
reg rdy=1'b0;
reg we, pre_we;
reg [ 3:0] pre_waddr;
reg [ 1:0] waddr;
reg [ 2:0] trig_d;
reg pre_ts,ts;
reg [15:0] time_mux;
always @ (posedge xclk) begin
if (!en) trig_d[2:0] <= 3'h0;
else trig_d[2:0] <= {trig_d[1:0], trig};
pre_ts <= !trig_d[2] && trig_d[1];
ts <= pre_ts; // delayed so arbiter will enable ts to go through
if (!en || pre_ts) pre_waddr[3:0] <= 4'b0;
else if (!pre_waddr[3]) pre_waddr[3:0] <= pre_waddr[3:0] + 1;
if (pre_waddr[0]) waddr[1:0] <=pre_waddr[2:1];
if (pre_waddr[0] && !pre_waddr[3]) case (pre_waddr[2:1])
2'b00: time_mux[15:0] <= usec[15:0];
2'b01: time_mux[15:0] <= {12'h0,usec[19:16]};
2'b10: time_mux[15:0] <= sec[15:0];
2'b11: time_mux[15:0] <= sec[31:16];
endcase
pre_we<=pre_waddr[0] && !pre_waddr[3];
we <= pre_we;
if (!en || pre_ts) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
if (pre_ts || (rd_stb && (raddr[1:0]==2'h3)) || !en) rdy <= 1'b0;
else if (we && (waddr[1:0]==2'h3)) rdy <= 1'b1;
end
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(2))
i_odbuf (.D(time_mux[15:0]),
.WE(we),
.clk(xclk),
.AW(waddr[1:0]),
.AR(raddr[1:0]),
.QW(),
.QR(rdata[15:0]));
endmodule
endmodule
/*******************************************************************************
* Module: imu_message393
* Date:2015-07-06
* Author: andrey
* Description:
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* imu_message393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* imu_message393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
/*
logs events from odometer (can be software triggered), includes 56-byte message written to the buffer
So it is possible to assert trig input (will request timestamp), write message by software, then
de-assert the trig input - message with the timestamp will be logged
fixed-length de-noise circuitry with latency 256*T(xclk) (~3usec)
*/
module imu_message393 ( sclk, // system clock, negedge
xclk, // half frequency (80 MHz nominal)
we, // write enable for registers to log (@negedge sclk), with lower data half
wa, // write address for register (4 bits, @negedge sclk)
di, // 16-bit data in multiplexed
en, // enable module operation, if 0 - reset
trig, // leading edge - sample time, trailing set rdy
ts, // timestamop request
rdy, // data ready
rd_stb, // data read strobe (increment address)
rdata); // data out (16 bits)
input sclk; // system clock, negedge
input xclk; // half frequency (80 MHz nominal)
input we; // write enable for registers to log (@negedge sclk)
input [3:0] wa; // write address for register (4 bits, @negedge sclk)
input [15:0] di; // 16-bit data in (32 multiplexed)
input en; // enable
input trig; // leading edge - sample time, trailing set rdy
output ts; // timestamp request
output rdy; // encoded nmea data ready
input rd_stb; // encoded nmea data read strobe (increment address)
output [15:0] rdata; // encoded data (16 bits)
reg [ 4:0] raddr;
reg rdy=1'b0;
reg we_d;
reg [ 4:1] waddr;
reg [ 2:0] trig_d;
reg [ 7:0] denoise_count;
reg [ 1:0] trig_denoise;
reg ts;
reg [15:0] di_d;
always @ (negedge sclk) begin
di_d[15:0] <= di[15:0];
waddr[4:1] <= wa[3:0];
we_d <=we;
end
always @ (posedge xclk) begin
if (!en) trig_d[2:0] <= 3'h0;
else trig_d[2:0] <= {trig_d[1:0], trig};
if (!en) trig_denoise[0] <= 1'b0;
else if (denoise_count[7:0]==8'h0) trig_denoise[0] <= trig_d[2];
if (trig_d[2]==trig_denoise[0]) denoise_count[7:0] <= 8'hff;
else denoise_count[7:0] <= denoise_count[7:0] - 1;
trig_denoise[1] <= trig_denoise[0];
ts <= !trig_denoise[1] && trig_denoise[0];
if (!en || ts) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
if (ts || (rd_stb && (raddr[4:0]==5'h1b)) || !en) rdy <= 1'b0;
else if (trig_denoise[1] && !trig_denoise[0]) rdy <= 1'b1;
end
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(5))
i_odbuf (.D(di_d[15:0]),
.WE(we | we_d),
.clk(~sclk),
.AW({waddr[4:1],we_d}),
.AR(raddr[4:0]),
.QW(),
.QR(rdata[15:0]));
endmodule
endmodule
This diff is collapsed.
/*******************************************************************************
* Module: imu_timestamps393
* Date:2015-07-06
* Author: andrey
* Description: Acquire timestmps for events
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* imu_timestamps393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* imu_timestamps393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module imu_timestamps393(
sclk, // 160MHz, negedge
xclk, // 80 MHz, posedge
rst, // reset (@posedge xclk)
sec, // running seconds (@negedge sclk)
usec, // running microseconds (@negedge sclk)
ts_rq,// requests to create timestamps (4 channels), @posedge xclk
ts_ackn, // timestamp for this channel is stored
ra, // read address (2 MSBs - channel number, 2 LSBs - usec_low, (usec_high ORed with channel <<24), sec_low, sec_high
dout);// output data
input sclk;
input xclk;
input rst;
input [31:0] sec;
input [19:0] usec;
input [ 3:0] ts_rq;
output [ 3:0] ts_ackn;
input [ 3:0] ra;
output [15:0] dout;
reg [31:0] sec_latched;
reg [19:0] usec_latched;
reg [15:0] ts_mux;
reg [ 3:0] wa;
reg srst;
reg [3:0] rq_d;
reg [3:0] rq_d2;
reg [3:0] rq_r;
reg [3:0] rq_sclk;
reg [3:0] rq_sclk2;
reg [3:0] pri_sclk;
reg [3:0] pri_sclk_d;
reg [3:0] rst_rq;
reg [9:0] proc;
wire wstart;
reg we;
wire [3:0] wrst_rq;
reg [3:0] ts_preackn;
reg [3:0] ts_ackn;
assign wstart=|pri_sclk[3:0] && (pri_sclk[3:0] != pri_sclk_d[3:0]);
assign wrst_rq[3:0]={wa[3]&wa[2],wa[3]&~wa[2],~wa[3]&wa[2],~wa[3]&~wa[2]} & {4{proc[5]}};
always @ (posedge xclk) begin
rq_d[3:0] <= ts_rq[3:0];
rq_d2[3:0] <= rq_d[3:0];
end
always @ (negedge sclk) begin
srst <= rst;
rq_sclk[3:0] <= srst?4'h0:(~rst_rq[3:0] & (rq_r[3:0] | rq_sclk[3:0])) ;
rq_sclk2[3:0] <= srst?4'h0:(~rst_rq[3:0] & rq_sclk[3:0]) ;
pri_sclk[3:0] <= {rq_sclk2[3] & ~|rq_sclk2[2:0],
rq_sclk2[2] & ~|rq_sclk2[1:0],
rq_sclk2[1] & ~rq_sclk2[0],
rq_sclk2[0]};
pri_sclk_d[3:0] <= pri_sclk[3:0];
proc[9:0] <= {proc[9:0], wstart};
if (proc[0]) wa[3:2] <= {|pri_sclk_d[3:2], pri_sclk_d[3] | pri_sclk_d[1]};
if (proc[0]) sec_latched[31:0] <= sec[31:0];
if (proc[0]) usec_latched[19:0] <= usec[19:0];
// if (proc[2]) ts_mux[15:0] <= {6'h0,wa[3:2],4'h0,usec[19:16]};
casex({proc[8],proc[6],proc[4],proc[2]})
// 4'bXXX1: ts_mux[15:0] <= {6'h0,wa[3:2],4'h0,usec_latched[19:16]};
// 4'bXX1X: ts_mux[15:0] <= usec_latched[15: 0];
// 4'bX1XX: ts_mux[15:0] <= sec_latched[31:16];
// 4'b1XXX: ts_mux[15:0] <= sec_latched[15: 0];
4'bXXX1: ts_mux[15:0] <= usec_latched[15: 0];
4'bXX1X: ts_mux[15:0] <= {6'h0,wa[3:2],4'h0,usec_latched[19:16]};
4'bX1XX: ts_mux[15:0] <= sec_latched[15: 0];
4'b1XXX: ts_mux[15:0] <= sec_latched[31:16];
endcase
we <= proc[3] || proc[5] || proc[7] || proc[9];
if (proc[2]) wa[1:0] <= 2'b0;
else if (we) wa[1:0] <= wa[1:0] + 1;
rst_rq[3:0] <= wrst_rq[3:0] | {4{srst}};
end
always @ (posedge xclk or posedge rq_sclk2[0]) begin
if (rq_sclk2[0]) rq_r[0] <= 1'b0;
else if (srst) rq_r[0] <= 1'b0;
else if (rq_d[0] && !rq_d2[0]) rq_r[0] <= 1'b1;
end
always @ (posedge xclk or posedge rq_sclk2[1]) begin
if (rq_sclk2[1]) rq_r[1] <= 1'b0;
else if (srst) rq_r[1] <= 1'b0;
else if (rq_d[1] && !rq_d2[1]) rq_r[1] <= 1'b1;
end
always @ (posedge xclk or posedge rq_sclk2[2]) begin
if (rq_sclk2[2]) rq_r[2] <= 1'b0;
else if (srst) rq_r[2] <= 1'b0;
else if (rq_d[2] && !rq_d2[2]) rq_r[2] <= 1'b1;
end
always @ (posedge xclk or posedge rq_sclk2[3]) begin
if (rq_sclk2[3]) rq_r[3] <= 1'b0;
else if (srst) rq_r[3] <= 1'b0;
else if (rq_d[3] && !rq_d2[3]) rq_r[3] <= 1'b1;
end
always @ (posedge xclk or posedge rst_rq[0]) begin
if (rst_rq[0]) ts_preackn[0] <= 1'b1;
else if (!ts_rq[0]) ts_preackn[0] <= 1'b0;
end
always @ (posedge xclk or posedge rst_rq[1]) begin
if (rst_rq[1]) ts_preackn[1] <= 1'b1;
else if (!ts_rq[1]) ts_preackn[1] <= 1'b0;
end
always @ (posedge xclk or posedge rst_rq[2]) begin
if (rst_rq[2]) ts_preackn[2] <= 1'b1;
else if (!ts_rq[2]) ts_preackn[2] <= 1'b0;
end
always @ (posedge xclk or posedge rst_rq[3]) begin
if (rst_rq[3]) ts_preackn[3] <= 1'b1;
else if (!ts_rq[3]) ts_preackn[3] <= 1'b0;
end
always @ (posedge xclk) begin
ts_ackn[3:0] <= ts_preackn[3:0] & ts_rq[3:0];
end
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(4))
i_ts (.D(ts_mux[15:0]),
.WE(we), // we_d, decoded sub_address
.clk(!sclk),
.AW(wa[3:0]),
.AR(ra[3:0]),
.QW(),
.QR(dout[15:0]));
endmodule
/*******************************************************************************
* Module: logger_arbiter393
* Date:2015-07-06
* Author: andrey
* Description: arbiter for the event_logger
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* logger_arbiter393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logger_arbiter393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module logger_arbiter393(
xclk, // 80 MHz, posedge
rst, // module reset
ts_rq_in, // in requests for timestamp (single-cycle - just leading edge )
ts_rq, // out request for timestamp, to timestmp module
ts_grant, // granted ts requests from timestamping module
rdy, // channels ready (leading edge - became ready, trailing - no more data, use zero)
nxt, // pulses to modules to output next word
channel, // decoded channel number (2 bits)
ts_sel, // select timestamp word to be output (0..3)
ts_en, // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready)
dv, // output data valid (from registered mux - 2 stage - first selects data and ready, second ts/data/zero)
sample_counter);// number of 64-byte samples logged
input xclk; // half frequency (80 MHz nominal)
input rst; // reset module
input [ 3:0] ts_rq_in; // in requests for timestamp (sinlgle-cycle)
output [ 3:0] ts_rq; // out request for timestamp, to timestmp module
input [ 3:0] ts_grant; // granted ts requests from timestamping module
input [ 3:0] rdy; // channels ready (leading edge - became ready, trailing - no more data, use zero)
output [ 3:0] nxt; // pulses to modules to output next word
output [ 1:0] channel; // decoded channel number (2 bits)
output [ 1:0] ts_sel; // select timestamp word to be output (0..3)
output ts_en; // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready)
output dv; // output data valid (from registered mux - 2 stage - first selects data and ready, second ts/data/zero)
output [23:0] sample_counter;// number of 64-byte samples logged
reg [3:0] ts_rq_in_d;
reg [3:0] ts_rq;
reg [3:0] ts_valid;
// reg [3:0] ts_rq_reset;
reg [3:0] channels_ready;// channels granted and ready
reg [3:1] chn1hot; // channels 1-hot - granted and ready, priority applied
reg rq_not_zero; // at least one channel is ready for processing (same time as chn1hot[3:0])
reg [1:0] channel;
reg start;
reg busy;
wire wstart;
reg ts_en;
reg [4:0] seq_cntr;
reg seq_cntr_last;
reg [1:0] ts_sel;
reg dv;
reg inc_sample_counter;
reg [23:0] sample_counter;// number of 64-byte samples logged
reg [ 3:0] nxt;
reg pre_nxt;
reg [ 3:0] chn_servicing; //1-hot channel being service
// reg [ 3:0] rdy_d;
wire [3:0] wts_rq;
assign wstart= !busy && rq_not_zero;
assign wts_rq[3:0]= ts_rq_in[3:0] & ~ts_rq_in_d[3:0] & (~rdy[3:0] | chn_servicing[3:0]);
always @ (posedge xclk) begin
ts_rq_in_d[3:0] <= ts_rq_in[3:0];
// rdy_d[3:0] <=rdy[3:0];
if (wstart) channel[1:0] <= {chn1hot[3] | chn1hot[2],chn1hot[3] | chn1hot[1]};
if (wstart) chn_servicing[3:0] <= {chn1hot[3:1], ~|chn1hot[3:1]};
else if (!busy) chn_servicing[3:0] <= 4'h0;
// if (rst) ts_rq[3:0] <= 4'h0;
// else ts_rq[3:0] <= ~ts_rq_reset[3:0] & ((ts_rq_in[3:0] & ~ts_rq_in_d[3:0]) | ts_rq[3:0]);
if (rst) ts_rq[3:0] <= 4'h0;
// else ts_rq[3:0] <= ~ts_grant & ( (ts_rq_in[3:0] & ~ts_rq_in_d[3:0] & (~rdy[3:0] | ~ts_valid[3:0])) | ts_rq[3:0]);
else ts_rq[3:0] <= ~ts_grant & ( wts_rq[3:0] | ts_rq[3:0]);
if (rst) ts_valid[3:0] <= 4'h0;
// else ts_valid[3:0] <= ~ts_rq_reset[3:0] &( ts_grant[3:0] | (ts_valid & ~(ts_rq_in[3:0] & ~ts_rq_in_d[3:0] & ~rdy[3:0])));
else ts_valid[3:0] <= (ts_grant[3:0] | (ts_valid & ~wts_rq[3:0]));
// if (rst) request[3:0] <= 4'h0;
// else request[3:0] <= ~ts_rq_reset[3:0] &( request[3:0] | (rdy[3:0] & ~rdy_d[3:0])));
// channels_ready[3:0] <= ts_grant[3:0] & rdy[3:0];
channels_ready[3:0] <= ts_valid[3:0] & rdy[3:0] & ~chn_servicing[3:0]; // ready should go down during servicing
rq_not_zero <= channels_ready[3:0] != 4'h0;
chn1hot[3:1] <= {channels_ready[3] & ~|channels_ready[2:0],
channels_ready[2] & ~|channels_ready[1:0],
channels_ready[1] & ~channels_ready[0]};
start <= wstart;
if ((seq_cntr[4:0]=='h1e) || rst) busy <= 1'b0;
else if (rq_not_zero) busy <= 1'b1;
// if (!busy) seq_cntr[4:0] <= 5'h1f;
if (!busy) seq_cntr[4:0] <= 5'h0;
else seq_cntr[4:0] <= seq_cntr[4:0] + 1;
seq_cntr_last <= (seq_cntr[4:0]=='h1e);
if (wstart) ts_en <=1'b1;
else if (seq_cntr[1:0]==2'h3) ts_en <=1'b0;
if (!ts_en) ts_sel[1:0] <= 2'h0;
else ts_sel[1:0] <= ts_sel[1:0] + 1;
if (!busy || (seq_cntr[4:0]=='h1d)) pre_nxt <= 1'b0;
else if (seq_cntr[4:0]=='h01) pre_nxt <= 1'b1;
/*
nxt [3:0] <= pre_nxt? { channel[1] & channel[0],
channel[1] & ~channel[0],
~channel[1] & channel[0],
~channel[1] & ~channel[0]}:4'h0;
*/
nxt [3:0] <= pre_nxt? chn_servicing[3:0]:4'h0;
/*
ts_rq_reset[3:0] <= start? { channel[1] & channel[0],
channel[1] & ~channel[0],
~channel[1] & channel[0],
~channel[1] & ~channel[0]}:4'h0;
*/
dv <= busy || seq_cntr_last;
inc_sample_counter <= seq_cntr_last;
if (rst) sample_counter[23:0] <= 24'h0;
else if (inc_sample_counter) sample_counter[23:0] <= sample_counter[23:0] +1;
end
endmodule
\ No newline at end of file
This diff is collapsed.
/*******************************************************************************
* Module: rs232_rcv393
* Date:2015-07-06
* Author: andrey
* Description: rs232 receiver
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* rs232_rcv393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* rs232_rcv393.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module rs232_rcv393(
xclk, // half frequency (80 MHz nominal)
bitHalfPeriod, // half of the serial bit duration, in xclk cycles
ser_di, // rs232 (ttl) serial data in
ser_rst, // reset (force re-sync)
ts_stb, // strobe timestamp (start of message) (reset bit counters in nmea decoder)
wait_just_pause,// may be used as reset for decoder
start, // serial character start (single pulse)
// char, // byte out
// char_stb); // char strobe (@posedge xclk)
ser_do, // serial data out(@posedge xclk) LSB first!
ser_do_stb, // output data strobe (@posedge xclk), first cycle after ser_do becomes valid
debug, // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset
bit_dur_cntr,
bit_cntr);
input xclk; // half frequency (80 MHz nominal)
input [15:0] bitHalfPeriod; // half of the serial bit duration, in xclk cycles
input ser_di; // rs232 (ttl) serial data in
input ser_rst; // reset (force re-sync)
output ts_stb; // strobe timestamp (start of message)
output wait_just_pause;// may be used as reset for decoder
output start; // serial character start (single pulse)
output [4:0] debug; // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset
output ser_do; // serial data out(@posedge xclk)
output ser_do_stb; // output data strobe (@posedge xclk), 2 cycles after ser_do becomes valid
output [15:0] bit_dur_cntr; // debug
output [4:0] bit_cntr; // debug
reg [4:0] ser_di_d;
reg ser_filt_di;
reg ser_filt_di_d;
reg bit_half_end; // last cycle in half-bit
reg last_half_bit;
reg wait_pause; // waiting input to stay at 1 for 10 cycles
reg wait_start; // (or use in_sync - set it after wait_pause is over?
reg receiving_byte;
reg start;
reg [15:0] bit_dur_cntr; // bit duration counter (half bit duration)
reg [4:0] bit_cntr; // counts half-bit intervals
wire error; // low level during stop slot
reg [1:0] restart;
wire reset_wait_pause;
reg ts_stb;
reg shift_en;
reg ser_do;
reg ser_do_stb;
wire sample_bit;
wire reset_bit_duration;
reg wait_just_pause;
wire wstart;
wire [4:0] debug;
reg [4:0] debug0; // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset
assign reset_wait_pause= (restart[1] && !restart[0]) || (wait_pause && !wait_start && !ser_di);
assign error=!ser_filt_di && last_half_bit && bit_half_end && receiving_byte;
assign sample_bit=shift_en && bit_half_end && !bit_cntr[0];
assign reset_bit_duration= reset_wait_pause || start || bit_half_end || ser_rst;
assign wstart=wait_start && ser_filt_di_d && !ser_filt_di;
assign debug[4:0] = {1'b0,wait_start,wait_pause,receiving_byte,shift_en};
always @ (posedge xclk) begin
// reg [4:0] ser_di_d;
// reg ser_filt_di;
// reg ser_filt_di_d;
ser_di_d[4:0] <= {ser_di_d[3:0],ser_di};
if (ser_rst || &ser_di_d[4:0]) ser_filt_di <= 1'b1;
else if (~|ser_di_d[4:0]) ser_filt_di <= 1'b0;
ser_filt_di_d <= ser_filt_di;
restart[1:0] <= {restart[0],(ser_rst || (last_half_bit && bit_half_end && receiving_byte))};
wait_pause <= !ser_rst && (reset_wait_pause ||
(receiving_byte && last_half_bit && bit_half_end ) ||
(wait_pause && !(last_half_bit && bit_half_end) && !(wait_start && !ser_filt_di)));
// start <= wait_start && ser_di_d && !ser_di;
start <= wstart;
// ts_stb <= !wait_pause && wait_start && ser_di_d && !ser_di;
ts_stb <= !wait_pause && wstart; // only first start after pause
bit_half_end <=(bit_dur_cntr[15:0]==16'h1) && !reset_bit_duration;
// wait_start <= ser_di && !ser_rst && ((wait_pause || receiving_byte) && last_half_bit && bit_half_end || wait_start);
wait_start <= !ser_rst && ((wait_pause || receiving_byte) && last_half_bit && bit_half_end || (wait_start && !wstart));
// receiving_byte <= !ser_rst && !error && (start || (receiving_byte && !(last_half_bit && bit_half_end)));
receiving_byte <= !ser_rst && (start || (receiving_byte && !(last_half_bit && bit_half_end)));
wait_just_pause <=wait_pause && !wait_start;
if (reset_bit_duration) bit_dur_cntr[15:0] <= bitHalfPeriod[15:0];
else bit_dur_cntr[15:0] <= bit_dur_cntr[15:0] - 1;
if (reset_wait_pause || ser_rst) bit_cntr[4:0] <= 5'h13;
else if (start) bit_cntr[4:0] <= 5'h12;
else if (bit_half_end) bit_cntr[4:0] <= bit_cntr[4:0] - 1;
last_half_bit <= ((bit_cntr[4:0] == 5'h0) && !bit_half_end);
shift_en <= receiving_byte && ((bit_half_end && ( bit_cntr[3:0]==4'h2))? bit_cntr[4]:shift_en);