📄 iic_master.v
字号:
/*I2C_Master.v - Verilog source for I2C moduleFeatures:- I2C Baud of 100Kbps or 400kbps- ACK or NACK during READ is controlled via LSB of in_data- SCL handshake (slave pulls SCL low to suspend master)Limitations:- Only supports master mode- no IRQ support but has a busy bit that can be polled to assure module is not busyThis program is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program. If not, see <http://www.gnu.org/licenses/>.*/`define BAUD400K 25`define BAUD100K 100`define IDLE 0`define START 1`define STOP 2`define READ 3`define WRITE 4module i2c_master(addr, in_data, out_data, sda, scl, cs, rd, wr, clk, iic_busy);output iic_busy;input wire [2:0] addr;input wire [7:0] in_data;output reg [7:0] out_data;inout sda;inout scl;input wire cs;input wire rd;input wire wr;input wire clk;reg out_sda = 1'b0;reg out_scl = 1'b0;reg [7:0] in_buffer = 8'b0;reg [7:0] buffer = 8'b0;reg ack = 1'b0;reg speed = 1'b0;reg i2c_clk = 1'b0;reg [6:0] clk_count = 7'b0;reg [2:0] state = 3'b0;reg [2:0] nextstate = 3'b0;reg [5:0] state_count = 6'b0;reg [2:0] bit_count = 3'b0;
reg [2:0] state_control = 3'b0;////
reg wr_rd_bit = 0;////wire busy;wire held;// I2C Clockalways@(posedge clk)begin clk_count = clk_count + 1; if(1) begin if(clk_count >= `BAUD400K) begin clk_count = 0; end // ~50/50 duty cycle if(clk_count > (`BAUD400K / 2)) begin i2c_clk <= 1'b0; end else begin i2c_clk <= 1'b1; end end else begin if(clk_count >= `BAUD100K) begin clk_count = 0; end // ~50/50 duty cycle if(clk_count > (`BAUD100K / 2)) begin i2c_clk <= 1'b0; end else begin i2c_clk <= 1'b1; end endend// Output Blockalways@(addr or cs or rd or buffer or speed or ack or held or busy)begin out_data = 8'bz; if(cs && rd) begin case(addr) // Data (read) 3'b011: begin out_data = buffer; end // Status 3'b100: begin out_data = {4'b0, speed, ack, held, busy}; end endcase endend// Input Blockalways@(posedge clk)begin nextstate <= nextstate; case(state) `IDLE: begin if(!busy)/*cs && wr && !busy*/ begin case(state_control) // Start 3'b000: begin nextstate <= `START;
if(wr_rd_bit) state_control <=3'b010;
else state_control <=3'b011; end // Stop 3'b001: begin nextstate <= `STOP; end // Read 3'b010: begin in_buffer = {7'b0, in_data[0]}; nextstate <= `READ; end // Data (write) 3'b011: begin in_buffer = 8'b00110011;//in_data; nextstate <= `WRITE;
state_control <=3'b001; end // Speed 3'b100: begin speed = in_data[0]; nextstate <= `IDLE; end
default: nextstate <= `IDLE;
endcase end end `START: begin if(state_count >= 6) begin nextstate <= `IDLE; end end `STOP: begin if(state_count >= 6) begin nextstate <= `IDLE; end end `READ: begin if(state_count >= 44) begin nextstate <= `IDLE; end end `WRITE: begin if(state_count >= 44) begin nextstate <= `IDLE; end end endcaseend// state_count and bit_countalways@(posedge i2c_clk)begin state <= nextstate; case(state) `START: begin if(state_count >= 6) begin state_count <= 0; end else begin state_count <= state_count + 1; end end `STOP: begin if(state_count >= 6) begin state_count <= 0; end else begin state_count <= state_count + 1; end end `READ: begin if(state_count >= 44) begin state_count <= 0; end else begin if(out_scl == scl) begin state_count <= state_count + 1; end end if(bit_count >= 4) begin bit_count <= 0; end else begin if(out_scl == scl) begin bit_count <= bit_count + 1; end end end `WRITE: begin if(state_count >= 44) begin state_count <= 0; end else begin if(out_scl == scl) begin state_count <= state_count + 1; end end if(bit_count >= 4) begin bit_count <= 0; end else begin if(out_scl == scl) begin bit_count <= bit_count + 1; end end end endcase end// SDA and SCLalways@(posedge i2c_clk)begin out_sda = out_sda; out_scl = out_scl; case(state) `START: begin case(state_count) 0: begin out_sda = 1'b1; out_scl = 1'b1; end 1: begin out_sda = 1'b1; out_scl = 1'b1; end 2: begin out_sda = 1'b1; out_scl = 1'b1; end 3: begin out_sda = 1'b0; out_scl = 1'b1; end 4: begin out_sda = 1'b0; out_scl = 1'b1; end 5: begin out_sda = 1'b0; out_scl = 1'b0; end 6: begin out_sda = 1'b0; out_scl = 1'b0; end endcase end `STOP: begin case(state_count) 0: begin out_sda = 1'b0; out_scl = 1'b0; end 1: begin out_sda = 1'b0; out_scl = 1'b1; end 2: begin out_sda = 1'b0; out_scl = 1'b1; end 3: begin out_sda = 1'b1; out_scl = 1'b1; end 4: begin out_sda = 1'b1; out_scl = 1'b1; end 5: begin out_sda = 1'b1; out_scl = 1'b1; end 6: begin out_sda = 1'b1; out_scl = 1'b1; end endcase end `READ: begin if(state_count >= 40) begin case(bit_count) 0: begin out_sda = ~in_buffer[0]; out_scl = 1'b0; end 1: begin out_sda = ~in_buffer[0]; out_scl = 1'b0; end 2: begin out_sda = ~in_buffer[0]; out_scl = 1'b1; end 3: begin out_sda = ~in_buffer[0]; out_scl = 1'b1; end 4: begin out_sda = ~in_buffer[0]; out_scl = 1'b0; end endcase end else begin case(bit_count) 0: begin out_sda = 1'b1; out_scl = 1'b0; buffer = buffer << 1; end 1: begin out_sda = 1'b1; out_scl = 1'b0; end 2: begin out_sda = 1'b1; out_scl = 1'b1; end 3: begin out_sda = 1'b1; out_scl = 1'b1; buffer[0] = sda; end 4: begin out_sda = 1'b1; out_scl = 1'b0; end endcase end end `WRITE: begin if(state_count == 0) begin buffer = in_buffer; end if(state_count >= 40) begin case(bit_count) 0: begin out_sda = 1'b1; out_scl = 1'b0; end 1: begin out_sda = 1'b1; out_scl = 1'b0; end 2: begin out_sda = 1'b1; out_scl = 1'b1; end 3: begin out_sda = 1'b1; out_scl = 1'b1; ack = sda; end 4: begin out_sda = 1'b1; out_scl = 1'b0; end endcase end else begin case(bit_count) 0: begin out_sda = buffer[7]; out_scl = 1'b0; end 1: begin out_sda = buffer[7]; out_scl = 1'b0; end 2: begin out_sda = buffer[7]; out_scl = 1'b1; end 3: begin out_sda = buffer[7]; out_scl = 1'b1; end 4: begin out_sda = buffer[7]; out_scl = 1'b0; buffer = buffer << 1; end endcase end end endcaseendassign sda = out_sda ? 1'bz : 1'b0;assign scl = out_scl ? 1'bz : 1'b0;assign busy = (state != `IDLE || nextstate != `IDLE) ? 1 : 0;assign iic_busy = (state != `IDLE || nextstate != `IDLE) ? 1 : 0;assign held = out_scl != scl;endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -