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
随机读完整代码:
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
先下载随机写完整代码到目标板中,将数据写入eeprom,然后再下载随机的读完整代码,读取数据,用Quartus 逻辑分析抓取波形:(开始到结束完整波形抓取不完,分两张截图),写入 0x0f = 0xaa, 看波形读取数据是对的
前半部分波形
后半部分波形,在NOACK时,不用考虑sda 是拉高 还是拉低,但是在产生stop前必须先拉低sda
下一个实验,将随机读 、写 整合在一起,准备用一个状态机完成读和写。