2. 組幀模塊 (i2c_ctrl):
module i2c_ctrl
(
input rst,
input clk,
input[15:0] clk_div_cnt,
// I2C signals
// i2c clock line
input scl_pad_i, //SCL-line input
output scl_pad_o, //SCL-line output (always 1'b0)
output scl_padoen_o, //SCL-line output enable (active low)
// i2c data line
input sda_pad_i, //SDA-line input
output sda_pad_o, //SDA-line output (always 1'b0)
output sda_padoen_o, //SDA-line output enable (active low)
input i2c_addr_2byte, //register address 16bit or 8bit
input i2c_read_req, //Read register request
output i2c_read_req_ack, //Read register request response
input i2c_write_req, //Write register request
output i2c_write_req_ack, //Write register request response
input[7:0] i2c_slave_dev_addr, //I2c device address
input[15:0] i2c_slave_reg_addr, //I2c register address
input[7:0] i2c_write_data, //I2c write register data
output reg[7:0] i2c_read_data,//I2c read register data
output reg error //The error indication, generally there is no response
);
//State machine definition cascatrix carson
localparam S_IDLE= 0;
localparam S_WR_DEV_ADDR=1;
localparam S_WR_REG_ADDR=2;
localparam S_WR_DATA=3;
localparam S_WR_ACK=4;
localparam S_WR_ERR_NACK=5;
localparam S_RD_DEV_ADDR0=6;
localparam S_RD_REG_ADDR=7;
localparam S_RD_DEV_ADDR1=8;
localparam S_RD_DATA=9;
localparam S_RD_STOP=10;
localparam S_WR_STOP=11;
localparam S_WAIT=12;
localparam S_WR_REG_ADDR1=13;
localparam S_RD_REG_ADDR1=14;
localparam S_RD_ACK=15;
reg start;
reg stop;
reg read;
reg write;
reg ack_in;
reg[7:0] txr;
wire[7:0] rxr;
wire i2c_busy;
wire i2c_al;
wire done;
wire irxack;
reg[3:0] state, next_state;
assign i2c_read_req_ack = (state == S_RD_ACK);
assign i2c_write_req_ack = (state == S_WR_ACK);
always@(posedge clk or posedge rst)
begin
if(rst)
state <= S_IDLE;
else
state <= next_state;
end
always@(*)
begin
case(state)
S_IDLE:
//Waiting for read and write requests
if(i2c_write_req)
next_state <= S_WR_DEV_ADDR;
else if(i2c_read_req)
next_state <= S_RD_DEV_ADDR0;
else
next_state <= S_IDLE;
//Write I2C device address
S_WR_DEV_ADDR:
if(done && irxack)
next_state <= S_WR_ERR_NACK;
else if(done)
next_state <= S_WR_REG_ADDR;
else
next_state <= S_WR_DEV_ADDR;
//Write the address of the I2C register
S_WR_REG_ADDR:
if(done)
//If it is the 8bit register address, it enters the write data state
next_state<=i2c_addr_2byte? S_WR_REG_AD DR1 : S_WR_DATA;
else
next_state <= S_WR_REG_ADDR;
S_WR_REG_ADDR1:
if(done)
next_state <= S_WR_DATA;
else
next_state <= S_WR_REG_ADDR1;
//Write data
S_WR_DATA:
if(done)
next_state <= S_WR_STOP;
else
next_state <= S_WR_DATA;
S_WR_ERR_NACK:
next_state <= S_WR_STOP;
S_RD_ACK,S_WR_ACK:
next_state <= S_WAIT;
S_WAIT:
next_state <= S_IDLE;
S_RD_DEV_ADDR0:
if(done && irxack)
next_state <= S_WR_ERR_NACK;
else if(done)
next_state <= S_RD_REG_ADDR;
else
next_state <= S_RD_DEV_ADDR0;
S_RD_REG_ADDR:
if(done)
next_state<=i2c_addr_2byte?S_RD_REG_ADDR1 : S_RD_DEV_ADDR1;
else
next_state <= S_RD_REG_ADDR;
S_RD_REG_ADDR1:
if(done)
next_state <= S_RD_DEV_ADDR1;
else
next_state <= S_RD_REG_ADDR1;
S_RD_DEV_ADDR1:
if(done)
next_state <= S_RD_DATA;
else
next_state <= S_RD_DEV_ADDR1;
S_RD_DATA:
if(done)
next_state <= S_RD_STOP;
else
next_state <= S_RD_DATA;
S_RD_STOP:
if(done)
next_state <= S_RD_ACK;
else
next_state <= S_RD_STOP;
S_WR_STOP:
if(done)
next_state <= S_WR_ACK;
else
next_state <= S_WR_STOP;
default:
next_state <= S_IDLE;
endcase
end
always@(posedge clk or posedge rst)
begin
if(rst)
error <= 1'b0;
else if(state == S_IDLE)
error <= 1'b0;
else if(state == S_WR_ERR_NACK)
error <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
start <= 1'b0;
else if(done)
start <= 1'b0;
else if(state == S_WR_DEV_ADDR || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1)
start <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
stop <= 1'b0;
else if(done)
stop <= 1'b0;
else if(state == S_WR_STOP || state == S_RD_STOP)
stop <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
ack_in <= 1'b0;
else
ack_in <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
write <= 1'b0;
else if(done)
write <= 1'b0;
else if(state == S_WR_DEV_ADDR || state == S_WR_REG_ADDR || state == S_WR_REG_ADDR1|| state == S_WR_DATA || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1 || state == S_RD_REG_ADDR || state == S_RD_REG_ADDR1)
write <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
read <= 1'b0;
else if(done)
read <= 1'b0;
else if(state == S_RD_DATA)
read <= 1'b1;
end
always@(posedge clk or posedge rst)
begin
if(rst)
i2c_read_data <= 8'h00;
else if(state == S_RD_DATA && done)
i2c_read_data <= rxr;
end
always@(posedge clk or posedge rst)
begin
if(rst)
txr <= 8'd0;
else
case(state)
S_WR_DEV_ADDR,S_RD_DEV_ADDR0:
txr <= {i2c_slave_dev_addr[7:1],1'b0};
S_RD_DEV_ADDR1:
txr <= {i2c_slave_dev_addr[7:1],1'b1};
S_WR_REG_ADDR,S_RD_REG_ADDR:
txr<=(i2c_addr_2byte==1'b1)?i2c_slave_reg_addr[15 :8] : i2c_slave_reg_addr[7:0];
S_WR_REG_ADDR1,S_RD_REG_ADDR1:
txr <= i2c_slave_reg_addr[7:0];
S_WR_DATA:
txr <= i2c_write_data;
default:
txr <= 8'hff;
endcase
end
i2c_byte_ctrl byte_controller (
.clk ( clk ),
.rst ( rst ),
.nReset ( 1'b1 ),
.ena ( 1'b1 ),
.clk_cnt ( clk_div_cnt ),
.start ( start ),
.stop ( stop ),
.read ( read ),
.write ( write ),
.ack_in ( ack_in ),
.din ( txr ),
.cmd_ack ( done ),
.ack_out ( irxack ),
.dout ( rxr ),
.i2c_busy ( i2c_busy ),
.i2c_al ( i2c_al ),
.scl_i ( scl_pad_i ),
.scl_o ( scl_pad_o ),
.scl_oen ( scl_padoen_o ),
.sda_i ( sda_pad_i ),
.sda_o ( sda_pad_o ),
.sda_oen ( sda_padoen_o )
);
endmodule
3. 字節控制模塊(i2c_byte_ctrl):
`define I2C_CMD_NOP 4'b0000
`define I2C_CMD_START 4'b0001
`define I2C_CMD_STOP 4'b0010
`define I2C_CMD_WRITE 4'b0100
`define I2C_CMD_READ 4'b1000
module i2c_byte_ctrl (
input clk, // master clock
input rst, // synchronous active high reset
input nReset, // asynchronous active low reset
input ena, // core enable signal
input [15:0] clk_cnt, // 4x SCL
// control inputs
input start,
input stop,
input read,
input write,
input ack_in,
input [7:0] din,
// status outputs
output reg cmd_ack,
output reg ack_out,
output i2c_busy,
output i2c_al,
output [7:0] dout,
// I2C signals
input scl_i,
output scl_o,
output scl_oen,
input sda_i,
output sda_o,
output sda_oen
);
//
// Variable declarations cascatrix carson
//
// statemachine
parameter [4:0] ST_IDLE = 5'b0_0000;
parameter [4:0] ST_START = 5'b0_0001;
parameter [4:0] ST_READ = 5'b0_0010;
parameter [4:0] ST_WRITE = 5'b0_0100;
parameter [4:0] ST_ACK = 5'b0_1000;
parameter [4:0] ST_STOP = 5'b1_0000;
// signals for bit_controller
reg [3:0] core_cmd;
reg core_txd;
wire core_ack, core_rxd;
// signals for shift register
reg [7:0] sr; //8bit shift register
reg shift, ld;
// signals for state machine
wire go;
reg [2:0] dcnt;
wire cnt_done;
// bit_controller
i2c_bit_ctrl bit_controller (
.clk ( clk ),
.rst ( rst ),
.nReset ( nReset ),
.ena ( ena ),
.clk_cnt ( clk_cnt ),
.cmd ( core_cmd ),
.cmd_ack ( core_ack ),
.busy ( i2c_busy ),
.al ( i2c_al ),
.din ( core_txd ),
.dout ( core_rxd ),
.scl_i ( scl_i ),
.scl_o ( scl_o ),
.scl_oen ( scl_oen ),
.sda_i ( sda_i ),
.sda_o ( sda_o ),
.sda_oen ( sda_oen )
);
// generate go-signal
assign go = (read | write | stop) & ~cmd_ack;
// assign dout output to shift-register
assign dout = sr;
// generate shift register
always @(posedge clk or negedge nReset)
if (!nReset)
sr <= #1 8'h0;
else if (rst)
sr <= #1 8'h0;
else if (ld)
sr <= #1 din;
else if (shift)
sr <= #1 {sr[6:0], core_rxd};
// generate counter
always @(posedge clk or negedge nReset)
if (!nReset)
dcnt <= #1 3'h0;
else if (rst)
dcnt <= #1 3'h0;
else if (ld)
dcnt <= #1 3'h7;
else if (shift)
dcnt <= #1 dcnt - 3'h1;
assign cnt_done = ~(|dcnt);
//
// state machine
//
reg [4:0] c_state; // synopsys enum_state
always @(posedge clk or negedge nReset)
if (!nReset)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else if (rst | i2c_al)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else
begin
// initially reset all signals
core_txd <= #1 sr[7];
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
case (c_state) // synopsys full_case parallel_case
ST_IDLE:
if (go)
begin
if (start)
begin
c_state <= #1 ST_START;
core_cmd <= #1 `I2C_CMD_START;
end
else if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else if (write)
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else // stop
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end
ld <= #1 1'b1;
end
ST_START:
if (core_ack)
begin
if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
ld <= #1 1'b1;
end
ST_WRITE:
if (core_ack)
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
// stay in same state
c_state <= #1 ST_WRITE;
// write next bit
core_cmd <= #1 `I2C_CMD_WRITE;
shift <= #1 1'b1;
end
ST_READ:
if (core_ack)
begin
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else
begin
// stay in same state
c_state <= #1 ST_READ;
// read next bit
core_cmd <= #1 `I2C_CMD_READ;
end
shift <= #1 1'b1;
core_txd <= #1 ack_in;
end
ST_ACK:
if (core_ack)
begin
if (stop)
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end
else
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end
// assign ack_out output to bit_controller_rxd (contains last received bit)
ack_out <= #1 core_rxd;
core_txd <= #1 1'b1;
end
else
core_txd <= #1 ack_in;
ST_STOP:
if (core_ack)
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;
// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end
endcase
end
endmodule
-
IIC
+關注
關注
11文章
300瀏覽量
38277 -
通信總線
+關注
關注
0文章
44瀏覽量
9844 -
SDA
+關注
關注
0文章
124瀏覽量
28118
發布評論請先 登錄
相關推薦
評論