|
- module i2c_at24cxx( //AT24Cxx I2C模块
- input clk, //50Mhz 时钟输入
- input [1:0] cmd, //[2位宽] I2C命令 0:I2C开始 1:I2C停止 2:I2C读 3:I2C写
- input call, //上升沿执行命令
- input [7:0] wb, //[8位宽] I2C写数据
- output reg [7:0] rb, //[8位宽] I2C读数据
- output reg ret, //命令执行完毕 发出上升沿
- output reg err, //ACK应答超时 发出上升沿
- inout sda, //[双向IO] 接24Cxx SDA脚
- output reg scl //接24Cxx SCL脚
- );
- reg rw = 1'b1; //SDA读写 1:输出 0:输入
- reg dat = 1'b1; //SDA写数据
- initial begin
- scl = 1'b1;
- err = 1'b0;
- end
- assign sda = rw ? dat : 1'bz;
- reg [4:0] state = 5'd0;
- reg [7:0] delay = 8'd0;
- wire [7:0] dclk = 8'd255;
- reg [15:0] timeout = 16'd0;
- reg [2:0] pc = 3'd0;
- reg [7:0] w = 8'd0;
- always @(posedge clk) begin
- if(|delay) begin //延时
- delay <= delay - 8'd1;
- end else begin
- case(state)
- 5'd0:begin
- err <= 1'b0;
- rw <= 1'b1;
- dat <= 1'b1;
- scl <= 1'b1;
- ret <= 1'b0;
- pc <= 3'd0;
- if(call) begin
- state <= {3'd0,cmd} + 5'd1;
- end else begin
- state <= 5'd0;
- end
- end
-
- 5'd1:begin //I2C开始
- rw <= 1'b1; //SDA输出
- dat <= 1'b1; //SDA=1
- scl <= 1'b1; //SCL=1
- delay <= dclk; //I2C_Delay();
- state <= 5'd5;
- end
-
- 5'd2:begin //I2C停止
- rw <= 1'b1; //SDA输出
- dat <= 1'b0;
- scl <= 1'b0;
- delay <= dclk;
- state <= 5'd8;
- end
-
- 5'd3:begin //I2C读
- rw <= 1'b1; //SDA输出
- rb <= 8'd0;
- scl <= 1'b0; //SCL=0
- delay <= dclk;
- state <= 5'd10;
- end
-
- 5'd4:begin //I2C写
- rw <= 1'b1; //SDA输出
- w <= wb;
- state <= 5'd14;
- end
-
- 5'd5:begin
- dat <= 1'b0;
- delay <= dclk;
- state <= 5'd6;
- end
-
- 5'd6:begin
- scl <= 1'b0;
- delay <= dclk;
- state <= 5'd7;
- end
-
- 5'd7:begin //返回
- ret <= 1'b1;
- state <= call ? 5'd7 : 5'd0;
- end
-
- 5'd8:begin
- scl <= 1'b1;
- delay <= dclk;
- state <= 5'd9;
- end
-
- 5'd9:begin
- dat <= 1'b1;
- state <= 5'd7;
- end
-
- 5'd10:begin
- dat <= 1'b1; //SDA=1
- delay <= dclk;
- state <= 5'd11;
- end
-
- 5'd11:begin //读 do
- rw <= 1'b0; //SDA输入
- scl <= 1'b1;
- delay <= dclk;
- state <= 5'd12;
- end
-
- 5'd12:begin
- rb[~pc] = sda;
- state <= 5'd13;
- end
-
- 5'd13:begin
- scl <= 1'b0;
- delay <= dclk;
- if(&pc) begin
- state <= 5'd7;
- end else begin
- state <= 5'd11;
- end
- pc <= pc + 3'd1;
- end
-
- 5'd14:begin //写 do
- scl <= 1'b0;
- delay <= dclk;
- state <= 5'd15;
- end
-
- 5'd15:begin
- dat <= w[~pc];
- delay <= dclk;
- state <= 5'd16;
- end
-
- 5'd16:begin
- scl <= 1'b1;
- delay <= dclk;
- if(&pc) begin
- state <= 5'd17;
- end else begin
- state <= 5'd14;
- end
- pc <= pc + 3'd1;
- end
-
- 5'd17:begin
- scl <= 1'b0;
- delay <= dclk;
- state <= 5'd18;
- end
-
- 5'd18:begin
- dat <= 1'b1;
- delay <= dclk;
- state <= 5'd19;
- end
-
- 5'd19:begin //ACK
- rw <= 1'b0; //SDA输入
- scl <= 1'b1;
- delay <= dclk;
- timeout <= 16'd0;
- state <= 5'd20;
- end
-
- 5'd20:begin
- if(sda) begin //等待ACK应答
- if(&timeout) begin //应答超时
- err <= 1'b1;
- state <= 5'd21;
- end else begin
- state <= 5'd20;
- timeout <= timeout + 16'd1;
- end
- end else begin
- state <= 5'd21;
- end
- end
-
- 5'd21:begin
- scl <= 1'b0;
- delay <= dclk;
- state <= 5'd7;
- end
-
- default:state <= 5'd0;
- endcase
- end
- end
- endmodule
- module at24c02(
- input clk, //50Mhz 时钟输入
- input rw, //高电平:读 低电平:写
- input call, //上升沿 开始执行操作
- input [7:0] pc, //[8位宽输入] 地址:0~255
- input [7:0] wb, //[8位宽输入] 写字节
- output reg [7:0] rb, //[8位宽输出] 读字节
- output reg ret, //操作完毕 发出上升沿
- output reg err, //高电平读写失败,低电平成功
- inout sda, //[双向IO] 接24C02 SDA脚
- output scl //接24C02 SCL脚
- );
- initial begin
- rb <= 8'd0;
- ret <= 1'b0;
- err <= 1'b0;
- end
- reg [7:0] i2c_w;
- wire [7:0] i2c_r;
- reg [1:0] i2c_cmd;
- reg [7:0] w;
- reg i2c_call;
- wire i2c_ret;
- wire i2c_err;
- reg [5:0] state = 6'd0;
- i2c_at24cxx i2c_at24cxx(
- .clk(!clk),
- .cmd(i2c_cmd),
- .call(i2c_call),
- .wb(i2c_w),
- .rb(i2c_r),
- .ret(i2c_ret),
- .err(i2c_err),
- .sda(sda),
- .scl(scl)
- );
- reg [17:0] delay = 18'd0;
- always @(posedge clk) begin
- if(|delay) begin
- delay <= delay - 18'd1;
- end else begin
- case(state)
- 6'd0:begin
- err <= 1'b0;
- ret <= 1'b0;
- if(call) begin
- state <= rw ? 6'd1 : 6'd2;
- end else begin
- state <= 6'd0;
- end
- end
-
- 6'd1:begin //读
- i2c_cmd <= 2'd0;
- state <= 6'd3;
- end
-
- 6'd2:begin //写
- w <= wb;
- i2c_cmd <= 2'd0;
- state <= 6'd25;
- end
-
- 6'd3:begin
- i2c_call <= 1'b1;
- state <= 6'd4;
- end
- 6'd4:begin
- state <= i2c_ret ? 6'd5 : 6'd4;
- end
-
- 6'd5:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= 8'hA0;
- state <= 6'd6;
- end
-
- 6'd6:begin
- i2c_call <= 1'b1;
- state <= 6'd7;
- end
- 6'd7:begin
- state <= i2c_ret ? 6'd8 : 6'd7;
- end
-
- 6'd8:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= pc;
- state <= i2c_err ? 6'd41 : 6'd9;
- end
-
- 6'd9:begin
- i2c_call <= 1'b1;
- state <= 6'd10;
- end
- 6'd10:begin
- state <= i2c_ret ? 6'd11 : 6'd10;
- end
-
- 6'd11:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd0;
- state <= i2c_err ? 6'd41 : 6'd12;
- end
-
- 6'd12:begin
- i2c_call <= 1'b1;
- state <= 6'd13;
- end
- 6'd13:begin
- state <= i2c_ret ? 6'd14 : 6'd13;
- end
-
- 6'd14:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= 8'hA1;
- state <= 6'd15;
- end
-
- 6'd15:begin
- i2c_call <= 1'b1;
- state <= 6'd16;
- end
- 6'd16:begin
- state <= i2c_ret ? 6'd17 : 6'd16;
- end
-
- 6'd17:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd2;
- state <= 6'd18;
- end
- 6'd18:begin
- i2c_call <= 1'b1;
- state <= 6'd19;
- end
- 6'd19:begin
- state <= i2c_ret ? 6'd20 : 6'd19;
- end
-
- 6'd20:begin
- i2c_call <= 1'b0;
- rb <= i2c_r;
- i2c_cmd <= 2'd1;
- state <= 6'd21;
- end
-
- 6'd21:begin
- i2c_call <= 1'b1;
- state <= 6'd22;
- end
- 6'd22:begin
- state <= i2c_ret ? 6'd23 : 6'd22;
- end
-
- 6'd23:begin
- i2c_call <= 1'b0;
- state <= 6'd24;
- end
-
- 6'd24:begin //返回
- ret <= 1'b1;
- state <= call ? 6'd24 : 6'd0;
- end
-
- 6'd25:begin
- i2c_call <= 1'b1;
- state <= 6'd26;
- end
-
- 6'd26:begin
- state <= i2c_ret ? 6'd27 : 6'd26;
- end
-
- 6'd27:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= 8'hA0;
- state <= 6'd28;
- end
-
- 6'd28:begin
- i2c_call <= 1'b1;
- state <= 6'd29;
- end
-
- 6'd29:begin
- state <= i2c_ret ? 6'd30 : 6'd29;
- end
-
- 6'd30:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= pc;
- state <= i2c_err ? 6'd41 : 6'd31;
- end
-
- 6'd31:begin
- i2c_call <= 1'b1;
- state <= 6'd32;
- end
-
- 6'd32:begin
- state <= i2c_ret ? 6'd33 : 6'd32;
- end
-
- 6'd33:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd3;
- i2c_w <= w;
- state <= i2c_err ? 6'd41 : 6'd34;
- end
-
- 6'd34:begin
- i2c_call <= 1'b1;
- state <= 6'd35;
- end
-
- 6'd35:begin
- state <= i2c_ret ? 6'd36 : 6'd35;
- end
-
- 6'd36:begin
- i2c_call <= 1'b0;
- i2c_cmd <= 2'd1;
- state <= i2c_err ? 6'd41 : 6'd37;
- end
-
- 6'd37:begin
- i2c_call <= 1'b1;
- state <= 6'd38;
- end
-
- 6'd38:begin
- state <= i2c_ret ? 6'd39 : 6'd38;
- end
-
- 6'd39:begin
- i2c_call <= 1'b0;
- state <= 6'd40;
- end
-
- 6'd40:begin //写完延时5ms
- delay <= 18'd250000;
- state <= 6'd24;
- end
-
- 6'd41:begin //读写错误
- err <= 1'b1;
- state <= 6'd24;
- end
- default:begin //其他状态
- state <= 6'd0;
- end
- endcase
- end
- end
- endmodule
- module main(
- input clk, //50Mhz 有源晶振 Pin17
- output reg led, //LED (低电平点亮) Pin3 闪烁:错误 熄灭:正在读写 点亮:完成
- inout sda, //AT24C02 Pin42
- output scl //AT24C02 Pin40
- );
- reg rw = 1'b1;
- wire ret;
- wire err;
- reg call = 1'b0;
- reg [7:0] pc = 8'd0;
- reg [7:0] wb = 8'd0;
- wire [7:0] rb;
- reg [3:0] state = 4'd0;
- reg [7:0] z;
- wire [7:0] b = ~z;
- integer i;
- at24c02 U1(
- .clk(clk),
- .rw(rw),
- .call(call),
- .pc(pc),
- .wb(wb),
- .rb(rb),
- .ret(ret),
- .err(err),
- .sda(sda),
- .scl(scl)
- );
- always @(posedge clk) begin
- case(state)
- 4'd0:begin
- led <= 1'b1;
- rw <= 1'b0;
- pc <= z;
- wb <= b;
- state <= 4'd1;
- end
-
- 4'd1:begin
- call <= 1'b1;
- state <= 4'd2;
- end
-
-
- 4'd2:begin
- state <= ret ? 4'd3 : 4'd2;
- end
-
- 4'd3:begin
- call <= 1'b0;
- state <= err ? 4'd4 : 4'd5;
- end
-
- 4'd4:begin
- i = i + 1;
- if(i >= 50000000/2/8) begin
- i = 0;
- led <= !led;
- end
- state <= 4'd4;
- end
-
- 4'd5:begin
- rw <= 1'b1;
- pc <= z;
- state <= 4'd6;
- end
-
- 4'd6:begin
- call <= 1'b1;
- state <= 4'd7;
- end
-
- 4'd7:begin
- state <= ret ? 4'd8 : 4'd7;
- end
-
- 4'd8:begin
- call <= 1'b0;
- state <= (err || (rb != b)) ? 4'd4 : 4'd9;
- end
-
- 4'd9:begin
- if(&z) begin
- led <= 1'b0;
- state <= 4'd9;
- end else begin
- z <= z + 8'd1;
- state <= 4'd0;
- end
- end
- endcase
- end
- endmodule
复制代码 |
|