HITDAQ/FPGA_firmware/sensor_algo_qsys/sensor_interface.v
2024-10-15 14:03:00 +02:00

787 lines
28 KiB
Verilog

// sensor_interface.v
/*Created by M.Dziewiecki in 2019
Modified by Lq.Qin on Oct 15th. 2024*/
`timescale 1 ps / 1 ps
module sensor_interface (
//Clock/reset
input wire clk_clk, // clk.clk
input wire rst_reset, // rst.reset
//Avalon MM slave
input wire [1:0] csr_address, // avalon_slave.address
input wire csr_read, // .read
output wire [31:0] csr_readdata, // .readdata
input wire csr_write, // .write
input wire [31:0] csr_writedata, // .writedata
input wire [3:0] csr_byteenable, // .byteenable
//Avalon ST transmitter
output wire [31:0] data_out_data, // avalon_streaming_source.data
output wire data_out_endofpacket, // .endofpacket
output wire data_out_startofpacket, // .startofpacket
input wire data_out_ready, // .ready
output wire data_out_valid, // .valid
output wire [1:0] data_out_empty, // .empty
//Sensor interface
input wire in_trg, // sensor.in_trg // This is the frame timer
output wire out_adc_clk, // .out_dac_clk
output wire out_adc_cnv, // .out_dac_cnv
input wire [4:0] in_adc_data, // .in_dac_data
output wire out_sensor_rst, // .out_sensor_rst
output wire out_sensor_clk, // .out_sensor_clk
output wire out_sensor_gain, // .out_sensor_gain
//Serial synchro interface
input wire serial_rx, //receive data
output wire serial_tx, //send data
input wire [7:0] ext_input, //SMA etc.
//Debug information
output wire [7:0] status_out, //status bits - same as in reg0_read[15:8]
output reg int_rst, //the reset for each new run
output reg [7:0] cluster_threshold, //from registers[3][7:0]
output reg [7:0] cluster_size, //from registers[3][15:8]
output reg [7:0] in_algo_threshold //from registers[3][23:16]
);
//Very important globals
reg[31:0] transmit_buffer[162:0]; //Data to send: 3 words header plus sensor data
wire readout_ready; //pulsing this signal causes copying data from frame buffer to transmit buffer and initiating transmission
wire start_transmission; //pulsing this signal causes the Avalon ST link to start transmission
reg[15:0] local_sync_ctr; //local synchronization counter, it increments by one at each frame
wire[8:0] global_sync_ctr; //global synchronization counter, it's simply the received value from serial RX.
wire global_sync_error; //RX error in the global synchronization counter
//Common generate variables
genvar i; //for generate loops
genvar j;
integer xi; //for normal loops
integer xj;
// *********************** CSR stuff ************************
/*
There are 4 32-bit R/W-able registers. They are used for setting up the module and checking its state
Reg0 is a bit different: when read, bits 15-8 (the status byte) are taken directly from device internals, not from register contents.
The bus can be accessed 32-, 16- or 8-bit-wise.
Register definition
//reg0
#define SENSOR_REG_COMMAND 0 //8 bits
#define SENSOR_REG_STATUS 1 //8 bits
#define SENSOR_REG_SENSORCLK 2 //8 bits, 6 used divider for producing sensor clock ('4' MHz)
#define SESNOR_REG_ADCCNV 3 //8 bits, 6 used time of conversion pulse in ADC clocks, should be > 500 ns
//reg1
#define SENSOR_REG_DELAY 4 //16 bits, 12 used reset signal delay in 50 MHz clocks
#define SENSOR_REG_SHUTTER 6 //16 bits, 12 used sensor reset ('shutter') time in sensor clocks
//reg2
#define SENSOR_REG_SERSPEED 8 //8 bits synchro baudrate, 50 for 1 Mbps
#define SENSOR_REG_HEADER_ANYDATA 9 //8 bits any data transmitted with SMA state (8 bits SMA + 8 bits anydata)
#define SENSOR_REG_HEADER_CMD 10 //16 bits command field of the command header transmitted in packet
//reg3 //configure reg3 17.July.2024 Qin,L
#define SENSOR_REG_CLUSTER_THRESHOLD 12 //8 bits the threshold for cluster locate, range 0~255
#define SENSOR_REG_CLUSTER_SIZE 13 //8 bits the size for clluster locate, range 0~255
#define SENSOR_REG_IN_ALGO_THRESHOLD 14 //8 bits the threshold inside Linear Regression, range 0~255
#define SENSOR_REG_RESERVED 15 //8 bits not used
Command bitmasks
#define SENSOR_CSR_EN_BITMASK 0x01 //enable operation
#define SENSOR_CSR_GAIN_BITMASK 0x02 //gain selection
#define SENSOR_CSR_ADCK_BITMASK 0x04 //ADC clock divider on/off
#define SENSOR_CSR_RESET_BITMASK 0x08 //Reset all logic //registers[0][3]
Status bitmasks
#define SENSOR_STATUS_SEND 0x01 //Sending over Avalon-ST
#define SENSOR_STATUS_TRG_WAITING 0x02 //The trigger came and is being delayed now
#define SENSOR_STATUS_RESET_ACTIVE 0x04 //The RESET signal for the sensor is active now
#define SENSOR_STATUS_ADC_ACTIVE 0x08 //The ADC is converting data (signal high over all 64 channels) or just finished and waits for reset high
#define SESNOR_STATUS_ADC_FINISHED 0x10 //The ADC waits for reset high
#define SESNOR_STATUS_TX_ACTIVE 0x20 //Sync port is sending
#define SESNOR_STATUS_RX_ACTIVE 0x40 //Sync port is receiving
*/
reg [31:0] registers[3:0]; //main register space
wire [31:0] reg0_read; //reg[0] is read indirectly to include status byt(bits 15-8)
//read logic
assign reg0_read[7:0] = registers[0][7:0]; // Readback of control bits
assign reg0_read[31:16] = registers[0][31:16]; // Readback of payload size
assign reg0_read[15] = 0; // Unused bits of the status byte
assign csr_readdata = (csr_address==0) ? reg0_read : registers[csr_address];
//write logic
generate
for (i = 0; i < 4; i = i+1)
begin : write_registers //Quartus wants labels for 'for' blocks
for (j = 0; j < 4; j = j+1)
begin : write_bytes
always @(posedge clk_clk or posedge rst_reset)
begin
if (rst_reset)
registers[i][8*j+7:8*j] <= 8'd0;
else
if (csr_byteenable[j] && (csr_address == i) && (csr_write))
registers[i][8*j+7:8*j] <= csr_writedata[8*j+7:8*j];
end
end
end
endgenerate
// *********************** Internal reset logic ************************
/*
The internal reset signal derives from the reset input and reset bit (reg0.3).
It drives all subcomponents but registers (which use simpy the reset input).
This signal is registered to be sure that no glitches from register bank pass.
*/
//reg int_rst;
always @(posedge clk_clk)
begin
int_rst <= rst_reset | registers[0][3];
end
// *********************** Avalon transmitter ************************
/*
The transmitter is used to transmit collected sensor data together with sync frame.
It can be later packed into UDP by UDP generator and sent over Ethernet. Or whatever.
The transmitter has 8-bit symbol, 4 symbols per beat. It's backpressurizable and includes packet signals.
The Empty signal is dummy (always zero), as the data is always aligned to 32-bit size.
The transmission starts when the 'start_transmission' signal gets pulsed
*/
assign data_out_empty = 2'b00;
reg [1:0] data_out_state; //State of the state machine
localparam DATA_OUT_STATE_IDLE = 0; //waiting for high
localparam DATA_OUT_STATE_SEND = 1; //sending data
localparam DATA_OUT_STATE_LOCK = 2; //waiting for trigger low
//localparam DATA_OUT_STATE_PEND = 3; //the pending when sending data
localparam WORDS_TO_SEND = 163;
//registers to drive output pins of ST interfaces
// reg reg_valid;
// reg [31:0] reg_data;
// reg reg_startofpacket;
// reg reg_endofpacket;
//Helper stuff
reg [15:0] tx_ctr; //counter of sent data words
//The state machine
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
begin
data_out_state <= DATA_OUT_STATE_IDLE;
cluster_threshold <= registers[3][7:0];
cluster_size <= registers[3][15:8];
in_algo_threshold <= registers[3][23:16];
end
else
case(data_out_state)
DATA_OUT_STATE_IDLE:
begin
if (start_transmission)
begin
data_out_state <= DATA_OUT_STATE_SEND;
tx_ctr <= 0;
cluster_threshold <= registers[3][7:0];
cluster_size <= registers[3][15:8];
in_algo_threshold <= registers[3][23:16];
end
end
DATA_OUT_STATE_SEND:
begin
if (data_out_ready)
begin
tx_ctr <= tx_ctr + 1'b1;
if (tx_ctr == (WORDS_TO_SEND-1))
data_out_state <= DATA_OUT_STATE_LOCK;
end
end
DATA_OUT_STATE_LOCK:
begin
if (~start_transmission)
data_out_state <= DATA_OUT_STATE_IDLE;
end
default:
data_out_state <= DATA_OUT_STATE_IDLE;
endcase
end
assign data_out_valid = (data_out_state == DATA_OUT_STATE_SEND)? 1'b1: 1'b0;
assign data_out_data = (data_out_state == DATA_OUT_STATE_SEND)? transmit_buffer[tx_ctr]: 32'b0;
assign data_out_startofpacket = (data_out_state == DATA_OUT_STATE_SEND && tx_ctr == 0) ? 1'b1: 1'b0;
assign data_out_endofpacket = (data_out_state == DATA_OUT_STATE_SEND && tx_ctr == (WORDS_TO_SEND-1)) ? 1'b1: 1'b0;
assign reg0_read[8] = ~(data_out_state == DATA_OUT_STATE_IDLE); //to status register
// *********************** Detector gain logic ************************
/*
The gain signal is simply derived from reg0.
*/
assign out_sensor_gain = registers[0][1];
// *********************** Trigger delay logic ************************
/*
Individual trigger delay settings are needed to synchronize multiple boards.
A 12-bit downcounter allows for delaying incoming trigger's rising edge by up to 4095 50MHz clock cycles, i.e. 81.9 us.
Note: A further delay of one sensor clock will be added in the sensor clock generation logic.
*/
reg [11:0] trg_delay_ctr;
wire int_trg;
reg [1:0] trg_state;
localparam TRG_STATE_IDLE = 0; //waiting for external trigger
localparam TRG_STATE_DELAY = 1; //downcounting
localparam TRG_STATE_ACTIVE = 2; //internal trigger active
localparam TRG_STATE_LOCK = 3; //waiting for external trigger inactive
//localparam TRG_DURATION = 4; //duration of the trigger signal
assign int_trg = (trg_state == TRG_STATE_ACTIVE) ? 1'b1 : 1'b0;
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
begin
trg_state <= TRG_STATE_LOCK;
end
else
begin
case(trg_state)
TRG_STATE_IDLE:
begin
if (in_trg && registers[0][0]) //react on trigger only if enabled
begin
trg_delay_ctr <= registers[1][11:0];
trg_state <= TRG_STATE_DELAY;
end
end
TRG_STATE_DELAY:
begin
trg_delay_ctr <= trg_delay_ctr - 1'b1;
if (trg_delay_ctr == 0)
begin
//trg_delay_ctr <= TRG_DURATION-1;
trg_state <= TRG_STATE_ACTIVE;
end
end
TRG_STATE_ACTIVE:
begin
//trg_delay_ctr <= trg_delay_ctr - 1;
//if (trg_delay_ctr == 0)
//begin
trg_state <= TRG_STATE_LOCK; //only one cycle of active int_trg
//end
end
TRG_STATE_LOCK:
begin
if (~in_trg)
trg_state <= TRG_STATE_IDLE;
end
endcase
end
end
assign reg0_read[9] = ~(trg_state == TRG_STATE_IDLE); //to status register
// *********************** Sensor clock logic ************************
/*
The sensor needs a clock of max. 4 MHz, which is generated by this module.
The actual clock speed is configurable by a register with a formula: Fs = Fi/2/(div+1),
where Fs is the sensor clock, Fi is input clock (50 MHz nom.) and div is a divider taken from the register.
A 5-bit downcounter allows for frequencies from 0.39 MHz (div=63) to 12.5 MHz (div=1).
The nominal setting is 6, giving 3.5714285 MHz.
Important: The sensor clock is synchronized to the rising edge of the (delayed) trigger input,
so that there is a positive slope at exactly one sensor clock period after the trigger.
This positive slope is then used to synchronize integration start signal (sensor reset or shutter).
The synchronization is done so that one of clock states (0 or 1) gets extended, but never shortened.
Note: 4 MHz is also the top speed accepted by the ADC module.
*/
reg [5:0] sensor_clk_ctr;
reg [1:0] sensor_clk_state;
localparam SENSOR_CLK_STATE_LOW = 2'd0;
localparam SENSOR_CLK_STATE_HIGH = 2'd1;
localparam SENSOR_CLK_STATE_LOWAIT = 2'd2;
localparam SENSOR_CLK_STATE_HIWAIT = 2'd3;
assign out_sensor_clk = sensor_clk_state[0];
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
begin
sensor_clk_state <= SENSOR_CLK_STATE_LOW;
sensor_clk_ctr <= registers[0][21:16];
end
else
begin
case(sensor_clk_state)
SENSOR_CLK_STATE_LOW:
begin
sensor_clk_ctr <= sensor_clk_ctr-1'b1;
if (int_trg)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_LOWAIT;
end
else if (sensor_clk_ctr == 0)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_HIGH;
end
end
SENSOR_CLK_STATE_HIGH:
begin
sensor_clk_ctr <= sensor_clk_ctr-1'b1;
if (int_trg)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_HIWAIT;
end
else if (sensor_clk_ctr == 0)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_LOW;
end
end
SENSOR_CLK_STATE_LOWAIT:
begin
sensor_clk_ctr <= sensor_clk_ctr-1'b1;
if (sensor_clk_ctr == 0)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_LOW;
end
end
SENSOR_CLK_STATE_HIWAIT:
begin
sensor_clk_ctr <= sensor_clk_ctr-1'b1;
if (sensor_clk_ctr == 0)
begin
sensor_clk_ctr <= registers[0][21:16];
sensor_clk_state <= SENSOR_CLK_STATE_LOW;
end
end
endcase
end
end
// *********************** Sensor reset (shutter) logic ************************
/*
This block generates a 'reset' (shutter) signal for the sensor.
It defines the integration time and is programmable by means of a register in sensor clock units.
The leading (positive) slope of this signal is synchronized with the first positive slope of the sensor clock after the trigger.
An internal 12-bit downcounter allows for a max. integration time of ca 1.15 ms. It can be further extended by slowing down the sensor clock.
It's user's responsibility to check if the integration period fits into the trigger period. If this requirement is not fulfilled, some triggers will be skipped.
Sorry for this ugly code, but since it works...
Important remark from sensor's specification: Rise of a RESET pulse must be set outside the video output period.
This must by guaranteed by user by means of proper timing. First video comes 18 cycles after negative slope of sensor reset and is 2 cycles long.
Then 2 cycles pause (here we can come with the positive reset slope), then next video and so on, every 4 cycles.
The minimum duration of reset low is 21 clocks, and 20 clocks for reset high.
Our logic requires that new reset low comes only after all channels are read.
*/
reg [11:0] sensor_rst_ctr;
reg sensor_rst_state;
assign out_sensor_rst = sensor_rst_state;
always @(posedge int_trg or posedge out_sensor_clk or posedge int_rst)
begin
if (int_rst)
begin
sensor_rst_state <= 0;
sensor_rst_ctr <= 0;
end
else if (int_trg)
begin
sensor_rst_ctr <= registers[1][27:16];
end
else
begin
if (sensor_rst_ctr == 0)
begin
sensor_rst_state <= 0;
end
else
begin
sensor_rst_ctr <= sensor_rst_ctr - 1'b1;
sensor_rst_state <= 1'b1;
end
end
end
assign reg0_read[10] = sensor_rst_state; //to status register
// *********************** ADC trigger logic ************************
/*
This piece produces triggering signals for ADC framework and cares about counting ADC samples.
It doesn't rely on incoming Trig signals, just generates them internally by counting clocks.
*/
reg [5:0] adc_current_channel;
reg [2:0] adc_trg_state;
reg [4:0] adc_trg_downctr;
wire int_adc_trg;
wire adc_trg_frame_ready;
localparam ADC_TRG_STATE_IDLE = 0; //nothing happens, RESET is high or initial state
localparam ADC_TRG_STATE_WAIT = 1; //waiting for the first video
localparam ADC_TRG_STATE_VIDEO1 = 2; //capturing video
localparam ADC_TRG_STATE_VIDEO2 = 3; //second cycle
localparam ADC_TRG_STATE_VIDEO3 = 4; //third cycle
localparam ADC_TRG_STATE_VIDEO4 = 5; //fourth cycle
localparam ADC_TRG_STATE_FINISH = 6; //finished readout, waiting for RESET high to enter idle
localparam ADC_TRG_STATE_INIT = 7; //used only for reset procedure
localparam ADC_TRG_INITIALWAIT = 5'd17; //initial wait for the first video
localparam ADC_TRG_VIDEOPERIOD = 4; //video output period
always @(posedge out_sensor_clk or posedge int_rst)
begin
if (int_rst)
begin
adc_current_channel <= 63;
adc_trg_downctr <= 0;
adc_trg_state <= ADC_TRG_STATE_INIT; //will go to IDLE when adc_trg_reset is high
end
else
case(adc_trg_state)
ADC_TRG_STATE_IDLE:
begin
if (~out_sensor_rst)
begin
adc_trg_downctr <= ADC_TRG_INITIALWAIT;
adc_current_channel <= 63;
adc_trg_state <= ADC_TRG_STATE_WAIT;
end
end
ADC_TRG_STATE_WAIT:
begin
adc_trg_downctr <= adc_trg_downctr - 1'b1;
if (adc_trg_downctr == 0)
begin
adc_trg_state <= ADC_TRG_STATE_VIDEO1;
end
end
ADC_TRG_STATE_VIDEO1:
begin
adc_current_channel <= adc_current_channel + 1'b1;
adc_trg_state = ADC_TRG_STATE_VIDEO2;
end
ADC_TRG_STATE_VIDEO2:
begin
adc_trg_state = ADC_TRG_STATE_VIDEO3;
end
ADC_TRG_STATE_VIDEO3:
begin
adc_trg_state = ADC_TRG_STATE_VIDEO4;
end
ADC_TRG_STATE_VIDEO4:
begin
if (adc_current_channel == 63)
adc_trg_state <= ADC_TRG_STATE_FINISH;
else
adc_trg_state = ADC_TRG_STATE_VIDEO1;
end
ADC_TRG_STATE_FINISH, ADC_TRG_STATE_INIT:
begin
if (out_sensor_rst)
adc_trg_state <= ADC_TRG_STATE_IDLE;
end
endcase
end
//Producing internal trigger for ADC framework (see below)
assign int_adc_trg = (adc_trg_state == ADC_TRG_STATE_VIDEO1) ? 1'b1 : 1'b0;
assign adc_trg_frame_ready = (adc_trg_state == ADC_TRG_STATE_FINISH) ? 1'b1 : 1'b0; //trigger data collection machine when the frame is ready
assign reg0_read[11] = ~(adc_trg_state == ADC_TRG_STATE_IDLE); //to status register
assign reg0_read[12] = (adc_trg_state == ADC_TRG_STATE_FINISH); //to status register
// *********************** ADC logic ************************
/*
SPI interface for ADCs. Triggers conversion and reads out the data on each incoming int_adc_trg.
The ADC framework and SPI runs with full clock frequency or with half of it, depending on register setting.
The ADC works in the 'CS Mode, 3-Wire Without Busy Indicator Serial Interface'.
The CNV signal length is defined by register and expressed in ADC clocks.
It's user's responsibility to ensure that the CNV pulse is longer than 500 ns (required by ADC spec).
The ADC clock can be selected to be either full or half system clock.
*/
//Clock divider and selection
reg adc_halfclock;
wire int_adc_clk;
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
adc_halfclock <= 0;
else
adc_halfclock <= ~adc_halfclock;
end
assign int_adc_clk = registers[0][2] ? adc_halfclock : clk_clk;
//The main state machine
reg [2:0] adc_state;
reg [5:0] adc_downctr;
localparam ADC_STATE_IDLE = 0; //waiting for conversion
localparam ADC_STATE_CNV = 1; //conversion on-going
localparam ADC_STATE_STARTREAD = 2; //prepare to read, conversion finished
localparam ADC_STATE_READ = 3; //reading data
localparam ADC_STATE_FINISH = 4; //copy data to global buffer
localparam ADC_STATE_FINISHED = 5; //wait until trigger low, then go to idle
always @(posedge int_adc_clk or posedge int_rst)
begin
if (int_rst)
begin
adc_downctr <= 0;
adc_state <= ADC_STATE_IDLE;
end
else
begin
case(adc_state)
ADC_STATE_IDLE:
begin
adc_downctr <= registers[0][29:24];
if (int_adc_trg)
adc_state <= ADC_STATE_CNV;
end
ADC_STATE_CNV:
begin
adc_downctr <= adc_downctr - 1'b1;
if (adc_downctr == 0)
adc_state <= ADC_STATE_STARTREAD;
end
ADC_STATE_STARTREAD:
begin
adc_downctr <= 15;
adc_state <= ADC_STATE_READ;
end
ADC_STATE_READ:
begin
adc_downctr <= adc_downctr - 1'b1;
if (adc_downctr == 0)
adc_state <= ADC_STATE_FINISH;
end
ADC_STATE_FINISH:
begin
adc_state <= ADC_STATE_FINISHED;
end
ADC_STATE_FINISHED:
begin
if (!int_adc_trg)
adc_state <= ADC_STATE_IDLE;
end
default
begin
adc_state <= ADC_STATE_IDLE;
end
endcase
end
end
//Reading data - this happens on the negative slope of clock!
reg [15:0] adc_buffer[4:0]; //A shift register for SPI acquisition
reg [15:0] frame_buffer[319:0]; //The 'big buffer' for whole frame
always @(negedge int_adc_clk or posedge int_rst)
begin
if (int_rst)
begin
for (xi = 0; xi < 5; xi = xi+1)
adc_buffer[xi] <= 0;
end
else
begin
case(adc_state)
ADC_STATE_STARTREAD:
begin
for (xi = 0; xi < 5; xi = xi+1)
adc_buffer[xi] <= 0;
end
ADC_STATE_READ:
begin
for (xi = 0; xi < 5; xi = xi+1)
begin
adc_buffer[xi][15:1] <= adc_buffer[xi][14:0];
adc_buffer[xi][0] <= in_adc_data[xi];
end
end
ADC_STATE_FINISH:
begin
for (xi = 0; xi < 5; xi = xi+1)
frame_buffer[64*xi + adc_current_channel] <= adc_buffer[xi];
end
endcase
end
end
assign out_adc_cnv = (adc_state == ADC_STATE_CNV) ? 1'b1 : 1'b0;
assign out_adc_clk = (adc_state == ADC_STATE_READ) ? int_adc_clk : 1'b1;
// *********************** Putting data together and letting transmit it ************************
/*
The data is sent together with a 3-word header (6 16-bit numbers),
which is compatible with v.1 head structures:
typedef struct
{
unsigned short marker; //must be 0x5555
unsigned short command;
unsigned short length;
} command_header;
typedef struct
{
//unsigned short channel_id;
unsigned short local_ctr;
unsigned short global_ctr;
unsigned short sma_state;
} sync_frame;
*/
reg [2:0] merger_state;
localparam MERGER_STATE_IDLE = 0; //waiting for ADC
localparam MERGER_STATE_COLLECT = 1; //collect frame information
localparam MERGER_STATE_SEND = 2; //run Avalon sender
localparam MERGER_STATE_FINISH = 3; //roll to idle
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
begin
merger_state <= ADC_STATE_IDLE;
for (xi= 0; xi < 163; xi = xi+1)
transmit_buffer[xi] <= 0;
end
else
begin
case(merger_state)
MERGER_STATE_IDLE:
begin
if (adc_trg_frame_ready)
merger_state <= MERGER_STATE_COLLECT;
end
MERGER_STATE_COLLECT:
begin
transmit_buffer[0][31:16] <= 16'h5555; //command_header.marker = 0x5555
transmit_buffer[0][15:0] <= registers[2][31:16]; //command_header.command = reg2.31-16
transmit_buffer[1][31:16] <= 16'd323; //16'd652; //command_header.length = 320 samples + 6 sync bytes = 323 * 16bit //16'h143
transmit_buffer[1][15:0] <= local_sync_ctr[15:0]; //sync_frame.local_ctr
transmit_buffer[2][24:16] <= global_sync_ctr; //sync_frame.global_ctr
transmit_buffer[2][25] <= global_sync_error;
transmit_buffer[2][31:26] <= 0;
transmit_buffer[2][7:0] <= ext_input; //sync_frame.sma_state[7:0] = ext_input
transmit_buffer[2][15:8] <= registers[2][15:8]; //sync_frame.sma_state[15:8] = reg2.15-8
for (xi = 0; xi < 160; xi = xi+1)
begin
//transmit_buffer[xi+3][15:0] <= frame_buffer[2*xi][15:0]; //ADC data
//transmit_buffer[xi+3][31:16] <= frame_buffer[2*xi+1][15:0];
transmit_buffer[xi+3][31:16] <= frame_buffer[2*xi][15:0]; //ADC data //CHANGED 26.11.2019
transmit_buffer[xi+3][15:0] <= frame_buffer[2*xi+1][15:0];
end
merger_state <= MERGER_STATE_SEND;
end
MERGER_STATE_SEND:
begin
merger_state <= MERGER_STATE_FINISH;
end
MERGER_STATE_FINISH:
begin
if (~adc_trg_frame_ready)
merger_state <= MERGER_STATE_IDLE;
end
endcase
end
end
//Generate Avalon trigger signal
assign start_transmission = (merger_state == MERGER_STATE_SEND) ? 1'b1 : 1'b0;
// *********************** Synchro counter update ************************
/*
Just increment sunchronization counter at every trigger.
The counter is reset by int_reset.
*/
always @(posedge clk_clk or posedge int_rst)
begin
if (int_rst)
begin
local_sync_ctr <= 0;
end
else
begin
if (int_trg)
local_sync_ctr <= local_sync_ctr + 1'b1;
end
end
// *********************** Synchronization serial ports ************************
/*
There is one TX and one RX module.
The TX is getting triggered by int_trg (same as for the main readout framework).
It sends 9 LSBs of the local synchro counter with programmed baudrate.
The default baudrate is 1 Mbps, which needs a setting of 50 for fclk=50MHz.
The RX puts freshly received data into global_sync_ctr. It does not need any triggering.
*/
wire tx_idle;
wire rx_idle;
assign reg0_read[13] = ~tx_idle;
assign reg0_read[14] = ~rx_idle;
serial_tx synchro_tx (
.clk (clk_clk), // full-speed clock
.rst (int_rst), // reset
.data (local_sync_ctr[8:0]), // data to send
.clk_divisor (registers[2][7:0]), // defines baudrate
.trigger (start_transmission), // pulse to start transmission - just AFTER collecting data from sensors
.tx (serial_tx), // tx serial connection
.idle (tx_idle) // 1 if sender in idle state
);
serial_rx synchro_rx(
.clk (clk_clk), // full-speed clock
.rst (int_rst), // reset
.clk_divisor (registers[2][7:0]), // defines baudrate
.rx (serial_rx), // rx serial connection
.newdata (), // pulses for new data received
.data (global_sync_ctr), // data received
.error (global_sync_error), // bad start or stop bit
.idle (rx_idle) // 1 if receiver in idle state
);
// *********************** Status output ************************
/*
The status of the module (== reg0_read[15:8]) is available at the output status bus.
It can be then routed to a scope or whatever for debugging
*/
assign status_out[7:0] = reg0_read[15:8];
endmodule