diff --git a/rtl/i2c_ctrl.v b/rtl/i2c_ctrl.v index 4fbd8ce..d82c800 100644 --- a/rtl/i2c_ctrl.v +++ b/rtl/i2c_ctrl.v @@ -10,13 +10,18 @@ parameter I2C_CLK_DIV = 5'd24, MAX = 10'd1000, SLAVE_ID = 7'h73; //状态机参数定义 -parameter IDLE = 3'd0, - START = 3'd1, - SLAVE_ADDR= 3'd2, - WAIT = 3'd3, - STOP = 3'd4; -reg [2: 0] state_c; -reg [2: 0] state_n; +parameter IDLE = 4'd0, + START = 4'd1, + SLAVE_ADDR = 4'd2, + ACK_1 = 4'd3, + ACK_2 = 4'd4, + ACK_3 = 4'd5, + DEVICE_ADDR = 4'd6, + DATA = 4'd7, + WAIT = 4'd8, + STOP = 4'd9; +reg [3: 0] state_c; +reg [3: 0] state_n; //// //i2c时钟计数器 @@ -26,7 +31,8 @@ reg i2c_clk; //中间信号定义 reg [9: 0] cnt_wait ;//1000us -reg skip_en_1 ;//跳转信号 +reg skip_en_1 ;//步骤1跳转信号 +reg skip_en_2 ;//步骤2跳转信号 reg [2: 0] step ;//步骤 reg [1: 0] cnt_i2c_clk ;//i2c计数器 reg [2: 0] cnt_bit ;//bit计数器 @@ -38,8 +44,9 @@ reg i2c_scl ; reg [7: 0] slave_addr ; reg [7: 0] device_addr ; reg [7: 0] wr_data ; +reg ack ;//接受信号 //三态门 -assign sda_en = 1'b1;//主机控制从机 +assign sda_en = ((state_c == ACK_1) || (state_c == ACK_2) || (state_c == ACK_3)) ? 1'b0: 1'b1;//发送主机控制从机,接受主机释放 assign sda_in = sda; assign sda = (sda_en == 1'b1)? i2c_sda : 1'bz; //i2c驱动时钟设计 @@ -79,13 +86,13 @@ end //状态机第二段 always @(*)begin case(state_c) - IDLE: if(skip_en_1 == 1'b1)begin + IDLE: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin state_n = START; end else begin state_n = IDLE; end - START: if(skip_en_1 == 1'b1)begin + START: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin state_n = SLAVE_ADDR; end else begin @@ -94,16 +101,49 @@ always @(*)begin SLAVE_ADDR: if(skip_en_1 == 1'b1)begin state_n = WAIT; end + else if(skip_en_2 == 1'b1)begin + state_n = ACK_1; + end else begin state_n = SLAVE_ADDR; end + ACK_1: if(skip_en_2 == 1'b1)begin + state_n = DEVICE_ADDR; + end + else begin + state_n = ACK_1; + end + DEVICE_ADDR:if(skip_en_2 == 1'b1)begin + state_n = ACK_2; + end + else begin + state_n = DEVICE_ADDR; + end + ACK_2: if(skip_en_2 == 1'b1)begin + state_n = DATA; + end + else begin + state_n = ACK_2; + end + DATA: if(skip_en_2 == 1'b1)begin + state_n = ACK_3; + end + else begin + state_n = DATA; + end + ACK_3: if(skip_en_2 == 1'b1)begin + state_n = STOP; + end + else begin + state_n = ACK_3; + end WAIT: if(skip_en_1 == 1'b1)begin state_n = STOP; end else begin state_n = WAIT; end - STOP: if(skip_en_1 == 1'b1)begin + STOP: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin state_n = IDLE; end else begin @@ -119,6 +159,7 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin cnt_wait <= 10'd0; skip_en_1 <= 1'b0; + skip_en_2 <= 1'b0;//步骤2跳转信号 step <= 3'd0; cnt_i2c_clk <= 2'd0; cnt_bit <= 3'd0; @@ -127,7 +168,7 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin else begin case(state_c) IDLE: begin - if(cnt_wait >= MAX - 1)begin + if(cnt_wait == MAX - 1)begin cnt_wait <= 10'd0; end else begin @@ -139,6 +180,12 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin else begin skip_en_1 <= 1'b0; end + if((cnt_wait == MAX - 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end end START: begin cnt_i2c_clk <= cnt_i2c_clk + 1'd1; @@ -148,6 +195,12 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin else begin skip_en_1 <= 1'b0; end + if((cnt_i2c_clk == 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end end SLAVE_ADDR: begin cnt_i2c_clk <= cnt_i2c_clk + 1'd1; @@ -157,6 +210,12 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin else begin skip_en_1 <= 1'b0; end + if((cnt_i2c_clk == 2'd2) && (step == 3'd1) && (cnt_bit == 3'd7))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))begin cnt_bit <= 3'd0; end @@ -167,9 +226,72 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin cnt_bit <= cnt_bit; end end + ACK_1: begin + cnt_i2c_clk <= cnt_i2c_clk + 1'd1; + if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end + end + DEVICE_ADDR:begin + cnt_i2c_clk <= cnt_i2c_clk + 1'b1; + if((cnt_i2c_clk == 2'd3) && (cnt_bit == 3'd7))begin + cnt_bit <= 3'd0; + end + else if(cnt_i2c_clk == 2'd3)begin + cnt_bit <= cnt_bit + 1'b1; + end + else begin + cnt_bit <= cnt_bit; + end + if((cnt_i2c_clk == 2'd2) && (cnt_bit == 3'd7) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end + end + ACK_2: begin + cnt_i2c_clk <= cnt_i2c_clk + 1; + if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end + end + DATA: begin + cnt_i2c_clk <= cnt_i2c_clk + 1'b1; + if((cnt_i2c_clk == 2'd3) && (cnt_bit == 3'd7))begin + cnt_bit <= 3'd0; + end + else if(cnt_i2c_clk == 2'd3)begin + cnt_bit <= cnt_bit + 1'b1; + end + else begin + cnt_bit <= cnt_bit; + end + if((cnt_i2c_clk == 2'd2) && (cnt_bit == 3'd7) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end + end + ACK_3: begin + cnt_i2c_clk <= cnt_i2c_clk + 1; + if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end + end WAIT: begin if(cnt_wait == MAX - 1'd1)begin - cnt_wait <= 10'd0; + cnt_wait <= 10'd0; end else begin cnt_wait <= cnt_wait + 1'd1; @@ -189,6 +311,12 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin else begin skip_en_1 <= 1'b0; end + if((cnt_i2c_clk == 2'd2) && (step == 3'd1))begin + skip_en_2 <= 1'b1; + end + else begin + skip_en_2 <= 1'b0; + end if(cnt_i2c_clk == 2'd2)begin i2c_end <= 1'b1; end @@ -205,6 +333,7 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin default: begin cnt_wait <= 10'd0; skip_en_1 <= 1'b0; + skip_en_2 <= 1'b0; step <= step; cnt_i2c_clk <= 2'd0; cnt_bit <= 3'd0; @@ -213,6 +342,13 @@ always @(posedge i2c_clk or negedge sys_rst_n)begin endcase end end +//ack +always @(*)begin + case(state_c) + ACK_1, ACK_2, ACK_3: ack = ~sda_in; + default: ack = 1'b0; + endcase +end //step always @(*)begin case(step) @@ -221,6 +357,11 @@ always @(*)begin device_addr = 8'h0; wr_data = 8'h0; end + 3'd1: begin + slave_addr = {SLAVE_ID, 1'b0}; + device_addr= {8'hef}; + wr_data = {8'h00}; + end default:begin slave_addr = 8'h0; device_addr = 8'h0; @@ -233,7 +374,8 @@ always @(*)begin case(state_c) IDLE: i2c_scl = 1'b1; START: i2c_scl = (cnt_i2c_clk <= 2'd2) ? 1'b1 : 1'b0; - SLAVE_ADDR: i2c_scl = ((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2)) ? 1'b1 : 1'b0; + SLAVE_ADDR, DEVICE_ADDR, DATA, ACK_1, ACK_2, ACK_3: + i2c_scl = ((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2)) ? 1'b1 : 1'b0; WAIT: i2c_scl = 1'b0; STOP: i2c_scl = (cnt_i2c_clk >= 2'd1) ? 1'b1 : 1'b0; endcase @@ -244,6 +386,10 @@ always @(*)begin IDLE: i2c_sda = 1'b1; START: i2c_sda = (cnt_i2c_clk > 2'd1) ? 1'b0 : 1'b1; SLAVE_ADDR: i2c_sda = slave_addr[7 - cnt_bit]; + DEVICE_ADDR:i2c_sda = device_addr[7 - cnt_bit]; + DATA: i2c_sda = wr_data[7 - cnt_bit]; + ACK_1, ACK_2, ACK_3: + i2c_sda = 1'b0; WAIT: i2c_sda = 1'b0; STOP: i2c_sda = (cnt_i2c_clk >= 2'd2) ? 1'b1 : 1'b0; default: i2c_sda = 1'b1;