📄 at24c02_rw.v
字号:
// AT24C02_RW.v
`timescale 1ns / 100ps
module AT24C02_RW(
clk,
reset_n,
addr,
data_i,
data_o,
cs_n,
wr_n,
iowait,
ioend,
scl,
sda
);
parameter STATE_IDLE = 0;
parameter STATE_START = 1;
parameter STATE_DADDR = 2;
parameter STATE_WADDR = 3;
parameter STATE_WR_DATA = 4;
parameter STATE_WR_WAIT = 5;
parameter STATE_START1 = 6;
parameter STATE_DADDR1 = 7;
parameter STATE_RD_DATA = 8;
parameter STATE_STOP = 9;
input clk; //1MHz
input reset_n;
input [7:0] addr;
input [7:0] data_i;
output [7:0] data_o;
input cs_n;
input wr_n;
input iowait;
output ioend;
output scl;
inout sda;
//inner signal
reg sda_oe;
reg sda_o;
reg [3:0] opstate;
reg [1:0] clkdiv;
wire count_en;
reg count_ld;
wire count_over;
reg [10:0] count_init;
reg sht_en;
reg sht_ld;
wire sht_sdo;
reg [7:0] sht_pdi;
wire [7:0] sht_pdo;
//i2c gen scl
always@(posedge clk or negedge reset_n)
clkdiv <= reset_n ? clkdiv + 1 : 2'b00;
wire scl_l = (clkdiv==2'b00);
wire scl_up = (clkdiv==2'b01);
wire scl_h = (clkdiv==2'b10);
wire scl_dn = (clkdiv==2'b11);
assign scl = ((opstate==STATE_IDLE)||(opstate==STATE_WR_WAIT)) ? 1 : clkdiv[1];
assign sda = sda_oe ? sda_o : 1'bz;
//wire count_over = (bitcount==0);
//bus io over
assign ioend = (opstate==STATE_STOP) && (count_over) && (scl_h) && iowait;
//assign data_o = sht_pdo;
//迭代器
dncounter #(.COUNTER_W (11)) u_count(
.clk (clk),
.reset (~reset_n),
.clk_en (count_en),
.load (count_ld),
.din (count_init),
.dout (),
.count_over (count_over)
);
//收发缓存
shiftbuf u_buf(
.clk (clk),
.reset (~reset_n),
.clk_en (sht_en),
.load (sht_ld),
.pdi (sht_pdi),
.pdo (sht_pdo),
.sdi (sda),
.sdo (sht_sdo)
);
//set counter init
always@(*) begin
case(opstate)
STATE_WR_DATA, STATE_RD_DATA: //发送数据,接收数据->发送stop
count_init = 1; //准备发送停止
STATE_STOP: //发送stop
count_init = 1280; //等待内部写5ms 1280*4*0.001=5.12
STATE_DADDR1:
count_init = 8;
default:
count_init = 8;
endcase
end
//set counter load
always@(*) begin
case(opstate)
STATE_START, STATE_START1: //发送start
count_ld= scl_h;
STATE_DADDR, STATE_DADDR1, STATE_WADDR, STATE_WR_DATA, STATE_RD_DATA: //发送设备地址写,发送读设备地址,发送字地址,发送数据,接收数据
count_ld = (scl_l && count_over);
STATE_STOP: //发送stop
count_ld = (scl_h && (count_over) && ~wr_n);
default:
count_ld = 0;
endcase
end
//set counter enable
assign count_en = scl_l;
//set shift reg init sht_pdi
always@(*) begin
case(opstate)
STATE_START: sht_pdi = 8'b1010_000_0; //device address and write
STATE_DADDR: sht_pdi = addr;
STATE_WADDR: sht_pdi = data_i;
STATE_START1: sht_pdi = 8'b1010_000_1; //device address and read
default: sht_pdi = 8'hxx;
endcase
end
//set shift reg load sht_ld
always@(*) begin
case(opstate)
STATE_START, STATE_START1: sht_ld = scl_h;
STATE_DADDR, STATE_WADDR: sht_ld = (scl_l && count_over);
default: sht_ld = 0;
endcase
end
//set shift reg enable sht_en
always@(*) begin
case(opstate)
STATE_DADDR, STATE_DADDR1, STATE_WADDR, STATE_WR_DATA: //发送
sht_en = scl_l;
STATE_RD_DATA: //接收数据
sht_en = scl_dn;
default:
sht_en = 0;
endcase
end
//oprate state
reg [7:0] data_o;
always@(posedge clk or negedge reset_n) begin
if(~reset_n) begin
opstate <= #1 STATE_IDLE;
sda_oe <= #1 1'b1;
sda_o <= #1 1'b1;
data_o <= 0;
end else begin
case(opstate)
STATE_IDLE: //空闲
begin
sda_o <= #1 1'b1;
sda_oe <= #1 1'b1;
if(iowait && scl_dn) //启动读写操作
opstate <= #1 STATE_START;
end
STATE_START: //发送start
begin
sda_oe <= #1 1'b1;
if(scl_h)
sda_o <= #1 1'b0; //send start
if(scl_h)
opstate <= #1 STATE_DADDR;
end
STATE_DADDR: //发送设备地址写
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_WADDR;
sda_o <= #1 1;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WADDR: //发送字地址
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 wr_n ? STATE_START1 : STATE_WR_DATA;
sda_o <= #1 1;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WR_DATA: //发送数据
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_STOP;
sda_o <= #1 0;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WR_WAIT: //等待内部写5ms
begin
if(scl_l && count_over)
opstate <= #1 STATE_IDLE;
end
STATE_START1: //发送start
begin
if(scl_dn)
sda_oe <= #1 1'b1;
if(sda_oe && scl_h) begin
opstate <= #1 STATE_DADDR1;
sda_o <= #1 1'b0; //send start
end
end
STATE_DADDR1: //发送读设备地址
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_RD_DATA;
sda_o <= #1 0;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_RD_DATA: //接收数据
begin
sda_oe <= #1 1'b0; //set Hiz
sda_o <= #1 0;
if(scl_l && count_over) begin
opstate <= #1 STATE_STOP;
data_o <= sht_pdo;
end
end
STATE_STOP: //发送stop
begin
if(scl_dn)
sda_oe <= #1 1'b1;
if(sda_oe && scl_h) begin
opstate <= #1 wr_n ? STATE_IDLE : STATE_WR_WAIT;
sda_o <= #1 1'b1; //send start
end
end
endcase
end
end
/*
always@(posedge clk or negedge reset_n) begin
if(~reset_n) begin
opstate <= #1 STATE_IDLE;
sda_oe <= #1 1'b1;
sda_o <= #1 1'b1;
end else begin
case(opstate)
STATE_IDLE: //空闲
begin
if(iowait) //启动读写操作
opstate <= #1 STATE_START;
end
STATE_START: //发送start
begin
sda_oe <= #1 1'b1;
if(scl_l)
sda_o <= #1 1'b1;
else if(scl_h)
sda_o <= #1 1'b0; //send start
if(scl_h)
opstate <= #1 STATE_DADDR;
end
STATE_DADDR: //发送设备地址写
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_WADDR;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WADDR: //发送字地址
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 wr_n ? STATE_START1 : STATE_WR_DATA;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WR_DATA: //发送数据
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_STOP;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_WR_WAIT: //等待内部写5ms
begin
if(scl_l && count_over)
opstate <= #1 STATE_IDLE;
end
STATE_START1: //发送start
begin
if(scl_dn)
sda_oe <= #1 1'b1;
if(sda_oe && scl_h) begin
opstate <= #1 STATE_DADDR1;
sda_o <= #1 1'b0; //send start
end else if(scl_l)
sda_o <= #1 1'b1;
end
STATE_DADDR1: //发送读设备地址
begin
if(scl_dn)
sda_oe <= ~count_over;
if(scl_l) begin
if(count_over) begin
opstate <= #1 STATE_RD_DATA;
end else begin
sda_o <= #1 sht_sdo; //send out
end
end
end
STATE_RD_DATA: //接收数据
begin
sda_oe <= #1 1'b0; //set Hiz
if(scl_h && count_over)
opstate <= #1 STATE_STOP;
end
STATE_STOP: //发送stop
begin
if(scl_dn)
sda_oe <= #1 1'b1;
if(sda_oe && scl_h) begin
opstate <= #1 wr_n ? STATE_IDLE : STATE_WR_WAIT;
sda_o <= #1 1'b1; //send start
end else if(scl_l)
sda_o <= #1 1'b0;
end
endcase
end
end
*/
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -