一文带你迅速了解常用串行总线之IIC协议2

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 addresss_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 registers_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 datas_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;endcaseend
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;endcaseend
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;endelse 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 endcaseend
endmodule

芯片行业背后是否“虚火”过旺?
三星S8还会有实体按键,只不过位置发生了改变,很有挑战的尝试
以FPGA+DSP为基础的RCM远控器研究详解
保证服务器安全的七个技巧
上海电信成功打造出全球首次5G+8K+VR直播音乐现场
一文带你迅速了解常用串行总线之IIC协议2
商务部回应:北京市商务局已收到字节跳动提交的许可申请
区块链治理的灯塔是什么
RFID线圈加上匹配电路后如何获得传递功率?
历史7年研发,中国最大MEMS代工企业发布量产公告,谷歌是幕后客户?
浅析锐龙4000系列 锐龙7-4800U和锐龙7-4800H和酷睿i9打平?
Intel处理器占据CPU单线程性能前17位 酷睿i9-9900KS仍稳居榜首
蓄电池的开路电压_蓄电池的终止电压
电子闹钟diy 从此不再被吵醒而是被吓醒
5G工业网关和4G工业网关有什么区别?
写一个自动化重启服务脚本
从EDA技术演变里看芯片创新之未来
电子芯闻早报:Intel最新战略引台厂响起警报
气密测试仪设备如何安装?是否需要定期维护?
AMDVega56深度评测 与1070非公默认极限大致相当