read bytes 0 to 63 of spd then store (sim passing)

This commit is contained in:
AngeloJacobo 2024-12-29 14:47:57 +08:00
parent fbc4b5ff9a
commit 75857a0af0
5 changed files with 114 additions and 28 deletions

View File

@ -0,0 +1,20 @@
############## clock define##################
create_clock -period 5.000 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_SSTL15 [get_ports sys_clk_p]
# no need to constrain N side (only P side) or else tool will analyze interclock oaths and show failure in timing
# https://support.xilinx.com/s/article/57109?language=en_US
#create_clock -period 5.000 [get_ports sys_clk_n]
set_property PACKAGE_PIN AE10 [get_ports sys_clk_p]
set_property PACKAGE_PIN AF10 [get_ports sys_clk_n]
set_property IOSTANDARD DIFF_SSTL15 [get_ports sys_clk_n]
############## SODIMM SPD define##################
set_property IOSTANDARD LVCMOS33 [get_ports i2c_scl]
set_property PACKAGE_PIN B20 [get_ports i2c_scl]
set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda]
set_property PACKAGE_PIN C20 [get_ports i2c_sda]
############## fan define##################
set_property IOSTANDARD LVCMOS25 [get_ports fan_pwm]
set_property PACKAGE_PIN AE26 [get_ports fan_pwm]
############## key define##################
set_property PACKAGE_PIN AG27 [get_ports i_rst_n]
set_property IOSTANDARD LVCMOS25 [get_ports i_rst_n]

View File

@ -7,7 +7,10 @@ module spd_reader (
input wire i_rst_n,
// i2c interface
inout wire i2c_scl,
inout wire i2c_sda
inout wire i2c_sda,
// state of spd reader
(* mark_debug = "true" *) output reg find_i2c_address_done,
(* mark_debug = "true" *) output reg read_spd_done
// uart interface
// input uart_rx,
// output uart_tx
@ -25,9 +28,9 @@ module spd_reader (
localparam I2C_ADDRESS = 7'h30;
localparam IDLE = 0,
READ_ADDRESS = 1,
READ_BYTE = 1,
WAIT_ACK = 2;
(* mark_debug = "true" *) reg[1:0] state_find_i2c_address;
(* mark_debug = "true" *) reg find_i2c_address_done;
(* mark_debug = "true" *) reg[6:0] i2c_address;
// i2c master interface
@ -38,7 +41,27 @@ module spd_reader (
wire[7:0] miso_data;
wire busy;
wire slave_nack;
(* mark_debug = "true" *) reg nack_unexpected_err;
(* mark_debug = "true" *) reg[2:0] state_read_spd;
(* mark_debug = "true" *) reg[5:0] byte_address; // read until byte 63
(* mark_debug = "true" *) reg[7:0] byte_data[63:0];
// initialize in case fpga starts with no reset
initial begin
state_find_i2c_address = IDLE;
find_i2c_address_done = 0;
enable = 1'b0;
read_write = 1'b0;
register_address = 8'd0;
i2c_address = 7'd0;
read_spd_done = 1'b0;
nack_unexpected_err = 1'b0;
state_read_spd = IDLE;
byte_address = 6'h00;
end
// main FSM
always @(posedge i_clk, negedge i_rst_n) begin
if(!i_rst_n) begin
state_find_i2c_address <= IDLE;
@ -47,13 +70,17 @@ module spd_reader (
read_write <= 1'b0;
register_address <= 8'd0;
i2c_address <= 7'd0;
read_spd_done <= 1'b0;
nack_unexpected_err <= 1'b0;
state_read_spd <= IDLE;
byte_address <= 6'h00;
end
else begin
// Find I2C Address of SPD
case(state_find_i2c_address)
IDLE: if(!find_i2c_address_done) begin
state_find_i2c_address <= READ_ADDRESS;
i2c_address <= 7'd0;
i2c_address <= 7'h01; // start brute force find i2c address from 1 (0 might be general call)
end
READ_ADDRESS: if(!busy) begin
enable <= 1'b1;
@ -71,10 +98,44 @@ module spd_reader (
state_find_i2c_address <= IDLE;
find_i2c_address_done <= 1'b1;
end
end
else begin
enable <= 1'b0;
end
default: state_find_i2c_address <= IDLE;
endcase
// read bytes from SPD
case(state_read_spd)
IDLE: if(find_i2c_address_done && !read_spd_done && !nack_unexpected_err) begin // start read SPD only once i2c address is found
state_read_spd <= READ_BYTE;
byte_address <= 6'h00; // start read from byte 0
end
else begin
enable <= 1'b0;
READ_BYTE: if(!busy) begin // if not busy, send i2c read transaction
enable <= 1'b1;
read_write <= 1'b1; // read i2c
register_address <= {2'b00,byte_address};
device_address <= i2c_address;
state_read_spd <= WAIT_ACK;
end
WAIT_ACK: if(!busy && !enable) begin
if(slave_nack) begin // if i2c_address NACKS, then something is wrong, raise nack_unexpected_err
nack_unexpected_err <= 1'b1;
state_read_spd <= IDLE;
end
else begin // I2C acks so store the received byte
byte_data[byte_address] <= miso_data;
state_read_spd <= READ_BYTE;
byte_address <= byte_address + 1;
if(byte_address == 63) begin
read_spd_done <= 1'b1;
state_read_spd <= IDLE;
end
end
end
else begin
enable <= 1'b0;
end
endcase
end
end

View File

@ -9,15 +9,21 @@ module spd_reader_top (
// i2c interface
inout wire i2c_scl,
inout wire i2c_sda,
output wire i2c_lsb,
// fan
output wire fan_pwm
output wire fan_pwm,
//Debug LEDs
output wire[3:0] led
);
assign fan_pwm = 1'b0; // turn on fan
assign i2c_lsb = 1'b0;
wire clk_locked;
wire main_clk_100;
wire find_i2c_address_done, read_spd_done;
assign fan_pwm = 1'b0; // turn on fan from the start
assign led[0] = find_i2c_address_done; // lights up once done
assign led[1] = find_i2c_address_done;
assign led[2] = read_spd_done;
assign led[3] = read_spd_done;
//===========================================================================
//Differentia system clock to single end clock
@ -51,7 +57,9 @@ module spd_reader_top (
.i_clk(main_clk_100),
.i_rst_n(i_rst_n && clk_locked),
.i2c_scl(i2c_scl),
.i2c_sda(i2c_sda)
.i2c_sda(i2c_sda),
.find_i2c_address_done(find_i2c_address_done),
.read_spd_done(read_spd_done)
);

View File

@ -72,7 +72,7 @@ module i2c_slave (scl, sda);
//
// parameters
//
parameter I2C_ADR = 7'b001_0000;
parameter I2C_ADR = 7'b000_0100;
//
// input && outpus
@ -86,13 +86,13 @@ module i2c_slave (scl, sda);
wire debug = 1'b1;
genvar i;
reg [7:0] mem [3:0]; // initiate memory
reg [7:0] mem [99:0]; // initiate memory
integer index;
initial begin
mem[0] = 8'd00;
mem[1] = 8'd01;
mem[2] = 8'd02;
mem[3] = 8'd03;
for (index = 0; index <= 100; index = index + 1) begin
mem[index] = index; // Assign each element with its index value
end
end
reg [7:0] mem_adr; // memory address
@ -350,14 +350,14 @@ module i2c_slave (scl, sda);
fast_tsu_sto = 600,
fast_tbuf = 1300;
$width(negedge scl, normal_scl_low); // scl low time
$width(posedge scl, normal_scl_high); // scl high time
// $width(negedge scl, normal_scl_low); // scl low time
// $width(posedge scl, normal_scl_high); // scl high time
$setup(posedge scl, negedge sda &&& scl, normal_tsu_sta); // setup start
$setup(negedge sda &&& scl, negedge scl, normal_thd_sta); // hold start
$setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // setup stop
// $setup(posedge scl, negedge sda &&& scl, normal_tsu_sta); // setup start
// $setup(negedge sda &&& scl, negedge scl, normal_thd_sta); // hold start
// $setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // setup stop
$setup(posedge tst_sta, posedge tst_sto, normal_tbuf); // stop to start time
// $setup(posedge tst_sta, posedge tst_sto, normal_tbuf); // stop to start time
endspecify
endmodule

View File

@ -17,10 +17,7 @@ module spd_reader_tb;
.i_rst_n(rst_n),
// i2c interface
.i2c_scl(scl),
.i2c_sda(sda),
.i2c_lsb(),
// fan
.fan_pwm()
.i2c_sda(sda)
);
initial begin
@ -28,7 +25,7 @@ module spd_reader_tb;
rst_n = 0;
#100;
rst_n = 1;
wait(DUT.spd_reader_inst.find_i2c_address_done);
wait(DUT.spd_reader_inst.read_spd_done);
#10_000;
$stop;
end