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

 

 

 

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

 

posted @ 2022-04-14 11:31  MyBooks  阅读(122)  评论(0编辑  收藏  举报