Code
/*
A module to update the registers in the ibis4_6600 image sensor.
Now need to:
- add a facilty to create custom register values based on the 'config_data'.
- add busy line.
*/
module ibis_reg_update (
//clock and reset
input logic clk_200M, nrst,
//Input data capture and latch
input logic [31:0] config_data,
input logic config_latch,
//SPI connections
output logic spi_data = 0, spi_clk = 0, reg_clk = 0,
//Status output
output logic busy
);
/* Variables correspoding to the IBIS4 config registers.
Defaults set for 30fps video at 640x480 pixels.
*/
logic [11:0]ibis_regs[13] = '{ //Default value Reg Name Addr Notes
12'b000000000000, //reg_sequencer 00 All normal
12'b000111100000, //reg_nrof_pixels 01 480 pixels
12'b001010000000, //reg_nrof_lines 02 640 lines
12'b000000000000, //reg_int_time 03 Not done \/ \/
12'b000000000011, //reg_delay 04
12'b000000000000, //reg_x_reg 05
12'b000000000000, //reg_y_reg 06
12'b000000000000, //reg_img_core_reg 07
12'b000000010000, //reg_amp_reg 08
12'b000000000000, //reg_dac_raw_reg 09
12'b000000000000, //reg_dac_fine_reg 10
12'b000000000000, //reg_dac_dark_reg 11
12'b000000000000 //reg_adc_reg 12
};
logic [3:0] reg_addr = 0;
logic [7:0] clock_div = 0;
logic start_pulse, reg_upd_clk = 0, spi_latch, spi_busy;
logic [1:0] trans_state = 0;
logic [15:0] spi_data_reg = 0, reg_upd_counter = 0;
//Generate 10MHz 'reg_upd_clk'
always_ff @ (posedge clk_200M or negedge nrst)
begin
//Reset
if(nrst == 0)
begin
reg_upd_clk = 0;
clock_div = 0;
end
//Generate clock
else
begin
if(clock_div == 9)
begin
reg_upd_clk <= ~reg_upd_clk;
clock_div <= 0;
end
else clock_div++;
end
end
//Latch the 'config_data' into the current memeory
always_ff @ (posedge config_latch)
begin
if(config_data == 0)
begin
//Default value Reg Name Addr Notes
ibis_regs[0] = 12'b000000000000; //reg_sequencer 00 All normal
ibis_regs[1] = 12'b000111100000; //reg_nrof_pixels 01 480 pixels
ibis_regs[2] = 12'b001010000000; //reg_nrof_lines 02 640 lines
ibis_regs[3] = 12'b000000000000; //reg_int_time 03 Not done \/ \/
ibis_regs[4] = 12'b000000000011; //reg_delay 04
ibis_regs[5] = 12'b000000000000; //reg_x_reg 05
ibis_regs[6] = 12'b000000000000; //reg_y_reg 06
ibis_regs[7] = 12'b000000000000; //reg_img_core_reg 07
ibis_regs[8] = 12'b000000010000; //reg_amp_reg 08
ibis_regs[9] = 12'b000000000000; //reg_dac_raw_reg 09
ibis_regs[10] = 12'b000000000000; //reg_dac_fine_reg 10
ibis_regs[11] = 12'b000000000000; //reg_dac_dark_reg 11
ibis_regs[12] = 12'b000000000000; //reg_adc_reg 12
end
end
//Start the register update sequence
always_ff @ (negedge reg_upd_clk or negedge nrst)
begin
//Reset
if(nrst == 0)
begin
trans_state = 0;
reg_upd_counter = 0;
spi_latch = 0;
reg_clk = 0;
reg_addr = 0;
end
//Run
else
begin
case(trans_state)
//Wait for the start pulse to start the transmission
0: begin
if(start_pulse == 1) trans_state = 1;
end
1: begin
//Reset the counter after 25 clock cycles
if(reg_upd_counter == 25)
begin
reg_upd_counter <= 0;
end
else
begin
//increment the counter
reg_upd_counter++;
case(reg_upd_counter)
1: begin
spi_data_reg[15:12] <= reg_addr;
spi_data_reg[11:0] <= ibis_regs[reg_addr];
end
2: begin
//Start the SPI transmission for 'reg_addr'.
spi_latch <= 1;
end
5: begin
spi_latch <= 0;
end
23: begin
//Latch the data int othe image sensor with 'reg_clk'.
reg_clk <= 1;
end
24: begin
//Repeat 13 times incrementing 'reg_addr' each time.
reg_clk <= 0;
if(reg_addr == 12)
begin
trans_state <= 0;
reg_addr <= 0;
end
else
begin
reg_addr++;
end
end
endcase
end
end
endcase
end
end
pulse_gen gen0( .in_edge(config_latch), .clk(reg_upd_clk), .out_pulse(start_pulse));
spi_16bit spi0( .clk_200M(clk_200M), .nrst(nrst),
.data_in(spi_data_reg),
.data_latch(spi_latch),
.spi_sclk(spi_clk),
.spi_data(spi_data),
.busy(spi_busy));
assign busy = spi_busy | trans_state;
endmodule
/*
A regular SPI hardware module to send a 16bit number at 10MHz with a 200MHz master clock.
*/
module spi_16bit( //Input control
input logic clk_200M, nrst,
//Input data
input logic [15:0] data_in,
input logic data_latch,
//Output pins
output logic spi_sclk = 0,
spi_data = 0,
busy
);
/*
Generate the 10MHz SCLK
*/
logic [3:0] clk_divider = 0;
logic int_spi_clk = 0;
always_ff @ (posedge clk_200M or negedge nrst)
begin
//Reset
if(nrst == 0)
begin
clk_divider = 0;
end
//Normal Operation
else
begin
if(clk_divider == 9)
begin
clk_divider = 0;
int_spi_clk = ~int_spi_clk;
end
else
begin
clk_divider++;
end
end
end
/*
Send the data out on the spi pin
*/
logic [15:0] int_spi_data;
logic state = 0, sclk_en = 0;
logic [15:0] data_stage = 16;
assign busy = state;
//Capture the input data on the rising edge of 'data_latch'
always_ff @ (posedge data_latch or negedge nrst)
begin
if(nrst == 0)
begin
int_spi_data = 0;
end
else
begin
int_spi_data = data_in;
end
end
always_comb
begin
if(sclk_en == 1) spi_sclk = int_spi_clk;
else spi_sclk = 0;
end
//Generates a starting pulse for the data transmission
pulse_gen gen0(.in_edge(data_latch), .clk(int_spi_clk), .out_pulse(output_pulse));
//Clock the data out
always_ff @ (negedge int_spi_clk or negedge nrst)
begin
if(nrst == 0)
begin
state = 0;
sclk_en = 0;
data_stage = 16;
end
else
begin
case(state)
0: begin
if(output_pulse == 1)
begin
state = 1;
end
end
1: begin
if(data_stage == 0)
begin
state <= 0;
sclk_en <= 0;
data_stage <= 16;
end
else
begin
sclk_en <= 1;
spi_data <= int_spi_data[data_stage - 1];
data_stage--;
end
end
endcase
end
end
endmodule
/*
Pulse generator creates a pulse of 'n' number of 'clk' cycles.
*/
module pulse_gen (
//Inputs
input logic in_edge,
clk,
//Output
output logic out_pulse
);
reg r1 = 0, r2 = 0, r3 = 0, r4 = 0;
always_ff @ (posedge clk)
begin
r1 <= in_edge; // first stage of 2-stage synchronizer
r2 <= r1; // second stage of 2-stage synchronizer
r3 <= r2; // edge detector memory
r4 <= r3;
end
assign out_pulse = r2 & ~r4;
endmodule