Commit e9862dab authored by Andrey Filippov's avatar Andrey Filippov

Converting event_logger to use serial timestamps and 4 sesnor channels

parent 6a297fff
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: move data from xclk to mclk domain * Description: move data from xclk to mclk domain
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* buf_xclk_mclk16_393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -21,63 +21,46 @@ ...@@ -21,63 +21,46 @@
`timescale 1ns/1ps `timescale 1ns/1ps
module buf_xclk_mclk16_393( module buf_xclk_mclk16_393(
xclk, // posedge input mclk, // system clock, posedge
mclk, // posedge input xclk, // half frequency (80 MHz nominal)
rst, // @posedge xclk input rst, // @posedge xclk reset module
din, input [15:0] din,
din_stb, input din_stb,
dout, output reg [15:0] dout,
dout_stb); output reg dout_stb);
input xclk; // half frequency (80 MHz nominal) reg [1:0] wa;
input mclk; // system clock - frequency (160 MHz nominal) reg [1:0] wa_mclk;
input rst; // reset module reg [1:0] wa_mclk_d;
input [15:0] din; reg rst_mclk;
input din_stb; reg [1:0] ra;
output [15:0] dout; reg [1:0] ra_next;
output dout_stb; reg inc_ra;
wire [15:0] pre_dout;
reg [1:0] wa; always @ (posedge xclk) begin
reg [1:0] wa_mclk; if (rst) wa[1:0] <= 2'h0;
reg [1:0] wa_mclk_d; else if (din_stb) wa[1:0] <={wa[0],~wa[1]};
reg rst_mclk; end
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
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
reg [15:0] fifo_4x16_ram[0:3];
always @ (posedge xclk) if (din_stb) fifo_4x16_ram[wa[1:0]] <= din[15:0];
assign pre_dout[15:0] = fifo_4x16_ram[ra[1:0]];
endmodule endmodule
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: top module of the event logger (ported from imu_logger) * Description: top module of the event logger (ported from imu_logger)
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* event_logger.v is free software; you can redistribute it and/or modify * event_logger.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -42,11 +42,11 @@ module event_logger#( ...@@ -42,11 +42,11 @@ module event_logger#(
parameter LOGGER_CONF_GPS_BITS = 4, parameter LOGGER_CONF_GPS_BITS = 4,
parameter LOGGER_CONF_MSG = 13, parameter LOGGER_CONF_MSG = 13,
parameter LOGGER_CONF_MSG_BITS = 5, parameter LOGGER_CONF_MSG_BITS = 5,
parameter LOGGER_CONF_SYN = 15, parameter LOGGER_CONF_SYN = 18, // 15,
parameter LOGGER_CONF_SYN_BITS = 1, parameter LOGGER_CONF_SYN_BITS = 4, // 1,
parameter LOGGER_CONF_EN = 17, parameter LOGGER_CONF_EN = 20, // 17,
parameter LOGGER_CONF_EN_BITS = 1, parameter LOGGER_CONF_EN_BITS = 1,
parameter LOGGER_CONF_DBG = 22, parameter LOGGER_CONF_DBG = 25, // 22,
parameter LOGGER_CONF_DBG_BITS = 4, parameter LOGGER_CONF_DBG_BITS = 4,
parameter GPIO_N = 10 // number of GPIO bits to control parameter GPIO_N = 10 // number of GPIO bits to control
...@@ -68,9 +68,27 @@ module event_logger#( ...@@ -68,9 +68,27 @@ module event_logger#(
input [GPIO_N-1:0] ext_di, input [GPIO_N-1:0] ext_di,
output [GPIO_N-1:0] ext_do, output [GPIO_N-1:0] ext_do,
output [GPIO_N-1:0] ext_en, output [GPIO_N-1:0] ext_en,
input [31:0] ts_rcv_sec, // [31:0] timestamp seconds received over the sync line
input [19:0] ts_rcv_usec, // [19:0] timestamp microseconds received over the sync line // input [31:0] ts_rcv_sec, // [31:0] timestamp seconds received over the sync line
input ts_stb, // strobe when received timestamp is valid - single negedge sclk cycle // input [19:0] ts_rcv_usec, // [19:0] timestamp microseconds received over the sync line
// input ts_stb, // strobe when received timestamp is valid - single negedge sclk cycle
// byte-parallel timestamps from 4 sesnors channels (in triggered mode all are the same, different only in free running mode)
// each may generate logger event, channel number encoded in bits 25:24 of the external microseconds
input ts_stb_chn0, // @mclk 1 clock before ts_rcv_data is valid
input [7:0] ts_data_chn0, // @mclk byte-wide serialized timestamp message received or local
input ts_stb_chn1, // @mclk 1 clock before ts_rcv_data is valid
input [7:0] ts_data_chn1, // @mclk byte-wide serialized timestamp message received or local
input ts_stb_chn2, // @mclk 1 clock before ts_rcv_data is valid
input [7:0] ts_data_chn2, // @mclk byte-wide serialized timestamp message received or local
input ts_stb_chn3, // @mclk 1 clock before ts_rcv_data is valid
input [7:0] ts_data_chn3, // @mclk byte-wide serialized timestamp message received or local
// TODO: Convert to 32-bit? // TODO: Convert to 32-bit?
output [15:0] data_out, // 16-bit data out to DMA1 (@negedge mclk) output [15:0] data_out, // 16-bit data out to DMA1 (@negedge mclk)
output data_out_stb,// data out valid (@negedge mclk) output data_out_stb,// data out valid (@negedge mclk)
...@@ -94,11 +112,14 @@ module event_logger#( ...@@ -94,11 +112,14 @@ module event_logger#(
reg we_period; reg we_period;
reg we_bit_duration; reg we_bit_duration;
reg we_message; reg we_message;
reg we_config; // reg we_config;
reg we_config_imu; // bits 1:0, 2 - enable slot[1:0] reg we_config_imu; // bits 1:0, 2 - enable slot[1:0]
reg we_config_gps; // bits 6:3, 7 - enable - {ext,invert, slot[1:0]} slot==0 - disable reg we_config_gps; // bits 6:3, 7 - enable - {ext,invert, slot[1:0]} slot==0 - disable
reg we_config_msg; // bits 12:8,13 - enable - {invert,extinp[3:0]} extinp[3:0]=='hf' - disable reg we_config_msg; // bits 12:8,13 - enable - {invert,extinp[3:0]} extinp[3:0]=='hf' - disable
reg we_config_syn; // bit 14, 15 - enable - enable logging external timestamps reg we_config_syn; // bit 14, 15 - enable - enable logging external timestamps
reg we_config_rst; // bit 14, 15 - enable - enable logging external timestamps
reg we_config_debug; // bit 14, 15 - enable - enable logging external timestamps
reg we_bitHalfPeriod;
// reg we_config_rst; // bit 16, 17 - enable - reset modules // reg we_config_rst; // bit 16, 17 - enable - reset modules
// reg we_config_debug; // bits 21:18, 22 - enable // reg we_config_debug; // bits 21:18, 22 - enable
...@@ -108,38 +129,50 @@ module event_logger#( ...@@ -108,38 +129,50 @@ module event_logger#(
reg [1:0] config_imu; reg [1:0] config_imu;
reg [3:0] config_gps; reg [3:0] config_gps;
reg [4:0] config_msg; reg [4:0] config_msg;
reg config_syn; // reg [3:0] config_syn;
reg config_rst; reg config_rst;
reg [3:0] config_debug; reg [3:0] config_debug;
reg [15:0] bitHalfPeriod;// serial gps speed - number of xclk pulses in half bit period
wire we_config_imu_xclk; // copy config_imu_mclk (@mclk) to config_imu (@xclk)
wire we_config_gps_xclk;
wire we_config_msg_xclk;
// wire we_config_syn_xclk;
wire we_config_rst_xclk;
wire we_config_debug_xclk;
wire we_bitHalfPeriod_xclk;
reg [1:0] config_imu_mclk; reg [1:0] config_imu_mclk;
reg [3:0] config_gps_mclk; reg [3:0] config_gps_mclk;
reg [4:0] config_msg_mclk; reg [4:0] config_msg_mclk;
reg config_syn_mclk; reg [3:0] config_syn_mclk;
reg config_rst_mclk; reg config_rst_mclk;
reg [3:0] config_debug_mclk; reg [3:0] config_debug_mclk;
reg [15:0] bitHalfPeriod_mclk;
reg [1:0] config_imu_pre; // reg [1:0] config_imu_pre;
reg [3:0] config_gps_pre; // reg [3:0] config_gps_pre;
reg [4:0] config_msg_pre; // reg [4:0] config_msg_pre;
reg config_syn_pre; // reg config_syn_pre;
reg config_rst_pre; // reg config_rst_pre;
reg [3:0] config_debug_pre; // reg [3:0] config_debug_pre;
reg [15:0] bitHalfPeriod;// serial gps speed - number of xclk pulses in half bit period
reg we_bitHalfPeriod;
reg [15:0] bitHalfPeriod_mclk;
reg enable_gps; reg enable_gps;
reg enable_msg; reg enable_msg;
reg enable_syn; // reg [3:0] enable_syn;
wire [3:0] enable_syn_mclk;
reg enable_timestamps; reg enable_timestamps;
wire message_trig; wire message_trig;
// reg ts_stb_rq; // reg ts_stb_rq;
// reg [1:0] ext_ts_stb; // reg [1:0] ext_ts_stb;
wire ts_stb_xclk; // re-clocked to posedge xclk // wire ts_stb_xclk; // re-clocked to posedge xclk
wire gps_ts_stb, ser_do,ser_do_stb; wire gps_ts_stb, ser_do,ser_do_stb;
wire [15:0] imu_data; wire [15:0] imu_data;
...@@ -281,76 +314,78 @@ module event_logger#( ...@@ -281,76 +314,78 @@ module event_logger#(
end end
*/ */
always @ (posedge mclk) begin // was negedge always @ (posedge mclk) begin // was negedge
if (cmd_we) cmd_data_r <= cmd_data; // valid next after cmd_we; if (cmd_we) cmd_data_r <= cmd_data; // valid next after cmd_we;
// if (we) di_d[15:0] <= di[15:0]; we_d <= cmd_we && !cmd_a;
we_d <= cmd_we && !cmd_a; we_imu <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_IMU);
we_imu <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_IMU); we_gps <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_GPS);
we_gps <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_GPS); we_message <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_MSG);
we_message <= cmd_we && !cmd_a && (ctrl_addr[6:5] == LOGGER_PAGE_MSG); we_period <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_PERIOD);
we_period <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_PERIOD); we_bit_duration <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_BIT_DURATION);
we_bit_duration <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_BIT_DURATION); we_bitHalfPeriod<= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_BIT_HALF_PERIOD);
we_bitHalfPeriod<= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_BIT_HALF_PERIOD); we_config_imu <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_IMU];
we_config <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG); we_config_gps <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_GPS];
we_config_imu <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_IMU]; we_config_msg <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_MSG];
we_config_gps <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_GPS]; we_config_syn <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_SYN];
we_config_msg <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_MSG]; we_config_rst <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_EN];
we_config_syn <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_SYN]; we_config_debug <= cmd_we && !cmd_a && (ctrl_addr[6:0] == LOGGER_CONFIG) && cmd_data[LOGGER_CONF_DBG];
if (we_config_imu) config_imu_mclk[1:0] <= cmd_data_r[LOGGER_CONF_IMU - 1 -: LOGGER_CONF_IMU_BITS]; // bits 1:0, 2 - enable slot[1:0]
if (we_config_gps) config_gps_mclk[3:0] <= cmd_data_r[LOGGER_CONF_GPS - 1 -: LOGGER_CONF_GPS_BITS]; // bits 6:3, 7 - enable - {ext,inver, slot[1:0]} slot==0 - disable
if (we_config_msg) config_msg_mclk[4:0] <= cmd_data_r[LOGGER_CONF_MSG - 1 -: LOGGER_CONF_MSG_BITS]; // bits 12:8,13 - enable - {invert,extinp[3:0]} extinp[3:0]=='hf' - disable
if (we_config_syn) config_syn_mclk <= cmd_data_r[LOGGER_CONF_SYN - 1 -: LOGGER_CONF_SYN_BITS]; // bit 14, 15 - enable
if (we_config && cmd_data_r[LOGGER_CONF_EN]) config_rst_mclk <= cmd_data_r[LOGGER_CONF_EN -1 -: LOGGER_CONF_EN_BITS]; // bit 16, 17 - enable
if (we_config && cmd_data_r[LOGGER_CONF_DBG]) config_debug_mclk[3:0] <= cmd_data_r[LOGGER_CONF_DBG - 1 -: LOGGER_CONF_DBG_BITS]; // bit 21:18, 22 - enable
if (we_bitHalfPeriod) bitHalfPeriod_mclk[15:0] <= cmd_data_r[15:0]; if (we_config_imu) config_imu_mclk[1:0] <= cmd_data_r[LOGGER_CONF_IMU - 1 -: LOGGER_CONF_IMU_BITS]; // bits 1:0, 2 - enable slot[1:0]
if (we_config_gps) config_gps_mclk[3:0] <= cmd_data_r[LOGGER_CONF_GPS - 1 -: LOGGER_CONF_GPS_BITS]; // bits 6:3, 7 - enable - {ext,inver, slot[1:0]} slot==0 - disable
if (cmd_we && cmd_a) ctrl_addr[6:5] <= cmd_data[6:5]; if (we_config_msg) config_msg_mclk[4:0] <= cmd_data_r[LOGGER_CONF_MSG - 1 -: LOGGER_CONF_MSG_BITS]; // bits 12:8,13 - enable - {invert,extinp[3:0]} extinp[3:0]=='hf' - disable
if (cmd_we && cmd_a) ctrl_addr[4:0] <= cmd_data[4:0]; if (we_config_syn) config_syn_mclk <= cmd_data_r[LOGGER_CONF_SYN - 1 -: LOGGER_CONF_SYN_BITS]; // bit 14, 15 - enable
else if (we_d && (ctrl_addr[4:0]!=5'h1f)) ctrl_addr[4:0] <=ctrl_addr[4:0]+1; // no roll over, if (we_config_rst) config_rst_mclk <= cmd_data_r[LOGGER_CONF_EN -1 -: LOGGER_CONF_EN_BITS]; // bit 16, 17 - enable
if (we_config_debug) config_debug_mclk[3:0] <= cmd_data_r[LOGGER_CONF_DBG - 1 -: LOGGER_CONF_DBG_BITS]; // bit 21:18, 22 - enable
if (we_bitHalfPeriod) bitHalfPeriod_mclk[15:0] <= cmd_data_r[15:0];
end if (cmd_we && cmd_a) ctrl_addr[6:5] <= cmd_data[6:5];
if (cmd_we && cmd_a) ctrl_addr[4:0] <= cmd_data[4:0];
else if (we_d && (ctrl_addr[4:0]!=5'h1f)) ctrl_addr[4:0] <=ctrl_addr[4:0]+1; // no roll over,
end
always @ (posedge xclk) begin assign enable_syn_mclk= config_rst_mclk? 4'b0 : config_syn_mclk;
bitHalfPeriod[15:0] <= bitHalfPeriod_mclk[15:0]; always @ (posedge xclk) begin
config_imu_pre[1:0] <= config_imu_mclk[1:0]; if (we_bitHalfPeriod_xclk) bitHalfPeriod[15:0] <= bitHalfPeriod_mclk[15:0];
config_gps_pre[3:0] <= config_gps_mclk[3:0]; if (we_config_imu_xclk) config_imu <= config_imu_mclk;
config_msg_pre[4:0] <= config_msg_mclk[4:0]; if (we_config_gps_xclk) config_gps <= config_gps_mclk;
config_syn_pre <= config_syn_mclk; if (we_config_msg_xclk) config_msg <= config_msg_mclk;
config_rst_pre <= config_rst_mclk; // if (we_config_syn_xclk) config_syn <= config_syn_mclk;
config_debug_pre[3:0] <= config_debug_mclk[3:0]; if (we_config_rst_xclk) config_rst <= config_rst_mclk;
if (we_config_debug_xclk) config_debug <= config_debug_mclk;
config_imu[1:0] <= config_imu_pre[1:0]; // enable_gps <= (config_gps[1:0] != 2'h0) && !config_rst;
config_gps[3:0] <= config_gps_pre[3:0]; enable_gps <= (^config_gps[1:0]) && !config_rst; // both 00 and 11 - disable
config_msg[4:0] <= config_msg_pre[4:0]; enable_msg <= (config_gps[3:0] != 4'hf) && !config_rst;
config_syn <= config_syn_pre; // enable_syn <= config_rst? 4'b0 : config_syn;
config_rst <= config_rst_pre; enable_timestamps <= !config_rst;
config_debug[3:0] <= config_debug_pre[3:0]; end
// enable_gps <= (config_gps[1:0] != 2'h0) && !config_rst;
enable_gps <= (^config_gps[1:0]) && !config_rst; // both 00 and 11 - disable
enable_msg <= (config_gps[3:0] != 4'hf) && !config_rst;
enable_syn <= config_syn && !config_rst;
enable_timestamps <= !config_rst;
end
always @ (posedge xclk) begin always @ (posedge xclk) begin
mux_data_source[15:0] <= channel[1]? mux_data_source[15:0] <= channel[1]?
(channel[0]?msg_data[15:0]:extts_data[15:0]): (channel[0]?msg_data[15:0]:extts_data[15:0]):
(channel[0]?nmea_data[15:0]:imu_data[15:0]); (channel[0]?nmea_data[15:0]:imu_data[15:0]);
mux_rdy_source <= channel[1]? mux_rdy_source <= channel[1]?
(channel[0]?channel_ready[3]:channel_ready[2]): (channel[0]?channel_ready[3]:channel_ready[2]):
(channel[0]?channel_ready[1]:channel_ready[0]); (channel[0]?channel_ready[1]:channel_ready[0]);
mux_data_final[15:0] <= ts_en? mux_data_final[15:0] <= ts_en?
timestamps_rdata[15:0]: timestamps_rdata[15:0]:
(mux_rdy_source? (mux_rdy_source?
mux_data_source[15:0]: mux_data_source[15:0]:
16'h0); // replace 16'h0 with some pattern to debug output 16'h0); // replace 16'h0 with some pattern to debug output
end end
pulse_cross_clock i_ts_stb_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(ts_stb), .out_pulse(ts_stb_xclk),.busy()); // pulse_cross_clock i_ts_stb_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(ts_stb), .out_pulse(ts_stb_xclk),.busy());
// generate strobes to copy configuration data from mclk to xclk domain
pulse_cross_clock i_we_config_imu_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_imu), .out_pulse(we_config_imu_xclk),.busy());
pulse_cross_clock i_we_config_gps_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_gps), .out_pulse(we_config_gps_xclk),.busy());
pulse_cross_clock i_we_config_msg_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_msg), .out_pulse(we_config_msg_xclk),.busy());
// pulse_cross_clock i_we_config_syn_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_syn), .out_pulse(we_config_syn_xclk),.busy());
pulse_cross_clock i_we_config_rst_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_rst), .out_pulse(we_config_rst_xclk),.busy());
pulse_cross_clock i_we_config_debug_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_config_debug), .out_pulse(we_config_debug_xclk),.busy());
pulse_cross_clock i_we_bitHalfPeriod_xclk (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(we_bitHalfPeriod), .out_pulse(we_bitHalfPeriod_xclk),.busy());
cmd_deser #( cmd_deser #(
.ADDR (LOGGER_ADDR), .ADDR (LOGGER_ADDR),
...@@ -386,131 +421,139 @@ module event_logger#( ...@@ -386,131 +421,139 @@ module event_logger#(
.start (status_start) // input .start (status_start) // input
); );
imu_spi393 i_imu_spi ( .sclk(mclk), // system clock, negedge imu_spi393 i_imu_spi (
.xclk(xclk), // half frequency (80 MHz nominal) // .rst(rst),
.we_ra(we_imu), // write enable for registers to log (@negedge mclk) .mclk (mclk), // system clock, negedge
.we_div(we_bit_duration),// write enable for clock dividing(@negedge mclk) .xclk (xclk), // half frequency (80 MHz nominal)
.we_period(we_period),// write enable for IMU cycle period(@negedge mclk) 0 - disable, 1 - single, >1 - half bit periods .we_ra (we_imu), // write enable for registers to log (@negedge mclk)
.wa(ctrl_addr[4:0]), // write address for register (5 bits, @negedge mclk) .we_div (we_bit_duration), // write enable for clock dividing(@negedge mclk)
.di(cmd_data_r[15:0]), // 16?-bit data in (di, not di_d) .we_period (we_period), // write enable for IMU cycle period(@negedge mclk) 0 - disable, 1 - single, >1 - half bit periods
.mosi(mosi), // to IMU, bit 2 in J9 .wa (ctrl_addr[4:0]), // write address for register (5 bits, @negedge mclk)
.miso(miso), // from IMU, bit 3 on J9 .din (cmd_data_r[31:0]), // 16?-bit data in (di, not di_d)
.config_debug(config_debug[3:0]), .mosi (mosi), // to IMU, bit 2 in J9
.sda(sda), // sda, shared with i2c, bit 1 .miso (miso), // from IMU, bit 3 on J9
.sda_en(sda_en), // enable sda output (when sda==0 and 1 cycle after sda 0->1) .config_debug (config_debug[3:0]),
.scl(scl), // scl, shared with i2c, bit 0 .sda (sda), // sda, shared with i2c, bit 1
.scl_en(scl_en), // enable scl output (when scl==0 and 1 cycle after sda 0->1) .sda_en (sda_en), // enable sda output (when sda==0 and 1 cycle after sda 0->1)
// .sngl_wire(sngl_wire), // single wire clock/data for the 103695 rev A .scl (scl), // scl, shared with i2c, bit 0
.scl_en (scl_en), // enable scl output (when scl==0 and 1 cycle after sda 0->1)
.ts(timestamp_request[0]), // timestamop request .ts (timestamp_request[0]), // timestamop request
.rdy(channel_ready[0]), // data ready .rdy (channel_ready[0]), // data ready
.rd_stb(channel_next[0]), // data read strobe (increment address) .rd_stb (channel_next[0]), // data read strobe (increment address)
.rdata(imu_data[15:0])); // data out (16 bits) .rdata (imu_data[15:0])); // data out (16 bits)
/* /*
logs events from odometer (can be software triggered), includes 56-byte message written to the buffer 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 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 de-assert the trig input - message with the timestamp will be logged
fixed-length de-noise circuitry with latency 256*T(xclk) (~3usec) fixed-length de-noise circuitry with latency 256*T(xclk) (~3usec)
*/ */
imu_message393 i_imu_message(.sclk(mclk), // system clock, negedge imu_message393 i_imu_message(
.xclk(xclk), // half frequency (80 MHz nominal) .mclk (mclk), // system clock, negedge
.we(we_message), // write enable for registers to log (@negedge sclk), with lower data half .xclk (xclk), // half frequency (80 MHz nominal)
.wa(ctrl_addr[3:0]), // write address for register (4 bits, @negedge sclk) .we (we_message), // write enable for registers to log (@negedge sclk), with lower data half
.di(cmd_data_r[15:0]), // 16-bit data in multiplexed .wa (ctrl_addr[3:0]), // write address for register (4 bits, @negedge sclk)
.en(enable_msg), // enable module operation, if 0 - reset .din (cmd_data_r[31:0]), // 16-bit data in multiplexed
.trig(message_trig), // leading edge - sample time, trailing set rdy .en (enable_msg), // enable module operation, if 0 - reset
.ts(timestamp_request[3]), // timestamop request .trig (message_trig), // leading edge - sample time, trailing set rdy
.rdy(channel_ready[3]), // data ready .ts (timestamp_request[3]),// timestamop request
.rd_stb(channel_next[3]), // data read strobe (increment address) .rdy (channel_ready[3]), // data ready
.rdata(msg_data[15:0])); // data out (16 bits) .rd_stb (channel_next[3]), // data read strobe (increment address)
.rdata (msg_data[15:0])); // data out (16 bits)
/* logs frame synchronization data from other camera (same as frame sync) */ /* logs frame synchronization data from other camera (same as frame sync) */
// ts_stb (mclk) -> trig) // ts_stb (mclk) -> trig)
imu_exttime393 i_imu_exttime(.xclk(xclk), // half frequency (80 MHz nominal) imu_exttime393 i_imu_exttime(
.en(enable_syn), // enable module operation, if 0 - reset .rst (rst), // input global reset
.trig(ts_stb_xclk), // ext_ts_stb[1]), // external time stamp updated, single pulse @posedge xclk .mclk (mclk), // system clock, negedge
.usec(ts_rcv_usec[19:0]), // microseconds from external timestamp (should not chnage after trig for 10 xclk) .xclk (xclk), // half frequency (80 MHz nominal)
.sec(ts_rcv_sec[31:0]), // seconds from external timestamp .en_chn_mclk (enable_syn_mclk), // enable module operation, if 0 - reset
.ts(timestamp_request[2]), // timestamop request .ts_stb_chn0 (ts_stb_chn0), // input
.rdy(channel_ready[2]), // data ready .ts_data_chn0 (ts_data_chn0), // input[7:0]
.rd_stb(channel_next[2]), // data read strobe (increment address) .ts_stb_chn1 (ts_stb_chn1), // input
.rdata(extts_data[15:0])); // data out (16 bits) .ts_data_chn1 (ts_data_chn1), // input[7:0]
.ts_stb_chn2 (ts_stb_chn2), // input
imu_timestamps393 i_imu_timestamps ( .ts_data_chn2 (ts_data_chn2), // input[7:0]
.sclk(mclk), // 160MHz, negedge .ts_stb_chn3 (ts_stb_chn3), // input
.xclk(xclk), // 80 MHz, posedge .ts_data_chn3 (ts_data_chn3), // input[7:0]
.rst(!enable_timestamps), // reset (@posedge xclk) .ts (timestamp_request[2]), // timestamop request
.sec(sec[31:0]), // running seconds (@negedge sclk) .rdy (channel_ready[2]), // data ready
.usec(usec[19:0]), // running microseconds (@negedge sclk) .rd_stb (channel_next[2]), // data read strobe (increment address)
.ts_rq(timestamp_request_long[3:0]),// requests to create timestamps (4 channels), @posedge xclk .rdata (extts_data[15:0])); // data out (16 bits)
.ts_ackn(timestamp_ackn[3:0]), // timestamp for this channel is stored
.ra({channel[1:0],timestamp_sel[1:0]}), // read address (2 MSBs - channel number, 2 LSBs - usec_low, (usec_high ORed with channel <<24), sec_low, sec_high imu_timestamps393 i_imu_timestamps (
.dout(timestamps_rdata[15:0]));// output data .sclk (mclk), // 160MHz, negedge
.xclk (xclk), // 80 MHz, posedge
.rst (!enable_timestamps), // reset (@posedge xclk)
.sec (sec[31:0]), // running seconds (@negedge sclk)
.usec (usec[19:0]), // running microseconds (@negedge sclk)
.ts_rq (timestamp_request_long[3:0]), // requests to create timestamps (4 channels), @posedge xclk
.ts_ackn (timestamp_ackn[3:0]), // timestamp for this channel is stored
.ra ({channel[1:0],timestamp_sel[1:0]}), // read address (2 MSBs - channel number, 2 LSBs - usec_low, (usec_high ORed with channel <<24), sec_low, sec_high
.dout (timestamps_rdata[15:0])); // output data
wire debug_unused_a; // SuppressThisWarning Veditor (unused) wire debug_unused_a; // SuppressThisWarning Veditor (unused)
rs232_rcv393 i_rs232_rcv (.xclk(xclk), // half frequency (80 MHz nominal) rs232_rcv393 i_rs232_rcv (
.bitHalfPeriod(bitHalfPeriod[15:0]), // half of the serial bit duration, in xclk cycles .xclk (xclk), // half frequency (80 MHz nominal)
.ser_di(ser_di), // rs232 (ttl) serial data in .bitHalfPeriod (bitHalfPeriod[15:0]), // half of the serial bit duration, in xclk cycles
.ser_rst(!enable_gps), // reset (force re-sync) .ser_di (ser_di), // rs232 (ttl) serial data in
.ts_stb(gps_ts_stb), // strobe timestamp (start of message) (reset bit counters in nmea decoder) .ser_rst (!enable_gps), // reset (force re-sync)
.wait_just_pause(rs232_wait_pause),// may be used as reset for decoder .ts_stb (gps_ts_stb), // strobe timestamp (start of message) (reset bit counters in nmea decoder)
.start(rs232_start), // serial character start (single pulse) .wait_just_pause (rs232_wait_pause), // may be used as reset for decoder
.start (rs232_start), // serial character start (single pulse)
.ser_do(ser_do), // serial data out(@posedge xclk) LSB first! .ser_do (ser_do), // serial data out(@posedge xclk) LSB first!
.ser_do_stb(ser_do_stb), // output data strobe (@posedge xclk), first cycle after ser_do becomes valid .ser_do_stb (ser_do_stb), // output data strobe (@posedge xclk), first cycle after ser_do becomes valid
// .debug(debug_state[4:0]), .debug ({debug_unused_a, debug_state[15:12]}),
.debug({debug_unused_a, debug_state[15:12]}), .bit_dur_cntr (debug_state[31:16]),
.bit_dur_cntr(debug_state[31:16]), .bit_cntr (debug_state[11:7])
.bit_cntr(debug_state[11:7]) );
);
// output [15:0] debug_state;
// reg [7:0] dbg_cntr;
// assign debug_state[15:12]=3'b0;
assign debug_state[6:0] = dbg_cntr [6:0]; assign debug_state[6:0] = dbg_cntr [6:0];
always @ (posedge xclk) begin always @ (posedge xclk) begin
if (!enable_gps) dbg_cntr[7:0] <= 8'h0; if (!enable_gps) dbg_cntr[7:0] <= 8'h0;
// else if (ser_do_stb) dbg_cntr[7:0] <= dbg_cntr[7:0]+1; else if (rs232_start) dbg_cntr[7:0] <= dbg_cntr[7:0]+1;
else if (rs232_start) dbg_cntr[7:0] <= dbg_cntr[7:0]+1; end
end
nmea_decoder393 i_nmea_decoder (.sclk(mclk), // system clock, @negedge nmea_decoder393 i_nmea_decoder (
.we(we_gps), // registers write enable (@negedge sclk) .mclk (mclk), // system clock, @posedge
.wa(ctrl_addr[4:0]), // registers write address .xclk (xclk), // 80MHz, posedge
.wd(cmd_data_r[7:0]), // write data .we (we_gps), // registers write enable
.xclk(xclk), // 80MHz, posedge .wa (ctrl_addr[4:0]), // registers write address
.start(gps_ts_stb), // start of the serial message .wd (cmd_data_r[7:0]), // write data
.rs232_wait_pause(rs232_wait_pause),// may be used as reset for decoder .start (gps_ts_stb), // start of the serial message
.start_char(rs232_start), // serial character start (single pulse) .rs232_wait_pause (rs232_wait_pause), // may be used as reset for decoder
.nmea_sent_start(nmea_sent_start), // serial character start (single pulse) .start_char (rs232_start), // serial character start (single pulse)
.ser_di(ser_do), // serial data in (LSB first) .nmea_sent_start (nmea_sent_start), // serial character start (single pulse)
.ser_stb(ser_do_stb),// serial data strobe, single-cycle, first cycle after ser_di valid .ser_di (ser_do), // serial data in (LSB first)
.rdy(channel_ready[1]), // encoded nmea data ready .ser_stb (ser_do_stb), // serial data strobe, single-cycle, first cycle after ser_di valid
.rd_stb(channel_next[1]), // encoded nmea data read strobe (increment address) .rdy (channel_ready[1]), // encoded nmea data ready
.rdata(nmea_data[15:0]), // encoded data (16 bits) .rd_stb (channel_next[1]), // encoded nmea data read strobe (increment address)
.ser_rst(!enable_gps), // reset (now only debug register) .rdata (nmea_data[15:0]), // encoded data (16 bits)
.debug() .ser_rst (!enable_gps), // reset (now only debug register)
); .debug()
);
// Logger handshakes timestamps through request/grant, so it is OK to make slow serial communication with RTC)
logger_arbiter393 i_logger_arbiter(.xclk(xclk), // 80 MHz, posedge logger_arbiter393 i_logger_arbiter(
.rst(config_rst), // module reset .xclk (xclk), // 80 MHz, posedge
.ts_rq_in(timestamp_request[3:0]), // in requests for timestamp (single-cycle - just leading edge ) .rst (config_rst), // module reset
.ts_rq(timestamp_request_long[3:0]), // out request for timestamp, to timestmp module .ts_rq_in (timestamp_request[3:0]), // in requests for timestamp (single-cycle - just leading edge )
.ts_grant(timestamp_ackn[3:0]), // granted ts requests from timestamping module .ts_rq (timestamp_request_long[3:0]),// out request for timestamp, to timestmp module
.rdy(channel_ready[3:0]), // channels ready (leading edge - became ready, trailing - no more data, use zero) .ts_grant (timestamp_ackn[3:0]), // granted ts requests from timestamping module
.nxt(channel_next[3:0]), // pulses to modules to output next word .rdy (channel_ready[3:0]), // channels ready (leading edge - became ready, trailing - no more data, use zero)
.channel(channel[1:0]), // decoded channel number (2 bits) .nxt (channel_next[3:0]), // pulses to modules to output next word
.ts_sel(timestamp_sel[1:0]), // select timestamp word to be output (0..3) .channel (channel[1:0]), // decoded channel number (2 bits)
.ts_en(ts_en), // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready) .ts_sel (timestamp_sel[1:0]), // select timestamp word to be output (0..3)
.dv(mux_data_valid), // output data valid (from registered mux - 2 stage - first selects data and ready, second ts/data/zero) .ts_en (ts_en), // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready)
.sample_counter(sample_counter));// number of 64-byte samples logged .dv (mux_data_valid), // output data valid (from registered mux - 2 stage - first selects data and ready, second ts/data/zero)
.sample_counter (sample_counter)); // number of 64-byte samples logged
buf_xclk_mclk16_393 i_buf_xclk_mclk16(.xclk(xclk), // posedge
.mclk(mclk), // posedge! buf_xclk_mclk16_393 i_buf_xclk_mclk16(
.rst(config_rst), // @posedge xclk .mclk (mclk), // posedge
.din(mux_data_final[15:0]), .xclk (xclk), // posedge
.din_stb(mux_data_valid), .rst (config_rst), // @posedge xclk
.dout(data_out[15:0]), .din (mux_data_final[15:0]),
.dout_stb(data_out_stb)); .din_stb (mux_data_valid),
.dout (data_out[15:0]),
.dout_stb (data_out_stb));
endmodule endmodule
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: get external timestamp (for image) * Description: get external timestamp (for image)
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* imu_exttime393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -20,77 +20,166 @@ ...@@ -20,77 +20,166 @@
*******************************************************************************/ *******************************************************************************/
`timescale 1ns/1ps `timescale 1ns/1ps
/* /*
logs frame synchronization data from other camera (same as frame sync) Logs frame synchronization data from other camera (same as frame sync)
When sesnors are running in free running mode, each sensor may provide individual timestamp (sampled at vsync)
*/ */
module imu_exttime393( module imu_exttime393(
xclk, // half frequency (80 MHz nominal) input rst,
en, // enable module operation, if 0 - reset input mclk, // system clock, negedge TODO:COnvert to posedge!
trig, // external time stamp updated input xclk, // half frequency (80 MHz nominal)
usec, // microseconds from external timestamp (should not chnage after trig for 10 xclk) input [3:0] en_chn_mclk, // enable per-channel module operation, if all 0 - reset
sec, // seconds from external timestamp // byte-parallel timestamps from 4 sesnors channels (in triggered mode all are the same, different only in free running mode)
ts, // timestamop request // each may generate logger event, channel number encoded in bits 25:24 of the external microseconds
rdy, // data ready
rd_stb, // data read strobe (increment address) input ts_stb_chn0, // @mclk 1 clock before ts_rcv_data is valid
rdata); // data out (16 bits) input [7:0] ts_data_chn0, // @mclk byte-wide serialized timestamp message received or local
input xclk; // half frequency (80 MHz nominal) input ts_stb_chn1, // @mclk 1 clock before ts_rcv_data is valid
input en; // enable input [7:0] ts_data_chn1, // @mclk byte-wide serialized timestamp message received or local
input trig; // external time stamp updated
input [19:0] usec; // microseconds from external timestamp input ts_stb_chn2, // @mclk 1 clock before ts_rcv_data is valid
input [31:0] sec; // seconds from external timestamp input [7:0] ts_data_chn2, // @mclk byte-wide serialized timestamp message received or local
output ts; // timestamp request
output rdy; // encoded nmea data ready input ts_stb_chn3, // @mclk 1 clock before ts_rcv_data is valid
input rd_stb;// encoded nmea data read strobe (increment address) input [7:0] ts_data_chn3, // @mclk byte-wide serialized timestamp message received or local
output [15:0] rdata; // encoded data (16 bits)
output ts, // timestamop request
reg [ 4:0] raddr; output reg rdy, // data ready will go up with timestamp request (ahead of actual time), but it will
reg rdy=1'b0; // anyway be ready sooner, than the local timestamp retrieved ant sent
input rd_stb, // data read strobe (increment address) - continuous 1'b1 until allthe packet is read out
output [15:0] rdata); // data out (16 bits)
reg we, pre_we;
reg [ 3:0] pre_waddr; reg [ 4:0] raddr;
reg [ 1:0] waddr; wire en_mclk = |en_chn_mclk;
reg [ 2:0] trig_d; wire [3:0] ts_stb = {ts_stb_chn3, ts_stb_chn2, ts_stb_chn1, ts_stb_chn0};
reg pre_ts,ts; reg en;
reg [15:0] time_mux;
always @ (posedge xclk) begin reg rd_stb_r;
if (!en) trig_d[2:0] <= 3'h0; reg rd_start; // 1 xclk pulse at the readout start
else trig_d[2:0] <= {trig_d[1:0], trig}; wire rd_start_mclk;
reg ts_full; // internal 4 x 16 fifo is full (or getting full)
pre_ts <= !trig_d[2] && trig_d[1]; reg [3:0] in_full; // input fifo has (or is acquiring) timestamp
ts <= pre_ts; // delayed so arbiter will enable ts to go through wire pre_copy_w;
if (!en || pre_ts) pre_waddr[3:0] <= 4'b0; reg [1:0] copy_selected; // copying from the winner of 4 input fifos to the x16 output fifo
else if (!pre_waddr[3]) pre_waddr[3:0] <= pre_waddr[3:0] + 1; reg copy_started;
if (pre_waddr[0]) waddr[1:0] <=pre_waddr[2:1]; reg [2:0] copy_cntr; // byte counter for copying
if (pre_waddr[0] && !pre_waddr[3]) case (pre_waddr[2:1]) reg [1:0] sel_chn; // selected channel
2'b00: time_mux[15:0] <= usec[15:0]; wire [3:0] chn1hot={(sel_chn == 2'h3), (sel_chn == 2'h2), (sel_chn == 2'h1), (sel_chn == 2'h0)};
2'b01: time_mux[15:0] <= {12'h0,usec[19:16]}; wire pre_copy_started = copy_selected == 'b01;
2'b10: time_mux[15:0] <= sec[15:0]; wire [3:0] chn_pri_w;
2'b11: time_mux[15:0] <= sec[31:16]; wire [1:0] chn_enc_w;
endcase
pre_we<=pre_waddr[0] && !pre_waddr[3]; reg [15:0] ts_ram [0:3]; // inner timestamp x16 memory that receives timestamp from one of the 4 input channel fifos
we <= pre_we; wire [7:0] dout_chn[0:3];
wire [7:0] copy_data; // data from the selected input fifos
if (!en || pre_ts) raddr[4:0] <= 5'h0; reg [7:0] copy_data_r; // low byte of the timestamp data being copied from one of the input fifos to the ts_ram
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
assign chn_pri_w = {in_full[3] & ~(|in_full[2:0]),
if (pre_ts || (rd_stb && (raddr[1:0]==2'h3)) || !en) rdy <= 1'b0; in_full[2] & ~(|in_full[1:0]),
else if (we && (waddr[1:0]==2'h3)) rdy <= 1'b1; in_full[1] & ~in_full[0],
end in_full[0]};
assign chn_enc_w = {chn_pri_w[3] | chn_pri_w[2],
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(2)) chn_pri_w[3] | chn_pri_w[1]};
i_odbuf (.D(time_mux[15:0]),
.WE(we), assign pre_copy_w = (|in_full) && !copy_selected[0] && !ts_full;
.clk(xclk), assign copy_data = dout_chn[sel_chn]; // 4:1 mux
.AW(waddr[1:0]),
.AR(raddr[1:0]), // acquire external timestamps @ mclk
.QW(),
.QR(rdata[15:0])); always @ (posedge mclk) begin
copy_started <= pre_copy_started;
if (!en_mclk) ts_full <= 0;
else if (pre_copy_started) ts_full <= 1; // turns on before in_full[*] - || will have no glitches
else if (rd_start_mclk) ts_full <= 0;
if (!en_mclk) in_full <= 0;
else in_full <= en_chn_mclk & (ts_stb | (in_full & ~(chn1hot & {4{copy_started}})));
copy_selected <= {copy_selected[0], pre_copy_w | (copy_selected[0] & ~(&copy_cntr[2:1]))}; // off at count 6
if (pre_copy_w) sel_chn <= chn_enc_w;
if (!copy_selected[1]) copy_cntr <= 0;
else copy_cntr <= copy_cntr + 1;
copy_data_r <= copy_data; // previous data is low byte
// write x16 timestamp data to RAM, inser channel number into unused microseconds byte
if (copy_selected[1] && copy_cntr[0]) ts_ram[copy_cntr[2:1]] <= {copy_selected[0]?copy_data:{6'b0,sel_chn},copy_data_r};
end
assign rdata[15:0] = ts_ram[raddr[1:0]];
always @ (posedge xclk) begin
en <= en_mclk;
rd_stb_r <= rd_stb;
rd_start <= en && rd_stb && ! rd_stb_r;
if (!en || ts) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
if (!en) rdy <= 1'b0;
else if (ts) rdy <= 1'b1; // too early, but it will become ready in time, before the local timestamp
else if (rd_stb && (raddr[1:0]==2'h3)) rdy <= 1'b0;
end
timestamp_fifo timestamp_fifo_chn0_i (
.rst (rst), // input
.sclk (mclk), // input
.pre_stb (ts_stb[0]), // input
.din (ts_data_chn0), // input[7:0]
.aclk (mclk), // input
.advance (ts_stb[0]), // enough time
.rclk (mclk), // input
.rstb (pre_copy_started && (sel_chn == 2'h0)),// input
.dout (dout_chn[0]) // output[7:0] reg valid with copy_selected[1]
);
timestamp_fifo timestamp_fifo_chn1_i (
.rst (rst), // input
.sclk (mclk), // input
.pre_stb (ts_stb[1]), // input
.din (ts_data_chn1), // input[7:0]
.aclk (mclk), // input
.advance (ts_stb[1]), // enough time
.rclk (mclk), // input
.rstb (pre_copy_started && (sel_chn == 2'h1)),// input
.dout (dout_chn[1]) // output[7:0] reg valid with copy_selected[1]
);
timestamp_fifo timestamp_fifo_chn2_i (
.rst (rst), // input
.sclk (mclk), // input
.pre_stb (ts_stb[2]), // input
.din (ts_data_chn2), // input[7:0]
.aclk (mclk), // input
.advance (ts_stb[2]), // enough time
.rclk (mclk), // input
.rstb (pre_copy_started && (sel_chn == 2'h2)),// input
.dout (dout_chn[2]) // output[7:0] reg valid with copy_selected[1]
);
timestamp_fifo timestamp_fifo_chn3_i (
.rst (rst), // input
.sclk (mclk), // input
.pre_stb (ts_stb[3]), // input
.din (ts_data_chn3), // input[7:0]
.aclk (mclk), // input
.advance (ts_stb[3]), // enough time
.rclk (mclk), // input
.rstb (pre_copy_started && (sel_chn == 2'h3)),// input
.dout (dout_chn[3]) // output[7:0] reg valid with copy_selected[1]
);
endmodule
pulse_cross_clock i_rd_start_mclk (.rst(1'b0), .src_clk(xclk), .dst_clk(mclk), .in_pulse(rd_start), .out_pulse(rd_start_mclk),.busy());
// generate timestamp request as soon as one of the sub-channels starts copying. That time stamp will be stored for this (ext) channel
pulse_cross_clock i_ts (.rst(1'b0), .src_clk(mclk), .dst_clk(xclk), .in_pulse(pre_copy_w), .out_pulse(ts),.busy());
endmodule endmodule
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: * Description:
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* imu_message393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -27,73 +27,58 @@ de-assert the trig input - message with the timestamp will be logged ...@@ -27,73 +27,58 @@ de-assert the trig input - message with the timestamp will be logged
fixed-length de-noise circuitry with latency 256*T(xclk) (~3usec) fixed-length de-noise circuitry with latency 256*T(xclk) (~3usec)
*/ */
module imu_message393 ( sclk, // system clock, negedge module imu_message393 (
xclk, // half frequency (80 MHz nominal) input mclk, // system clock, negedge TODO:COnvert to posedge!
we, // write enable for registers to log (@negedge sclk), with lower data half input xclk, // half frequency (80 MHz nominal)
wa, // write address for register (4 bits, @negedge sclk) input we, // write enable for registers to log (@negedge mclk), with lower data half
di, // 16-bit data in multiplexed input [3:0] wa, // write address for register (4 bits, @negedge mclk)
en, // enable module operation, if 0 - reset // input [15:0] di, // 16-bit data in multiplexed
trig, // leading edge - sample time, trailing set rdy input [31:0] din, // 32-bit data in, non-multiplexed
ts, // timestamop request input en, // enable module operation, if 0 - reset
rdy, // data ready input trig, // leading edge - sample time, trailing set rdy
rd_stb, // data read strobe (increment address) output ts, // timestamop request
rdata); // data out (16 bits) output rdy, // data ready
input rd_stb, // data read strobe (increment address)
output [15:0] rdata); // data out (16 bits)
input sclk; // system clock, negedge reg [ 4:0] raddr;
input xclk; // half frequency (80 MHz nominal) reg rdy_r=1'b0;
input we; // write enable for registers to log (@negedge sclk) reg [ 2:0] trig_d;
input [3:0] wa; // write address for register (4 bits, @negedge sclk) reg [ 7:0] denoise_count;
input [15:0] di; // 16-bit data in (32 multiplexed) reg [ 1:0] trig_denoise;
input en; // enable reg ts_r;
input trig; // leading edge - sample time, trailing set rdy
output ts; // timestamp request assign rdy = rdy_r;
output rdy; // encoded nmea data ready assign ts = ts_r;
input rd_stb; // encoded nmea data read strobe (increment address)
output [15:0] rdata; // encoded data (16 bits) always @ (posedge xclk) begin
if (!en) trig_d[2:0] <= 3'h0;
reg [ 4:0] raddr; else trig_d[2:0] <= {trig_d[1:0], trig};
reg rdy=1'b0;
reg we_d; if (!en) trig_denoise[0] <= 1'b0;
reg [ 4:1] waddr; else if (denoise_count[7:0]==8'h0) trig_denoise[0] <= trig_d[2];
reg [ 2:0] trig_d;
reg [ 7:0] denoise_count; if (trig_d[2]==trig_denoise[0]) denoise_count[7:0] <= 8'hff;
reg [ 1:0] trig_denoise; else denoise_count[7:0] <= denoise_count[7:0] - 1;
reg ts;
reg [15:0] di_d; trig_denoise[1] <= trig_denoise[0];
always @ (negedge sclk) begin ts_r <= !trig_denoise[1] && trig_denoise[0];
di_d[15:0] <= di[15:0];
waddr[4:1] <= wa[3:0]; if (!en || ts_r) raddr[4:0] <= 5'h0;
we_d <=we; else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
end
always @ (posedge xclk) begin if (ts_r || (rd_stb && (raddr[4:0]==5'h1b)) || !en) rdy_r <= 1'b0;
if (!en) trig_d[2:0] <= 3'h0; else if (trig_denoise[1] && !trig_denoise[0]) rdy_r <= 1'b1;
else trig_d[2:0] <= {trig_d[1:0], trig}; end
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
reg [31:0] odbuf0_ram[0:15];
wire [31:0] odbuf0_ram_out;
always @ (posedge mclk) if (we) begin
odbuf0_ram[wa[3:0]] <= din[31:0];
end
assign odbuf0_ram_out = odbuf0_ram[raddr[4:1]];
assign rdata[15:0] = raddr[0] ? odbuf0_ram_out[15:0] : odbuf0_ram_out[31:16];
endmodule endmodule
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: SPI interface for the IMU * Description: SPI interface for the IMU
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* imu_spi393.v is free software; you can redistribute it and/or modify * imu_spi393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -21,32 +21,33 @@ ...@@ -21,32 +21,33 @@
`timescale 1ns/1ps `timescale 1ns/1ps
module imu_spi393( module imu_spi393(
sclk, // system clock, negedge // input rst,
xclk, // half frequency (80 MHz nominal) input mclk, // system clock, negedge TODO:COnvert to posedge!
we_ra, // write enable for registers to log (@negedge clk) input xclk, // half frequency (80 MHz nominal)
we_div,// write enable for clock dividing(@negedge clk)
we_period,// write enable for IMU cycle period(@negedge clk) 0 - disable, 1 - single, >1 - half bit periods input we_ra, // write enable for registers to log (@negedge clk)
wa, // write address for register (5 bits, @negedge clk) input we_div,// write enable for clock dividing(@negedge clk)
di, // 16?-bit data in (di, not di_d) input we_period,// write enable for IMU cycle period(@negedge clk) 0 - disable, 1 - single, >1 - half bit periods
mosi, // to IMU, bit 2 in J9 input [ 4:0] wa, // write address for register (5 bits, @negedge clk)
miso, // from IMU, bit 3 on J9 input [31:0] din, //
config_debug, // bit 0 - long sda_en output mosi, // to IMU, bit 2 in J9
sda, // sda, shared with i2c, bit 1 input miso, // from IMU, bit 3 on J9
sda_en, // enable sda output (when sda==0 and 1 cycle after sda 0->1) input [ 3:0] config_debug, // bit 0 - long sda_en
scl, // scl, shared with i2c, bit 0 output sda, // sda, shared with i2c, bit 1
scl_en, // enable scl output (when scl==0 and 1 cycle after sda 0->1) output sda_en, // enable sda output (when sda==0 and 1 cycle after sda 0->1)
// sngl_wire, // single wire clock/data for the 103695 rev A output scl, // scl, shared with i2c, bit 0
ts, // timestamop request output scl_en, // enable scl output (when scl==0 and 1 cycle after sda 0->1)
rdy, // data ready output ts, // timestamop request
rd_stb, // data read strobe (increment address) output rdy, // data ready
rdata); // data out (16 bits) input rd_stb, // data read strobe (increment address)
output [15:0] rdata); // data out (16 bits)
input sclk; // system clock, negedge /*
input mclk; // system clock, negedge
input xclk; // half frequency (80 MHz nominal) input xclk; // half frequency (80 MHz nominal)
input we_ra; // write enable for registers to log (@negedge sclk) input we_ra; // write enable for registers to log (@negedge mclk)
input we_div;// write enable for clock dividing(@negedge sclk) input we_div;// write enable for clock dividing(@negedge mclk)
input we_period;// write enable for IMU cycle period(@negedge clk) input we_period;// write enable for IMU cycle period(@negedge clk)
input [4:0] wa; // write address for register (5 bits, @negedge sclk) input [4:0] wa; // write address for register (5 bits, @negedge mclk)
input [15:0] di; // 16-bit data in input [15:0] di; // 16-bit data in
output mosi; // to IMU, bit 2 in J9 output mosi; // to IMU, bit 2 in J9
input miso; // from IMU, bit 3 on J9 input miso; // from IMU, bit 3 on J9
...@@ -61,303 +62,302 @@ module imu_spi393( ...@@ -61,303 +62,302 @@ module imu_spi393(
input rd_stb; // encoded nmea data read strobe (increment address) input rd_stb; // encoded nmea data read strobe (increment address)
output [15:0] rdata; // encoded data (16 bits) output [15:0] rdata; // encoded data (16 bits)
// output sngl_wire; // combined clock/data // output sngl_wire; // combined clock/data
*/
reg [ 7:0] bit_duration_mclk=8'h0;
reg [ 7:0] bit_duration;
reg [ 7:0] bit_duration_cntr=8'h0;
reg bit_duration_zero; // just for simulation
reg [ 3:0] clk_en=4'h0;
reg [ 1:0] clk_div;
reg [ 4:0] imu_in_word= 5'b0; // number of IMU output word in a sample (0..31), 0..3 - timestamp
reg pre_imu_wr_buf,imu_wr_buf;
wire [15:0] imu_in_buf;
reg [4:0] reg_seq_number; // number of register in a sequence
wire [6:1] imu_reg_number; // register numer to read
reg [ 7:0] bit_duration_mclk=8'h0; reg [1:0] seq_state; // 0 - idle, 1 - prepare spi(4?), 2 - spi-comm(32*29), 3 - finish (2)
reg [ 7:0] bit_duration; reg [9:0] seq_counter;
reg [ 7:0] bit_duration_cntr=8'h0; reg end_spi, end_prepare;
reg bit_duration_zero; // just for simulation reg set_mosi_prepare, set_mosi_spi;
reg seq_counter_zero, pre_seq_counter_zero;
reg [ 3:0] clk_en=4'h0; reg [15:0] mosi_reg;
reg [ 1:0] clk_div; // wire mosi;
reg [ 4:0] imu_in_word= 5'b0; // number of IMU output word in a sample (0..31), 0..3 - timestamp reg [1:0] sda_r;
reg pre_imu_wr_buf,imu_wr_buf; reg [1:0] scl_r;
wire [15:0] imu_in_buf; // wire scl_en;
reg shift_miso;
reg [4:0] reg_seq_number; // number of register in a sequence reg [15:0] miso_reg;
wire [6:1] imu_reg_number; // register numer to read reg last_bit; // last clk _/~ in spi word (but first one)
reg last_bit_ext=1'b0; // from last bit till buffer write
reg last_buf_wr;
reg [ 4:0] raddr;
reg rdy_r=1'b0;
reg imu_start;
reg ts_r; // delay imu_start by one cycle, so it will be after rdy is reset
reg [31:0] period; // 0 - disable, 1 - single, >1 - period in 50 ns steps
// reg [15:0] di_d;
reg imu_enabled_mclk;
reg [1:0] imu_enabled=2'h0;
reg imu_run_mclk;
reg [1:0] imu_run;
reg imu_when_ready_mclk;
reg [1:0] imu_when_ready;
reg [1:0] seq_state; // 0 - idle, 1 - prepare spi(4?), 2 - spi-comm(32*29), 3 - finish (2) reg imu_run_confirmed;
reg [9:0] seq_counter; reg imu_start_mclk;
reg end_spi, end_prepare; reg [1:0] imu_start_grant;
reg set_mosi_prepare, set_mosi_spi; reg imu_start_first;
reg seq_counter_zero, pre_seq_counter_zero; reg imu_start_first_was;
reg [15:0] mosi_reg; reg [31:0] period_counter;
wire mosi; wire en;
reg sda, sda_d; reg [4:01] we_timer;
wire sda_en; reg first_prepare;
reg scl, scl_d; reg [1:0] first_prepare_d;
wire scl_en; wire config_long_sda_en;
reg shift_miso; wire config_late_clk;
reg [15:0] miso_reg; reg [7:0] stall_dur_mclk;
reg last_bit; // last clk _/~ in spi word (but first one) reg [7:0] stall_dur;
reg last_bit_ext=1'b0; // from last bit till buffer write reg stall; // stall between words to satisfy SPI stall time
reg last_buf_wr; reg [7:0] stall_cntr; // stall counter (in half mclk periods)
reg [ 4:0] raddr; reg set_stall;
reg rdy=1'b0; reg skip_stall; // first word after CS -\_
reg imu_start; wire shift_mosi;
reg ts; // delay imu_start by one cycle, so it will be aftre rdy is reset
reg [31:0] period; // 0 - disable, 1 - single, >1 - period in 50 ns steps
reg [15:0] di_d;
reg imu_enabled_mclk;
reg [1:0] imu_enabled=2'h0;
reg imu_run_mclk;
reg [1:0] imu_run;
reg imu_when_ready_mclk;
reg [1:0] imu_when_ready;
reg imu_run_confirmed; reg imu_ready_reset;
reg imu_start_mclk; reg [6:0] imu_ready_denoise_count;
reg [1:0] imu_start_grant; reg [2:0] imu_data_ready_d;
reg imu_start_first; reg [5:0] imu_data_ready;
reg imu_start_first_was; reg [1:0] seq_state_zero;
reg [31:0] period_counter;
wire en; reg pre_scl;
reg [4:01] we_timer; reg [2:0] sngl_wire_stb;
reg first_prepare; reg [1:0] sngl_wire_r;
reg [1:0] first_prepare_d; wire sngl_wire;
wire config_long_sda_en; wire config_single_wire; // used in 103695 rev A
wire config_late_clk;
reg [7:0] stall_dur_mclk;
reg [7:0] stall_dur;
reg stall; // stall between words to satisfy SPI stall time
reg [7:0] stall_cntr; // stall counter (in half sclk periods)
reg set_stall;
reg skip_stall; // first word after CS -\_
wire shift_mosi;
reg imu_ready_reset; assign sngl_wire = ~|sngl_wire_r[1:0];
reg [6:0] imu_ready_denoise_count;
reg [2:0] imu_data_ready_d;
reg [5:0] imu_data_ready;
reg [1:0] seq_state_zero;
reg pre_scl;
reg [2:0] sngl_wire_stb;
reg [1:0] sngl_wire_r;
wire sngl_wire;
wire config_single_wire; // used in 103695 rev A
assign sngl_wire=~|sngl_wire_r[1:0]; assign shift_mosi = (clk_en[3] && seq_counter[0] && !stall);
assign mosi = config_single_wire?sngl_wire:mosi_reg[15];
assign shift_mosi=(clk_en[3] && seq_counter[0] && !stall); assign config_long_sda_en = config_debug[0];
assign mosi=config_single_wire?sngl_wire:mosi_reg[15]; assign config_late_clk = config_debug[1];
assign config_single_wire = config_debug[2];
assign config_long_sda_en=config_debug[0]; assign en= imu_enabled[1];
assign config_late_clk= config_debug[1]; assign sda_en= !config_single_wire && (!sda_r[0] || !sda_r[1] || (config_long_sda_en && (seq_state[1:0]!=2'b0)));
assign config_single_wire=config_debug[2]; assign scl_en= !config_single_wire && (!scl_r[0] || !scl_r[1]);
assign en=imu_enabled[1]; assign sda = sda_r[0];
assign sda_en= !config_single_wire && (!sda || !sda_d || (config_long_sda_en && (seq_state[1:0]!=2'b0))); assign scl = scl_r[0];
assign scl_en= !config_single_wire && (!scl || !scl_d); assign rdy = rdy_r;
assign ts = ts_r;
always @ (negedge sclk) begin
di_d[15:0] <= di[15:0]; always @ (posedge mclk) begin
if (we_div) bit_duration_mclk[7:0]<=di_d[7:0]; // di_d[15:0] <= di[15:0];
if (we_div) stall_dur_mclk[7:0]<=di_d[15:8]; if (we_div) bit_duration_mclk[7:0] <= din[7:0];
we_timer[4:1] <= {we_timer[3:1], we_period}; if (we_div) stall_dur_mclk[7:0] <= din[15:8];
we_timer[4:1] <= {we_timer[3:1], we_period};
if (we_period) period[31:0]<={di[15:0],di_d[15:0]};
if (we_timer[2]) imu_run_mclk <= (period[31:1]!=31'b0); // double-cycle
if (we_timer[3]) imu_enabled_mclk <= imu_run_mclk | period[0];
if (we_timer[2]) imu_when_ready_mclk <= &period[31:16]; // double-cycle
if (!imu_enabled_mclk || imu_start_grant[1]) imu_start_mclk<=1'b0; if (we_period) period[31:0] <= din[31:0];
else if (we_timer[4])imu_start_mclk<=imu_enabled_mclk; if (we_timer[2]) imu_run_mclk <= (period[31:1]!=31'b0); // double-cycle
if (we_timer[3]) imu_enabled_mclk <= imu_run_mclk | period[0];
end
if (we_timer[2]) imu_when_ready_mclk <= &period[31:16]; // double-cycle
if (!imu_enabled_mclk || imu_start_grant[1]) imu_start_mclk <= 1'b0;
else if (we_timer[4])imu_start_mclk <= imu_enabled_mclk;
end
// debounce imu_data_ready // debounce imu_data_ready
always @ (posedge xclk) begin always @ (posedge xclk) begin
seq_state_zero[1:0] <= {seq_state_zero[0], ~|seq_state[1:0]}; seq_state_zero[1:0] <= {seq_state_zero[0], ~|seq_state[1:0]};
imu_ready_reset <= !imu_enabled[1] || (seq_state[1:0]!=2'b0) || !imu_when_ready[1]; imu_ready_reset <= !imu_enabled[1] || (seq_state[1:0]!=2'b0) || !imu_when_ready[1];
if (imu_ready_reset) imu_data_ready_d[2:0] <=3'b0; if (imu_ready_reset) imu_data_ready_d[2:0] <=3'b0;
else imu_data_ready_d[2:0] <= {imu_data_ready_d[1:0], miso}; else imu_data_ready_d[2:0] <= {imu_data_ready_d[1:0], miso};
if (imu_ready_reset) imu_data_ready[0] <= 1'b0;
else if (imu_ready_denoise_count[6:0]==7'h0) imu_data_ready[0] <= imu_data_ready_d[2];
if (imu_data_ready_d[2]==imu_data_ready[0]) imu_ready_denoise_count[6:0] <= 7'h7f; // use period LSBs?
else imu_ready_denoise_count[6:0] <= imu_ready_denoise_count[6:0] - 1;
if (imu_ready_reset) imu_data_ready[1] <= 1'b0;
else if (imu_data_ready[0]) imu_data_ready[1] <= 1'b1;
if (imu_ready_reset) imu_data_ready[2] <= 1'b0;
else if (imu_data_ready[1] && !imu_data_ready[0]) imu_data_ready[2] <= 1'b1;
if (imu_ready_reset) imu_data_ready[3] <= 1'b0;
else if (imu_data_ready[2] && imu_data_ready[0]) imu_data_ready[3] <= 1'b1;
if (clk_en[1]) imu_data_ready[4] <= imu_data_ready[3] ;
imu_data_ready[5] <=clk_en[1] && imu_data_ready[3] && !imu_data_ready[4]; // single pulse @clk_en[2]
end
always @ (posedge xclk) begin
imu_enabled[1:0] <= {imu_enabled[0],imu_enabled_mclk};
imu_run[1:0] <= {imu_run[0],imu_run_mclk};
if (imu_ready_reset) imu_data_ready[0] <= 1'b0; imu_when_ready[1:0] <= {imu_when_ready[0],imu_when_ready_mclk};
else if (imu_ready_denoise_count[6:0]==7'h0) imu_data_ready[0] <= imu_data_ready_d[2];
if (imu_data_ready_d[2]==imu_data_ready[0]) imu_ready_denoise_count[6:0] <= 7'h7f; // use period LSBs? if (~imu_run[1:0]) imu_run_confirmed <= 1'b0;
else imu_ready_denoise_count[6:0] <= imu_ready_denoise_count[6:0] - 1; else if (imu_start_first) imu_run_confirmed <= imu_run[1];
imu_start_grant[1:0] <= {imu_enabled_mclk && (imu_start_grant[0] || (imu_start_grant[1] && !imu_start)),imu_start_mclk};
imu_start_first_was <= imu_start_grant[1] && (imu_start_first || imu_start_first_was);
imu_start_first<=clk_en[1] && imu_start_grant[1] && !imu_start_first_was; // single xclk at clk_en[2] time slot
imu_start <=(!imu_when_ready[1] && imu_start_first)||
(!imu_when_ready[1] && imu_run_confirmed && (period_counter[31:0]==32'h1) && clk_en[2]) ||
imu_data_ready[5]; // single pulses at clk_en[3]
if (imu_ready_reset) imu_data_ready[1] <= 1'b0; if (imu_start || imu_when_ready[1]) period_counter[31:0] <= period[31:0];
else if (imu_data_ready[0]) imu_data_ready[1] <= 1'b1; else if (clk_en[3]) period_counter[31:0] <= period_counter[31:0] - 1;
end
always @ (posedge xclk) begin
bit_duration[7:0] <= bit_duration_mclk[7:0];
stall_dur[7:0] <= stall_dur_mclk[7:0];
if (imu_ready_reset) imu_data_ready[2] <= 1'b0; bit_duration_zero <= (bit_duration[7:0] == 8'h0);
else if (imu_data_ready[1] && !imu_data_ready[0]) imu_data_ready[2] <= 1'b1; clk_div[1:0] <= en ? (clk_div[1:0] + 1) : 2'b0;
clk_en[3:0] <= {clk_en[2:0], clk_div[1:0] == 2'h3};
if (bit_duration_zero || (bit_duration_cntr[7:0]==8'h0)) bit_duration_cntr[7:0]<=bit_duration[7:0];
else bit_duration_cntr[7:0] <= bit_duration_cntr[7:0]-1;
clk_en[3:0] <= {clk_en[2:0], bit_duration_cntr[7:0] == 8'h3 }; // change 9'h3 to enforce frequency limit
end
always @ (posedge xclk) begin
pre_seq_counter_zero <= clk_en[1] && (seq_counter[9:0]==10'h0) && (seq_state[1:0]!=2'h0); // active at clk_en[2]
seq_counter_zero <= pre_seq_counter_zero; // active at clk_en[3]
if (!en) seq_state[1:0] <= 2'h0;
else if (imu_start) seq_state[1:0] <= 2'h1;
else if (seq_counter_zero ) seq_state[1:0] <= seq_state[1:0] + 1; // will not count from 0 as seq_counter_zero will be disabled
if (!en) first_prepare <=1'b0;
else if (imu_start) first_prepare <=1'b1;
else if (clk_en[3]) first_prepare <=1'b0;
if (!en) first_prepare_d[1:0] <= 2'b0;
else if (clk_en[3]) first_prepare_d[1:0] <= {first_prepare_d[0],first_prepare};
end_prepare <= pre_seq_counter_zero && (seq_state[1:0]==2'h1);
end_spi <= pre_seq_counter_zero && (seq_state[1:0]==2'h2);
if (!en) seq_counter[9:0] <= 10'h000;
else if (imu_start) seq_counter[9:0] <= config_late_clk?10'h005:10'h003; // should be odd
else if (end_prepare) seq_counter[9:0] <= 10'h39f;
else if (end_spi) seq_counter[9:0] <= 10'h001;
else if (clk_en[3] && (seq_state[1:0]!=2'h0) && !stall) seq_counter[9:0] <= seq_counter[9:0] - 1;
set_mosi_prepare <= clk_en[2] && first_prepare;
// set_mosi_spi <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && (seq_counter[9:5]!=6'h0) && !stall; // last word use zero
set_mosi_spi <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && (seq_counter[9:5] != 0) && !stall; // last word use zero
// no stall before the first word
if (!en) skip_stall <= 1'b0;
else if (end_prepare) skip_stall <= 1'b1;
else if (clk_en[3]) skip_stall <= 1'b0;
set_stall <= clk_en[0] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && !skip_stall && !stall; // @ clk_en[1]
if (imu_ready_reset) imu_data_ready[3] <= 1'b0; if (!en) mosi_reg[15:0] <= 16'h0;
else if (imu_data_ready[2] && imu_data_ready[0]) imu_data_ready[3] <= 1'b1; else if (set_mosi_prepare) mosi_reg[15:0] <= 16'h7fff;
else if (set_mosi_spi) mosi_reg[15:0] <= {1'b0,imu_reg_number[6:1],9'b0};
else if (shift_mosi) mosi_reg[15:0] <= {mosi_reg[14:0],1'b0};
if (clk_en[1]) imu_data_ready[4] <= imu_data_ready[3] ; // stall switches at clk_en[2]
// stall switches at clk_en[1]
if (!en) stall_cntr[7:0] <= 8'h0;
else if (set_stall) stall_cntr[7:0] <= stall_dur[7:0];
else if (clk_en[1]) stall_cntr[7:0] <= stall?(stall_cntr[7:0]-1):8'h0;
imu_data_ready[5] <=clk_en[1] && imu_data_ready[3] && !imu_data_ready[4]; // single pulse @clk_en[2]
end
always @ (posedge xclk) begin
imu_enabled[1:0] <= {imu_enabled[0],imu_enabled_mclk};
imu_run[1:0] <= {imu_run[0],imu_run_mclk};
imu_when_ready[1:0] <= {imu_when_ready[0],imu_when_ready_mclk};
if (~imu_run[1:0]) imu_run_confirmed <= 1'b0;
else if (imu_start_first) imu_run_confirmed <= imu_run[1];
imu_start_grant[1:0] <= {imu_enabled_mclk && (imu_start_grant[0] || (imu_start_grant[1] && !imu_start)),imu_start_mclk};
imu_start_first_was <= imu_start_grant[1] && (imu_start_first || imu_start_first_was);
imu_start_first<=clk_en[1] && imu_start_grant[1] && !imu_start_first_was; // single xclk at clk_en[2] time slot if (!en) stall <= 1'b0;
imu_start <=(!imu_when_ready[1] && imu_start_first)|| else if (set_stall) stall <= (stall_dur[7:0]!=0);
(!imu_when_ready[1] && imu_run_confirmed && (period_counter[31:0]==32'h1) && clk_en[2]) || else if (clk_en[1] && (stall_cntr[7:1]==0)) stall <= 1'b0;
imu_data_ready[5]; // single pulses at clk_en[3]
if (imu_start || imu_when_ready[1]) period_counter[31:0] <= period[31:0];
else if (clk_en[3]) period_counter[31:0] <= period_counter[31:0] - 1;
end
always @ (posedge xclk) begin
bit_duration[7:0] <= bit_duration_mclk[7:0];
stall_dur[7:0] <= stall_dur_mclk[7:0];
bit_duration_zero <= (bit_duration[7:0]==8'h0);
clk_div[1:0]=en?(clk_div[1:0]+1):2'b0;
clk_en[3:0] <= {clk_en[2:0],clk_div[1:0]==2'h3};
if (bit_duration_zero || (bit_duration_cntr[7:0]==8'h0)) bit_duration_cntr[7:0]<=bit_duration[7:0];
else bit_duration_cntr[7:0] <= bit_duration_cntr[7:0]-1;
clk_en[3:0] <= {clk_en[2:0],bit_duration_cntr[7:0]==8'h3}; // change 9'h3 to enforce frequency limit
end
always @ (posedge xclk) begin
pre_seq_counter_zero <= clk_en[1] && (seq_counter[9:0]==10'h0) && (seq_state[1:0]!=2'h0); // active at clk_en[2]
seq_counter_zero <= pre_seq_counter_zero; // active at clk_en[3]
if (!en) seq_state[1:0] <= 2'h0;
else if (imu_start) seq_state[1:0] <= 2'h1;
else if (seq_counter_zero ) seq_state[1:0] <= seq_state[1:0] + 1; // will not count from 0 as seq_counter_zero will be disabled
if (!en) first_prepare <=1'b0;
else if (imu_start) first_prepare <=1'b1;
else if (clk_en[3]) first_prepare <=1'b0;
if (!en) first_prepare_d[1:0] <= 2'b0; if (!en) sda_r <=2'b11;
else if (clk_en[3]) first_prepare_d[1:0] <= {first_prepare_d[0],first_prepare}; else if (clk_en[3]) sda_r <= {sda_r[0], !(first_prepare_d[1] || (seq_counter[0] && (seq_state[1:0]==2'h3)))} ;
end_prepare <= pre_seq_counter_zero && (seq_state[1:0]==2'h1);
end_spi <= pre_seq_counter_zero && (seq_state[1:0]==2'h2);
if (!en) seq_counter[9:0] <= 10'h000; if (!en) pre_scl <=1'b1;
else if (imu_start) seq_counter[9:0] <= config_late_clk?10'h005:10'h003; // should be odd else if (clk_en[2]) pre_scl <= (seq_state[1:0]!=2'h2) || !seq_counter[0] || stall;
else if (end_prepare) seq_counter[9:0] <= 10'h39f;
else if (end_spi) seq_counter[9:0] <= 10'h001; scl_r[0] <= pre_scl;
else if (clk_en[3] && (seq_state[1:0]!=2'h0) && !stall) seq_counter[9:0] <= seq_counter[9:0] - 1; if (!en) scl_r[1] <=1'b1;
set_mosi_prepare <= clk_en[2] && first_prepare; else if (clk_en[3]) scl_r[1] <= scl_r[0];
set_mosi_spi <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && (seq_counter[9:5]!=6'h0) && !stall; // last word use zero
// no stall before the first word
if (!en) skip_stall <= 1'b0; sngl_wire_stb[2:0] <={sngl_wire_stb[1:0], en & ((scl_r[0] ^ pre_scl) | end_prepare)};
else if (end_prepare) skip_stall <= 1'b1;
else if (clk_en[3]) skip_stall <= 1'b0;
// set_stall <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && !skip_stall; // same as set_mosi_spi, but including last
// set_stall <= clk_en[1] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && !skip_stall && !stall; // @ clk_en[2]
set_stall <= clk_en[0] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && !skip_stall && !stall; // @ clk_en[1]
if (!en) mosi_reg[15:0] <= 16'h0;
else if (set_mosi_prepare) mosi_reg[15:0] <= 16'h7fff;
else if (set_mosi_spi) mosi_reg[15:0] <= {1'b0,imu_reg_number[6:1],9'b0};
else if (shift_mosi) mosi_reg[15:0] <= {mosi_reg[14:0],1'b0};
// assign shift_mosi=(clk_en[3] && seq_counter[0] && !stall);
// stall switches at clk_en[2]
// stall switches at clk_en[1]
if (!en) stall_cntr[7:0] <= 8'h0;
else if (set_stall) stall_cntr[7:0] <= stall_dur[7:0];
else if (clk_en[1]) stall_cntr[7:0] <= stall?(stall_cntr[7:0]-1):8'h0;
if (!en) stall <= 1'b0;
else if (set_stall) stall <= (stall_dur[7:0]!=0);
else if (clk_en[1] && (stall_cntr[7:1]==0)) stall <= 1'b0;
if (!en) sngl_wire_r[0]<=1'b0;
else if ((pre_scl ^scl_r[0]) | end_prepare) sngl_wire_r[0]<=1'b1;
if (!en) sda <=1'b1; else if (!mosi_reg[15] || sngl_wire_stb[2] || scl_r[0]) sngl_wire_r[0]<=1'b0;
else if (clk_en[3]) sda <= !(first_prepare_d[1] || (seq_counter[0] && (seq_state[1:0]==2'h3))) ;
if (!en) sda_d <=1'b1;
else if (clk_en[3]) sda_d <= sda; if (imu_start) reg_seq_number[4:0] <= 5'h04;
else if (set_mosi_spi) reg_seq_number[4:0] <= reg_seq_number[4:0] + 1;
// if (!en) scl <=1'b1;
// else if (clk_en[3]) scl <= (seq_state[1:0]!=2'h2) || !seq_counter[0] || stall;
if (!en) pre_scl <=1'b1;
else if (clk_en[2]) pre_scl <= (seq_state[1:0]!=2'h2) || !seq_counter[0] || stall;
scl <= pre_scl; shift_miso <= !scl_r[1] && clk_en[2]; // active at clk_en[3]
sngl_wire_stb[2:0] <={sngl_wire_stb[1:0], en & ((scl ^ pre_scl) | end_prepare)}; if (shift_miso) miso_reg[15:0] <= {miso_reg[14:0], miso};
if (!en) sngl_wire_r[0]<=1'b0;
// else if (!pre_scl && scl) sngl_wire_r[0]<=1'b1;
// else if (!mosi || sngl_wire_stb[2]) sngl_wire_r[0]<=1'b0;
else if ((pre_scl ^scl) | end_prepare) sngl_wire_r[0]<=1'b1;
else if (!mosi_reg[15] || sngl_wire_stb[2] || scl) sngl_wire_r[0]<=1'b0;
last_bit <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h0) && (seq_counter[9:5]!=5'h1c);
if (!en) scl_d <=1'b1; last_bit_ext <= en && (last_bit || (last_bit_ext && !(clk_en[2] && !seq_counter[0])));
else if (clk_en[3]) scl_d <= scl;
if (imu_start) reg_seq_number[4:0] <= 5'h04; pre_imu_wr_buf <=clk_en[1] && last_bit_ext && !seq_counter[0];
else if (set_mosi_spi) reg_seq_number[4:0] <= reg_seq_number[4:0] + 1; imu_wr_buf <= pre_imu_wr_buf;
if (imu_start) imu_in_word[4:0] <= 5'h0;
shift_miso <= !scl_d && clk_en[2]; // active at clk_en[3] else if (imu_wr_buf) imu_in_word[4:0] <= imu_in_word[4:0] + 1;
// shift_miso <= !scl_d && clk_en[2] && !stall; // active at clk_en[3]
last_buf_wr <= (pre_imu_wr_buf && (seq_state[1:0]==2'h3));
if (shift_miso) miso_reg[15:0] <= {miso_reg[14:0], miso};
last_bit <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h0) && (seq_counter[9:5]!=5'h1c);
last_bit_ext <= en && (last_bit || (last_bit_ext && !(clk_en[2] && !seq_counter[0])));
pre_imu_wr_buf <=clk_en[1] && last_bit_ext && !seq_counter[0];
imu_wr_buf <= pre_imu_wr_buf;
if (imu_start) imu_in_word[4:0] <= 5'h0;
else if (imu_wr_buf) imu_in_word[4:0] <= imu_in_word[4:0] + 1;
last_buf_wr <= (pre_imu_wr_buf && (seq_state[1:0]==2'h3));
end end
always @ (negedge xclk) begin always @ (negedge xclk) begin
sngl_wire_r[1] <= sngl_wire_stb[0]; sngl_wire_r[1] <= sngl_wire_stb[0];
end end
always @ (posedge xclk) begin always @ (posedge xclk) begin
if (!en || imu_start) raddr[4:0] <= 5'h0; if (!en || imu_start) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1; else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
if (imu_start || (rd_stb && (raddr[4:0]==5'h1b)) || !en) rdy <= 1'b0; // only 28 words, not 32 if (imu_start || (rd_stb && (raddr[4:0]==5'h1b)) || !en) rdy_r <= 1'b0; // only 28 words, not 32
else if (last_buf_wr) rdy <= 1'b1; else if (last_buf_wr) rdy_r <= 1'b1;
ts <=imu_start; ts_r <=imu_start;
end end
assign imu_in_buf[15:0]= miso_reg[15:0]; assign imu_in_buf[15:0]= miso_reg[15:0];
/*
myRAM_WxD_D #( .DATA_WIDTH(6),.DATA_DEPTH(5)) myRAM_WxD_D #( .DATA_WIDTH(6),.DATA_DEPTH(5))
i_registers2log (.D(di_d[6:1]), i_registers2log (.D(di_d[6:1]),
.WE(we_ra), .WE(we_ra),
.clk(!sclk), .clk(!mclk),
.AW(wa[4:0]), .AW(wa[4:0]),
.AR(reg_seq_number[4:0]), .AR(reg_seq_number[4:0]),
.QW(), .QW(),
.QR(imu_reg_number[6:1])); .QR(imu_reg_number[6:1]));
*/
reg [5:0] registers2log_ram[0:31];
always @ (posedge mclk) if (we_ra) begin
registers2log_ram[wa[4:0]] <= din[6:1];
end
assign imu_reg_number[6:1] = registers2log_ram[reg_seq_number[4:0]];
/*
myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(5)) myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(5))
i_odbuf0 (.D(imu_in_buf[15:0]), i_odbuf0 (.D(imu_in_buf[15:0]),
.WE(imu_wr_buf), .WE(imu_wr_buf),
...@@ -366,7 +366,12 @@ module imu_spi393( ...@@ -366,7 +366,12 @@ module imu_spi393(
.AR(raddr[4:0]), .AR(raddr[4:0]),
.QW(), .QW(),
.QR(rdata[15:0])); .QR(rdata[15:0]));
*/
reg [15:0] odbuf0_ram[0:31];
always @ (posedge xclk) if (imu_wr_buf) begin
odbuf0_ram[imu_in_word[4:0]] <= imu_in_buf[15:0];
end
assign rdata[15:0] = odbuf0_ram[raddr[4:0]];
endmodule endmodule
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: Acquire timestmps for events * Description: Acquire timestmps for events
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* imu_timestamps393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: arbiter for the event_logger * Description: arbiter for the event_logger
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* logger_arbiter393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -21,19 +21,19 @@ ...@@ -21,19 +21,19 @@
`timescale 1ns/1ps `timescale 1ns/1ps
module logger_arbiter393( module logger_arbiter393(
xclk, // 80 MHz, posedge input xclk, // half frequency (80 MHz nominal)
rst, // module reset input rst, // module reset (sync)
ts_rq_in, // in requests for timestamp (single-cycle - just leading edge ) input [3:0] ts_rq_in, // in requests for timestamp (single-cycle - just leading edge )
ts_rq, // out request for timestamp, to timestmp module output [3:0] ts_rq, // out request for timestamp, to timestmp module
ts_grant, // granted ts requests from timestamping module input [3:0] ts_grant, // granted ts requests from timestamping module
rdy, // channels ready (leading edge - became ready, trailing - no more data, use zero) input [3:0] rdy, // channels ready (leading edge - became ready, trailing - no more data, use zero)
nxt, // pulses to modules to output next word output reg [3:0] nxt, // pulses to modules to output next word
channel, // decoded channel number (2 bits) output [1:0] channel, // decoded channel number (2 bits)
ts_sel, // select timestamp word to be output (0..3) output [1:0] ts_sel, // select timestamp word to be output (0..3)
ts_en, // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready) output 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) output reg 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 output [23:0] sample_counter);// number of 64-byte samples logged
/*
input xclk; // half frequency (80 MHz nominal) input xclk; // half frequency (80 MHz nominal)
input rst; // reset module input rst; // reset module
input [ 3:0] ts_rq_in; // in requests for timestamp (sinlgle-cycle) input [ 3:0] ts_rq_in; // in requests for timestamp (sinlgle-cycle)
...@@ -46,102 +46,88 @@ module logger_arbiter393( ...@@ -46,102 +46,88 @@ module logger_arbiter393(
output ts_en; // 1 - use timestamp, 0 - channel data (or 16'h0 if !ready) 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 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 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; reg [3:0] ts_rq_in_d;
/* reg [3:0] ts_rq_r;
ts_rq_reset[3:0] <= start? { channel[1] & channel[0], reg [3:0] ts_valid;
channel[1] & ~channel[0], // reg [3:0] ts_rq_reset;
~channel[1] & channel[0], reg [3:0] channels_ready;// channels granted and ready
~channel[1] & ~channel[0]}:4'h0; 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])
dv <= busy || seq_cntr_last; reg [1:0] channel_r;
// reg start; Not used!
inc_sample_counter <= seq_cntr_last; reg busy;
wire wstart;
if (rst) sample_counter[23:0] <= 24'h0; reg ts_en_r;
else if (inc_sample_counter) sample_counter[23:0] <= sample_counter[23:0] +1; reg [4:0] seq_cntr;
reg seq_cntr_last;
reg [1:0] ts_sel_r;
end // reg dv;
reg inc_sample_counter;
reg [23:0] sample_counter_r;// number of 64-byte samples logged
// reg [ 3:0] nxt;
reg pre_nxt;
reg [ 3:0] chn_servicing; //1-hot channel being service
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]);
assign sample_counter = sample_counter_r;
assign ts_rq = ts_rq_r;
assign channel = channel_r;
assign ts_en = ts_en_r;
assign ts_sel = ts_sel_r;
always @ (posedge xclk) begin
ts_rq_in_d[3:0] <= ts_rq_in[3:0];
if (wstart) channel_r[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_r[3:0] <= 4'h0;
else ts_rq_r[3:0] <= ~ts_grant & ( wts_rq[3:0] | ts_rq_r[3:0]);
if (rst) ts_valid[3:0] <= 4'h0;
else ts_valid[3:0] <= (ts_grant[3:0] | (ts_valid & ~wts_rq[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; Not used !
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'h0;
else seq_cntr[4:0] <= seq_cntr[4:0] + 1;
seq_cntr_last <= (seq_cntr[4:0]=='h1e);
if (wstart) ts_en_r <=1'b1;
else if (seq_cntr[1:0]==2'h3) ts_en_r <=1'b0;
if (!ts_en_r) ts_sel_r[1:0] <= 2'h0;
else ts_sel_r[1:0] <= ts_sel_r[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? chn_servicing[3:0]:4'h0;
dv <= busy || seq_cntr_last;
inc_sample_counter <= seq_cntr_last;
if (rst) sample_counter_r[23:0] <= 24'h0;
else if (inc_sample_counter) sample_counter_r[23:0] <= sample_counter_r[23:0] +1;
end
endmodule endmodule
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: Decode some of the NMEA sentences (to compress them) * Description: Decode some of the NMEA sentences (to compress them)
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* nmea_decoder393.v is free software; you can redistribute it and/or modify * nmea_decoder393.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -21,315 +21,270 @@ ...@@ -21,315 +21,270 @@
`timescale 1ns/1ps `timescale 1ns/1ps
module nmea_decoder393( module nmea_decoder393(
sclk, // system clock, @negedge input mclk, // system clock, posedge
we, // registers write enable (@negedge sclk) input xclk, // half frequency (80 MHz nominal)
wa, // registers write address input we, // registers write enable (@negedge mclk)
wd, // write data input [4:0] wa, // registers write address
xclk, // 80MHz, posedge input [7:0] wd, // write data
start, // start of the serail message input start, // start of the serail message
rs232_wait_pause,// may be used as reset for decoder input rs232_wait_pause,// may be used as reset for decoder
start_char, // serial character start (single pulse) input start_char, // serial character start (single pulse)
nmea_sent_start, // serial character start (single pulse) output reg nmea_sent_start, // serial character start (single pulse)
ser_di, // serial data in (LSB first) input ser_di, // serial data in (LSB first)
ser_stb,// serial data strobe, single-cycle, first cycle after ser_di valid input ser_stb,// serial data strobe, single-cycle, first cycle after ser_di valid
rdy, // encoded nmea data ready output rdy, // encoded nmea data ready
rd_stb, // encoded nmea data read strobe (increment address) input rd_stb, // encoded nmea data read strobe (increment address)
rdata, // encoded data (16 bits) output [15:0] rdata, // encoded data (16 bits)
ser_rst, input ser_rst,
debug); output [23:0] debug);
input sclk; // system clock, @negedge
input we; // registers write enable (@negedge sclk)
input [4:0] wa; // registers write address
input [7:0] wd; // write data
input xclk; // 80MHz, posedge
input start; // start of the serail message (after pause only)
input rs232_wait_pause;// may be used as reset for decoder
input start_char; // serial character start (single pulse)
output nmea_sent_start; // serial character start (single pulse), will repeat until got "$" and the sentence recognized
input ser_di; // serial data in (LSB first)
input ser_stb;// serial data strobe, single-cycle, ends 2 cycles after ser_di valid
output rdy; // encoded nmea data ready
input rd_stb; // encoded nmea data read strobe (increment address)
output [15:0] rdata; // encoded data (16 bits)
input ser_rst; reg [ 9:0] bitnum;
output[23:0] debug; reg gp_exp_bit;
reg valid; // so far it is a valid sentence
reg [3:0] sentence1hot; // one-hot sentence, matching first 6 bytes ($GPxxx)
reg restart; // reset byte number if the first byte was not "$"
reg start_d;
reg [3:0] stb; // ser_stb delayed
reg msb,bits37,bit3;
reg vfy_dollar;
reg vfy_gp;
reg vfy_sel_sent;
reg vfy_first_comma; // first comma after $GPxxx
reg proc_fields;
reg last_vfy_gp; // delayed by 1 cycle from bit counters
reg last_vfy_sent; // delayed by 1 cycle from bit counters
reg lsbs5; // 5 LSBs during reading 3 last letters in $GPxxx
reg [3:0] gpxxx_addr;
wire [3:1] sentence1hot_pri; // sentence1hot made really one-hot
reg [1:0] sentence; // decoded sentence number (0..3)
reg [4:0] format_length; // number of fields in the sentence
reg [4:0] format_length_plus_7;
reg [4:0] format_field; // current number of the field in the sentence
wire start_format;
reg read_format_length; //, read_format_length_d;
reg read_format_byte;
reg shift_format_byte;
reg format_over;
reg sentence_over;
reg [7:0] format_byte;
reg [7:1] last_byte;
wire wcomma; // comma
wire weof; //asterisk, or cr/lf (<0x10)
wire wsep; //any separator
reg [3:0] nibble;
reg [3:0] nibble_pre;
wire [7:0] wbyte;
reg nibble_stb;
reg first_byte_in_field;
reg [1:0] extra_nibble; // empty byte field - send two 4'hf nibbles
reg [6:0] nibble_count;
reg [4:0] raddr;
wire [3:0] gpxxx_w_one;
wire [7:0] format_data;
wire w_sentence_over;
reg [4:0] last_word_written; // number of the last word (4 nibbles) written - used ro deassert rdy (garbage after)
reg rdy_r=1'b0;
reg save_sent_number;
reg [ 7:0] debug0;
reg [15:0] debug1;
reg [15:0] debug1_or;
assign debug[23:0] = {1'b0,
proc_fields,
vfy_first_comma,
vfy_sel_sent,
vfy_gp,
vfy_dollar,
bitnum[9:0],
debug0[7:0]};
reg [ 9:0] bitnum; assign sentence1hot_pri[3:1] = {sentence1hot[3]& ~|sentence1hot[2:0],
reg gp_exp_bit; sentence1hot[2]& ~|sentence1hot[1:0],
reg valid; // so far valid sentence sentence1hot[1]& ~sentence1hot[0]};
reg [3:0] sentence1hot; // one-hot sentence, matching first 6 bytes ($GPxxx) assign start_format= (vfy_first_comma && (sentence1hot[3:0]!=4'h0) && (stb[3] && msb));
reg restart; // reset byte number if the first byte was not "$"
reg start_d;
reg [3:0] stb; // ser_stb delayed
reg msb,bits37,bit3;
reg vfy_dollar;
reg vfy_gp;
reg vfy_sel_sent;
reg vfy_first_comma; // first comma after $GPxxx
reg proc_fields; assign wbyte[7:0] = {ser_di,last_byte[7:1]}; // valid up to stb[3];
reg last_vfy_gp; // delayed by 1 cycle from bit counters assign wcomma = proc_fields && msb && (wbyte[7:0]==8'h2c);
reg last_vfy_sent; // delayed by 1 cycle from bit counters assign weof = proc_fields && msb && ((wbyte[7:0]==8'h2a) || (wbyte[7:4]==4'h0)); // 0x2a or 0x0? (<0x10)
// reg [3:0] sent_sel_cntr; // counts 3 times to 5, as $GPxxx - each 'x' is an upper case latter (0x40..0x5f) assign wsep = wcomma || weof;
reg lsbs5; // 5 LSBs during reading 3 last letters in $GPxxx assign w_sentence_over = wsep && (format_field[4:0]==format_length_plus_7[4:0]);
reg [3:0] gpxxx_addr; assign rdy = rdy_r;
wire [3:1] sentence1hot_pri; // sentence1hot made really one-hot
reg [1:0] sentence; // decoded sentence number (0..3)
reg [4:0] format_length; // number of fields in the sentence
reg [4:0] format_length_plus_7;
reg [4:0] format_field; // current number of the field in the sentence
wire start_format;
reg read_format_length; //, read_format_length_d;
reg read_format_byte;
reg shift_format_byte;
reg format_over;
reg sentence_over;
reg [7:0] format_byte;
reg [7:1] last_byte;
wire wcomma; // comma
wire weof; //asterisk, or cr/lf (<0x10)
wire wsep; //any separator
reg [3:0] nibble;
reg [3:0] nibble_pre;
wire [7:0] wbyte;
reg nibble_stb;
reg first_byte_in_field;
reg [1:0] extra_nibble; // empty byte field - send two 4'hf nibbles
reg [6:0] nibble_count;
wire [15:0] rdata; // encoded data (16 bits)
reg [ 4:0] raddr;
wire [3:0] gpxxx_w_one;
wire [7:0] format_data;
wire w_sentence_over;
reg [4:0] last_word_written; // number of the last word (4 nibbles) written - used ro deassert rdy (garbage after)
reg rdy=1'b0;
reg nmea_sent_start;
reg save_sent_number;
// input ser_rst;
reg [ 7:0] debug0;
reg [15:0] debug1;
reg [15:0] debug1_or;
wire [23:0] debug;
// assign debug[23:0] = {debug1[15:0],debug0[7:0]};
assign debug[23:0] = {1'b0,
proc_fields,
vfy_first_comma,
vfy_sel_sent,
vfy_gp,
vfy_dollar,
bitnum[9:0],
debug0[7:0]};
assign sentence1hot_pri[3:1]={sentence1hot[3]& ~|sentence1hot[2:0],
sentence1hot[2]& ~|sentence1hot[1:0],
sentence1hot[1]& ~sentence1hot[0]};
// assign start_format=(last_vfy_sent && (sentence1hot[3:0]!=4'h0) && (stb[3] && msb));
assign start_format=(vfy_first_comma && (sentence1hot[3:0]!=4'h0) && (stb[3] && msb));
assign wbyte[7:0]={ser_di,last_byte[7:1]}; // valid up to stb[3];
assign wcomma= proc_fields && msb && (wbyte[7:0]==8'h2c);
assign weof= proc_fields && msb && ((wbyte[7:0]==8'h2a) || (wbyte[7:4]==4'h0)); // 0x2a or 0x0? (<0x10)
assign wsep= wcomma || weof;
// assign w_sentence_over=wsep && (format_field[2:0]==format_length[2:0]) && (format_field[4:3]==(format_length[4:3]+1));
assign w_sentence_over=wsep && (format_field[4:0]==format_length_plus_7[4:0]);
//format_length_plus_7 //format_length_plus_7
always @ (posedge xclk) begin always @ (posedge xclk) begin
if (ser_rst) debug0 [7:0] <= 8'b0; if (ser_rst) debug0 [7:0] <= 8'b0;
else debug0 [7:0] <=debug0 [7:0] | {rdy, else debug0 [7:0] <=debug0 [7:0] | {rdy_r,
proc_fields, proc_fields,
shift_format_byte, shift_format_byte,
start_format, start_format,
vfy_first_comma, vfy_first_comma,
vfy_sel_sent, vfy_sel_sent,
vfy_gp, vfy_gp,
vfy_dollar}; vfy_dollar};
if (ser_rst) debug1 [15:0] <= 16'b0; if (ser_rst) debug1 [15:0] <= 16'b0;
else if (stb[1] && vfy_sel_sent && lsbs5) debug1 [15:0] <= debug1 [15:0] | debug1_or [15:0]; else if (stb[1] && vfy_sel_sent && lsbs5) debug1 [15:0] <= debug1 [15:0] | debug1_or [15:0];
case (gpxxx_addr[3:0]) case (gpxxx_addr[3:0])
4'h0: debug1_or[15:0] <= 16'h0001; 4'h0: debug1_or[15:0] <= 16'h0001;
4'h1: debug1_or[15:0] <= 16'h0002; 4'h1: debug1_or[15:0] <= 16'h0002;
4'h2: debug1_or[15:0] <= 16'h0004; 4'h2: debug1_or[15:0] <= 16'h0004;
4'h3: debug1_or[15:0] <= 16'h0008; 4'h3: debug1_or[15:0] <= 16'h0008;
4'h4: debug1_or[15:0] <= 16'h0010; 4'h4: debug1_or[15:0] <= 16'h0010;
4'h5: debug1_or[15:0] <= 16'h0020; 4'h5: debug1_or[15:0] <= 16'h0020;
4'h6: debug1_or[15:0] <= 16'h0040; 4'h6: debug1_or[15:0] <= 16'h0040;
4'h7: debug1_or[15:0] <= 16'h0080; 4'h7: debug1_or[15:0] <= 16'h0080;
4'h8: debug1_or[15:0] <= 16'h0100; 4'h8: debug1_or[15:0] <= 16'h0100;
4'h9: debug1_or[15:0] <= 16'h0200; 4'h9: debug1_or[15:0] <= 16'h0200;
4'ha: debug1_or[15:0] <= 16'h0400; 4'ha: debug1_or[15:0] <= 16'h0400;
4'hb: debug1_or[15:0] <= 16'h0800; 4'hb: debug1_or[15:0] <= 16'h0800;
4'hc: debug1_or[15:0] <= 16'h1000; 4'hc: debug1_or[15:0] <= 16'h1000;
4'hd: debug1_or[15:0] <= 16'h2000; 4'hd: debug1_or[15:0] <= 16'h2000;
4'he: debug1_or[15:0] <= 16'h4000; 4'he: debug1_or[15:0] <= 16'h4000;
4'hf: debug1_or[15:0] <= 16'h8000; 4'hf: debug1_or[15:0] <= 16'h8000;
endcase endcase
stb[3:0] <= {stb[2:0], ser_stb}; stb[3:0] <= {stb[2:0], ser_stb};
start_d <= start; start_d <= start;
restart <= start || sentence_over || stb[2] && msb && ((!valid && (vfy_dollar || last_vfy_gp || vfy_first_comma)) || // may abort earlier (use vfy_gp) restart <= start || sentence_over || stb[2] && msb && ((!valid && (vfy_dollar || last_vfy_gp || vfy_first_comma)) || // may abort earlier (use vfy_gp)
((sentence1hot==4'h0) && last_vfy_sent)); // may abort earlier (use vfy_sel_sent) ((sentence1hot==4'h0) && last_vfy_sent)); // may abort earlier (use vfy_sel_sent)
if (start_d) bitnum[2:0] <= 3'h0; if (start_d) bitnum[2:0] <= 3'h0;
else if (stb[3]) bitnum[2:0] <= bitnum[2:0] + 1; else if (stb[3]) bitnum[2:0] <= bitnum[2:0] + 1;
if (start_d) msb <= 1'b0; if (start_d) msb <= 1'b0;
else if (stb[3]) msb <= (bitnum[2:0] ==3'h6); else if (stb[3]) msb <= (bitnum[2:0] ==3'h6);
if (start_d) bit3 <= 1'b0; if (start_d) bit3 <= 1'b0;
else if (stb[3]) bit3 <= (bitnum[2:0] ==3'h2); else if (stb[3]) bit3 <= (bitnum[2:0] ==3'h2);
if (start_d) bits37 <= 1'b0;
else if (stb[3]) bits37 <= (bitnum[1:0] ==2'h2);
if (start_d) lsbs5 <= 1'b1;
else if (stb[3]) lsbs5 <= !bitnum[2] || (bitnum[2:0] ==3'h7);
if (restart) bitnum[9:3] <= 'h0;
else if (stb[3] && msb) bitnum[9:3] <= bitnum[9:3] + 1;
if (restart || rs232_wait_pause) vfy_dollar <= 1'b1; // byte 0
else if (stb[3] && msb) vfy_dollar <= 1'b0;
last_vfy_gp <= vfy_gp && !bitnum[3];
if (start_d) bits37 <= 1'b0; if (restart) vfy_gp <= 1'b0;
else if (stb[3]) bits37 <= (bitnum[1:0] ==2'h2); else if (stb[3] && msb) vfy_gp <= (valid && vfy_dollar) || (vfy_gp && !last_vfy_gp); // bytes 1-2
last_vfy_sent <= vfy_sel_sent && (bitnum[3] && bitnum[5]);
if (start_d) lsbs5 <= 1'b1; if (restart) vfy_sel_sent <= 1'b0;
else if (stb[3]) lsbs5 <= !bitnum[2] || (bitnum[2:0] ==3'h7); else if (stb[3] && msb) vfy_sel_sent <= (valid && last_vfy_gp) || (vfy_sel_sent && !last_vfy_sent); // bytes 3,4,5
if (restart) vfy_first_comma <= 1'b0;
else if (stb[3] && msb) vfy_first_comma <= last_vfy_sent;
if (restart) valid <= 1'b1; // ready @ stb[2]
else if (stb[1] && (ser_di!=gp_exp_bit) &&
(vfy_dollar || vfy_gp || vfy_first_comma || (vfy_sel_sent && !lsbs5))) valid <= 1'b0;
if (restart) bitnum[9:3] <= 'h0;
else if (stb[3] && msb) bitnum[9:3] <= bitnum[9:3] + 1; if (!vfy_sel_sent) gpxxx_addr[3:0] <= 4'h0;
else if (lsbs5 &&stb[3]) gpxxx_addr[3:0] <= gpxxx_addr[3:0] + 1;
if (vfy_gp) sentence1hot[3:0] <= 4'hf;
else if (stb[1] && vfy_sel_sent && lsbs5) sentence1hot[3:0] <= sentence1hot & (ser_di?(gpxxx_w_one[3:0]): (~gpxxx_w_one[3:0]));
if (restart || rs232_wait_pause) vfy_dollar <= 1'b1; // byte 0 if (last_vfy_sent && stb[3] && msb) sentence[1:0] <= {sentence1hot_pri[3] | sentence1hot_pri[2], sentence1hot_pri[3] | sentence1hot_pri[1]};
else if (stb[3] && msb) vfy_dollar <= 1'b0;
if (restart || sentence_over) proc_fields <=1'b0;
else if (start_format) proc_fields <=1'b1;
if (!proc_fields) format_field[4:0] <= 5'h0;
else if (read_format_length) format_field[4:0] <= 5'h8;
else if (format_over) format_field[4:0] <= format_field[4:0] + 1;
last_vfy_gp <= vfy_gp && !bitnum[3]; format_length_plus_7[4:0] <= format_length[4:0]+7;
if (restart) vfy_gp <= 1'b0;
else if (stb[3] && msb) vfy_gp <= (valid && vfy_dollar) || (vfy_gp && !last_vfy_gp); // bytes 1-2
last_vfy_sent <= vfy_sel_sent && (bitnum[3] && bitnum[5]); if (start_format) first_byte_in_field <=1'b1;
if (restart) vfy_sel_sent <= 1'b0; else if (stb[3] && msb) first_byte_in_field <= format_over;
else if (stb[3] && msb) vfy_sel_sent <= (valid && last_vfy_gp) || (vfy_sel_sent && !last_vfy_sent); // bytes 3,4,5
read_format_length <= start_format;
if (read_format_length) format_length[4:0] <= format_data[4:0];
read_format_byte <= read_format_length || (format_over && format_field[2:0]==3'h7); // @stb[4]
if (restart) vfy_first_comma <= 1'b0; shift_format_byte <= format_over; // @stb[4]
else if (stb[3] && msb) vfy_first_comma <= last_vfy_sent;
if (restart) valid <= 1'b1; // ready @ stb[2]
else if (stb[1] && (ser_di!=gp_exp_bit) &&
(vfy_dollar || vfy_gp || vfy_first_comma || (vfy_sel_sent && !lsbs5))) valid <= 1'b0;
if (read_format_byte) format_byte[7:0] <= format_data[7:0];
if (!vfy_sel_sent) gpxxx_addr[3:0] <= 4'h0; else if (shift_format_byte) format_byte[7:0] <= {1'b0,format_byte[7:1]};
else if (lsbs5 &&stb[3]) gpxxx_addr[3:0] <= gpxxx_addr[3:0] + 1;
if (vfy_gp) sentence1hot[3:0] <= 4'hf;
else if (stb[1] && vfy_sel_sent && lsbs5) sentence1hot[3:0] <= sentence1hot & (ser_di?(gpxxx_w_one[3:0]): (~gpxxx_w_one[3:0]));
if (last_vfy_sent && stb[3] && msb) sentence[1:0] <= {sentence1hot_pri[3] | sentence1hot_pri[2], sentence1hot_pri[3] | sentence1hot_pri[1]}; // format_byte[0] - current format
if (stb[3]) last_byte[7:1] <= {ser_di,last_byte[7:2]};
if (restart || sentence_over) proc_fields <=1'b0;
else if (start_format) proc_fields <=1'b1; format_over <= stb[2] && wsep;
if (!proc_fields) format_field[4:0] <= 5'h0; sentence_over <= stb[2] && (weof || w_sentence_over);
else if (read_format_length) format_field[4:0] <= 5'h8;
else if (format_over) format_field[4:0] <= format_field[4:0] + 1;
format_length_plus_7[4:0] <= format_length[4:0]+7;
if (start_format) first_byte_in_field <=1'b1;
else if (stb[3] && msb) first_byte_in_field <= format_over;
read_format_length <= start_format; if (bits37 && stb[3]) nibble_pre[3:0] <= last_byte[4:1]; // always OK
if (read_format_length) format_length[4:0] <= format_data[4:0]; if (stb[3] && bit3) nibble[3:0] <= nibble_pre[3:0];
else if (stb[3] && msb && wsep && (first_byte_in_field || !format_byte[0])) nibble[3:0] <= 4'hf;
else if (stb[3] && msb && format_byte[0]) nibble[3:0] <= {wsep,nibble_pre[2:0]};
else if (save_sent_number) nibble[3:0] <= {2'b0,sentence[1:0]};
//first_byte_in_field
read_format_byte <= read_format_length || (format_over && format_field[2:0]==3'h7); // @stb[4] extra_nibble[1:0] <= {extra_nibble[0],
shift_format_byte <= format_over; // @stb[4] msb && wsep && first_byte_in_field & proc_fields & stb[3] & format_byte[0]};// active at stb[4], stb[5]
if (read_format_byte) format_byte[7:0] <= format_data[7:0];
else if (shift_format_byte) format_byte[7:0] <= {1'b0,format_byte[7:1]};
// format_byte[0] - current format
if (stb[3]) last_byte[7:1] <= {ser_di,last_byte[7:2]};
format_over <= stb[2] && wsep;
// sentence_over <= stb[2] && (weof || (wsep && w_sentence_over));
sentence_over <= stb[2] && (weof || w_sentence_over);
if (bits37 && stb[3]) nibble_pre[3:0] <= last_byte[4:1]; // always OK save_sent_number <= start_format; // valid at stb[4]
if (stb[3] && bit3) nibble[3:0] <= nibble_pre[3:0]; nibble_stb <= save_sent_number ||
else if (stb[3] && msb && wsep && (first_byte_in_field || !format_byte[0])) nibble[3:0] <= 4'hf; (proc_fields && ((stb[3] && bit3 && !first_byte_in_field) ||
else if (stb[3] && msb && format_byte[0]) nibble[3:0] <= {wsep,nibble_pre[2:0]}; (stb[3] && msb && !first_byte_in_field && format_byte[0]) ||
else if (save_sent_number) nibble[3:0] <= {2'b0,sentence[1:0]}; (stb[3] && msb && wsep))) || extra_nibble[1]; // extra_nibble[1] will repeat 4'hf
//first_byte_in_field if (start_format) nibble_count[6:0] <= 7'h0;
else if (nibble_stb) nibble_count[6:0] <= nibble_count[6:0] + 1;
if (sentence_over) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
extra_nibble[1:0] <= {extra_nibble[0], if (nibble_stb) last_word_written[4:0]<=nibble_count[6:2];
msb && wsep && first_byte_in_field & proc_fields & stb[3] & format_byte[0]};// active at stb[4], stb[5]
save_sent_number <= start_format; // valid at stb[4]
nibble_stb <= save_sent_number ||
(proc_fields && ((stb[3] && bit3 && !first_byte_in_field) ||
(stb[3] && msb && !first_byte_in_field && format_byte[0]) ||
(stb[3] && msb && wsep))) || extra_nibble[1]; // extra_nibble[1] will repeat 4'hf
if (start_format) nibble_count[6:0] <= 7'h0;
else if (nibble_stb) nibble_count[6:0] <= nibble_count[6:0] + 1;
// if (weof && stb[3]) raddr[4:0] <= 5'h0;
if (sentence_over) raddr[4:0] <= 5'h0;
else if (rd_stb) raddr[4:0] <= raddr[4:0] + 1;
if (nibble_stb) last_word_written[4:0]<=nibble_count[6:2];
if (start || vfy_first_comma || (rd_stb && ((raddr[4:0]==5'h1b) ||(raddr[4:0]==last_word_written[4:0])))) rdy <= 1'b0;
else if (sentence_over) rdy <= 1'b1;
nmea_sent_start <= start_char && vfy_dollar;
end
// output buffer to hold up to 32 16-bit words. Written 1 nibble at a time
myRAM_WxD_D #( .DATA_WIDTH(4),.DATA_DEPTH(5))
i_odbuf0 (.D(nibble[3:0]),
.WE(nibble_stb && (nibble_count[1:0]==2'h0)),
.clk(xclk),
.AW(nibble_count[6:2]),
.AR(raddr[4:0]),
.QW(),
.QR(rdata[3:0]));
myRAM_WxD_D #( .DATA_WIDTH(4),.DATA_DEPTH(5)) if (start || vfy_first_comma || (rd_stb && ((raddr[4:0]==5'h1b) ||(raddr[4:0]==last_word_written[4:0])))) rdy_r <= 1'b0;
i_odbuf1 (.D(nibble[3:0]), else if (sentence_over) rdy_r <= 1'b1;
.WE(nibble_stb && (nibble_count[1:0]==2'h1)),
.clk(xclk),
.AW(nibble_count[6:2]),
.AR(raddr[4:0]),
.QW(),
.QR(rdata[7:4]));
myRAM_WxD_D #( .DATA_WIDTH(4),.DATA_DEPTH(5)) nmea_sent_start <= start_char && vfy_dollar;
i_odbuf2 (.D(nibble[3:0]), end
.WE(nibble_stb && (nibble_count[1:0]==2'h2)), // output buffer to hold up to 32 16-bit words. Written 1 nibble at a time
.clk(xclk), // replaced 6 RAM modules with inferred ones
.AW(nibble_count[6:2]), reg [3:0] odbuf0_ram[0:31];
.AR(raddr[4:0]), reg [3:0] odbuf1_ram[0:31];
.QW(), reg [3:0] odbuf2_ram[0:31];
.QR(rdata[11:8])); reg [3:0] odbuf3_ram[0:31];
always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h0)) odbuf0_ram[nibble_count[6:2]] <= nibble[3:0];
always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h1)) odbuf1_ram[nibble_count[6:2]] <= nibble[3:0];
always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h2)) odbuf2_ram[nibble_count[6:2]] <= nibble[3:0];
always @ (posedge xclk) if (nibble_stb && (nibble_count[1:0] == 2'h3)) odbuf3_ram[nibble_count[6:2]] <= nibble[3:0];
myRAM_WxD_D #( .DATA_WIDTH(4),.DATA_DEPTH(5)) assign rdata[ 3: 0] = odbuf0_ram[raddr[4:0]];
i_odbuf3 (.D(nibble[3:0]), assign rdata[ 7: 4] = odbuf1_ram[raddr[4:0]];
.WE(nibble_stb && (nibble_count[1:0]==2'h3)), assign rdata[11: 8] = odbuf2_ram[raddr[4:0]];
.clk(xclk), assign rdata[15:12] = odbuf3_ram[raddr[4:0]];
.AW(nibble_count[6:2]),
.AR(raddr[4:0]),
.QW(),
.QR(rdata[15:12]));
myRAM_WxD_D #( .DATA_WIDTH(4),.DATA_DEPTH(4)) reg [3:0] gpxxx_ram[0:3];
i_gpxxx (.D(wd[3:0]), always @ (posedge mclk) if (we & ~wa[4]) gpxxx_ram[wa[3:0]] <= wd[3:0];
.WE(we & ~wa[4]), // we_d, decoded sub_address assign gpxxx_w_one[3:0] = gpxxx_ram[gpxxx_addr[3:0]];
.clk(!sclk),
.AW(wa[3:0]),
.AR(gpxxx_addr[3:0]),
.QW(),
.QR(gpxxx_w_one[3:0]));
// for each of the four sentences first byte - number of field (<=24), next 3 bytes - formats for each nmea filed (LSB first): // for each of the four sentences first byte - number of field (<=24), next 3 bytes - formats for each nmea filed (LSB first):
// 0 - nibble ("-" -> 0xd, "." -> 0xe), terminated with 0xf // 0 - nibble ("-" -> 0xd, "." -> 0xe), terminated with 0xf
// 1 - byte (2 nibbles), all bytes but last have MSB clear, last - set. // 1 - byte (2 nibbles), all bytes but last have MSB clear, last - set.
// No padding of nibbles to byte borders, bytes are encoded as 2 nibbles // No padding of nibbles to byte borders, bytes are encoded as 2 nibbles
myRAM_WxD_D #( .DATA_WIDTH(8),.DATA_DEPTH(4)) reg [7:0] format_ram[0:3];
i_format (.D(wd[7:0]), always @ (posedge mclk) if (we & wa[4]) format_ram[wa[3:0]] <= wd[7:0];
.WE(we & wa[4]), // we_d, decoded sub_address assign format_data[7:0] = format_ram[{sentence[1:0],format_field[4:3]}];
.clk(!sclk),
.AW(wa[3:0]),
.AR({sentence[1:0],format_field[4:3]}),
.QW(),
.QR(format_data[7:0]));
// ROM to decode "$GP" // ROM to decode "$GP"
always @ (posedge xclk) begin always @ (posedge xclk) begin
if (ser_stb) case ({(bitnum[4] & ~ vfy_sel_sent) | vfy_first_comma, bitnum[3] | vfy_sel_sent | vfy_first_comma, bitnum[2:0]}) // during vfy_sel_sent will point to 1 ('G') if (ser_stb) case ({(bitnum[4] & ~ vfy_sel_sent) | vfy_first_comma, bitnum[3] | vfy_sel_sent | vfy_first_comma, bitnum[2:0]}) // during vfy_sel_sent will point to 1 ('G')
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: andrey * Author: andrey
* Description: rs232 receiver * Description: rs232 receiver
* *
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> . * Copyright (c) 2015 Elphel, Inc.
* rs232_rcv393.v is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
...@@ -21,109 +21,91 @@ ...@@ -21,109 +21,91 @@
`timescale 1ns/1ps `timescale 1ns/1ps
module rs232_rcv393( module rs232_rcv393(
xclk, // half frequency (80 MHz nominal) input xclk, // half frequency (80 MHz nominal)
bitHalfPeriod, // half of the serial bit duration, in xclk cycles input [15:0] bitHalfPeriod, // half of the serial bit duration, in xclk cycles
ser_di, // rs232 (ttl) serial data in input ser_di, // rs232 (ttl) serial data in
ser_rst, // reset (force re-sync) input ser_rst, // reset (force re-sync)
ts_stb, // strobe timestamp (start of message) (reset bit counters in nmea decoder) output ts_stb, // strobe timestamp (start of message) (reset bit counters in nmea decoder)
wait_just_pause,// may be used as reset for decoder output reg wait_just_pause,// may be used as reset for decoder
start, // serial character start (single pulse) output start, // serial character start (single pulse)
// char, // byte out output reg ser_do, // serial data out(@posedge xclk) LSB first!
// char_stb); // char strobe (@posedge xclk) output reg ser_do_stb, // output data strobe (@posedge xclk), first cycle after ser_do becomes valid
ser_do, // serial data out(@posedge xclk) LSB first! // Next outputs are just fro debugging
ser_do_stb, // output data strobe (@posedge xclk), first cycle after ser_do becomes valid output [4:0] debug, // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset
debug, // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset output [15:0] bit_dur_cntr,
bit_dur_cntr, output [4:0] bit_cntr);
bit_cntr);
input xclk; // half frequency (80 MHz nominal) reg [4:0] ser_di_d;
input [15:0] bitHalfPeriod; // half of the serial bit duration, in xclk cycles reg ser_filt_di;
input ser_di; // rs232 (ttl) serial data in reg ser_filt_di_d;
input ser_rst; // reset (force re-sync) reg bit_half_end; // last cycle in half-bit
output ts_stb; // strobe timestamp (start of message) reg last_half_bit;
output wait_just_pause;// may be used as reset for decoder reg wait_pause; // waiting input to stay at 1 for 10 cycles
output start; // serial character start (single pulse) reg wait_start; // (or use in_sync - set it after wait_pause is over?
output [4:0] debug; // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset reg receiving_byte;
output ser_do; // serial data out(@posedge xclk) reg start_r;
output ser_do_stb; // output data strobe (@posedge xclk), 2 cycles after ser_do becomes valid reg [15:0] bit_dur_cntr_r; // bit duration counter (half bit duration)
output [15:0] bit_dur_cntr; // debug reg [4:0] bit_cntr_r; // counts half-bit intervals
output [4:0] bit_cntr; // debug wire error; // low level during stop slot
reg [1:0] restart;
wire reset_wait_pause;
reg ts_stb_r;
reg shift_en;
reg [4:0] ser_di_d; wire sample_bit;
reg ser_filt_di; wire reset_bit_duration;
reg ser_filt_di_d; wire wstart;
reg bit_half_end; // last cycle in half-bit // reg [4:0] debug0; // {was_ts_stb, was_start, was_error, was_ser_di_1, was_ser_di_0} - once after reset
reg last_half_bit; assign reset_wait_pause = (restart[1] && !restart[0]) || (wait_pause && !wait_start && !ser_di);
reg wait_pause; // waiting input to stay at 1 for 10 cycles assign error = !ser_filt_di && last_half_bit && bit_half_end && receiving_byte;
reg wait_start; // (or use in_sync - set it after wait_pause is over? assign sample_bit = shift_en && bit_half_end && !bit_cntr[0];
reg receiving_byte; assign reset_bit_duration = reset_wait_pause || start || bit_half_end || ser_rst;
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; assign wstart = wait_start && ser_filt_di_d && !ser_filt_di;
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};
assign debug[4:0] = {error, wait_start, wait_pause, receiving_byte, shift_en};
assign debug[4:0] = {1'b0,wait_start,wait_pause,receiving_byte,shift_en}; assign bit_dur_cntr = bit_dur_cntr_r; // bit duration counter (half bit duration)
always @ (posedge xclk) begin assign bit_cntr = bit_cntr_r; // counts half-bit intervals
// reg [4:0] ser_di_d; assign start = start_r;
// reg ser_filt_di; assign ts_stb = ts_stb_r;
// reg ser_filt_di_d;
ser_di_d[4:0] <= {ser_di_d[3:0],ser_di}; always @ (posedge xclk) begin
if (ser_rst || &ser_di_d[4:0]) ser_filt_di <= 1'b1; ser_di_d[4:0] <= {ser_di_d[3:0],ser_di};
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);
if (ser_rst || &ser_di_d[4:0]) ser_filt_di <= 1'b1;
if (sample_bit) ser_do <= ser_filt_di; else if (~|ser_di_d[4:0]) ser_filt_di <= 1'b0;
ser_do_stb <= sample_bit;
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_r <= wstart;
ts_stb_r <= !wait_pause && wstart; // only first start after pause
bit_half_end <=(bit_dur_cntr_r[15:0]==16'h1) && !reset_bit_duration;
wait_start <= !ser_rst && ((wait_pause || receiving_byte) && last_half_bit && bit_half_end || (wait_start && !wstart));
receiving_byte <= !ser_rst && (start_r || (receiving_byte && !(last_half_bit && bit_half_end)));
wait_just_pause <=wait_pause && !wait_start;
if (reset_bit_duration) bit_dur_cntr_r[15:0] <= bitHalfPeriod[15:0];
else bit_dur_cntr_r[15:0] <= bit_dur_cntr_r[15:0] - 1;
if (reset_wait_pause || ser_rst) bit_cntr_r[4:0] <= 5'h13;
else if (start_r) bit_cntr_r[4:0] <= 5'h12;
else if (bit_half_end) bit_cntr_r[4:0] <= bit_cntr_r[4:0] - 1;
if (ser_rst) debug0[4:0] <=5'b0; last_half_bit <= ((bit_cntr_r[4:0] == 5'h0) && !bit_half_end);
else debug0[4:0] <= debug | {ts_stb,start,error,ser_di_d,~ser_di_d}; shift_en <= receiving_byte && ((bit_half_end && ( bit_cntr_r[3:0]==4'h2))? bit_cntr_r[4]:shift_en);
end
if (sample_bit) ser_do <= ser_filt_di;
ser_do_stb <= sample_bit;
// if (ser_rst) debug0[4:0] <=5'b0;
// else debug0[4:0] <= debug | {ts_stb_r,start_r,error,ser_di_d,~ser_di_d};
end
endmodule endmodule
...@@ -30,7 +30,7 @@ module timestamp_fifo( ...@@ -30,7 +30,7 @@ module timestamp_fifo(
input pre_stb, // marks pre-first input byte (s0,s1,s2,s3,u0,u1,u2,u3) input pre_stb, // marks pre-first input byte (s0,s1,s2,s3,u0,u1,u2,u3)
input [7:0] din, // data in - valid for 8 cycles after pre_stb input [7:0] din, // data in - valid for 8 cycles after pre_stb
input aclk, // clock to synchronize advance puls input aclk, // clock to synchronize "advance" commands
input advance, // @aclk advance registers input advance, // @aclk advance registers
input rclk, // output clock input rclk, // output clock
...@@ -65,11 +65,11 @@ module timestamp_fifo( ...@@ -65,11 +65,11 @@ module timestamp_fifo(
always @(posedge rst or posedge rclk) begin always @(posedge rst or posedge rclk) begin
if (rst) snd <= 0; if (rst) snd <= 0;
else if (rstb) snd <= 1; else if (rstb) snd <= 1;
else if (&rpntr[2:0]) snd <= 0; else if (&rpntr[2:1]) snd <= 0; // at count 6
if (rst) rpntr[2:0] <= 0; if (rst) rpntr[2:0] <= 0;
else if (!snd) rpntr[2:0] <= 0; else if (!snd && !rstb) rpntr[2:0] <= 0;
else rpntr[2:0] <= rpntr[2:0] + 1; else rpntr[2:0] <= rpntr[2:0] + 1;
if (snd) dout <= fifo_ram[rpntr]; if (snd) dout <= fifo_ram[rpntr];
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment