• 2022年4月13日 状态机练习 基于EEPROM的I2C 随机读


    eeprom I2C随机读  完整时序:

     状态机:

     设计思路参考 状态机练习  --  随机写 日志。

    完整代码:

      1 module eeprom_rd(
      2                     clk,
      3                     rst_n,
      4                     rd_en,
      5 //                    slave_address,
      6 //                    reg_address,
      7 //                    reg_data,
      8                     rec_buf,
      9                     scl,
     10                     sda
     11 );
     12 parameter        D_W            = 8  ;
     13 parameter         SCL_100K     = 500;
     14 
     15 parameter        IDLE         = 0;
     16 parameter        START         = 1;
     17 parameter        SLAVE_ADD    = 2;
     18 parameter        ACK            = 3;
     19 parameter        REG_ADD        = 4;
     20 parameter        REC_DAT        = 5;
     21 parameter        NOACK        = 6;
     22 parameter        STOP        = 7;
     23 
     24 
     25 parameter        slave_address  = 8'b1010_0000;
     26 parameter        reg_address    = 8'h0f;
     27 parameter        reg_data       = 8'h5f;
     28 
     29 input             clk             ;
     30 input            rst_n         ;
     31 input            rd_en         ;
     32 //input[D_W-1:0]    slave_address;
     33 //input[D_W-1:0]    reg_address     ;
     34 //input[D_W-1:0]    reg_data     ;
     35 
     36 output[D_W-1:0] rec_buf    ;
     37 output            scl        ;
     38 inout            sda        ;
     39 
     40 
     41 wire[D_W-1:0]    slave_address_r;
     42 assign            slave_address_r  = slave_address | 1'b1;
     43 
     44 wire            SCL_H2L          ;
     45 wire            SCL_L2H          ;
     46 wire            SCL_H_MIDDLE     ;
     47 wire             add_cnt0         ;
     48 wire             end_cnt0         ;
     49 wire             add_cnt1         ;
     50 wire             end_cnt1         ;
     51 
     52 wire            IDLE2START         ;
     53 wire            START2SLAVE_ADD    ;
     54 wire            SLAVE_ADD2ACK    ;
     55 wire            ACK2START        ;
     56 wire            ACK2REG_ADD     ;
     57 wire            ACK2REC_DAT        ;
     58 wire            REG_ADD2ACK     ;
     59 wire            REC_DAT2NOACK    ;
     60 wire            NOACK2STOP        ;
     61 wire            STOP2IDLE         ;
     62                                 
     63 reg[9 -1 : 0]    cnt0;
     64 reg[4 -1 : 0]    cnt1;        
     65 
     66 
     67 reg             scl        ;
     68 reg[D_W-1:0]     rec_buf    ;
     69 reg             ack_err ;
     70 reg[4-1:0]        state_c /* synthesis keep*/;
     71 reg[4-1:0]        state_n /* synthesis keep*/;
     72 reg[4-1:0]        x        ;
     73 reg                rd_vld    ;
     74 reg[2-1:0]         ack_flag; 
     75 
     76 always @(posedge clk or negedge rst_n)begin
     77     if(!rst_n)begin
     78         rd_vld <= 0;
     79     end
     80     else if(rd_en)begin
     81         rd_vld <= 1;
     82     end
     83     else if(state_c == STOP && end_cnt1)begin
     84         rd_vld <= 0;
     85     end
     86 end
     87 
     88 //计数产生scl时钟
     89 always @(posedge clk or negedge rst_n)begin
     90     if(!rst_n)begin
     91         cnt0 <= 0;
     92     end
     93     else if(add_cnt0)begin
     94         if(end_cnt0)begin
     95             cnt0 <= 0;
     96         end
     97         else begin
     98             cnt0 <= cnt0 + 1;
     99         end
    100     end
    101 end
    102 
    103 assign add_cnt0 = rd_vld;
    104 assign end_cnt0 = add_cnt0 && cnt0 == SCL_100K - 1;
    105 
    106 //计数scl周期数量
    107 always @(posedge clk or  negedge rst_n)begin
    108     if(!rst_n)begin
    109         cnt1 <= 0;
    110     end
    111     else if(add_cnt1)begin
    112         if(end_cnt1)begin
    113             cnt1 <= 0;
    114         end    
    115         else begin
    116             cnt1 <= cnt1 + 1;
    117         end
    118     end
    119 end
    120 
    121 assign add_cnt1 = end_cnt0;
    122 assign end_cnt1 = add_cnt1 && cnt1 == x - 1;
    123 
    124 always @(*)begin
    125     if(state_c == START || state_c == ACK || state_c == NOACK ||state_c == STOP)begin
    126         x = 1;
    127     end
    128     else begin
    129         x = 8;
    130     end
    131 end
    132 
    133 //scl时钟周期  _--_
    134 always @(posedge clk or negedge rst_n)begin
    135     if(!rst_n)begin
    136         scl <= 1;
    137     end
    138     else if(add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1 && state_c != STOP)begin
    139         scl <= 0;
    140     end
    141     else if(add_cnt0 && cnt0 == (SCL_100K>>2) -1)begin
    142         scl <= 1;
    143     end
    144 end
    145 
    146 assign SCL_H2L         = add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1; //下降沿
    147 assign SCL_L2H         = add_cnt0 && cnt0 == (SCL_100K>>2) -1;    //上升沿
    148 assign SCL_H_MIDDLE = add_cnt0 && cnt0 == (SCL_100K>>1) -1;    //高电平中间
    149 
    150 //第一段
    151 always @(posedge clk or negedge rst_n)begin
    152     if(!rst_n)begin
    153         state_c <= IDLE;
    154     end
    155     else begin
    156         state_c <= state_n; 
    157     end
    158 end
    159 
    160 //第二段
    161 always @(*)begin
    162     case(state_c)
    163     IDLE:begin
    164         if(IDLE2START)begin
    165             state_n = START;
    166         end
    167         else begin
    168             state_n = state_c;
    169         end
    170     end
    171     
    172     START:begin
    173         if(START2SLAVE_ADD)begin
    174             state_n = SLAVE_ADD;
    175         end
    176         else begin
    177             state_n = state_c;
    178         end
    179     end
    180     
    181     SLAVE_ADD:begin
    182         if(SLAVE_ADD2ACK)begin
    183             state_n = ACK;
    184         end
    185         else begin
    186             state_n = state_c;
    187         end
    188     end
    189     
    190     ACK:begin
    191         if(ACK2REG_ADD)begin
    192             state_n = REG_ADD;
    193         end
    194         else if(ACK2START)begin
    195             state_n = START;
    196         end
    197         else if(ACK2REC_DAT)begin
    198             state_n = REC_DAT;
    199         end
    200         else begin
    201             state_n = state_c;
    202         end
    203     end
    204     
    205     REG_ADD:begin
    206         if(REG_ADD2ACK)begin
    207             state_n = ACK;
    208         end
    209         else begin
    210             state_n = state_c;
    211         end
    212     end
    213 
    214     REC_DAT:begin
    215         if(REC_DAT2NOACK)begin
    216             state_n = NOACK;
    217         end
    218         else begin
    219             state_n = state_c;
    220         end
    221     end
    222     
    223     NOACK:begin
    224         if(NOACK2STOP)begin
    225             state_n = STOP;
    226         end
    227         else begin
    228             state_n = state_c;
    229         end
    230     end
    231     
    232     STOP:begin
    233         if(STOP2IDLE)begin
    234             state_n = IDLE;
    235         end
    236         else begin
    237             state_n = state_c;
    238         end
    239     end
    240 
    241     default:begin
    242         state_n = IDLE;
    243     end
    244     
    245     endcase
    246 end
    247 
    248 //第三段
    249 assign IDLE2START             = state_c == IDLE         && rd_vld  ;
    250 assign START2SLAVE_ADD        = state_c == START         && end_cnt1;
    251 assign SLAVE_ADD2ACK        = state_c == SLAVE_ADD    && end_cnt1;
    252 assign ACK2REG_ADD             = state_c == ACK        && end_cnt1 && ack_flag == 0;
    253 assign ACK2START            = state_c == ACK        && end_cnt1    && ack_flag == 1;
    254 assign ACK2REC_DAT            = state_c == ACK        && end_cnt1 && ack_flag == 2;
    255 assign REG_ADD2ACK          = state_c == REG_ADD    && end_cnt1;
    256 assign REC_DAT2NOACK        = state_c == REC_DAT    && end_cnt1;
    257 assign NOACK2STOP            = state_c == NOACK        && end_cnt1;
    258 assign STOP2IDLE             = state_c == STOP        && end_cnt1;
    259 
    260 //第四段
    261 //标记ack位置,如果到了发送数据阶段,可以知道是第几个ack了
    262 always @(posedge clk or negedge rst_n)begin
    263     if(!rst_n)begin
    264         ack_flag <= 0;
    265     end
    266     else if(state_c == SLAVE_ADD && ack_flag == 0)begin
    267         ack_flag <= 0;
    268     end
    269     else if(state_c == REG_ADD)begin
    270         ack_flag <= 1; //代表是发送完寄存器地址后面的ACK
    271     end
    272     else if(state_c == SLAVE_ADD && ack_flag == 1)begin
    273         ack_flag <= 2; 
    274     end
    275     else if(state_c == STOP && end_cnt1)begin
    276         ack_flag <= 0;
    277     end
    278 end
    279 
    280 
    281 reg  link;
    282 always @(posedge clk or negedge rst_n)begin
    283     if(!rst_n)begin
    284         link <= 1;
    285     end
    286     else if((state_c ==  ACK && add_cnt0 && cnt0 >= 0 && cnt0 <((SCL_100K>>1)+ (SCL_100K>>2)))  || state_c == REC_DAT)begin
    287         link <= 0;    //释放sda,准备接收数据 ,注意在接收数据期间是要一直释放的
    288     end
    289     else begin
    290         link <= 1;
    291     end
    292 end
    293 
    294 //sda 发输出数据
    295 reg sda_temp;
    296 always @(posedge clk or negedge rst_n)begin
    297     if(!rst_n)begin
    298         sda_temp <= 1;
    299     end
    300     else if(state_c == START && SCL_H_MIDDLE)begin //在高电平中间拉低sda 
    301         sda_temp <= 0; //产生start信号 
    302     end
    303     else if(state_c == ACK && end_cnt1 && ack_flag == 0)begin
    304         sda_temp <= 1; //拉高SDA,准备再次产生start信号
    305     end
    306     else if(state_c == SLAVE_ADD && ack_flag == 0)begin
    307         sda_temp <= slave_address[7-cnt1];
    308     end
    309     else if(state_c == REG_ADD)begin
    310         sda_temp <= reg_address[7-cnt1];
    311     end
    312     else if(state_c == SLAVE_ADD && ack_flag == 2)begin
    313         sda_temp <= slave_address_r[7-cnt1];
    314     end
    315     else if(state_c == NOACK)begin
    316         sda_temp <= 0;    //在产生stop之前,先将sda信号拉低
    317     end
    318     else if(state_c == STOP && SCL_H_MIDDLE)begin
    319         sda_temp <= 1;
    320     end
    321 end
    322 
    323 //接收读取的数据
    324 always @(posedge clk or negedge rst_n)begin
    325     if(!rst_n)begin
    326         rec_buf <= 0;
    327     end
    328     else if(state_c == REC_DAT && SCL_H_MIDDLE)begin
    329         rec_buf <= {rec_buf[6:0],sda};
    330     end
    331 end
    332 
    333 //sda接收数据 ,主要是判断是否接收到有效的ack
    334 always @(posedge clk or negedge rst_n)begin
    335     if(!rst_n)begin
    336         ack_err <= 0;
    337     end
    338     else if(state_c == ACK && SCL_H_MIDDLE)begin
    339         ack_err <= sda;
    340     end
    341 end
    342 
    343 assign sda = link? sda_temp : 1'bz;
    344 
    345 endmodule

    仿真测试代码:

     1 `timescale 1ns/1ns
     2 
     3 module eeprom_sim();
     4 
     5 reg            clk;
     6 reg            rst_n;
     7 reg            wr_en;
     8 reg            rd_en;
     9 reg[8-1:0]    slave_address;
    10 reg[8-1:0]    reg_address;
    11 reg[8-1:0]    reg_data;
    12 
    13 wire         scl;
    14 wire        sda;
    15 wire[8-1:0]    rec_buf;
    16 
    17 parameter    CYCLE = 20;
    18 
    19 initial    begin
    20     clk = 0;
    21     forever begin
    22         #(CYCLE/2);
    23         clk = ~clk;
    24     end
    25 end
    26 
    27 initial begin
    28     rst_n = 1;
    29     #1;
    30     rst_n = 0;
    31     #(CYCLE*2);
    32     rst_n = 1;
    33 end
    34 
    35 initial begin
    36     wr_en             = 0;
    37     rd_en             = 0;
    38     slave_address  = 8'b1010_0000;
    39     reg_address    = 8'ha2;
    40     reg_data       = 8'haa;
    41     
    42     #1;
    43     #(CYCLE*5);
    44     wr_en = 1;
    45     rd_en = 1;
    46     #(CYCLE);
    47     wr_en = 0;
    48     rd_en = 0;
    49 end
    50 
    51 /*
    52 eeprom_wr    u1_inist(
    53                         .clk            (clk),
    54                         .rst_n            (rst_n),
    55                         .wr_en            (wr_en),
    56                         .slave_address  (slave_address),
    57                         .reg_address    (reg_address),
    58                         .reg_data        (reg_data),
    59                         .scl            (scl),
    60                         .sda            (sda)
    61 );
    62 */
    63 
    64 
    65 eeprom_rd u1_inist(
    66                         .clk(clk),
    67                         .rst_n(rst_n),
    68                         .rd_en(rd_en),
    69 //                        .slave_address(slave_address),
    70 //                        .reg_address(reg_address),
    71 //                        .reg_data(reg_data),
    72                         .rec_buf(rec_buf),
    73                         .scl(scl),
    74                         .sda(sda)
    75 );
    76 
    77 
    78 endmodule

    仿真波形:

    随机写完整代码: 

      1 module eeprom_wr(
      2                     clk,
      3                     rst_n,
      4                     wr_en,
      5 //                    slave_address,
      6 //                    reg_address,
      7 //                    reg_data,
      8                     scl,
      9                     sda
     10 );
     11 parameter        D_W            = 8  ;
     12 parameter         SCL_100K     = 500;
     13 parameter        IDLE         = 0     ;
     14 parameter        START         = 1     ;
     15 parameter        SLAVE_ADD    = 2     ;
     16 parameter        ACK             = 3     ;
     17 parameter        REG_ADD         = 4     ;
     18 parameter        REG_DAT         = 5     ;
     19 parameter        STOP         = 6     ;
     20 
     21 parameter        slave_address  = 8'b1010_0000;
     22 parameter        reg_address    = 8'h0f;
     23 parameter        reg_data       = 8'haa;
     24 
     25 input             clk             ;
     26 input            rst_n         ;
     27 input            wr_en         ;
     28 //input[D_W-1:0]    slave_address;
     29 //input[D_W-1:0]    reg_address     ;
     30 //input[D_W-1:0]    reg_data     ;
     31 
     32 output            scl;
     33 inout            sda;
     34 
     35 wire            SCL_H2L          ;
     36 wire            SCL_L2H          ;
     37 wire            SCL_H_MIDDLE     ;
     38 wire             add_cnt0         ;
     39 wire             end_cnt0         ;
     40 wire             add_cnt1         ;
     41 wire             end_cnt1         ;
     42 
     43 wire            IDLE2START         ;
     44 wire            START2SLAVE_ADD    ;
     45 wire            SLAVE_ADD2ACK    ;
     46 wire            ACK2REG_ADD        ;
     47 wire            ACK2REG_DAT     ;
     48 wire            ACK2STOP        ;
     49 wire            REG_ADD2ACK     ;
     50 wire            REG_DAT2ACK        ;
     51 wire            STOP2IDLE         ;
     52 
     53 
     54 reg[9 -1 : 0]    cnt0;
     55 reg[4 -1 : 0]    cnt1;        
     56 
     57 
     58 reg             scl        ;
     59 reg             ack_err ;
     60 reg[4-1:0]        state_c /* synthesis keep*/;
     61 reg[4-1:0]        state_n /* synthesis keep*/;
     62 reg[4-1:0]        x        ;
     63 reg                wr_vld    ;
     64 reg[2-1:0]         ack_flag; 
     65 
     66 always @(posedge clk or negedge rst_n)begin
     67     if(!rst_n)begin
     68         wr_vld <= 0;
     69     end
     70     else if(wr_en)begin
     71         wr_vld <= 1;
     72     end
     73     else if(state_c == STOP && end_cnt1)begin
     74         wr_vld <= 0;
     75     end
     76 end
     77 
     78 //计数产生scl时钟
     79 always @(posedge clk or negedge rst_n)begin
     80     if(!rst_n)begin
     81         cnt0 <= 0;
     82     end
     83     else if(add_cnt0)begin
     84         if(end_cnt0)begin
     85             cnt0 <= 0;
     86         end
     87         else begin
     88             cnt0 <= cnt0 + 1;
     89         end
     90     end
     91 end
     92 
     93 assign add_cnt0 = wr_vld;
     94 assign end_cnt0 = add_cnt0 && cnt0 == SCL_100K - 1;
     95 
     96 //计数scl周期数量
     97 always @(posedge clk or  negedge rst_n)begin
     98     if(!rst_n)begin
     99         cnt1 <= 0;
    100     end
    101     else if(add_cnt1)begin
    102         if(end_cnt1)begin
    103             cnt1 <= 0;
    104         end    
    105         else begin
    106             cnt1 <= cnt1 + 1;
    107         end
    108     end
    109 end
    110 
    111 assign add_cnt1 = end_cnt0;
    112 assign end_cnt1 = add_cnt1 && cnt1 == x - 1;
    113 
    114 always @(*)begin
    115     if(state_c == START || state_c == ACK || state_c == STOP)begin
    116         x = 1;
    117     end
    118     else begin
    119         x = 8;
    120     end
    121 end
    122 
    123 //scl时钟周期  _--_
    124 always @(posedge clk or negedge rst_n)begin
    125     if(!rst_n)begin
    126         scl <= 1;
    127     end
    128     else if(add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1 && state_c != STOP)begin
    129         scl <= 0;
    130     end
    131     else if(add_cnt0 && cnt0 == (SCL_100K>>2) -1)begin
    132         scl <= 1;
    133     end
    134 end
    135 
    136 assign SCL_H2L         = add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1; //下降沿
    137 assign SCL_L2H         = add_cnt0 && cnt0 == (SCL_100K>>2) -1;    //上升沿
    138 assign SCL_H_MIDDLE = add_cnt0 && cnt0 == (SCL_100K>>1) -1;    //高电平中间
    139 
    140 //第一段
    141 always @(posedge clk or negedge rst_n)begin
    142     if(!rst_n)begin
    143         state_c <= IDLE;
    144     end
    145     else begin
    146         state_c <= state_n; 
    147     end
    148 end
    149 
    150 //第二段
    151 always @(*)begin
    152     case(state_c)
    153     IDLE:begin
    154         if(IDLE2START)begin
    155             state_n = START;
    156         end
    157         else begin
    158             state_n = state_c;
    159         end
    160     end
    161     
    162     START:begin
    163         if(START2SLAVE_ADD)begin
    164             state_n = SLAVE_ADD;
    165         end
    166         else begin
    167             state_n = state_c;
    168         end
    169     end
    170     
    171     SLAVE_ADD:begin
    172         if(SLAVE_ADD2ACK)begin
    173             state_n = ACK;
    174         end
    175         else begin
    176             state_n = state_c;
    177         end
    178     end
    179     
    180     ACK:begin
    181         if(ACK2REG_ADD)begin
    182             state_n = REG_ADD;
    183         end
    184         else if(ACK2REG_DAT)begin
    185             state_n = REG_DAT;
    186         end
    187         else if(ACK2STOP)begin
    188             state_n = STOP;
    189         end
    190         else begin
    191             state_n = state_c;
    192         end
    193     end
    194     
    195     REG_ADD:begin
    196         if(REG_ADD2ACK)begin
    197             state_n = ACK;
    198         end
    199         else begin
    200             state_n = state_c;
    201         end
    202     end
    203 
    204     REG_DAT:begin
    205         if(REG_DAT2ACK)begin
    206             state_n = ACK;
    207         end
    208         else begin
    209             state_n = state_c;
    210         end
    211     end
    212     
    213     STOP:begin
    214         if(STOP2IDLE)begin
    215             state_n = IDLE;
    216         end
    217         else begin
    218             state_n = state_c;
    219         end
    220     end
    221 
    222     default:begin
    223         state_n = IDLE;
    224     end
    225     
    226     endcase
    227 end
    228 
    229 //第三段
    230 assign IDLE2START             = state_c == IDLE         && wr_vld  ;
    231 assign START2SLAVE_ADD        = state_c == START         && end_cnt1;
    232 assign SLAVE_ADD2ACK        = state_c == SLAVE_ADD    && end_cnt1;
    233 assign ACK2REG_ADD            = state_c == ACK        && end_cnt1    && ack_flag == 0;
    234 assign ACK2REG_DAT             = state_c == ACK        && end_cnt1 && ack_flag == 1;
    235 assign ACK2STOP                = state_c == ACK        && end_cnt1 && ack_flag == 2;
    236 assign REG_ADD2ACK          = state_c == REG_ADD    && end_cnt1;
    237 assign REG_DAT2ACK            = state_c == REG_DAT    && end_cnt1;
    238 assign STOP2IDLE             = state_c == STOP        && end_cnt1;
    239 
    240 //第四段
    241 //标记ack位置,如果到了发送数据阶段,可以知道是第几个ack了
    242 always @(posedge clk or negedge rst_n)begin
    243     if(!rst_n)begin
    244         ack_flag <= 0;
    245     end
    246     else if(state_c == REG_ADD)begin
    247         ack_flag <= 1; //代表是发送完寄存器地址后面的ACK
    248     end
    249     else if(state_c == REG_DAT)begin
    250         ack_flag <= 2; //代表是发送完寄存器数据后面的ACK
    251     end
    252     else if(state_c == STOP && end_cnt1)begin
    253         ack_flag <= 0;
    254     end
    255 end
    256 
    257 
    258 reg  link;
    259 always @(posedge clk or negedge rst_n)begin
    260     if(!rst_n)begin
    261         link <= 1;
    262     end
    263     else if(state_c ==  ACK && add_cnt0 && cnt0 >= 0 && cnt0 <((SCL_100K>>1)+ (SCL_100K>>2)))begin
    264         link <= 0;    //释放sda,准备接收数据
    265     end
    266     else begin
    267         link <= 1;
    268     end
    269 end
    270 
    271 //sda 发输出数据
    272 reg sda_temp;
    273 always @(posedge clk or negedge rst_n)begin
    274     if(!rst_n)begin
    275         sda_temp <= 1;
    276     end
    277     else if(state_c == START && SCL_H_MIDDLE)begin
    278         sda_temp <= 0; //产生start信号
    279     end
    280     else if(state_c == SLAVE_ADD)begin
    281         sda_temp <= slave_address[7-cnt1];
    282     end
    283     else if(state_c == REG_ADD)begin
    284         sda_temp <= reg_address[7-cnt1];
    285     end
    286     else if(state_c == REG_DAT)begin
    287         sda_temp <= reg_data[7-cnt1];
    288     end
    289     else if(state_c == ACK && end_cnt0 && ack_flag == 2)begin
    290         sda_temp <= 0;    //在产生stop之前,先将sda信号拉低
    291     end
    292     else if(state_c == STOP && SCL_H_MIDDLE)begin
    293         sda_temp <= 1;
    294     end
    295 end
    296 
    297 //sda接收数据 ,主要是判断是否接收到有效的ack
    298 always @(posedge clk or negedge rst_n)begin
    299     if(!rst_n)begin
    300         ack_err <= 0;
    301     end
    302     else if(state_c == ACK && SCL_H_MIDDLE)begin
    303         ack_err <= sda;
    304     end
    305 end
    306 
    307 assign sda = link? sda_temp : 1'bz;
    308 
    309 endmodule
    View Code

    随机读完整代码:

      1 module eeprom_rd(
      2                     clk,
      3                     rst_n,
      4                     rd_en,
      5 //                    slave_address,
      6 //                    reg_address,
      7 //                    reg_data,
      8                     rec_buf,
      9                     scl,
     10                     sda
     11 );
     12 parameter        D_W            = 8  ;
     13 parameter         SCL_100K     = 500;
     14 
     15 parameter        IDLE         = 0;
     16 parameter        START         = 1;
     17 parameter        SLAVE_ADD    = 2;
     18 parameter        ACK            = 3;
     19 parameter        REG_ADD        = 4;
     20 parameter        REC_DAT        = 5;
     21 parameter        NOACK        = 6;
     22 parameter        STOP        = 7;
     23 
     24 
     25 parameter        slave_address  = 8'b1010_0000;
     26 parameter        reg_address    = 8'h0f;
     27 parameter        reg_data       = 8'h5f;
     28 
     29 input             clk             ;
     30 input            rst_n         ;
     31 input            rd_en         ;
     32 //input[D_W-1:0]    slave_address;
     33 //input[D_W-1:0]    reg_address     ;
     34 //input[D_W-1:0]    reg_data     ;
     35 
     36 output[D_W-1:0] rec_buf    ;
     37 output            scl        ;
     38 inout            sda        ;
     39 
     40 
     41 wire[D_W-1:0]    slave_address_r;
     42 assign            slave_address_r  = slave_address | 1'b1;
     43 
     44 wire            SCL_H2L          ;
     45 wire            SCL_L2H          ;
     46 wire            SCL_H_MIDDLE     ;
     47 wire             add_cnt0         ;
     48 wire             end_cnt0         ;
     49 wire             add_cnt1         ;
     50 wire             end_cnt1         ;
     51 
     52 wire            IDLE2START         ;
     53 wire            START2SLAVE_ADD    ;
     54 wire            SLAVE_ADD2ACK    ;
     55 wire            ACK2START        ;
     56 wire            ACK2REG_ADD     ;
     57 wire            ACK2REC_DAT        ;
     58 wire            REG_ADD2ACK     ;
     59 wire            REC_DAT2NOACK    ;
     60 wire            NOACK2STOP        ;
     61 wire            STOP2IDLE         ;
     62                                 
     63 reg[9 -1 : 0]    cnt0;
     64 reg[4 -1 : 0]    cnt1;        
     65 
     66 
     67 reg             scl        ;
     68 reg[D_W-1:0]     rec_buf    ;
     69 reg             ack_err ;
     70 reg[4-1:0]        state_c /* synthesis keep*/;
     71 reg[4-1:0]        state_n /* synthesis keep*/;
     72 reg[4-1:0]        x        ;
     73 reg                rd_vld    ;
     74 reg[2-1:0]         ack_flag; 
     75 
     76 always @(posedge clk or negedge rst_n)begin
     77     if(!rst_n)begin
     78         rd_vld <= 0;
     79     end
     80     else if(rd_en)begin
     81         rd_vld <= 1;
     82     end
     83     else if(state_c == STOP && end_cnt1)begin
     84         rd_vld <= 0;
     85     end
     86 end
     87 
     88 //计数产生scl时钟
     89 always @(posedge clk or negedge rst_n)begin
     90     if(!rst_n)begin
     91         cnt0 <= 0;
     92     end
     93     else if(add_cnt0)begin
     94         if(end_cnt0)begin
     95             cnt0 <= 0;
     96         end
     97         else begin
     98             cnt0 <= cnt0 + 1;
     99         end
    100     end
    101 end
    102 
    103 assign add_cnt0 = rd_vld;
    104 assign end_cnt0 = add_cnt0 && cnt0 == SCL_100K - 1;
    105 
    106 //计数scl周期数量
    107 always @(posedge clk or  negedge rst_n)begin
    108     if(!rst_n)begin
    109         cnt1 <= 0;
    110     end
    111     else if(add_cnt1)begin
    112         if(end_cnt1)begin
    113             cnt1 <= 0;
    114         end    
    115         else begin
    116             cnt1 <= cnt1 + 1;
    117         end
    118     end
    119 end
    120 
    121 assign add_cnt1 = end_cnt0;
    122 assign end_cnt1 = add_cnt1 && cnt1 == x - 1;
    123 
    124 always @(*)begin
    125     if(state_c == START || state_c == ACK || state_c == NOACK ||state_c == STOP)begin
    126         x = 1;
    127     end
    128     else begin
    129         x = 8;
    130     end
    131 end
    132 
    133 //scl时钟周期  _--_
    134 always @(posedge clk or negedge rst_n)begin
    135     if(!rst_n)begin
    136         scl <= 1;
    137     end
    138     else if(add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1 && state_c != STOP)begin
    139         scl <= 0;
    140     end
    141     else if(add_cnt0 && cnt0 == (SCL_100K>>2) -1)begin
    142         scl <= 1;
    143     end
    144 end
    145 
    146 assign SCL_H2L         = add_cnt0 && cnt0 == ((SCL_100K>>1)+ (SCL_100K>>2)) -1; //下降沿
    147 assign SCL_L2H         = add_cnt0 && cnt0 == (SCL_100K>>2) -1;    //上升沿
    148 assign SCL_H_MIDDLE = add_cnt0 && cnt0 == (SCL_100K>>1) -1;    //高电平中间
    149 
    150 //第一段
    151 always @(posedge clk or negedge rst_n)begin
    152     if(!rst_n)begin
    153         state_c <= IDLE;
    154     end
    155     else begin
    156         state_c <= state_n; 
    157     end
    158 end
    159 
    160 //第二段
    161 always @(*)begin
    162     case(state_c)
    163     IDLE:begin
    164         if(IDLE2START)begin
    165             state_n = START;
    166         end
    167         else begin
    168             state_n = state_c;
    169         end
    170     end
    171     
    172     START:begin
    173         if(START2SLAVE_ADD)begin
    174             state_n = SLAVE_ADD;
    175         end
    176         else begin
    177             state_n = state_c;
    178         end
    179     end
    180     
    181     SLAVE_ADD:begin
    182         if(SLAVE_ADD2ACK)begin
    183             state_n = ACK;
    184         end
    185         else begin
    186             state_n = state_c;
    187         end
    188     end
    189     
    190     ACK:begin
    191         if(ACK2REG_ADD)begin
    192             state_n = REG_ADD;
    193         end
    194         else if(ACK2START)begin
    195             state_n = START;
    196         end
    197         else if(ACK2REC_DAT)begin
    198             state_n = REC_DAT;
    199         end
    200         else begin
    201             state_n = state_c;
    202         end
    203     end
    204     
    205     REG_ADD:begin
    206         if(REG_ADD2ACK)begin
    207             state_n = ACK;
    208         end
    209         else begin
    210             state_n = state_c;
    211         end
    212     end
    213 
    214     REC_DAT:begin
    215         if(REC_DAT2NOACK)begin
    216             state_n = NOACK;
    217         end
    218         else begin
    219             state_n = state_c;
    220         end
    221     end
    222     
    223     NOACK:begin
    224         if(NOACK2STOP)begin
    225             state_n = STOP;
    226         end
    227         else begin
    228             state_n = state_c;
    229         end
    230     end
    231     
    232     STOP:begin
    233         if(STOP2IDLE)begin
    234             state_n = IDLE;
    235         end
    236         else begin
    237             state_n = state_c;
    238         end
    239     end
    240 
    241     default:begin
    242         state_n = IDLE;
    243     end
    244     
    245     endcase
    246 end
    247 
    248 //第三段
    249 assign IDLE2START             = state_c == IDLE         && rd_vld  ;
    250 assign START2SLAVE_ADD        = state_c == START         && end_cnt1;
    251 assign SLAVE_ADD2ACK        = state_c == SLAVE_ADD    && end_cnt1;
    252 assign ACK2REG_ADD             = state_c == ACK        && end_cnt1 && ack_flag == 0;
    253 assign ACK2START            = state_c == ACK        && end_cnt1    && ack_flag == 1;
    254 assign ACK2REC_DAT            = state_c == ACK        && end_cnt1 && ack_flag == 2;
    255 assign REG_ADD2ACK          = state_c == REG_ADD    && end_cnt1;
    256 assign REC_DAT2NOACK        = state_c == REC_DAT    && end_cnt1;
    257 assign NOACK2STOP            = state_c == NOACK        && end_cnt1;
    258 assign STOP2IDLE             = state_c == STOP        && end_cnt1;
    259 
    260 //第四段
    261 //标记ack位置,如果到了发送数据阶段,可以知道是第几个ack了
    262 always @(posedge clk or negedge rst_n)begin
    263     if(!rst_n)begin
    264         ack_flag <= 0;
    265     end
    266     else if(state_c == SLAVE_ADD && ack_flag == 0)begin
    267         ack_flag <= 0;
    268     end
    269     else if(state_c == REG_ADD)begin
    270         ack_flag <= 1; //代表是发送完寄存器地址后面的ACK
    271     end
    272     else if(state_c == SLAVE_ADD && ack_flag == 1)begin
    273         ack_flag <= 2; //代表是发送完寄存器数据后面的ACK
    274     end
    275     else if(state_c == STOP && end_cnt1)begin
    276         ack_flag <= 0;
    277     end
    278 end
    279 
    280 
    281 reg  link;
    282 always @(posedge clk or negedge rst_n)begin
    283     if(!rst_n)begin
    284         link <= 1;
    285     end
    286     else if((state_c ==  ACK && add_cnt0 && cnt0 >= 0 && cnt0 <((SCL_100K>>1)+ (SCL_100K>>2)))  || state_c == REC_DAT)begin
    287         link <= 0;    //释放sda,准备接收数据
    288     end
    289     else begin
    290         link <= 1;
    291     end
    292 end
    293 
    294 //sda 发输出数据
    295 reg sda_temp;
    296 always @(posedge clk or negedge rst_n)begin
    297     if(!rst_n)begin
    298         sda_temp <= 1;
    299     end
    300     else if(state_c == START && SCL_H_MIDDLE)begin
    301         sda_temp <= 0; //产生start信号
    302     end
    303     else if(state_c == ACK && end_cnt1 && ack_flag == 0)begin
    304         sda_temp <= 1; //拉高SDA,准备产生start信号
    305     end
    306     else if(state_c == SLAVE_ADD && ack_flag == 0)begin
    307         sda_temp <= slave_address[7-cnt1];
    308     end
    309     else if(state_c == REG_ADD)begin
    310         sda_temp <= reg_address[7-cnt1];
    311     end
    312     else if(state_c == SLAVE_ADD && ack_flag == 2)begin
    313         sda_temp <= slave_address_r[7-cnt1];
    314     end
    315     else if(state_c == NOACK)begin
    316         sda_temp <= 0;    //在产生stop之前,先将sda信号拉低
    317     end
    318     else if(state_c == STOP && SCL_H_MIDDLE)begin
    319         sda_temp <= 1;
    320     end
    321 end
    322 
    323 
    324 always @(posedge clk or negedge rst_n)begin
    325     if(!rst_n)begin
    326         rec_buf <= 0;
    327     end
    328     else if(state_c == REC_DAT && SCL_H_MIDDLE)begin
    329         rec_buf <= {rec_buf[6:0],sda};
    330     end
    331 end
    332 
    333 //sda接收数据 ,主要是判断是否接收到有效的ack
    334 always @(posedge clk or negedge rst_n)begin
    335     if(!rst_n)begin
    336         ack_err <= 0;
    337     end
    338     else if(state_c == ACK && SCL_H_MIDDLE)begin
    339         ack_err <= sda;
    340     end
    341 end
    342 
    343 assign sda = link? sda_temp : 1'bz;
    344 
    345 endmodule
    View Code

    先下载随机写完整代码到目标板中,将数据写入eeprom,然后再下载随机的读完整代码,读取数据,用Quartus 逻辑分析抓取波形:(开始到结束完整波形抓取不完,分两张截图),写入 0x0f = 0xaa, 看波形读取数据是对的

    前半部分波形

     后半部分波形,在NOACK时,不用考虑sda 是拉高 还是拉低,但是在产生stop前必须先拉低sda

     

    下一个实验,将随机读 、写 整合在一起,准备用一个状态机完成读和写。

  • 相关阅读:
    NET CORE EF事务
    搭建Vue-nuxt.js
    VUE获取URL(导航)参数方法
    第十二届蓝桥杯大赛软件赛决赛题解
    第十二届蓝桥杯大赛软件赛省赛第二场题解
    P1955 [NOI2015] 程序自动分析
    P1621 集合
    将博客搬至CSDN
    2021第六届GPLT 团体程序设计天梯赛CCCC 个人题解
    Divide by Zero 2021 and Codeforces Round #714 (Div. 2)
  • 原文地址:https://www.cnblogs.com/wen2376/p/16143809.html
Copyright © 2020-2023  润新知