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悂寮幏宀€绠婚柛蹇fDLE 342 inner_state <= INIT; //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fNIT 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悂寮幏宀€绠婚柛蹇fDLE 736 inner_state <= INIT; //ACK濠㈡儼绮剧憴锕傛儍閸曨喚妯堥柨娑樼焸閸f悂寮幏宀€绠婚柛蹇fNIT 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
第二个版本,只写了随机写,但感觉状态机是多余的,完全是按照计数器实现的,没体现状态机的优势
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
以上两个版本计数器都是按照常规的思路,scl的拉高 和拉低 都比较传统,就是cnt0 = 0时 ,scl拉高,在end_cnt0时拉低,这样就导致了后面的条件转移设计及sda发送的数据比较麻烦,因为sda是在scl的低电平中间发送,而这个时候的cnt1是跨在
两个状态机之间,比如cnt1 = 1时,状态机可能是在start状态或是slave_add状态下,就没法对齐,边界分的不清楚,导致后面的sda_temp 加的条件判断特别麻烦。
总结: 在设计状态机时,思路要明确,尤其是跳转条件,分析的透彻之后,写起来就比较爽快,一个always里面就写一个信号,一次就考虑一个信号,考虑该信号 变高点 和 变低点 ,逐个完善每个信号。不要一锅端