状态机练习- 基于EEPROM的I2C 随机读、写

I2C完整的随机读写时序前面已经贴出来了,这里直接贴状态机图:

 

设计思路同之前的方法,有了前面的随机读、 写的实验,这里将读、写融合在一个状态机里面,很快就整合完了,验证也是非常的OK。

注意区分在写状态时的ack_flag 和 读状态时的ack_flag,同时加上wr_vld 和 rd_vld 来区分ack 将跳转下一个状态。

完整的代码:

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

在随机写状态时的仿真波形:主要看start 、ACK 、stop 几个状态是否正确

 

 在随机读状态时的仿真波形

 

 

 通过检查波形,产生的时序是正确的,接下来用 Quartus 的逻辑分析在抓取硬件的回应:

(1)、抓取的写时序,主要看ACK

(2)、主要看接收的数据

 

 OK 整个I2C 读写实验基本全都完成了,完成之后,感觉轻松多了,之前写了很多的版本,感觉都不怎么好,代码繁琐,且很麻烦,不够精简。

贴出几个其他的版本,功能都能实现:

第一个版本,写的特别长,每个bit都当做一个状态机,虽然好理解,但觉得很幼稚

  1 module AT24C02(
  2                 clk,
  3                 rst_n,
  4                     
  5                 led,
  6                 scl,
  7                 sda
  8                 );
  9                 
 10 parameter     IDLE = 2'd0,
 11             WRITE_TASK = 2'd1,
 12             READ_TASK = 2'd2;
 13             
 14 parameter    INIT             = 6'd0,
 15             GEN_START         = 6'd1,
 16             DEV_ADDR_D7     = 6'd2,
 17             DEV_ADDR_D6     = 6'd3,
 18             DEV_ADDR_D5     = 6'd4,
 19             DEV_ADDR_D4     = 6'd5,
 20             DEV_ADDR_D3     = 6'd6,
 21             DEV_ADDR_D2     = 6'd7,
 22             DEV_ADDR_D1     = 6'd8,
 23             DEV_ADDR_D0     = 6'd9,
 24             DEV_RELEASE_SDA = 6'd10,
 25             DEV_READ_ACK    = 6'd11,
 26             DEV_CHECK_ACK     = 6'd12,
 27             
 28             REG_ADDR_D7     = 6'd13,
 29             REG_ADDR_D6     = 6'd14,
 30             REG_ADDR_D5     = 6'd15,
 31             REG_ADDR_D4     = 6'd16,
 32             REG_ADDR_D3     = 6'd17,
 33             REG_ADDR_D2     = 6'd18,
 34             REG_ADDR_D1     = 6'd19,
 35             REG_ADDR_D0     = 6'd20,
 36             REG_RELEASE_SDA = 6'd21,
 37             REG_READ_ACK    = 6'd22,
 38             REG_CHECK_ACK     = 6'd23,
 39             
 40             
 41             SEND_D7         = 6'd24,
 42             SEND_D6         = 6'd25,
 43             SEND_D5         = 6'd26,
 44             SEND_D4         = 6'd27,
 45             SEND_D3         = 6'd28,
 46             SEND_D2         = 6'd29,
 47             SEND_D1         = 6'd30,
 48             SEND_D0         = 6'd31,
 49             DAT_RELEASE_SDA = 6'd32,
 50             DAT_READ_ACK    = 6'd33,
 51             DAT_CHECK_ACK     = 6'd34,
 52             STOP            = 6'd35,
 53             WR_FINISH        = 6'd36,
 54             
 55             RD_DATA_7        = 6'd37,
 56             RD_DATA_6        = 6'd38,
 57             RD_DATA_5        = 6'd39,
 58             RD_DATA_4        = 6'd40,
 59             RD_DATA_3        = 6'd41,
 60             RD_DATA_2        = 6'd42,
 61             RD_DATA_1        = 6'd43,
 62             RD_DATA_0        = 6'd44,
 63             NO_ACK            = 6'd45,
 64             RD_FINISH        = 6'd46;
 65             
 66             
 67             
 68 parameter     device_addr     = 8'b1010_0000;
 69 parameter     reg_addr         = 8'h02;
 70 parameter    data            = 8'h10;
 71 
 72 input     clk        ;
 73 input     rst_n    ;
 74 
 75 output     led;
 76 output    scl        ;
 77 inout    sda        ;
 78 
 79 wire    sda        ;
 80 wire      led        ;
 81 
 82 reg        wr_req    ;
 83 reg     rd_req    ;
 84 
 85 wire     add_cnt0;
 86 wire     end_cnt0;
 87 
 88 reg        link;
 89 reg     sda_temp;
 90 
 91 
 92 
 93 //濞存籂鍛櫢SCL闁哄啫鐖奸幐
 94 reg [8:0] cnt0;
 95 always @(posedge clk or negedge rst_n)begin
 96     if(!rst_n)begin
 97         cnt0 <= 0;
 98     end
 99     else if(add_cnt0)begin
100         if(end_cnt0)begin
101             cnt0 <= 0;
102         end
103         else begin
104             cnt0 <= cnt0 + 1;
105         end
106     end
107 end
108 
109 assign add_cnt0 = 1;
110 assign end_cnt0 = add_cnt0 && cnt0 == 500 - 1;  // SCL 100Khz
111 
112 
113 reg    scl;
114 always @(posedge clk or negedge rst_n)begin
115     if(!rst_n)begin
116         scl <= 1;
117     end
118     else if(add_cnt0 && cnt0 >= 250 && cnt0 < 500)begin
119         scl <= 0;
120     end
121     else if(add_cnt0 && cnt0 >= 0 && cnt0 < 250)begin
122         scl <= 1;
123     end
124 end
125 
126 reg scl_pos;
127 reg scl_neg;
128 reg scl_h_center;
129 reg scl_l_center;
130 always @(posedge clk or negedge rst_n)begin
131     if(!rst_n)begin
132         scl_pos <= 0;
133     end
134     else if(end_cnt0)begin
135         scl_pos <= 1;
136     end
137     else begin
138         scl_pos <= 0;
139     end
140 end
141 
142 always @(posedge clk or negedge rst_n)begin
143     if(!rst_n)begin
144         scl_h_center <= 0;
145     end
146     else if(add_cnt0 && cnt0 == 125-1)begin
147         scl_h_center <= 1;
148     end
149     else begin
150         scl_h_center <= 0;
151     end
152 end
153 
154 always @(posedge clk or negedge rst_n)begin
155     if(!rst_n)begin
156         scl_neg <= 0;
157     end
158     else if(add_cnt0 && cnt0 == 250-1)begin
159         scl_neg <= 1;
160     end
161     else begin
162         scl_neg <= 0;
163     end
164 end
165 
166 always @(posedge clk or negedge rst_n)begin
167     if(!rst_n)begin
168         scl_l_center <= 0;
169     end
170     else if(add_cnt0 && cnt0 == 375-1)begin
171         scl_l_center <= 1;
172     end
173     else begin
174         scl_l_center <= 0;
175     end
176 end
177 
178 reg rd_flag;
179 reg wr_done;
180 reg rd_done;
181 reg [1:0] main_state;
182 reg [5:0] inner_state;
183 reg [7:0] rd_buf;
184 always @(posedge clk or negedge rst_n)begin
185     if(!rst_n)begin
186         main_state <= IDLE;
187         inner_state <= INIT;
188         wr_done <= 0;
189         rd_done <= 0;
190         link <= 1;
191         sda_temp <= 1;
192         
193         rd_req <= 0;
194         wr_req <= 1;
195         
196         rd_flag <= 0;
197         rd_buf = 8'h00;
198     end
199     else    
200     case(main_state)
201         IDLE: begin
202             if(wr_req)begin
203                 wr_req <= 0;
204                 main_state <= WRITE_TASK;
205             end
206             else if(rd_req)begin
207                 rd_req <= 0;
208                 main_state <= READ_TASK;
209             end
210             rd_done <= 0;
211             wr_done <= 0;
212             link <= 1;
213             sda_temp <= 1;
214             rd_flag <= 0;
215         end
216         
217         WRITE_TASK:
218             case(inner_state)
219                 INIT     :    
220                     inner_state <= GEN_START;
221                     
222                 GEN_START:    
223                     if(scl_h_center)begin
224                         link  <= 1;
225                         sda_temp <= 0;
226                         inner_state <= DEV_ADDR_D7;
227                     end
228                     else begin
229                         inner_state <= GEN_START;
230                     end
231                 
232                 DEV_ADDR_D7:
233                     if(scl_l_center)begin
234                         link  <= 1;
235                         sda_temp <= device_addr[7];
236                         inner_state <= DEV_ADDR_D6;
237                     end
238                     else begin
239                         inner_state <= DEV_ADDR_D7;
240                     end
241                 
242                 DEV_ADDR_D6:
243                     if(scl_l_center)begin
244                         link  <= 1;
245                         sda_temp <= device_addr[6];
246                         inner_state <= DEV_ADDR_D5;
247                     end
248                     else begin
249                         inner_state <= DEV_ADDR_D6;
250                     end
251                     
252                 DEV_ADDR_D5:
253                     if(scl_l_center)begin
254                         link  <= 1;
255                         sda_temp <= device_addr[5];
256                         inner_state <= DEV_ADDR_D4;
257                     end
258                     else begin
259                         inner_state <= DEV_ADDR_D5;
260                     end
261                 
262                 DEV_ADDR_D4:
263                     if(scl_l_center)begin
264                         link  <= 1;
265                         sda_temp <= device_addr[4];
266                         inner_state <= DEV_ADDR_D3;
267                     end
268                     else begin
269                         inner_state <= DEV_ADDR_D4;
270                     end
271                 
272                 DEV_ADDR_D3:
273                     if(scl_l_center)begin
274                         link  <= 1;
275                         sda_temp <= device_addr[3];
276                         inner_state <= DEV_ADDR_D2;
277                     end
278                     else begin
279                         inner_state <= DEV_ADDR_D3;
280                     end
281                 
282                 DEV_ADDR_D2:
283                     if(scl_l_center)begin
284                         link  <= 1;
285                         sda_temp <= device_addr[2];
286                         inner_state <= DEV_ADDR_D1;
287                     end
288                     else begin
289                         inner_state <= DEV_ADDR_D2;
290                     end
291                 
292                 DEV_ADDR_D1:
293                     if(scl_l_center)begin
294                         link  <= 1;
295                         sda_temp <= device_addr[1];
296                         inner_state <= DEV_ADDR_D0;
297                     end
298                     else begin
299                         inner_state <= DEV_ADDR_D1;
300                     end
301                 
302                 DEV_ADDR_D0:
303                     if(scl_l_center)begin
304                         link  <= 1;
305                         sda_temp <= device_addr[0];
306                         inner_state <= DEV_RELEASE_SDA;
307                     end
308                     else begin
309                         inner_state <= DEV_ADDR_D0;
310                     end
311                 
312                 DEV_RELEASE_SDA:
313                     if(scl_l_center)begin
314                         link <= 0; //闂佹彃锕ラ弬涓糄A
315                         inner_state <= DEV_READ_ACK;
316                     end
317                     else begin
318                         inner_state <= DEV_RELEASE_SDA;
319                     end
320                     
321                 DEV_READ_ACK: 
322                     if(scl_h_center)begin
323                         link <= 0; //闂佹彃锕ラ弬涓糄A
324                         sda_temp <= sda;
325                         inner_state <= DEV_CHECK_ACK;
326                     end
327                     else begin
328                         inner_state <= DEV_READ_ACK;
329                     end
330                 
331                 DEV_CHECK_ACK: 
332                     if(scl_neg)begin
333                         link <= 1;
334                         inner_state <= REG_ADDR_D7;
335                     end
336                     else if(!sda_temp)begin 
337                         link <= 0; //闂佹彃锕ラ弬涓糄A
338                         inner_state <= DEV_CHECK_ACK;
339                     end
340                     else if(sda_temp)begin
341                         main_state <= IDLE;      //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fDLE
342                         inner_state <= INIT;    //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fNIT
343                     end
344 
345                 //闁告瑦鍨块埀顑跨閻﹀海鈧稒锚濞呮帡宕烽弶鎸庣祷                
346                 REG_ADDR_D7:
347                     if(scl_l_center)begin
348                         link  <= 1;
349                         sda_temp <= reg_addr[7];
350                         inner_state <= REG_ADDR_D6;
351                     end
352                     else begin
353                         inner_state <= REG_ADDR_D7;
354                     end
355                 
356                 REG_ADDR_D6:
357                     if(scl_l_center)begin
358                         link  <= 1;
359                         sda_temp <= reg_addr[6];
360                         inner_state <= REG_ADDR_D5;
361                     end
362                     else begin
363                         inner_state <= REG_ADDR_D6;
364                     end
365                     
366                 REG_ADDR_D5:
367                     if(scl_l_center)begin
368                         link  <= 1;
369                         sda_temp <= reg_addr[5];
370                         inner_state <= REG_ADDR_D4;
371                     end
372                     else begin
373                         inner_state <= REG_ADDR_D5;
374                     end
375                 
376                 REG_ADDR_D4:
377                     if(scl_l_center)begin
378                         link  <= 1;
379                         sda_temp <= reg_addr[4];
380                         inner_state <= REG_ADDR_D3;
381                     end
382                     else begin
383                         inner_state <= REG_ADDR_D4;
384                     end
385                 
386                 REG_ADDR_D3:
387                     if(scl_l_center)begin
388                         link  <= 1;
389                         sda_temp <= reg_addr[3];
390                         inner_state <= REG_ADDR_D2;
391                     end
392                     else begin
393                         inner_state <= REG_ADDR_D3;
394                     end
395                 
396                 REG_ADDR_D2:
397                     if(scl_l_center)begin
398                         link  <= 1;
399                         sda_temp <= reg_addr[2];
400                         inner_state <= REG_ADDR_D1;
401                     end
402                     else begin
403                         inner_state <= REG_ADDR_D2;
404                     end
405                 
406                 REG_ADDR_D1:
407                     if(scl_l_center)begin
408                         link  <= 1;
409                         sda_temp <= reg_addr[1];
410                         inner_state <= REG_ADDR_D0;
411                     end
412                     else begin
413                         inner_state <= REG_ADDR_D1;
414                     end
415                 
416                 REG_ADDR_D0:
417                     if(scl_l_center)begin
418                         link  <= 1;
419                         sda_temp <= reg_addr[0];
420                         inner_state <= REG_RELEASE_SDA;
421                     end
422                     else begin
423                         inner_state <= REG_ADDR_D0;
424                     end
425                 
426                 REG_RELEASE_SDA:
427                     if(scl_l_center)begin
428                         link <= 0; //闂佹彃锕ラ弬涓糄A
429                         inner_state <= REG_READ_ACK;
430                     end
431                     else begin
432                         inner_state <= REG_RELEASE_SDA;
433                     end
434                     
435                 REG_READ_ACK: 
436                     if(scl_h_center)begin
437                         link <= 0; //闂佹彃锕ラ弬涓糄A
438                         sda_temp <= sda;
439                         inner_state <= REG_CHECK_ACK;
440                     end
441                     else begin
442                         inner_state <= REG_READ_ACK;
443                     end
444                 
445                 REG_CHECK_ACK: 
446                     if(scl_neg)begin
447                             link <= 1;
448                             inner_state <= SEND_D7;
449                     end
450                     else if(!sda_temp)begin 
451                             inner_state <= REG_CHECK_ACK;
452                     end
453                     else if(sda_temp)begin
454                         main_state <= IDLE;
455                         inner_state <= INIT;
456                     end
457                 
458                 //閺夆晜绋戦崣鍡涘矗閹达腹鍋撴担瑙勬闁            
459                 SEND_D7:
460                     if(scl_l_center)begin
461                         link  <= 1;
462                         sda_temp <= data[7];
463                         inner_state <= SEND_D6;
464                     end
465                     else begin
466                         inner_state <= SEND_D7;
467                     end
468                 
469                 SEND_D6:
470                     if(scl_l_center)begin
471                         link  <= 1;
472                         sda_temp <= data[6];
473                         inner_state <= SEND_D5;
474                     end
475                     else begin
476                         inner_state <= SEND_D6;
477                     end
478                     
479                 SEND_D5:
480                     if(scl_l_center)begin
481                         link  <= 1;
482                         sda_temp <= data[5];
483                         inner_state <= SEND_D4;
484                     end
485                     else begin
486                         inner_state <= SEND_D5;
487                     end
488                 
489                 SEND_D4:
490                     if(scl_l_center)begin
491                         link  <= 1;
492                         sda_temp <= data[4];
493                         inner_state <= SEND_D3;
494                     end
495                     else begin
496                         inner_state <= SEND_D4;
497                     end
498                 
499                 SEND_D3:
500                     if(scl_l_center)begin
501                         link  <= 1;
502                         sda_temp <= data[3];
503                         inner_state <= SEND_D2;
504                     end
505                     else begin
506                         inner_state <= SEND_D3;
507                     end
508                 
509                 SEND_D2:
510                     if(scl_l_center)begin
511                         link  <= 1;
512                         sda_temp <= data[2];
513                         inner_state <= SEND_D1;
514                     end
515                     else begin
516                         inner_state <= SEND_D2;
517                     end
518                 
519                 SEND_D1:
520                     if(scl_l_center)begin
521                         link  <= 1;
522                         sda_temp <= data[1];
523                         inner_state <= SEND_D0;
524                     end
525                     else begin
526                         inner_state <= SEND_D1;
527                     end
528                 
529                 SEND_D0:
530                     if(scl_l_center)begin
531                         link  <= 1;
532                         sda_temp <= data[0];
533                         inner_state <= DAT_RELEASE_SDA;
534                     end
535                     else begin
536                         inner_state <= SEND_D0;
537                     end
538                 
539                 DAT_RELEASE_SDA:
540                     if(scl_l_center)begin
541                         link <= 0; //闂佹彃锕ラ弬涓糄A
542                         inner_state <= DAT_READ_ACK;
543                     end
544                     else begin
545                         inner_state <= DAT_RELEASE_SDA;
546                     end
547                     
548                 DAT_READ_ACK: 
549                     if(scl_h_center)begin
550                         link <= 0; //闂佹彃锕ラ弬涓糄A
551                         sda_temp <= sda;
552                         inner_state <= DAT_CHECK_ACK;
553                     end
554                     else begin
555                         inner_state <= DAT_READ_ACK;
556                     end
557                 
558                 DAT_CHECK_ACK:
559                     if(scl_neg)begin
560                             link <= 1;
561                             inner_state <= STOP;
562                     end
563                     else if(!sda_temp)begin 
564                             link <= 0; //闂佹彃锕ラ弬涓糄A
565                             inner_state <= DAT_CHECK_ACK;
566                     end
567                     else if(sda_temp)begin
568                         main_state <= IDLE;
569                         inner_state <= INIT;
570                     end
571                 
572                 STOP:
573                     if(scl_l_center)begin
574                         link <= 1;
575                         sda_temp <= 0;
576                         inner_state <= STOP;
577                     end
578                     else if(scl_h_center)begin
579                         link <= 1;
580                         sda_temp <= 1;
581                         inner_state <= WR_FINISH;
582                     end
583                     else begin
584                         inner_state <= STOP;
585                     end
586                 
587                 WR_FINISH:
588                     begin
589                         link <= 1;
590 //                        inner_state <= WR_FINISH;
591                         main_state <= IDLE;
592                         wr_done <= 1;
593                         rd_req <= 1;
594                         wr_req <= 0;
595                     end    
596                     
597                 default: inner_state <= INIT;
598             endcase
599                         
600         READ_TASK:    
601         case(inner_state)
602                 INIT     :    
603                     inner_state <= GEN_START;
604                     
605                 GEN_START:    
606                     if(scl_h_center)begin
607                         link  <= 1;
608                         sda_temp <= 0;
609                         inner_state <= DEV_ADDR_D7;
610                     end
611                     else begin
612                         inner_state <= GEN_START;
613                     end
614                 
615                 DEV_ADDR_D7:
616                     if(scl_l_center)begin
617                         link  <= 1;
618                         sda_temp <= device_addr[7];
619                         inner_state <= DEV_ADDR_D6;
620                     end
621                     else begin
622                         inner_state <= DEV_ADDR_D7;
623                     end
624                 
625                 DEV_ADDR_D6:
626                     if(scl_l_center)begin
627                         link  <= 1;
628                         sda_temp <= device_addr[6];
629                         inner_state <= DEV_ADDR_D5;
630                     end
631                     else begin
632                         inner_state <= DEV_ADDR_D6;
633                     end
634                     
635                 DEV_ADDR_D5:
636                     if(scl_l_center)begin
637                         link  <= 1;
638                         sda_temp <= device_addr[5];
639                         inner_state <= DEV_ADDR_D4;
640                     end
641                     else begin
642                         inner_state <= DEV_ADDR_D5;
643                     end
644                 
645                 DEV_ADDR_D4:
646                     if(scl_l_center)begin
647                         link  <= 1;
648                         sda_temp <= device_addr[4];
649                         inner_state <= DEV_ADDR_D3;
650                     end
651                     else begin
652                         inner_state <= DEV_ADDR_D4;
653                     end
654                 
655                 DEV_ADDR_D3:
656                     if(scl_l_center)begin
657                         link  <= 1;
658                         sda_temp <= device_addr[3];
659                         inner_state <= DEV_ADDR_D2;
660                     end
661                     else begin
662                         inner_state <= DEV_ADDR_D3;
663                     end
664                 
665                 DEV_ADDR_D2:
666                     if(scl_l_center)begin
667                         link  <= 1;
668                         sda_temp <= device_addr[2];
669                         inner_state <= DEV_ADDR_D1;
670                     end
671                     else begin
672                         inner_state <= DEV_ADDR_D2;
673                     end
674                 
675                 DEV_ADDR_D1:
676                     if(scl_l_center)begin
677                         link  <= 1;
678                         sda_temp <= device_addr[1];
679                         inner_state <= DEV_ADDR_D0;
680                     end
681                     else begin
682                         inner_state <= DEV_ADDR_D1;
683                     end
684                 
685                 DEV_ADDR_D0:
686                     if(scl_l_center)begin
687                         link  <= 1;
688                         if(!rd_flag)begin
689                             sda_temp <= device_addr[0];  //
690                         end
691                         else if(rd_flag)begin
692                             sda_temp <= device_addr[0] | 1'b1; //鐠                    
693                         end
694                         inner_state <= DEV_RELEASE_SDA;
695                     end
696                     else begin
697                         inner_state <= DEV_ADDR_D0;
698                     end
699                 
700                 DEV_RELEASE_SDA:
701                     if(scl_l_center)begin
702                         link <= 0; 
703                         inner_state <= DEV_READ_ACK;
704                     end
705                     else begin
706                         inner_state <= DEV_RELEASE_SDA;
707                     end
708                     
709                 DEV_READ_ACK: 
710                     if(scl_h_center)begin
711                         link <= 0;
712                         sda_temp <= sda;
713                         inner_state <= DEV_CHECK_ACK;
714                     end
715                     else begin
716                         inner_state <= DEV_READ_ACK;
717                     end
718                 
719                 DEV_CHECK_ACK: 
720                     if(scl_neg)begin
721                         if(!rd_flag)begin
722                             link <= 1;
723                             inner_state <= REG_ADDR_D7;
724                         end
725                         else if(rd_flag)begin
726                             link <= 0; 
727                             inner_state <= RD_DATA_7;
728                         end
729                     end
730                     else if(!sda_temp)begin 
731                         link <= 0; //闂佹彃锕ラ弬涓糄A
732                         inner_state <= DEV_CHECK_ACK;
733                     end
734                     else if(sda_temp)begin
735                         main_state <= IDLE;      //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fDLE
736                         inner_state <= INIT;    //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fNIT
737                     end
738 
739                 //闁告瑦鍨块埀顑跨閻﹀海鈧稒锚濞呮帡宕烽弶鎸庣祷                
740                 REG_ADDR_D7:
741                     if(scl_l_center)begin
742                         link  <= 1;
743                         sda_temp <= reg_addr[7];
744                         inner_state <= REG_ADDR_D6;
745                     end
746                     else begin
747                         inner_state <= REG_ADDR_D7;
748                     end
749                 
750                 REG_ADDR_D6:
751                     if(scl_l_center)begin
752                         link  <= 1;
753                         sda_temp <= reg_addr[6];
754                         inner_state <= REG_ADDR_D5;
755                     end
756                     else begin
757                         inner_state <= REG_ADDR_D6;
758                     end
759                     
760                 REG_ADDR_D5:
761                     if(scl_l_center)begin
762                         link  <= 1;
763                         sda_temp <= reg_addr[5];
764                         inner_state <= REG_ADDR_D4;
765                     end
766                     else begin
767                         inner_state <= REG_ADDR_D5;
768                     end
769                 
770                 REG_ADDR_D4:
771                     if(scl_l_center)begin
772                         link  <= 1;
773                         sda_temp <= reg_addr[4];
774                         inner_state <= REG_ADDR_D3;
775                     end
776                     else begin
777                         inner_state <= REG_ADDR_D4;
778                     end
779                 
780                 REG_ADDR_D3:
781                     if(scl_l_center)begin
782                         link  <= 1;
783                         sda_temp <= reg_addr[3];
784                         inner_state <= REG_ADDR_D2;
785                     end
786                     else begin
787                         inner_state <= REG_ADDR_D3;
788                     end
789                 
790                 REG_ADDR_D2:
791                     if(scl_l_center)begin
792                         link  <= 1;
793                         sda_temp <= reg_addr[2];
794                         inner_state <= REG_ADDR_D1;
795                     end
796                     else begin
797                         inner_state <= REG_ADDR_D2;
798                     end
799                 
800                 REG_ADDR_D1:
801                     if(scl_l_center)begin
802                         link  <= 1;
803                         sda_temp <= reg_addr[1];
804                         inner_state <= REG_ADDR_D0;
805                     end
806                     else begin
807                         inner_state <= REG_ADDR_D1;
808                     end
809                 
810                 REG_ADDR_D0:
811                     if(scl_l_center)begin
812                         link  <= 1;
813                         sda_temp <= reg_addr[0];
814                         inner_state <= REG_RELEASE_SDA;
815                     end
816                     else begin
817                         inner_state <= REG_ADDR_D0;
818                     end
819                 
820                 REG_RELEASE_SDA:
821                     if(scl_l_center)begin
822                         link <= 0; //闂佹彃锕ラ弬涓糄A
823                         inner_state <= REG_READ_ACK;
824                     end
825                     else begin
826                         inner_state <= REG_RELEASE_SDA;
827                     end
828                     
829                 REG_READ_ACK: 
830                     if(scl_h_center)begin
831                         link <= 0; //闂佹彃锕ラ弬涓糄A
832                         sda_temp <= sda;
833                         inner_state <= REG_CHECK_ACK;
834                     end
835                     else begin
836                         inner_state <= REG_READ_ACK;
837                     end
838                 
839                 REG_CHECK_ACK: 
840                     if(scl_l_center)begin
841                         rd_flag <= 1;
842                         link <= 1;
843                         sda_temp <= 1;
844                         inner_state <= GEN_START;
845                     end
846                     else if(scl_neg)begin
847                         rd_flag <= 1;
848                         link <= 1;
849                         inner_state <= REG_CHECK_ACK;
850                     end
851                     else if(!sda_temp)begin 
852                             inner_state <= REG_CHECK_ACK;
853                     end
854                     else if(sda_temp)begin
855                         main_state <= IDLE;
856                         inner_state <= INIT;
857                     end
858         
859                 
860                 //閺夆晜绋戦崣鍡欐嫚缂佹ɑ娈堕柟                
861                 RD_DATA_7:
862                     if(scl_h_center)begin
863                         link  <= 0;
864                         rd_buf[7] <= sda;
865                         inner_state <= RD_DATA_6;
866                     end
867                     else begin
868                         inner_state <= RD_DATA_7;
869                     end
870                 
871                 RD_DATA_6:
872                     if(scl_h_center)begin
873                         link  <= 0;
874                         rd_buf[6] <= sda;
875                         inner_state <= RD_DATA_5;
876                     end
877                     else begin
878                         inner_state <= RD_DATA_6;
879                     end
880                     
881                 RD_DATA_5:
882                     if(scl_h_center)begin
883                         link  <= 0;
884                         rd_buf[5] <= sda;
885                         inner_state <= RD_DATA_4;
886                     end
887                     else begin
888                         inner_state <= RD_DATA_5;
889                     end
890                 
891                 RD_DATA_4:
892                     if(scl_h_center)begin
893                         link  <= 0;
894                         rd_buf[4] <= sda;
895                         inner_state <= RD_DATA_3;
896                     end
897                     else begin
898                         inner_state <= RD_DATA_4;
899                     end
900                 
901                 RD_DATA_3:
902                     if(scl_h_center)begin
903                         link  <= 0;
904                         rd_buf[3] <= sda;
905                         inner_state <= RD_DATA_2;
906                     end
907                     else begin
908                         inner_state <= RD_DATA_3;
909                     end
910                 
911                 RD_DATA_2:
912                     if(scl_h_center)begin
913                         link  <= 0;
914                         rd_buf[2] <= sda;
915                         inner_state <= RD_DATA_1;
916                     end
917                     else begin
918                         inner_state <= RD_DATA_2;
919                     end
920                 
921                 RD_DATA_1:
922                     if(scl_h_center)begin
923                         link  <= 0;
924                         rd_buf[1] <= sda;
925                         inner_state <= RD_DATA_0;
926                     end
927                     else begin
928                         inner_state <= RD_DATA_1;
929                     end
930                 
931                 RD_DATA_0:
932                     if(scl_h_center)begin
933                         link  <= 0;
934                         rd_buf[0] <= sda;
935                         inner_state <= NO_ACK;
936                     end
937                     else begin
938                         inner_state <= RD_DATA_0;
939                     end
940                 
941                 NO_ACK:
942                     if(scl_l_center)begin
943                         link <= 1;
944                         sda_temp <= 0;
945                         inner_state <= STOP;
946                     end
947                     else if(scl_neg)begin
948                         link <= 1;
949                         inner_state <= NO_ACK;
950                     end
951         
952                 STOP:
953                     if(scl_h_center)begin
954                         link <= 1;
955                         sda_temp <= 1;
956                         inner_state <= RD_FINISH;
957                     end
958                     else begin
959                         inner_state <= STOP;
960                     end
961                 
962                 RD_FINISH:
963                     begin
964                         link <= 1;
965                         inner_state <= RD_FINISH;
966                         rd_done <= 1;
967                         rd_flag <= 0;
968                         sda_temp <= 1;
969                     end    
970                 default: inner_state <= INIT;
971             endcase
972         default : main_state <= IDLE;
973     
974     endcase
975 end
976 
977 reg led_temp;
978 always @(posedge clk or negedge rst_n)begin
979     if(!rst_n)begin
980         led_temp <= 0;
981     end
982     else if(rd_buf == data)begin
983         led_temp <= 1;
984     end
985     else begin
986         led_temp <= 0;
987     end
988 end
989 assign sda = link ? sda_temp : 1'bz;
990 
991 assign led = led_temp;
992 
993 endmodule
View Code

第二个版本,只写了随机写,但感觉状态机是多余的,完全是按照计数器实现的,没体现状态机的优势

  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 
 12 parameter       IDLE          = 0;
 13 parameter       START         = 1;
 14 parameter       SLAVE_ADD     = 2;
 15 parameter       ACK            = 3;
 16 parameter       REG_ADD       = 4;
 17 parameter       REG_DAT       = 5;
 18 parameter       STOP        = 6;
 19 
 20 parameter       SCL_100K      = 500;
 21 parameter        D_W            = 8;
 22 
 23 input            clk                ;
 24 input            rst_n            ;
 25 input            wr_en            ;
 26 input[D_W-1:0]    slave_address    ;
 27 input[D_W-1:0]    reg_address        ;
 28 input[D_W-1:0]    reg_data        ;
 29 
 30 output            scl;
 31 inout            sda;
 32         
 33 reg                scl        ;
 34 reg                sda_temp;
 35 reg             wr_vld    ;
 36 wire            link    ;
 37 
 38 reg[3-1:0]        state_c;
 39 reg[3-1:0]        state_n;        
 40 
 41 reg[9-1:0]         cnt0;
 42 reg[5-1:0]         cnt1;
 43 
 44 wire             scl_l_middle;
 45 wire            scl_h_middle;
 46 wire            add_cnt0    ;
 47 wire             end_cnt0    ;
 48 wire            add_cnt1    ;
 49 wire            end_cnt1    ;
 50 
 51 wire             idle2start         ;
 52 wire             start2slave_add ;
 53 wire             slave_add2ack     ;
 54 wire             ack2reg_add        ;
 55 wire             ack2reg_dat     ;
 56 wire             ack2stop         ;
 57 wire             reg_add2ack     ;
 58 wire             reg_dat2ack     ;
 59 wire             stop2idle       ;
 60 
 61 //产生 “写" 有效保持信号
 62 always @(posedge clk or negedge rst_n)begin
 63     if(!rst_n)begin
 64         wr_vld <= 0; 
 65     end
 66     else if(wr_en)begin
 67         wr_vld <= 1; 
 68     end
 69     else if(end_cnt1)begin
 70         wr_vld <= 0; 
 71     end
 72 end
 73 
 74 //计数cnt0,用于产生scl
 75 always @(posedge clk or negedge rst_n)begin
 76     if(!rst_n)begin
 77         cnt0 <= 0;
 78     end
 79     else if(add_cnt0)begin
 80         if(end_cnt0)begin
 81             cnt0 <= 0;
 82         end
 83         else begin
 84             cnt0 <= cnt0 + 1;
 85         end
 86     end
 87 end
 88 
 89 assign add_cnt0 = wr_vld;
 90 assign end_cnt0 = add_cnt0 && cnt0 == SCL_100K -1; // SCL_100K = 500;
 91 
 92 //计数器cnt1,写数据时,需要产生scl的数量
 93 always @(posedge clk or negedge rst_n)begin
 94     if(!rst_n)begin
 95         cnt1 <= 0;
 96     end
 97     else if(add_cnt1)begin
 98         if(end_cnt1)begin
 99             cnt1 <= 0;
100         end
101         else begin
102             cnt1 <= cnt1 + 1;
103         end
104     end
105 end
106 
107 assign add_cnt1 = end_cnt0;
108 assign end_cnt1 = add_cnt1 && cnt1 == 29 -1;
109 
110 //产生scl
111 always @(posedge clk or negedge rst_n)begin
112     if(!rst_n)begin
113         scl <= 1;
114     end
115     else if(add_cnt0 && cnt0 == 250 - 1 && cnt1 != 1-1)begin // 在第一个时钟时, scl不拉低
116         scl <= 1;
117     end
118     else if(end_cnt0)begin
119         scl <= 0;
120     end
121 end
122 
123 //第一段,状态跳转
124 always @(posedge clk or negedge rst_n)begin
125     if(!rst_n)begin
126         state_c <= IDLE;
127     end
128     else begin
129         state_c <= state_n;
130     end
131 end
132 
133 
134 //写数据:idle -> start -> send slave_address -> wait ack -> send reg address -> wait ack -> 写数据 -> wait ack -> stop
135 //第二段,罗列出所有条件跳转
136 always @(*)begin
137     case(state_c)
138         IDLE:begin
139             if(idle2start)begin
140                 state_n = START;
141             end
142             else begin
143                 state_n = state_c;
144             end
145         end
146         
147         START:begin
148             if(start2slave_add)begin
149                 state_n = SLAVE_ADD;
150             end
151             else begin
152                 state_n = state_c;
153             end
154         end
155         
156         SLAVE_ADD:begin
157             if(slave_add2ack)begin
158                 state_n = ACK;
159             end
160             else begin
161                 state_n = state_c;
162             end
163         end
164         
165         ACK:begin
166             if(ack2reg_add)begin
167                 state_n = REG_ADD;
168             end
169             else if(ack2reg_dat)begin
170                 state_n = REG_DAT;
171             end
172             else if(ack2stop)begin
173                 state_n = STOP;
174             end
175             else begin
176                 state_n = state_c;
177             end
178         end
179         
180         REG_ADD:begin
181             if(reg_add2ack)begin
182                 state_n = ACK;
183             end
184             else begin
185                 state_n = state_c;
186             end
187         end
188         
189         REG_DAT:begin
190             if(reg_dat2ack)begin
191                 state_n = ACK;
192             end
193             else begin
194                 state_n = state_c;
195             end
196         end
197         
198         STOP:begin
199             if(stop2idle)begin
200                 state_n = IDLE;
201             end
202             else begin
203                 state_n = state_c;
204             end
205         end
206         
207         default:begin
208             state_n = IDLE;
209         end
210         
211     endcase 
212 end
213 
214 assign scl_h_middle =  add_cnt0 && cnt0 == 375-1;
215 assign scl_l_middle =  add_cnt0 && cnt0 == 125-1;
216 //assign scl_h_2_l    =  end_cnt0;
217 assign scl_l_2_h    =  add_cnt0 && cnt0 == 250-1;
218 
219 //第三段,设计跳转条件
220 assign idle2start         = state_c == IDLE         && wr_vld && scl_l_middle && (cnt1 == 1  - 1);
221 assign start2slave_add  = state_c == START        && end_cnt0;
222 assign slave_add2ack     = state_c == SLAVE_ADD && scl_l_middle && (cnt1 == 10 - 1);
223 assign ack2reg_add        = state_c == ACK       && end_cnt0        && (cnt1 == 10 - 1);
224 assign ack2reg_dat         = state_c == ACK       && end_cnt0       && (cnt1 == 19 - 1);
225 assign ack2stop         = state_c == ACK       && end_cnt0       && (cnt1 == 28 - 1);
226 assign reg_add2ack         = state_c == REG_ADD   && scl_l_middle && (cnt1 == 19 - 1);
227 assign reg_dat2ack      = state_c == REG_DAT   && scl_l_middle && (cnt1 == 28 - 1);
228 assign stop2idle        = state_c == STOP       && end_cnt1;
229 
230 //sda 
231 always @(posedge clk or negedge rst_n)begin
232     if(!rst_n)begin
233         sda_temp <= 1;
234     end
235     else if(state_c == IDLE)begin
236         sda_temp <= 1;
237     end
238     else if(state_c == START && scl_l_2_h)begin
239         sda_temp <= 0;
240     end
241     else if(scl_l_middle && cnt1 >= 2-1 && cnt1 < 9)begin     //&& state_c == SLAVE_ADD
242         sda_temp <= slave_address[8-cnt1];
243     end
244     else if(scl_l_middle && cnt1 >= 11-1 && cnt1 < 18)begin //&& state_c == REG_ADD
245         sda_temp <= reg_address[17-cnt1];
246     end
247     else if(scl_l_middle && cnt1 >= 20-1 && cnt1 < 27)begin //&& state_c == REG_DAT
248         sda_temp <= reg_data[26-cnt1]; 
249     end
250 //    else if(end_cnt0 && cnt1 == 28-1)begin
251 //        sda_temp <= 1;
252 //    end
253     else if(state_c == STOP && scl_l_middle)begin
254         sda_temp <= 0;
255     end
256     else if(state_c == STOP && scl_h_middle)begin
257         sda_temp <= 1;
258     end
259 end
260 
261 //sda方向控制, 等待ack时 sda需要释放,还有接收数据时,也需要释放
262 assign link = state_c == ACK ? 1'b0 : 1'b1;
263 
264 reg rd_ack;
265 always @(posedge clk or negedge rst_n)begin
266     if(!rst_n)begin
267         rd_ack <= 1;
268     end
269     else if(state_c == ACK && scl_h_middle)begin // 在高电平中间读ack
270         rd_ack <= sda;
271     end
272 end
273 
274 reg ack_err;
275 always @(posedge clk or negedge rst_n)begin
276     if(!rst_n)begin
277         ack_err <= 0;
278     end
279     else if(!rd_ack)begin
280         ack_err <= 1;    //说明读的ACK不是0
281     end
282     else begin
283         ack_err <= 0;
284     end
285 end
286 
287 assign sda = link ? sda_temp : 1'bz;
288 
289 endmodule
View Code

以上两个版本计数器都是按照常规的思路,scl的拉高 和拉低 都比较传统,就是cnt0 = 0时 ,scl拉高,在end_cnt0时拉低,这样就导致了后面的条件转移设计及sda发送的数据比较麻烦,因为sda是在scl的低电平中间发送,而这个时候的cnt1是跨在

两个状态机之间,比如cnt1 = 1时,状态机可能是在start状态或是slave_add状态下,就没法对齐,边界分的不清楚,导致后面的sda_temp 加的条件判断特别麻烦。

 

总结:  在设计状态机时,思路要明确,尤其是跳转条件,分析的透彻之后,写起来就比较爽快,一个always里面就写一个信号,一次就考虑一个信号,考虑该信号  变高点变低点 ,逐个完善每个信号。不要一锅端

posted @ 2022-04-15 08:32  MyBooks  阅读(496)  评论(0编辑  收藏  举报