blob: f3e9175fb51c74332666eea2787ad39d42d8f9e0 [file] [log] [blame] [edit]
`timescale 1ns/1ps
module i2c_scan (
// Clock and reset
input wire clk,
input wire rst,
// I2C control signals for 3-state IO buffers
input wire scl_i,
output wire scl_o,
output wire scl_t,
input wire sda_i,
output wire sda_o,
output wire sda_t,
// UART
input wire rx,
output wire tx,
// Scan control
input wire i_trg,
output reg i_bsy
);
// ============================================================================
parameter UART_PRESCALER = 868; // UART prescaler
parameter [15:0] I2C_PRESCALER = 999; // I2C prescaler
parameter [6 :0] I2C_BEG_ADDR = 7'b0000_100;
parameter [6 :0] I2C_END_ADDR = 7'b1111_000;
// UART transfer interval
localparam TX_INTERVAL = UART_PRESCALER * 11; // Wait for 10-bits + 1 extra
// ============================================================================
// I2C probing module
reg probe_i_stb;
reg [6:0] probe_i_adr;
wire probe_i_bsy;
wire probe_o_stb;
wire probe_o_ack;
i2c_probe #
(
.I2C_PRESCALER (I2C_PRESCALER)
)
i2c_probe
(
.clk (clk),
.rst (rst),
.scl_i (scl_i),
.scl_o (scl_o),
.scl_t (scl_t),
.sda_i (sda_i),
.sda_o (sda_o),
.sda_t (sda_t),
.i_stb (probe_i_stb),
.i_adr (probe_i_adr),
.i_bsy (probe_i_bsy),
.o_stb (probe_o_stb),
.o_ack (probe_o_ack)
);
// ============================================================================
// Control FSM
localparam FSM_IDLE = 'h00;
localparam FSM_INIT = 'h20;
localparam FSM_PROBE_REQ = 'h30;
localparam FSM_PROBE_WAIT = 'h40;
localparam FSM_PROBE_DONE = 'h50;
localparam FSM_TX_1 = 'h60;
localparam FSM_TX_2 = 'h61;
localparam FSM_TX_3 = 'h62;
localparam FSM_TX_4 = 'h63;
localparam FSM_TX_5 = 'h64;
localparam FSM_TX_6 = 'h65;
localparam FSM_NEXT = 'h70;
integer fsm;
initial fsm <= FSM_IDLE;
always @(posedge clk)
if (rst) fsm <= FSM_IDLE;
else case(fsm)
FSM_IDLE: if (i_trg) fsm <= FSM_INIT;
else fsm <= fsm;
FSM_INIT: fsm <= FSM_PROBE_REQ;
FSM_PROBE_REQ: fsm <= FSM_PROBE_WAIT;
FSM_PROBE_WAIT: if (probe_o_stb) fsm <= FSM_PROBE_DONE;
else fsm <= fsm;
FSM_PROBE_DONE: fsm <= FSM_TX_1;
FSM_TX_1: if (wait_s) fsm <= FSM_TX_2;
else fsm <= fsm;
FSM_TX_2: if (wait_s) fsm <= FSM_TX_3;
else fsm <= fsm;
FSM_TX_3: if (wait_s) fsm <= FSM_TX_4;
else fsm <= fsm;
FSM_TX_4: if (wait_s) fsm <= FSM_TX_5;
else fsm <= fsm;
FSM_TX_5: if (wait_s) fsm <= FSM_TX_6;
else fsm <= fsm;
FSM_TX_6: if (wait_s) fsm <= FSM_NEXT;
else fsm <= fsm;
FSM_NEXT: if (probe_i_adr == I2C_END_ADDR) fsm <= FSM_IDLE;
else fsm <= FSM_PROBE_REQ;
default: fsm <= fsm;
endcase
// ============================================================================
// Busy signal
always @(posedge clk)
if (rst) i_bsy <= 1'd0;
else case (fsm)
FSM_IDLE: if(i_trg) i_bsy <= 1'b1;
else i_bsy <= 1'b0;
default: i_bsy <= i_bsy;
endcase
// ============================================================================
// Wait counter
reg [32:0] wait_cnt;
wire wait_s;
always @(posedge clk)
if (rst) wait_cnt <= 0;
else case (fsm)
FSM_TX_1: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
FSM_TX_2: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
FSM_TX_3: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
FSM_TX_4: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
FSM_TX_5: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
FSM_TX_6: if (wait_s) wait_cnt <= TX_INTERVAL;
else wait_cnt <= wait_cnt - 1;
default: if (wait_s) wait_cnt <= wait_cnt;
else wait_cnt <= wait_cnt - 1;
endcase
assign wait_s = wait_cnt[32];
// ============================================================================
// I2C probe control
reg probe_o_ack_r;
always @(posedge clk)
if (probe_o_stb)
probe_o_ack_r <= probe_o_ack;
else
probe_o_ack_r <= probe_o_ack_r;
always @(posedge clk)
if (rst) probe_i_stb <= 1'd0;
else case (fsm)
FSM_PROBE_REQ: probe_i_stb <= 1'd1;
default: probe_i_stb <= 1'd0;
endcase
always @(posedge clk)
case (fsm)
FSM_INIT: probe_i_adr <= I2C_BEG_ADDR;
FSM_NEXT: probe_i_adr <= probe_i_adr + 1;
default: probe_i_adr <= probe_i_adr;
endcase
// ============================================================================
// Output data formatter
reg uart_i_stb;
reg [4:0] uart_i_dat;
always @(posedge clk)
if (rst) uart_i_stb <= 1'b0;
else case(fsm)
FSM_TX_1: uart_i_stb <= wait_s;
FSM_TX_2: uart_i_stb <= wait_s;
FSM_TX_3: uart_i_stb <= wait_s;
FSM_TX_4: uart_i_stb <= wait_s;
FSM_TX_5: uart_i_stb <= wait_s;
FSM_TX_6: uart_i_stb <= wait_s;
default: uart_i_stb <= 1'b0;
endcase
always @(posedge clk)
case(fsm)
FSM_TX_1: uart_i_dat <= {2'b0, probe_i_adr[6:4]};
FSM_TX_2: uart_i_dat <= {1'b0, probe_i_adr[3:0]};
FSM_TX_3: uart_i_dat <= 5'h1F;
FSM_TX_4: uart_i_dat <= probe_o_ack_r;
FSM_TX_5: uart_i_dat <= 5'h10;
FSM_TX_6: uart_i_dat <= 5'h11;
endcase
// ============================================================================
// UART character mapper
reg uart_x_stb;
reg [7:0] uart_x_dat;
always @(posedge clk)
case (uart_i_dat)
5'h00: uart_x_dat <= "0";
5'h01: uart_x_dat <= "1";
5'h02: uart_x_dat <= "2";
5'h03: uart_x_dat <= "3";
5'h04: uart_x_dat <= "4";
5'h05: uart_x_dat <= "5";
5'h06: uart_x_dat <= "6";
5'h07: uart_x_dat <= "7";
5'h08: uart_x_dat <= "8";
5'h09: uart_x_dat <= "9";
5'h0A: uart_x_dat <= "A";
5'h0B: uart_x_dat <= "B";
5'h0C: uart_x_dat <= "C";
5'h0D: uart_x_dat <= "D";
5'h0E: uart_x_dat <= "E";
5'h0F: uart_x_dat <= "F";
5'h10: uart_x_dat <= "\r";
5'h11: uart_x_dat <= "\n";
default: uart_x_dat <= " ";
endcase
always @(posedge clk or posedge rst)
if (rst) uart_x_stb <= 1'd0;
else uart_x_stb <= uart_i_stb;
// ============================================================================
// UART
// Baudrate prescaler initializer
reg [7:0] reg_div_we_sr;
wire reg_div_we;
always @(posedge clk or posedge rst)
if (rst) reg_div_we_sr <= 8'h01;
else reg_div_we_sr <= {reg_div_we_sr[6:0], 1'd0};
assign reg_div_we = reg_div_we_sr[7];
// The UART
simpleuart uart
(
.clk (clk),
.resetn (!rst),
.ser_rx (rx),
.ser_tx (tx),
.reg_div_we ({reg_div_we, reg_div_we, reg_div_we, reg_div_we}),
.reg_div_di (UART_PRESCALER),
.reg_div_do (),
.reg_dat_we (uart_x_stb),
.reg_dat_re (1'd0),
.reg_dat_di ({24'd0, uart_x_dat}),
.reg_dat_do (),
.reg_dat_wait ()
);
// Debug
always @(posedge clk)
if (uart_x_stb)
$display("[%02Xh] %c", uart_x_dat, uart_x_dat);
endmodule