zoukankan      html  css  js  c++  java
  • 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读写控制器

      1 `timescale 1 ns / 1 ps
      2 `define SIM
      3 `define SYS_CLK    50000000
      4 `define IIC_CLK    100000
      5 `define IIC_CLK_DIV        `SYS_CLK/`IIC_CLK
      6 `define ADV7181B
      7 `define SCLK_CNT_WIDTH    9
      8 //VERSION:V0.0
      9 module iic_ctrl(
     10                         //common
     11                         sys_clk,
     12                         sys_rst_n,
     13                         iic_sclk,
     14                         iic_sdat,
     15                         //read
     16                         rreq_i,
     17                         iic_rd_addr_i,
     18                         rd_en_i,
     19                         iic_rd_ack_o,
     20                         sys_byte_o,
     21                         //write
     22                         wreq_i,
     23                         wr_en_i,
     24                         iic_wr_addr_i,
     25                         sys_byte_i,
     26                         iic_wr_ack_o
     27                         );
     28 //common port
     29 input sys_clk;                //global clk in
     30 input sys_rst_n;            //global rst_n in
     31 output iic_sclk;                //iic sclk
     32 inout iic_sdat;                //iic sdat
     33 //read port
     34 input rreq_i;                    //read requast in
     35 input [7:0] iic_rd_addr_i;        //read register address in
     36 input rd_en_i;                //read enable in
     37 output iic_rd_ack_o;        //module read ack
     38 output [7:0] sys_byte_o;    //read byte out 
     39 //write port
     40 input wreq_i;                //write request in
     41 input wr_en_i;                //write enable in
     42 input [7:0] iic_wr_addr_i;            //write register address in
     43 input [7:0] sys_byte_i;            //byte to be written
     44 output iic_wr_ack_o;            //module write ack
     45 //macro
     46 `ifdef ADV7181B
     47     parameter DEVICE_READ = 8'h41;        //器件读操作地址
     48     parameter DEVICE_WRITE = 8'h40;        //器件写操作地址
     49 `endif
     50 //marcro
     51 `ifdef SIM
     52         parameter ST_WIDTH = 56;
     53         parameter IDLE = "IDLE...",
     54                         START1 = "START1.",
     55                         WR_SLAVE = "WR_SLAV",
     56                         ACK1 = "ACK1...",
     57                         SET_REG = "SET_REG",
     58                         ACK2 = "ACK2...",
     59                         WR_DATA = "WR_DATA",
     60                         ACK3 = "ACK3...",
     61                         STOP = "STOP...";
     62         parameter START2 = "START2.",
     63                         RD_SLAVE = "RD_SLAV",
     64                         ACK4 = "ACK4...",
     65                         RD_DATA = "RD_DATA",
     66                         NACK = "NACK...";
     67 
     68 `else
     69         `define FSM    14
     70         parameter ST_WIDTH = 14;
     71         parameter IDLE = `FSM'b00_0000_0000_0001,
     72                         START1 =  `FSM'b00_0000_0000_0010,    //写操作一共有1个start,读操作一共2个start
     73                         WR_SLAVE =  `FSM'b00_0000_0000_0100,
     74                         ACK1 =  `FSM'b00_0000_0000_1000,
     75                         SET_REG =  `FSM'b00_0000_0001_0000,
     76                         ACK2 =  `FSM'b00_0000_0010_0000,
     77                         WR_DATA =  `FSM'b00_0000_0100_0000,
     78                         ACK3 =  `FSM'b00_0000_1000_0000,
     79                         STOP =  `FSM'b00_0001_0000_0000;
     80         parameter START2 = `FSM'b00_0010_0000_0000,
     81                         RD_SLAVE = `FSM'b00_0100_0000_0000,
     82                         ACK4 = `FSM'b00_1000_0000_0000,
     83                         RD_DATA = `FSM'b01_0000_0000_0001,
     84                         NACK = `FSM'b10_0000_0000_0001;
     85 `endif
     86 //caputre the posedge of rreq_i;
     87 reg rreq_r0 = 0;
     88 always @ (posedge sys_clk) begin
     89 if(sys_rst_n == 1'b0)    rreq_r0 <= 0;
     90 else rreq_r0 <= rreq_i;
     91 end
     92 wire do_rreq = rreq_i & ~rreq_r0 & rd_en_i;
     93 //generate the rd_start;
     94 reg rd_start = 0;
     95 always @ (posedge sys_clk) begin
     96 if(sys_rst_n == 1'b0)    rd_start <= 0;
     97 else if(iic_rd_ack_o == 1'b1) rd_start <= 0;
     98 else if(do_rreq)    rd_start <= 1;
     99 else rd_start <= rd_start;
    100 end
    101 //caputre the posedge of wreq_i;
    102 reg wreq_r0 = 0;
    103 always @ (posedge sys_clk) begin
    104 if(sys_rst_n == 1'b0)    wreq_r0 <= 0;
    105 else wreq_r0 <= wreq_i;
    106 end
    107 wire do_wreq = wreq_i & ~wreq_r0 & wr_en_i;
    108 //generate the wr_start;
    109 reg wr_start = 0;
    110 always @ (posedge sys_clk) begin
    111 if(sys_rst_n == 1'b0)    wr_start <= 0;
    112 else if(iic_wr_ack_o == 1'b1) wr_start <= 0;
    113 else if(do_wreq)    wr_start <= 1;
    114 else wr_start <= wr_start;
    115 end
    116 //GENERATE SCLK
    117 reg [`SCLK_CNT_WIDTH-1:0] sclk_cnt = 0;
    118 wire sclk_cnt_en1 = ((sclk_cnt < `IIC_CLK_DIV-1)&&(wr_en_i == 1'b1)&&(wr_start == 1'b1))?1'b1:1'b0;
    119 wire sclk_cnt_en2 = ((sclk_cnt < `IIC_CLK_DIV-1)&&(rd_en_i == 1'b1)&&(rd_start == 1'b1))?1'b1:1'b0;
    120 always @ (posedge sys_clk) begin
    121 if(1'b0 == sys_rst_n) sclk_cnt <= 0;
    122 else if(sclk_cnt_en1 | sclk_cnt_en2) sclk_cnt <= sclk_cnt + 1'd1;
    123 else sclk_cnt <= 0;
    124 end
    125 //时间片
    126 `define SCLK_POS    (sclk_cnt == `SCLK_CNT_WIDTH'd499)
    127 `define SCLK_HIGH    (sclk_cnt == `SCLK_CNT_WIDTH'd124)
    128 `define SCLK_NEG    (sclk_cnt == `SCLK_CNT_WIDTH'd249)
    129 `define SCLK_LOW    (sclk_cnt == `SCLK_CNT_WIDTH'd374)
    130 //内部i2c串行时钟
    131 wire iic_sclk_w = ((sclk_cnt <= `SCLK_CNT_WIDTH'd249)&&(rd_en_i | wr_en_i))?1'b1:1'b0;
    132 //fsm registers
    133 reg [7:0] iic_byte = 0;
    134 reg [7:0] sys_byte_o = 0;
    135 reg sdat_r = 1;
    136 reg link = 0;            //read:0
    137 reg [3:0] bit_cnt = 0;
    138 reg [ST_WIDTH-1:0] c_st = IDLE;
    139 reg [ST_WIDTH-1:0] n_st = IDLE;
    140 //FSM-1
    141 always @ (posedge sys_clk) begin
    142 if(1'b0 == sys_rst_n) c_st <= IDLE;
    143 else c_st <= n_st;
    144 end
    145 //FSM-2,实际的状态转移中ack[2:0]比物理等待的ack少四分之一
    146 always @ (*) begin
    147     n_st = IDLE;
    148     case(c_st)
    149     IDLE:begin
    150                 n_st = ((wr_start == 1'b1)||(rd_start == 1'b1))?START1:IDLE;end
    151     START1:begin
    152                     n_st = (`SCLK_LOW)?WR_SLAVE:START1;end    //sclk为高电平中心时转移
    153     WR_SLAVE:begin
    154                             n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
    155     ACK1:begin 
    156                 n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
    157     SET_REG:begin
    158                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK2:SET_REG;end//数据在低电平是更新
    159     ACK2:begin
    160                     if(`SCLK_NEG) begin
    161                             n_st = (wr_start == 1'b1)?WR_DATA:START2;end
    162                     else begin
    163                                 n_st = ACK2;end
    164             end//为保证下一步设置寄存器,提前1/4进入下一个状态
    165     WR_DATA:begin
    166                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK3:WR_DATA;end
    167     ACK3:begin
    168                     n_st = (`SCLK_NEG)?STOP:ACK3;end
    169     STOP:begin
    170                     n_st = (`SCLK_NEG)?IDLE:STOP;end
    171     START2:begin
    172                     n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
    173     RD_SLAVE:begin
    174                             n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK4:RD_SLAVE;end
    175     ACK4:begin
    176                     n_st = (`SCLK_NEG)?RD_DATA:ACK4;end
    177     RD_DATA:begin
    178                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?NACK:RD_DATA;end
    179     NACK:begin
    180                     n_st = (`SCLK_NEG)?STOP:NACK;end
    181     default:begin
    182                     n_st = IDLE;end
    183     endcase
    184 end
    185 //FSM-3
    186 always @ (posedge sys_clk) begin
    187 if(sys_rst_n == 1'b0) begin
    188                                 link <= 1'd0;
    189                                 iic_byte <= 0;
    190                                 sys_byte_o <= sys_byte_o;        //保持
    191                                 bit_cnt <= 4'd0;
    192                                 sdat_r <= 1'd1;
    193                                 end
    194 else begin
    195     case(c_st)
    196     IDLE:begin
    197                                 link <= 1'd0;
    198                                 sys_byte_o <= sys_byte_o;
    199                                 iic_byte <= DEVICE_WRITE;
    200                                 bit_cnt <= 4'd0;
    201                                 sdat_r <= 1'd1;
    202             end
    203     START1:begin
    204                                 link <= 1'd1;
    205                                 bit_cnt <= 4'd1;
    206                                 sys_byte_o <= sys_byte_o;
    207                                 iic_byte <= (`SCLK_LOW)?iic_byte<<1:iic_byte;
    208                                 if(`SCLK_HIGH) begin
    209                                                         sdat_r <= 1'b0;end
    210                                 else if(`SCLK_LOW) begin
    211                                                         sdat_r <= iic_byte[7];end    //pull down,由于i2c_byte缓存一级的缘故,需要提前在START里输出第MSB位
    212                                 else begin
    213                                                 sdat_r <= sdat_r;end
    214                 end
    215     WR_SLAVE:begin
    216                             sys_byte_o <= sys_byte_o;
    217                             if(`SCLK_LOW) begin
    218                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
    219                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
    220                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
    221                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
    222                             else begin
    223                                     link <= link;
    224                                     bit_cnt <= bit_cnt;
    225                                     iic_byte <= iic_byte;
    226                                     sdat_r <= sdat_r;end
    227                         end
    228     ACK1:begin
    229                                 link <= 1'd0;
    230                                 sys_byte_o <= sys_byte_o;
    231                                 if(`SCLK_POS) begin
    232                                         iic_byte <= (wr_start==1'b1)?iic_wr_addr_i:iic_rd_addr_i;end
    233                                 else begin
    234                                         iic_byte <= iic_byte;end    //读入待写的寄存器地址
    235                                 bit_cnt <= 4'd0;
    236                                 sdat_r <= 1'd1;
    237                                 end
    238     SET_REG:begin
    239                             sys_byte_o <= sys_byte_o;
    240                             if(`SCLK_LOW) begin
    241                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
    242                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
    243                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
    244                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
    245                             else begin
    246                                     link <= link;
    247                                     bit_cnt <= bit_cnt;
    248                                     iic_byte <= iic_byte;
    249                                     sdat_r <= sdat_r;end
    250                         end
    251     ACK2:begin
    252                                 link <= 1'd0;
    253                                 bit_cnt <= 4'd0;
    254                                 sdat_r <= 1'd1;
    255                                 sys_byte_o <= sys_byte_o;
    256                                 if(`SCLK_POS) begin
    257                                             iic_byte <= (wr_start)?sys_byte_i:DEVICE_READ;end    //读入待写的寄存器地址
    258                                 else begin    
    259                                             iic_byte <= iic_byte;end
    260                                 end
    261     WR_DATA:begin
    262                             sys_byte_o <= sys_byte_o;
    263                             if(`SCLK_LOW) begin
    264                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
    265                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
    266                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
    267                                     sdat_r <= iic_byte[7];end
    268                             else begin
    269                                     link <= link;
    270                                     bit_cnt <= bit_cnt;
    271                                     iic_byte <= iic_byte;
    272                                     sdat_r <= sdat_r;end
    273                         end
    274     ACK3:begin
    275                     sys_byte_o <= sys_byte_o;
    276                     link <= 1'd0;
    277                     sdat_r <= 1'd0;//预先拉低
    278                     bit_cnt <= bit_cnt;
    279                     iic_byte <= iic_byte;end
    280     STOP:begin
    281                     sys_byte_o <= sys_byte_o;
    282                     link <= (`SCLK_LOW)?1'b1:link;
    283                     bit_cnt <= bit_cnt;
    284                     iic_byte <= iic_byte;
    285                     if(`SCLK_LOW) begin
    286                                             sdat_r <= 1'b0;end
    287                     else if(`SCLK_HIGH) begin
    288                                             sdat_r <= 1'b1;end
    289                     else begin
    290                                             sdat_r <= sdat_r;end
    291             end
    292     START2:begin
    293                     link <= (`SCLK_LOW)?1'b1:link;
    294                     sys_byte_o <= sys_byte_o;
    295                     iic_byte <= iic_byte;
    296                     bit_cnt <= bit_cnt;
    297                     sdat_r <= (`SCLK_HIGH)?1'b0:sdat_r;
    298                     end
    299     RD_SLAVE:begin
    300                             sys_byte_o <= sys_byte_o;
    301                             if(`SCLK_LOW) begin
    302                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;
    303                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1; 
    304                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
    305                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
    306                             else begin
    307                                     link <= link;
    308                                     bit_cnt <= bit_cnt;
    309                                     iic_byte <= iic_byte;
    310                                     sdat_r <= sdat_r;end
    311                             end
    312     ACK4:begin
    313                 link <= 1'b0;
    314                 bit_cnt <= 4'd0;
    315                 sys_byte_o <= sys_byte_o;
    316                 iic_byte <= 0;
    317                 sdat_r <= 1'd1;end
    318     RD_DATA:begin
    319                         sys_byte_o <= sys_byte_o;
    320                             if(`SCLK_POS) begin
    321                                     link <= (bit_cnt == 4'd8)?1'b1:1'b0;    //为主设备产生NACK准备
    322                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
    323                                     iic_byte[7:1] <= iic_byte[6:0];//左移一位
    324                                     iic_byte[0] <= iic_sdat;end
    325                             else begin
    326                                     link <= link;
    327                                     bit_cnt <= bit_cnt;
    328                                     iic_byte <= iic_byte;
    329                                     sdat_r <= sdat_r;end
    330                         end
    331     NACK:begin
    332                     link <= 1'd1;
    333                     sdat_r <= 1'd1;//预先拉低
    334                     bit_cnt <= bit_cnt;
    335                     iic_byte <= iic_byte;
    336                     sys_byte_o <= iic_byte;end
    337     default:begin
    338                                 link <= 1'd0;
    339                                 iic_byte <= 8'd0;
    340                                 bit_cnt <= 4'd0;
    341                                 sdat_r <= 1'd1;
    342                                 sys_byte_o <= sys_byte_o;
    343                                 end
    344     endcase
    345     end
    346 end
    347 //assign
    348 assign iic_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(rd_start))?1'b1:1'b0;
    349 assign iic_sclk = (c_st != IDLE)?iic_sclk_w:1'b1;
    350 assign iic_sdat = (link == 1'b1)?sdat_r:1'bz;
    351 assign iic_wr_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(wr_start))?1'b1:1'b0;
    352 
    353 endmodule

    源码2:写iic的寄存器地址和数据,移植不同器件更改这部分查找表内容

    `timescale 1 ns / 1 ps
    `define LUT_WIDTH 6
    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 [7:0] sys_byte_o;
    output [7:0] iic_wr_addr_o; 
    output wr_config_done_o;
    
    //generate wreq_o
    reg wreq_o = 0;
    reg [`LUT_WIDTH-1:0] lut_index = 0;
    reg [15:0] lut_data = 0;
    always @ (posedge sys_clk) begin
    if(1'b0 == sys_rst_n) begin
                                    wreq_o <= 1;
                                    lut_index <= 0;end
    else if((iic_wr_ack_i == 1'b1)&&(wr_config_done_o == 1'b0)) begin
                                    wreq_o <= 1;
                                    lut_index <= lut_index + 1'd1;end
    else begin
            wreq_o <= 0;
            lut_index <= lut_index;end
    end
    
    //generate done
    reg wr_config_done_o = 0;
    always @ (posedge sys_clk) begin
    if(sys_rst_n == 1'b0)    wr_config_done_o <= 0;
    else if((lut_index == 6'd34) && (iic_wr_ack_i == 1'b1))    wr_config_done_o <= 1;
    else wr_config_done_o <= wr_config_done_o;
    end
    
    //assign
    assign sys_byte_o = lut_data[7:0];
    assign iic_wr_addr_o = lut_data[15:8];
    //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 <= 16'h0080;
        endcase
    end
    endmodule

    源码3:读回写入寄存器内容

     1 `timescale 1 ns / 1 ps
     2 `define LUT_WIDTH    6
     3 module rd_check(
     4                             sys_clk,
     5                             sys_rst_n,
     6                             key_n,
     7                             rreq_o,
     8                             iic_rd_addr_o
     9                             );
    10 input sys_clk;
    11 input sys_rst_n;
    12 input key_n;
    13 output rreq_o;
    14 output [7:0] iic_rd_addr_o;
    15 
    16 //capture the negedge of key_n;
    17 reg key_n_r0 = 1;
    18 always @ (posedge sys_clk) begin
    19 if(1'b0 == sys_rst_n) key_n_r0 <= 1;
    20 else key_n_r0 <= key_n;
    21 end
    22 wire key_neg = ~key_n & key_n_r0;
    23 //generate the rreq_o
    24 reg rreq_o = 0;
    25 always @ (posedge sys_clk) begin
    26 if(1'b0 == sys_rst_n) rreq_o <= 0;
    27 else if(key_neg) rreq_o <= 1;
    28 else rreq_o <= 0;
    29 end
    30 
    31 //generate the iic_rd_addr_o
    32 reg [6:0] lut_index = 0;
    33 reg [7:0] lut_data = 0;
    34 always @ (posedge sys_clk) begin
    35 if(1'b0 == sys_rst_n) lut_index <= 0;
    36 else if(lut_index == `LUT_WIDTH'd35) lut_index <= 0;
    37 else if(key_neg) lut_index <= lut_index + 1'd1;
    38 else lut_index <= lut_index;
    39 end
    40 
    41 always @ (*) begin
    42     case(lut_index)
    43     `LUT_WIDTH'd0:lut_data <= 8'hFF;        //offset no meaning
    44     `LUT_WIDTH'd1:lut_data <= 8'h00;
    45     `LUT_WIDTH'd2:lut_data <= 8'h07;
    46     `LUT_WIDTH'd3:lut_data <= 8'h15;
    47     `LUT_WIDTH'd4:lut_data <= 8'h17;
    48     `LUT_WIDTH'd5:lut_data <= 8'h19;
    49     `LUT_WIDTH'd6:lut_data <= 8'h1D;
    50     `LUT_WIDTH'd7:lut_data <= 8'h0F;
    51     `LUT_WIDTH'd8:lut_data <= 8'h3A;
    52     `LUT_WIDTH'd9:lut_data <= 8'h3D;
    53     `LUT_WIDTH'd10:lut_data <= 8'h3F;
    54     `LUT_WIDTH'd11:lut_data <= 8'h50;
    55     `LUT_WIDTH'd12:lut_data <= 8'hC3;
    56     `LUT_WIDTH'd13:lut_data <= 8'hC4;
    57     `LUT_WIDTH'd14:lut_data <= 8'h0E;
    58     `LUT_WIDTH'd15:lut_data <= 8'h50;
    59     `LUT_WIDTH'd16:lut_data <= 8'h52;
    60     `LUT_WIDTH'd17:lut_data <= 8'h58;
    61     `LUT_WIDTH'd18:lut_data <= 8'h77;
    62     `LUT_WIDTH'd19:lut_data <= 8'h7C;
    63     `LUT_WIDTH'd20:lut_data <= 8'h7D;
    64     `LUT_WIDTH'd21:lut_data <= 8'h90;
    65     `LUT_WIDTH'd22:lut_data <= 8'h91;
    66     `LUT_WIDTH'd23:lut_data <= 8'h92;
    67     `LUT_WIDTH'd24:lut_data <= 8'h93;
    68     `LUT_WIDTH'd25:lut_data <= 8'h94;
    69     `LUT_WIDTH'd26:lut_data <= 8'hCF;
    70     `LUT_WIDTH'd27:lut_data <= 8'hD0;
    71     `LUT_WIDTH'd28:lut_data <= 8'hD6;
    72     `LUT_WIDTH'd29:lut_data <= 8'hE5;
    73     `LUT_WIDTH'd30:lut_data <= 8'hD5;
    74     `LUT_WIDTH'd31:lut_data <= 8'hD7;
    75     `LUT_WIDTH'd32:lut_data <= 8'hE4;
    76     `LUT_WIDTH'd33:lut_data <= 8'hE9;
    77     `LUT_WIDTH'd34:lut_data <= 8'hEA;
    78     `LUT_WIDTH'd35:lut_data <= 8'h0E;
    79     default:lut_data <= 8'h00;
    80     endcase
    81 end
    82 //assign
    83 assign iic_rd_addr_o = lut_data;
    84 
    85 endmodule

    源码4:顶层例化文件

     1 `timescale 1 ns / 1 ps
     2 module iic_driver(
     3                                 sys_clk,
     4                                 sys_rst_n,
     5                                 iic_sclk,
     6                                 iic_sdat,
     7                                 //for test
     8                                 key_n
     9                                 );
    10 input sys_clk;
    11 input sys_rst_n;
    12 input key_n;
    13 output iic_sclk;
    14 inout iic_sdat;
    15 
    16 wire wreq;
    17 wire rreq;
    18 
    19 wire iic_wr_ack;
    20 wire iic_rd_ack;
    21 
    22 wire [7:0] sys_data_o;
    23 wire [7:0] sys_data_i;
    24 
    25 wire [7:0] iic_wr_addr;
    26 wire [7:0] iic_rd_addr;
    27 
    28 wire wr_config_done;
    29 
    30 wr_config                inst_wr_config(
    31                             .sys_clk(sys_clk),
    32                             .sys_rst_n(sys_rst_n),
    33                             .iic_wr_ack_i(iic_wr_ack),
    34                             .wreq_o(wreq),
    35                             .sys_byte_o(sys_data_i),
    36                             .iic_wr_addr_o(iic_wr_addr),
    37                             .wr_config_done_o(wr_config_done)
    38                             );
    39 
    40 rd_check                inst_rd_check(
    41                             .sys_clk(sys_clk),
    42                             .sys_rst_n(sys_rst_n),
    43                             .key_n(key_n),
    44                             .rreq_o(rreq),
    45                             .iic_rd_addr_o(iic_rd_addr)
    46                             );
    47 
    48 iic_ctrl                inst_iic_ctrl(
    49                         //common
    50                         .sys_clk(sys_clk),
    51                         .sys_rst_n(sys_rst_n),
    52                         .iic_sclk(iic_sclk),
    53                         .iic_sdat(iic_sdat),
    54                         //read
    55                         .rreq_i(rreq),
    56                         .iic_rd_addr_i(iic_rd_addr),
    57                         .rd_en_i(wr_config_done),
    58                         .iic_rd_ack_o(iic_rd_ack),
    59                         .sys_byte_o(sys_data_o),
    60                         //write
    61                         .wreq_i(wreq),
    62                         .wr_en_i(~wr_config_done),
    63                         .iic_wr_addr_i(iic_wr_addr),
    64                         .sys_byte_i(sys_data_i),
    65                         .iic_wr_ack_o(iic_wr_ack)
    66                         );
    67                         
    68                         
    69 endmodule

    源码5:仿真文件

     1 `timescale 1 ns / 1 ps
     2 `define T1    10000000
     3 `define T20    20
     4 `define T500 500000
     5 module iic_tsb;
     6 
     7 reg sys_clk;
     8 reg sys_rst_n;
     9 reg key_n;
    10 
    11 initial begin
    12 sys_clk=1;
    13 sys_rst_n=0;
    14 key_n=1;
    15 #100 sys_rst_n=1;
    16 #`T1 key_n=0;
    17 #`T20 key_n=1;
    18 #`T500 key_n=0;
    19 #`T20 key_n=1;
    20 #`T500 key_n=0;
    21 #`T20 key_n=1;
    22 end
    23 
    24 always begin
    25 #10 sys_clk=~sys_clk;
    26 end
    27 
    28 wire iic_sclk;
    29 wire iic_sdat;
    30 
    31 iic_driver        inst_iic_driver(
    32                         .sys_clk(sys_clk),
    33                         .sys_rst_n(sys_rst_n),
    34                         .iic_sclk(iic_sclk),
    35                         .iic_sdat(iic_sdat),
    36                         .key_n(key_n)
    37                         );
    38 
    39 endmodule

    脚本文件1:windows .bat

    1 rd work /s /q
    2 del *.wlf
    3 del modelsim.ini
    4 del transcript
    5 
    6 vsim -do iic_tsb.do

    脚本文件2:仿真tcl脚本

     1 # creat lib
     2 vlib work
     3 vmap work work
     4 
     5 # compile
     6 vlog -work work iic_ctrl.v
     7 vlog -work work rd_check.v
     8 vlog -work work wr_config.v
     9 vlog -work work iic_driver.v
    10 vlog -work work iic_tsb.v
    11 
    12 # simulation
    13 vsim -novopt -lib work iic_tsb
    14 
    15 # wave
    16 view wave
    17 add wave sim:/iic_tsb/inst_iic_driver/sys_clk
    18 add wave sim:/iic_tsb/inst_iic_driver/sys_rst_n
    19 add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2host
    20 add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2slave
    21 add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_wr_addr
    22 add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_rd_addr
    23 add wave sim:/iic_tsb/inst_iic_driver/wreq
    24 add wave sim:/iic_tsb/inst_iic_driver/rreq
    25 add wave sim:/iic_tsb/inst_iic_driver/iic_wr_ack
    26 add wave sim:/iic_tsb/inst_iic_driver/iic_rd_ack
    27 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk
    28 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk_w
    29 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sdat
    30 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/sdat_r
    31 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/link
    32 add wave -radix unsigned sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/bit_cnt
    33 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_byte
    34 add wave -radix ascii sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/c_st
    35 #write config cost 10ms
    36 run 12ms
  • 相关阅读:
    [leetcode]133. Clone Graph 克隆图
    [leetcode]366. Find Leaves of Binary Tree捡树叶
    [leetcode]311. Sparse Matrix Multiplication 稀疏矩阵相乘
    [leetcode]151. Reverse Words in a String翻转给定字符串中的单词
    [leetcode]150. Evaluate Reverse Polish Notation逆波兰表示法
    Union and Intersection of two sorted lists 并集和交集
    [leetcode]205. Isomorphic Strings 同构字符串
    [leetcode]428. Serialize and Deserialize N-ary Tree序列化与反序列化N叉树
    [leetcode]364. Nested List Weight Sum II嵌套列表加权和II
    属性 元素的内容 创建,插入和删除节点 虚拟节点
  • 原文地址:https://www.cnblogs.com/loadomain/p/3253304.html
Copyright © 2011-2022 走看看