!!求助 i2c verilog 程序是否成功发送接收数据 求详解
/////////////////////////////////////////////////////////////////////
//// ////
////I2C slave RTL code ////
//// ////
module I2Cslave(rst, sysclk, scl, sda, RAM_DO, RAM_DI, RAM_Addr, RAM_RW, RAM_EN);
// system interface
input rst;
input sysclk;
// I2C interface
input scl;
inout sda;
// RAM port interface
input RAM_DO;
output RAM_Addr;
output RAM_DI;
output RAM_RW;
output RAM_EN;
parameter I2C_ADR = 7'b0010000;// The 7-bits address for our I2C slave
//////////////////////////
// varialbes declaration
//////////////////////////
reg scl_r, sda_r; // scl/sda input register
reg scl_r2, sda_r2; // scl/sda input register second stage
reg start_con, stop_con;// start / stop condition pulse
reg sr; // shift register to store the input bits
reg ld; // bit down counter sync load signal
reg cycle_pulse; // cycle positive pulse clock enalbe
reg cycle_pulse_n; // cycle negative pulse clock enalbe
reg operation_dir; // read operation ( =1 ) or write operation ( =0 )
reg bit_cnt; // down counter
reg sda_in; // registed type of sda
reg sda_oe; // sda output enable (for tristate, low active)
reg mem_adr; // memory address register
reg mem_do; // memory output register
reg memory_rw; // memory read enable
reg ram_clken,ram_clken_r;// SRAM clock enable
reg rw_reg_en; // clock enable for register operation_dir
reg mem_load, mem_acc, mem_acc_r; // signals for register mem_adr
reg mem_update;
wire sda_rise, sda_fall;
wire byte_done;
// statemachine declaration
parameter start = 3'b001;
parameter slave_addr= 3'b010;
parameter slave_addr_ack = 3'b011;
parameter mem_addr= 3'b100;
parameter mem_addr_ack= 3'b101;
parameter data = 3'b110;
parameter data_ack= 3'b111;
reg cs,ns;
////////////////////////////////////////////////////////////////////////////////
// rtl body
////////////////////////////////////////////////////////////////////////////////
//////////////////////////
// I2C slave <--> RAM interface logic
//////////////////////////
assign RAM_Addr = mem_adr;
assign RAM_RW = operation_dir;
assign RAM_DI = sr;
assign RAM_EN = ram_clken && ~ram_clken_r;
always @(posedge sysclk)
ram_clken_r <= ram_clken;
always @(posedge sysclk)
if (mem_update)
mem_do <= RAM_DO;
else if (cycle_pulse_n)
if(!byte_done && operation_dir)
mem_do <= {mem_do, 1'b1};// insert 1'b1 for host ack generation
//////////////////////////
// I2C input logic
//////////////////////////
// synchronize scl and sda inputs into registers
always @(posedge sysclk or posedge rst)
if (rst)
begin
scl_r <= 1'b1;
sda_r <= 1'b1;
scl_r2 <= 1'b1;
sda_r2 <= 1'b1;
end
else
begin
scl_r <= scl;
sda_r <= sda;
scl_r2 <= scl_r;
sda_r2 <= sda_r;
end
// detect start condition => detect falling edge on sda while scl is high
// detect stop condition => detect rising edge on sda while scl is high
assign sda_rise = sda_r && ~sda_r2;
assign sda_fall = sda_r2 && ~sda_r;
always @(posedge sysclk or posedge rst)
if (rst)
begin
start_con <= 1'b0;
stop_con <= 1'b0;
end
else
begin
start_con <= sda_fall && scl_r;
stop_con <= sda_rise && scl_r;
end
// generate cycle pulse signal to pace the procedure in low operation speed
always @(posedge sysclk)
if (scl_r && ~scl_r2)
cycle_pulse <= 1'b1;
else
cycle_pulse <= 1'b0;
always @(posedge sysclk)
if (~scl_r && scl_r2)
cycle_pulse_n <= 1'b1;
else
cycle_pulse_n <= 1'b0;
// store sda input into register
always @(posedge sysclk) sda_in <= sda;
//////////////////////////
// I2C incoming bits down counter & shift register
//////////////////////////
// one byte transmission done signal
assign byte_done = !(|bit_cnt);
always @(posedge sysclk)
if (ld)
bit_cnt <= 4'b1000;
else
if(cycle_pulse) bit_cnt <= bit_cnt - 4'h1;
// shift register
always @(posedge sysclk)
if(cycle_pulse)
sr <= {sr,sda_in};
//////////////////////////
// I2C slave address comparasion
//////////////////////////
wire addr_match = (sr == I2C_ADR);
//////////////////////////
// register space address validation
//////////////////////////
wire addr_valid = (mem_adr <= 15);
//////////////////////////
// I2C slave tri-states sda line
//////////////////////////
assign sda = sda_oe ? 1'bz : 1'b0;
//////////////////////////
// misc logic derived from statemachine
//////////////////////////
// operation_dir logic
always @(posedge sysclk or posedge rst)
if (rst)
operation_dir <= 1'b0;// default : write
else if (rw_reg_en)
operation_dir <= memory_rw; // store the current session r/w (r=1,w=0)
// mem_adr logic
always @(posedge sysclk)
mem_acc_r <= mem_acc;
always @(posedge sysclk or posedge rst)
if (rst)
mem_adr <= 4'h0;
else if (mem_load)
mem_adr <= sr; // mem address storage
else if (mem_acc && ~mem_acc_r)
mem_adr <= mem_adr + 8'h1; // mem internal accumulator
//////////////////////////
// I2C slave statemachine
//////////////////////////
// state machine current state flip-flop
always @(posedge sysclk or posedge rst)
if (rst)
cs <= start;
else if (start_con || stop_con)
cs <= start;
else if (cycle_pulse_n)
cs <= ns;
wire master_nack = sr;
// state machine next state codec
always @(cs, byte_done, addr_match, operation_dir, master_nack)
case(cs) // synopsys full_case parallel_case
start:
ns <= slave_addr;
slave_addr:
if (byte_done && addr_match)
ns <= slave_addr_ack;
else
ns <= slave_addr;
slave_addr_ack:
if(operation_dir)
ns <= data;
else
ns <= mem_addr;
mem_addr:
if(byte_done)
ns <= mem_addr_ack;
else
ns <= mem_addr;
mem_addr_ack:
ns <= data;
data:
if(byte_done)
ns <= data_ack;
else
ns <= data;
data_ack:
if(operation_dir)
if(master_nack) // read operation && master send NACK
ns <= start;
else
ns <= data;
else
ns <= data;
endcase
// state machine output codec
always @(rst, cs, byte_done, addr_match, operation_dir, master_nack, addr_valid, mem_do, sr)
if (rst)
begin
ld <= 1'b1; // down counter load disable
sda_oe <= 1'b1; // sda output disabled
ram_clken <= 1'b0;// ram clock disabled
memory_rw <= 1'b0;
rw_reg_en <= 1'b0;
mem_load <= 1'b0;
mem_acc <= 1'b0;
mem_update <= 1'b0;
end
else begin
// state machine default output
ld <= 1'b0; // down counter load disable
sda_oe <= 1'b1; // sda output disabled
ram_clken <= 1'b0;// ram clock disabled
memory_rw <= 1'b0;
rw_reg_en <= 1'b0;
mem_load <= 1'b0;
mem_acc <= 1'b0;
mem_update <= 1'b0;
case (cs)
start:
ld <= 1'b1;
slave_addr:
if (byte_done && addr_match)
begin
rw_reg_en <= 1'b1;
if(sr) memory_rw <= 1'b1;
end
slave_addr_ack:
begin
ld <= 1'b1; // reset the down counter
sda_oe <= 1'b0;// generate i2c_ack
if (operation_dir) begin
mem_update <= 1'b1;
ram_clken <= 1'b1;
end
end
mem_addr: // wait for memory address
if(byte_done) mem_load <= 1'b1;// store memory address
mem_addr_ack:
begin
sda_oe <= !addr_valid;// generate i2c_ack, for valid address
ld <= 1'b1; // reset the down counter
end
data: // receive or drive data
begin
// read operation
if(operation_dir) sda_oe <= mem_do;
if(operation_dir && byte_done) mem_acc <= 1'b1;
end
data_ack:
begin
// write operation
if(!operation_dir) mem_acc <= 1'b1;
ram_clken <= 1'b1;
mem_update <= 1'b1;
ld <= 1'b1;
if(operation_dir) // receive ack on read
sda_oe <= 1'b1;
else // send ack on write,
sda_oe <= 1'b0;
end
endcase
end
endmodule 这个自己仿真比较靠谱,别人给你说的都茫然
页:
[1]