I2C控制器的Verilog建模之三(完结版)
前言:终于到了测试篇,不过悲剧了一下。按照之前《二》里面的思路,在顶层用一个复用器驱动读写独立模块的I2C总线确实失败。虽然综合过去了,不过警告里已经说明:底层的2个原本是inout三态口的数据线在顶层复用时候被综合成wire,这样在默认情况下顶层的inout总是输出有效,失去了三态口的作用。囧,看来为了测试I2C的写还是得把读模块并进去可避免这一尴尬……
测试:DE2+Questasim10.0c+Q2_9.1;
日期:2013七夕夜
结果:以下2张图为仿真波形图与逻辑分析仪采样的时序波形图。之前还踩不到ACK信号,因为宏定义里读写器件的地址弄饭了。(若这里程序与之前的《一》《二》有出路须以此篇修改之后为准)。对比可知基本上二者相同,也踩到从器件的相应。不过有个问题,在响应的一个完整时钟周期里的后四分之一变成高电平,也就是说一个ACK仅仅保持了四分之三的低电平,这个是不是应该算正常?如果从数据有效来看,时钟高电平保持了ACK一直为低电平,似乎是对的。
解决:出现这样目前只好等读模块嵌入,如果能读出正确写入的数据,那么说明是正常的。
last update:因为其他时间耽搁了,断断续续终于今天整理完毕。仿真和硬件均测试通过。最后附出仿真文件、建模源码以及tcl脚本。
总结:IIC中从机响应脉冲宽度并未填满一整个周期,这也是之前图里的疑问。如何分辨正确:仅记ack和nack在时钟上升沿改变在时钟下降沿即可改变;不同器件数据变化时间时刻不一样,如果移植到不同器件测试得到不用stp2也无需惊讶,抓住根本的就行;
源码1:iic读写控制器
- `timescale ns / ps
- `define SIM
- `define SYS_CLK
- `define IIC_CLK
- `define IIC_CLK_DIV `SYS_CLK/`IIC_CLK
- `define ADV7181B
- `define SCLK_CNT_WIDTH
- //VERSION:V0.0
- module iic_ctrl(
- //common
- sys_clk,
- sys_rst_n,
- iic_sclk,
- iic_sdat,
- //read
- rreq_i,
- iic_rd_addr_i,
- rd_en_i,
- iic_rd_ack_o,
- sys_byte_o,
- //write
- wreq_i,
- wr_en_i,
- iic_wr_addr_i,
- sys_byte_i,
- iic_wr_ack_o
- );
- //common port
- input sys_clk; //global clk in
- input sys_rst_n; //global rst_n in
- output iic_sclk; //iic sclk
- inout iic_sdat; //iic sdat
- //read port
- input rreq_i; //read requast in
- input [:] iic_rd_addr_i; //read register address in
- input rd_en_i; //read enable in
- output iic_rd_ack_o; //module read ack
- output [:] sys_byte_o; //read byte out
- //write port
- input wreq_i; //write request in
- input wr_en_i; //write enable in
- input [:] iic_wr_addr_i; //write register address in
- input [:] sys_byte_i; //byte to be written
- output iic_wr_ack_o; //module write ack
- //macro
- `ifdef ADV7181B
- parameter DEVICE_READ = 'h41; //器件读操作地址
- parameter DEVICE_WRITE = 'h40; //器件写操作地址
- `endif
- //marcro
- `ifdef SIM
- parameter ST_WIDTH = ;
- parameter IDLE = "IDLE...",
- START1 = "START1.",
- WR_SLAVE = "WR_SLAV",
- ACK1 = "ACK1...",
- SET_REG = "SET_REG",
- ACK2 = "ACK2...",
- WR_DATA = "WR_DATA",
- ACK3 = "ACK3...",
- STOP = "STOP...";
- parameter START2 = "START2.",
- RD_SLAVE = "RD_SLAV",
- ACK4 = "ACK4...",
- RD_DATA = "RD_DATA",
- NACK = "NACK...";
- `else
- `define FSM
- parameter ST_WIDTH = ;
- parameter IDLE = `FSM'b00_0000_0000_0001,
- START1 = `FSM'b00_0000_0000_0010, //写操作一共有1个start,读操作一共2个start
- WR_SLAVE = `FSM'b00_0000_0000_0100,
- ACK1 = `FSM'b00_0000_0000_1000,
- SET_REG = `FSM'b00_0000_0001_0000,
- ACK2 = `FSM'b00_0000_0010_0000,
- WR_DATA = `FSM'b00_0000_0100_0000,
- ACK3 = `FSM'b00_0000_1000_0000,
- STOP = `FSM'b00_0001_0000_0000;
- parameter START2 = `FSM'b00_0010_0000_0000,
- RD_SLAVE = `FSM'b00_0100_0000_0000,
- ACK4 = `FSM'b00_1000_0000_0000,
- RD_DATA = `FSM'b01_0000_0000_0001,
- NACK = `FSM'b10_0000_0000_0001;
- `endif
- //caputre the posedge of rreq_i;
- reg rreq_r0 = ;
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) rreq_r0 <= 0;
- else rreq_r0 <= rreq_i;
- end
- wire do_rreq = rreq_i & ~rreq_r0 & rd_en_i;
- //generate the rd_start;
- reg rd_start = ;
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) rd_start <= 0;
- else if(iic_rd_ack_o == 'b1) rd_start <= 0;
- else if(do_rreq) rd_start <= ;
- else rd_start <= rd_start;
- end
- //caputre the posedge of wreq_i;
- reg wreq_r0 = ;
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) wreq_r0 <= 0;
- else wreq_r0 <= wreq_i;
- end
- wire do_wreq = wreq_i & ~wreq_r0 & wr_en_i;
- //generate the wr_start;
- reg wr_start = ;
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) wr_start <= 0;
- else if(iic_wr_ack_o == 'b1) wr_start <= 0;
- else if(do_wreq) wr_start <= ;
- else wr_start <= wr_start;
- end
- //GENERATE SCLK
- reg [`SCLK_CNT_WIDTH-:] sclk_cnt = ;
- wire sclk_cnt_en1 = ((sclk_cnt < `IIC_CLK_DIV-)&&(wr_en_i == 'b1)&&(wr_start == 1'b1))?'b1:1'b0;
- wire sclk_cnt_en2 = ((sclk_cnt < `IIC_CLK_DIV-)&&(rd_en_i == 'b1)&&(rd_start == 1'b1))?'b1:1'b0;
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) sclk_cnt <= 0;
- else if(sclk_cnt_en1 | sclk_cnt_en2) sclk_cnt <= sclk_cnt + 'd1;
- else sclk_cnt <= ;
- end
- //时间片
- `define SCLK_POS (sclk_cnt == `SCLK_CNT_WIDTH'd499)
- `define SCLK_HIGH (sclk_cnt == `SCLK_CNT_WIDTH'd124)
- `define SCLK_NEG (sclk_cnt == `SCLK_CNT_WIDTH'd249)
- `define SCLK_LOW (sclk_cnt == `SCLK_CNT_WIDTH'd374)
- //内部i2c串行时钟
- wire iic_sclk_w = ((sclk_cnt <= `SCLK_CNT_WIDTH'd249)&&(rd_en_i | wr_en_i))?1'b1:'b0;
- //fsm registers
- reg [:] iic_byte = ;
- reg [:] sys_byte_o = ;
- reg sdat_r = ;
- reg link = ; //read:0
- reg [:] bit_cnt = ;
- reg [ST_WIDTH-:] c_st = IDLE;
- reg [ST_WIDTH-:] n_st = IDLE;
- //FSM-1
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) c_st <= IDLE;
- else c_st <= n_st;
- end
- //FSM-2,实际的状态转移中ack[2:0]比物理等待的ack少四分之一
- always @ (*) begin
- n_st = IDLE;
- case(c_st)
- IDLE:begin
- n_st = ((wr_start == 'b1)||(rd_start == 1'b1))?START1:IDLE;end
- START1:begin
- n_st = (`SCLK_LOW)?WR_SLAVE:START1;end //sclk为高电平中心时转移
- WR_SLAVE:begin
- n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
- ACK1:begin
- n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
- SET_REG:begin
- n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK2:SET_REG;end//数据在低电平是更新
- ACK2:begin
- if(`SCLK_NEG) begin
- n_st = (wr_start == 'b1)?WR_DATA:START2;end
- else begin
- n_st = ACK2;end
- end//为保证下一步设置寄存器,提前1/4进入下一个状态
- WR_DATA:begin
- n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK3:WR_DATA;end
- ACK3:begin
- n_st = (`SCLK_NEG)?STOP:ACK3;end
- STOP:begin
- n_st = (`SCLK_NEG)?IDLE:STOP;end
- START2:begin
- n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
- RD_SLAVE:begin
- n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK4:RD_SLAVE;end
- ACK4:begin
- n_st = (`SCLK_NEG)?RD_DATA:ACK4;end
- RD_DATA:begin
- n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?NACK:RD_DATA;end
- NACK:begin
- n_st = (`SCLK_NEG)?STOP:NACK;end
- default:begin
- n_st = IDLE;end
- endcase
- end
- //FSM-3
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) begin
- link <= 'd0;
- iic_byte <= ;
- sys_byte_o <= sys_byte_o; //保持
- bit_cnt <= 'd0;
- sdat_r <= 'd1;
- end
- else begin
- case(c_st)
- IDLE:begin
- link <= 'd0;
- sys_byte_o <= sys_byte_o;
- iic_byte <= DEVICE_WRITE;
- bit_cnt <= 'd0;
- sdat_r <= 'd1;
- end
- START1:begin
- link <= 'd1;
- bit_cnt <= 'd1;
- sys_byte_o <= sys_byte_o;
- iic_byte <= (`SCLK_LOW)?iic_byte<<:iic_byte;
- if(`SCLK_HIGH) begin
- sdat_r <= 'b0;end
- else if(`SCLK_LOW) begin
- sdat_r <= iic_byte[];end //pull down,由于i2c_byte缓存一级的缘故,需要提前在START里输出第MSB位
- else begin
- sdat_r <= sdat_r;end
- end
- WR_SLAVE:begin
- sys_byte_o <= sys_byte_o;
- if(`SCLK_LOW) begin
- link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
- bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
- iic_byte <= {iic_byte[:],'d0};//左移一位
- sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
- else begin
- link <= link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sdat_r <= sdat_r;end
- end
- ACK1:begin
- link <= 'd0;
- sys_byte_o <= sys_byte_o;
- if(`SCLK_POS) begin
- iic_byte <= (wr_start=='b1)?iic_wr_addr_i:iic_rd_addr_i;end
- else begin
- iic_byte <= iic_byte;end //读入待写的寄存器地址
- bit_cnt <= 'd0;
- sdat_r <= 'd1;
- end
- SET_REG:begin
- sys_byte_o <= sys_byte_o;
- if(`SCLK_LOW) begin
- link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
- bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
- iic_byte <= {iic_byte[:],'d0};//左移一位
- sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
- else begin
- link <= link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sdat_r <= sdat_r;end
- end
- ACK2:begin
- link <= 'd0;
- bit_cnt <= 'd0;
- sdat_r <= 'd1;
- sys_byte_o <= sys_byte_o;
- if(`SCLK_POS) begin
- iic_byte <= (wr_start)?sys_byte_i:DEVICE_READ;end //读入待写的寄存器地址
- else begin
- iic_byte <= iic_byte;end
- end
- WR_DATA:begin
- sys_byte_o <= sys_byte_o;
- if(`SCLK_LOW) begin
- link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
- bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
- iic_byte <= {iic_byte[:],'d0};//左移一位
- sdat_r <= iic_byte[];end
- else begin
- link <= link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sdat_r <= sdat_r;end
- end
- ACK3:begin
- sys_byte_o <= sys_byte_o;
- link <= 'd0;
- sdat_r <= 'd0;//预先拉低
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;end
- STOP:begin
- sys_byte_o <= sys_byte_o;
- link <= (`SCLK_LOW)?'b1:link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- if(`SCLK_LOW) begin
- sdat_r <= 'b0;end
- else if(`SCLK_HIGH) begin
- sdat_r <= 'b1;end
- else begin
- sdat_r <= sdat_r;end
- end
- START2:begin
- link <= (`SCLK_LOW)?'b1:link;
- sys_byte_o <= sys_byte_o;
- iic_byte <= iic_byte;
- bit_cnt <= bit_cnt;
- sdat_r <= (`SCLK_HIGH)?'b0:sdat_r;
- end
- RD_SLAVE:begin
- sys_byte_o <= sys_byte_o;
- if(`SCLK_LOW) begin
- link <= (bit_cnt == 'd8)?1'b0:'b1;
- bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
- iic_byte <= {iic_byte[:],'d0};//左移一位
- sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
- else begin
- link <= link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sdat_r <= sdat_r;end
- end
- ACK4:begin
- link <= 'b0;
- bit_cnt <= 'd0;
- sys_byte_o <= sys_byte_o;
- iic_byte <= ;
- sdat_r <= 'd1;end
- RD_DATA:begin
- sys_byte_o <= sys_byte_o;
- if(`SCLK_POS) begin
- link <= (bit_cnt == 'd8)?1'b1:'b0; //为主设备产生NACK准备
- bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
- iic_byte[:] <= iic_byte[:];//左移一位
- iic_byte[] <= iic_sdat;end
- else begin
- link <= link;
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sdat_r <= sdat_r;end
- end
- NACK:begin
- link <= 'd1;
- sdat_r <= 'd1;//预先拉低
- bit_cnt <= bit_cnt;
- iic_byte <= iic_byte;
- sys_byte_o <= iic_byte;end
- default:begin
- link <= 'd0;
- iic_byte <= 'd0;
- bit_cnt <= 'd0;
- sdat_r <= 'd1;
- sys_byte_o <= sys_byte_o;
- end
- endcase
- end
- end
- //assign
- assign iic_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(rd_start))?'b1:1'b0;
- assign iic_sclk = (c_st != IDLE)?iic_sclk_w:'b1;
- assign iic_sdat = (link == 'b1)?sdat_r:1'bz;
- assign iic_wr_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(wr_start))?'b1:1'b0;
- endmodule
源码2:写iic的寄存器地址和数据,移植不同器件更改这部分查找表内容
- `timescale ns / ps
- `define LUT_WIDTH
- module wr_config(
- sys_clk,
- sys_rst_n,
- iic_wr_ack_i,
- wreq_o,
- sys_byte_o,
- iic_wr_addr_o,
- wr_config_done_o
- );
- input sys_clk;
- input sys_rst_n;
- input iic_wr_ack_i;
- output wreq_o;
- output [:] sys_byte_o;
- output [:] iic_wr_addr_o;
- output wr_config_done_o;
- //generate wreq_o
- reg wreq_o = ;
- reg [`LUT_WIDTH-:] lut_index = ;
- reg [:] lut_data = ;
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) begin
- wreq_o <= ;
- lut_index <= ;end
- else if((iic_wr_ack_i == 'b1)&&(wr_config_done_o == 1'b0)) begin
- wreq_o <= ;
- lut_index <= lut_index + 'd1;end
- else begin
- wreq_o <= ;
- lut_index <= lut_index;end
- end
- //generate done
- reg wr_config_done_o = ;
- always @ (posedge sys_clk) begin
- if(sys_rst_n == 'b0) wr_config_done_o <= 0;
- else if((lut_index == 'd34) && (iic_wr_ack_i == 1'b1)) wr_config_done_o <= ;
- else wr_config_done_o <= wr_config_done_o;
- end
- //assign
- assign sys_byte_o = lut_data[:];
- assign iic_wr_addr_o = lut_data[:];
- //lut
- always @ (*) begin
- case(lut_index)
- `LUT_WIDTH'd0:lut_data <= 16'h0080;
- `LUT_WIDTH'd1:lut_data <= 16'h0701;
- `LUT_WIDTH'd2:lut_data <= 16'h1500;
- `LUT_WIDTH'd3:lut_data <= 16'h1741;
- `LUT_WIDTH'd4:lut_data <= 16'h19FA;
- `LUT_WIDTH'd5:lut_data <= 16'h1D40;
- `LUT_WIDTH'd6:lut_data <= 16'h0F40;
- `LUT_WIDTH'd7:lut_data <= 16'h3A16;
- `LUT_WIDTH'd8:lut_data <= 16'h3DC3;
- `LUT_WIDTH'd9:lut_data <= 16'h3FE4;
- `LUT_WIDTH'd10:lut_data <= 16'h500A;
- `LUT_WIDTH'd11:lut_data <= 16'hC309;
- `LUT_WIDTH'd12:lut_data <= 16'hC480;
- `LUT_WIDTH'd13:lut_data <= 16'h0E80;
- `LUT_WIDTH'd14:lut_data <= 16'h5020;
- `LUT_WIDTH'd15:lut_data <= 16'h5218;
- `LUT_WIDTH'd16:lut_data <= 16'h58ED;
- `LUT_WIDTH'd17:lut_data <= 16'h77C5;
- `LUT_WIDTH'd18:lut_data <= 16'h7C93;
- `LUT_WIDTH'd19:lut_data <= 16'h7D00;
- `LUT_WIDTH'd20:lut_data <= 16'h90C9;
- `LUT_WIDTH'd21:lut_data <= 16'h9140;
- `LUT_WIDTH'd22:lut_data <= 16'h923C;
- `LUT_WIDTH'd23:lut_data <= 16'h93CA;
- `LUT_WIDTH'd24:lut_data <= 16'h94D5;
- `LUT_WIDTH'd25:lut_data <= 16'hCF50;
- `LUT_WIDTH'd26:lut_data <= 16'hD04E;
- `LUT_WIDTH'd27:lut_data <= 16'hD6DD;
- `LUT_WIDTH'd28:lut_data <= 16'hE551;
- `LUT_WIDTH'd29:lut_data <= 16'hD5A0;
- `LUT_WIDTH'd30:lut_data <= 16'hD7EA;
- `LUT_WIDTH'd31:lut_data <= 16'hE43E;
- `LUT_WIDTH'd32:lut_data <= 16'hE93E;
- `LUT_WIDTH'd33:lut_data <= 16'hEA0F;
- `LUT_WIDTH'd34:lut_data <= 16'h0E00;
- default:lut_data <= 'h0080;
- endcase
- end
- endmodule
源码3:读回写入寄存器内容
- `timescale ns / ps
- `define LUT_WIDTH
- module rd_check(
- sys_clk,
- sys_rst_n,
- key_n,
- rreq_o,
- iic_rd_addr_o
- );
- input sys_clk;
- input sys_rst_n;
- input key_n;
- output rreq_o;
- output [:] iic_rd_addr_o;
- //capture the negedge of key_n;
- reg key_n_r0 = ;
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) key_n_r0 <= 1;
- else key_n_r0 <= key_n;
- end
- wire key_neg = ~key_n & key_n_r0;
- //generate the rreq_o
- reg rreq_o = ;
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) rreq_o <= 0;
- else if(key_neg) rreq_o <= ;
- else rreq_o <= ;
- end
- //generate the iic_rd_addr_o
- reg [:] lut_index = ;
- reg [:] lut_data = ;
- always @ (posedge sys_clk) begin
- if('b0 == sys_rst_n) lut_index <= 0;
- else if(lut_index == `LUT_WIDTH'd35) lut_index <= 0;
- else if(key_neg) lut_index <= lut_index + 'd1;
- else lut_index <= lut_index;
- end
- always @ (*) begin
- case(lut_index)
- `LUT_WIDTH'd0:lut_data <= 8'hFF; //offset no meaning
- `LUT_WIDTH'd1:lut_data <= 8'h00;
- `LUT_WIDTH'd2:lut_data <= 8'h07;
- `LUT_WIDTH'd3:lut_data <= 8'h15;
- `LUT_WIDTH'd4:lut_data <= 8'h17;
- `LUT_WIDTH'd5:lut_data <= 8'h19;
- `LUT_WIDTH'd6:lut_data <= 8'h1D;
- `LUT_WIDTH'd7:lut_data <= 8'h0F;
- `LUT_WIDTH'd8:lut_data <= 8'h3A;
- `LUT_WIDTH'd9:lut_data <= 8'h3D;
- `LUT_WIDTH'd10:lut_data <= 8'h3F;
- `LUT_WIDTH'd11:lut_data <= 8'h50;
- `LUT_WIDTH'd12:lut_data <= 8'hC3;
- `LUT_WIDTH'd13:lut_data <= 8'hC4;
- `LUT_WIDTH'd14:lut_data <= 8'h0E;
- `LUT_WIDTH'd15:lut_data <= 8'h50;
- `LUT_WIDTH'd16:lut_data <= 8'h52;
- `LUT_WIDTH'd17:lut_data <= 8'h58;
- `LUT_WIDTH'd18:lut_data <= 8'h77;
- `LUT_WIDTH'd19:lut_data <= 8'h7C;
- `LUT_WIDTH'd20:lut_data <= 8'h7D;
- `LUT_WIDTH'd21:lut_data <= 8'h90;
- `LUT_WIDTH'd22:lut_data <= 8'h91;
- `LUT_WIDTH'd23:lut_data <= 8'h92;
- `LUT_WIDTH'd24:lut_data <= 8'h93;
- `LUT_WIDTH'd25:lut_data <= 8'h94;
- `LUT_WIDTH'd26:lut_data <= 8'hCF;
- `LUT_WIDTH'd27:lut_data <= 8'hD0;
- `LUT_WIDTH'd28:lut_data <= 8'hD6;
- `LUT_WIDTH'd29:lut_data <= 8'hE5;
- `LUT_WIDTH'd30:lut_data <= 8'hD5;
- `LUT_WIDTH'd31:lut_data <= 8'hD7;
- `LUT_WIDTH'd32:lut_data <= 8'hE4;
- `LUT_WIDTH'd33:lut_data <= 8'hE9;
- `LUT_WIDTH'd34:lut_data <= 8'hEA;
- `LUT_WIDTH'd35:lut_data <= 8'h0E;
- default:lut_data <= 'h00;
- endcase
- end
- //assign
- assign iic_rd_addr_o = lut_data;
- endmodule
源码4:顶层例化文件
- `timescale ns / ps
- module iic_driver(
- sys_clk,
- sys_rst_n,
- iic_sclk,
- iic_sdat,
- //for test
- key_n
- );
- input sys_clk;
- input sys_rst_n;
- input key_n;
- output iic_sclk;
- inout iic_sdat;
- wire wreq;
- wire rreq;
- wire iic_wr_ack;
- wire iic_rd_ack;
- wire [:] sys_data_o;
- wire [:] sys_data_i;
- wire [:] iic_wr_addr;
- wire [:] iic_rd_addr;
- wire wr_config_done;
- wr_config inst_wr_config(
- .sys_clk(sys_clk),
- .sys_rst_n(sys_rst_n),
- .iic_wr_ack_i(iic_wr_ack),
- .wreq_o(wreq),
- .sys_byte_o(sys_data_i),
- .iic_wr_addr_o(iic_wr_addr),
- .wr_config_done_o(wr_config_done)
- );
- rd_check inst_rd_check(
- .sys_clk(sys_clk),
- .sys_rst_n(sys_rst_n),
- .key_n(key_n),
- .rreq_o(rreq),
- .iic_rd_addr_o(iic_rd_addr)
- );
- iic_ctrl inst_iic_ctrl(
- //common
- .sys_clk(sys_clk),
- .sys_rst_n(sys_rst_n),
- .iic_sclk(iic_sclk),
- .iic_sdat(iic_sdat),
- //read
- .rreq_i(rreq),
- .iic_rd_addr_i(iic_rd_addr),
- .rd_en_i(wr_config_done),
- .iic_rd_ack_o(iic_rd_ack),
- .sys_byte_o(sys_data_o),
- //write
- .wreq_i(wreq),
- .wr_en_i(~wr_config_done),
- .iic_wr_addr_i(iic_wr_addr),
- .sys_byte_i(sys_data_i),
- .iic_wr_ack_o(iic_wr_ack)
- );
- endmodule
源码5:仿真文件
- `timescale ns / ps
- `define T1
- `define T20
- `define T500
- module iic_tsb;
- reg sys_clk;
- reg sys_rst_n;
- reg key_n;
- initial begin
- sys_clk=;
- sys_rst_n=;
- key_n=;
- # sys_rst_n=;
- #`T1 key_n=;
- #`T20 key_n=;
- #`T500 key_n=;
- #`T20 key_n=;
- #`T500 key_n=;
- #`T20 key_n=;
- end
- always begin
- # sys_clk=~sys_clk;
- end
- wire iic_sclk;
- wire iic_sdat;
- iic_driver inst_iic_driver(
- .sys_clk(sys_clk),
- .sys_rst_n(sys_rst_n),
- .iic_sclk(iic_sclk),
- .iic_sdat(iic_sdat),
- .key_n(key_n)
- );
- endmodule
脚本文件1:windows .bat
- rd work /s /q
- del *.wlf
- del modelsim.ini
- del transcript
- vsim -do iic_tsb.do
脚本文件2:仿真tcl脚本
- # creat lib
- vlib work
- vmap work work
- # compile
- vlog -work work iic_ctrl.v
- vlog -work work rd_check.v
- vlog -work work wr_config.v
- vlog -work work iic_driver.v
- vlog -work work iic_tsb.v
- # simulation
- vsim -novopt -lib work iic_tsb
- # wave
- view wave
- add wave sim:/iic_tsb/inst_iic_driver/sys_clk
- add wave sim:/iic_tsb/inst_iic_driver/sys_rst_n
- add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2host
- add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2slave
- add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_wr_addr
- add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_rd_addr
- add wave sim:/iic_tsb/inst_iic_driver/wreq
- add wave sim:/iic_tsb/inst_iic_driver/rreq
- add wave sim:/iic_tsb/inst_iic_driver/iic_wr_ack
- add wave sim:/iic_tsb/inst_iic_driver/iic_rd_ack
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk_w
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sdat
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/sdat_r
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/link
- add wave -radix unsigned sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/bit_cnt
- add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_byte
- add wave -radix ascii sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/c_st
- #write config cost 10ms
- run 12ms
I2C控制器的Verilog建模之三(完结版)的更多相关文章
- I2C控制器的Verilog建模之一
前言:之前申请了ADI公司的一款ADV7181CBSTZ的视频解码芯片,正好原装DE2板子安的是同系列的ADV7181BBSTZ.虽然都是ADV7181的宗出,但是寄存器配置等等还是有些诧异,引脚也不 ...
- Norflash控制器的Verilog建模之三(測試)
前言:回校了,辦好手續就著手寫測試篇.初步的norflash控制器已經完成,通過硬件測試.目前的norflash完成扇区块擦除.单字节写.单字节读3个功能.博文最后附上源码. 总结:和之前的博文一样, ...
- I2C控制器的Verilog建模之二
前言:接着上一篇的I2C写操作,今天要实现一个I2C的读操作.虽然在ADV7181B配置内部寄存器时没有必要使用到读操作,但是为了进一步确认寄存器是否在I2C写模块下被正确配置,这一步是必不可少的. ...
- Norflash控制器的Verilog建模之二(仿真)
前言:经过几天修改,norflash控制器基本已经完成,通过仿真.完整的norflash包含2个模块:直接操作硬件的norflash_ctrl.v与控制ctrl模块的驱动norflash_driver ...
- Norflash控制器的Verilog建模之一
摘要:今天驱动一款SPANSION公司生产的norflash——S29AL032D70,没有别的参考资料,大致了解一下norflash的内部cmos电路架构以及其用途之后,直接看手册吧. 如何看手册: ...
- SDRAM控制器的Verilog建模之一
前言:作为经典存储器的三剑客中的flash和sram已经建模测试过了,虽然现在都已经ddr2,ddr3,667MHZ.1333MHZ的天下了,但是接下这周来准备写一下sdram的controller. ...
- 异步SRAM控制器的Verilog建模
前言:sram顾名思义静态随机存储器,分为asram异步型和ssram同步型.这里驱动DE2上一块ISSI公司的512KB的asram. 设计思路:因为实际应用中单字节读写效率不高,所以本设计中仿照s ...
- VGA逐行扫描控制器的Verilog建模
前言:因为VGA是一种模拟图像传输数据接口,所要将数字信号用DAC转换成模拟量.本文用的一款ADI公司高精度的视频IC,实则一款高带宽的视频DAC.因为VGA时序较为简单,并且网上的VGA驱动基本大同 ...
- Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写
"./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0内核中三星SoC的i2c控制器驱动程序, 本文试图通过对这个程序的分析, 剥离繁复的细节, 总 ...
随机推荐
- Lantern卫星接收器:为你提供免费上网服务
包括笔者在内,许多现代人的日常生活都无法离开网络,因为在网络上我们几乎可以找到任何我们需要的信息.但你是否有想过在户外无网络信号的情况下如何接收网络数据呢?一个名为Outernet Inc.的公司为我 ...
- a few changes of Android 5.0
1.Service Intent must be explicit Intent serviceIntent = new Intent(context,MyService.class);context ...
- ffmepg-nginx-nginx-rtmp-module配置脚本
把上个月写的的配置脚本贴一下: #!/bin/bash #version:-- #create by itn #dis: this is used to auto install ffmpeg+ngi ...
- Windows Server 2012 R2在桌面上顯示我的電腦等圖示
Windows Server 2012 R2在桌面上顯示我的電腦等圖示 從Windows2012開始,微軟取消了服務器桌面個性化選項,如何重新調出配置界面,可以使用微軟命令調出.方法如下: 同時按 ...
- 从零开始学习Node.js例子四 多页面实现数学运算
app-node.js ; var http = require('http'); var htutil = require('./htutil'); var server = http.create ...
- 阿里 RocketMQ 安装与简介
一.简介 官方简介: l RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: l 能够保证严格的消息顺序 l 提供丰富的消息拉取模式 l 高效的订阅者水平扩展能力 l 实时的 ...
- 数据库update死锁
比较常见的死锁场景,并发批量update时的一个场景: update cross_marketing set gmtModified = NOW(), pageview = pageview+ #ex ...
- Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题
标签:scrollview android 滑动 嵌套 scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview ...
- Android学习七:new Date使用
1.例子 学习时间函数,并实现了简单的多个按钮监听同一个事件的方法 2.代码 代码很简单,也很清晰 package com.example.datetime; import java.text.Sim ...
- SpringMVC学习系列(5) 之 数据绑定-2
在系列(4)中我们介绍了如何用@RequestParam来绑定数据,下面我们来看一下其它几个数据绑定注解的使用方法. 1.@PathVariable 用来绑定URL模板变量值,这个我们已经在系列(3) ...