当前位置:网站首页>FSM和i2c实验报告
FSM和i2c实验报告
2022-07-06 09:25:00 【湖大金胜宇】
平台2HDL语言与验证实验报告
一、自定FSM说明
1、状态描述
S0:sleep,S1:起床,S2:早餐,S3:运动,S4:上课,S5:中餐,S6:开摆,S7:午休,S8:锻炼,S9:自习,S10:洗澡,S11:吃夜宵
2、设计代码说明
首先是对我们定义的状态进行编码,编码如下:
state0=4'b0000,
state1=4'b0001,
state2=4'b0010,
state3=4'b0011,
state4=4'b0100,
state5=4'b0101,
state6=4'b0110,
state7=4'b0111,
state8=4'b1000,
state9=4'b1001,
state10=4'b1010,
state11=4'b1111;
接下来,是对每个状态之间的跳转的代码:
[email protected](*)
case(state)
state0:if(start)next_st=state1;
else next_st=state0;
state1:next_st=state2;
state2:if(skip1)next_st=state3;
else next_st=state4;
state3:next_st=state5;
state4:next_st=state5;
state5:if(play)next_st=state6;
else next_st=state7;
state6:next_st=state7;
state7:if(read)next_st=state9;
else next_st=state8;
state8:next_st=state10;
state9:if(wash)next_st=state10;
else next_st=state11;
state10:if(eat)next_st=state11;
else next_st=state0;
state11:next_st=state0;
default:next_st=state0;
endcase
这里,代码的实现是非常简单的,就是当一个状态一个条件的时候,就会跳转到另一个条件,这里由于我画的图太丑了,就不展示在这了。
3、仿真波形说明(截图+文字标注)
仿真之前,我们需要写一个测试的文件,也就是具体控制波形输出的一个文件:
initial begin
start=0; skip1=0; play=0; read=0; wash=0;
#1;
#200 start = 1;
#200 start = 0;skip1 = 1;
#200 skip1 = 0;play = 1;
#200 read = $random;wash = 1;
#200 eat=1;
wait(zot ==4'b1010)
repeat(1024)@(posedge clk);
$stop;
end
这里,我们定义的是每隔200ns设置一个信号量,根据代码我们可以推断出在1ns处,reset信号为1,让所有的信号初始化为0。
保持200ns之后,start信号变为1(也就是闹钟响了,要起床了),这里我们推测状态变为S1(也就是4'h1),同时由于S1和S2之间没有条件判断跳转,所以这一段时间中最后会变成S2状态(也就是无论如何你都会去吃早饭)。
上述情况保持200ns之后,start信号被设置为0,skip1信号被设置为1,也就是S2状态会变成S3状态(也就是吃完早饭之后出门散散步),S3和S5之间同样没有条件判断是否跳转,这里就是你吃完早饭散会步,散饿了自然会去吃午饭了。
再隔200ns之后,skip信号被设置为0,play信号被设置为1了。这里就会从S5状态跳转到S6状态(也就是吃完饭了,自然需要玩会游戏了)。同样不可能一直玩游戏的,一段时间之后会自动跳转到S7状态,这里也就是摆一会之后,自然就需要进行午休了。
又隔了200ns,read信号被设置为了随机值(也就是午休之后,可能去自习,也可能不去),同时wash信号被设置为了1,也就是不论是自习还是不去自习,若read信号为1的话,会在自习之后去洗一个澡,若read信号为0的话,就不会去上自习了,而是去锻炼,锻炼之后再去洗澡。
最后200ns之后,eat信号被设置为1,也就是洗完澡之后,我们就要去吃夜宵了也就是S11状态,最后的最后我们就要sleep了,这一天就结束了。
通过波形,验证出我们的分析是正确的。以上分析就是对仿真波形的分析。
二、EEPROM读写代码设计及仿真
1、代码说明
端口
`timescale 1ns / 1ps //时间单位1ns,精度1ps
module i2c(
input clk, //时钟
input rstn, //复位
input write_op, //写操作
input [7:0]write_data, //需要写入的数据
input read_op, //读操作
output reg [7:0]read_data, //读出的数据
input [7:0]addr, //数据地址
output op_done, //操作结束
output reg scl, //scl
inout sda //sda
);
状态
Byte Write : START + DEVICE +ACK + ADDR + ACK + DATA + ACK + STOP
Random Read : START + DEVICE + ACK +ADDR + ACK+START + DEVICE + DATA + NO ACK + STOP
每个状态用8位16进制数表示,对照上面图中SDA上数据传输情况,每一位数据传输都有一个对应的状态,多出了一些等待状态。
parameter IDLE =8'h00,
WAIT_WTICK0=8'h01,
WAIT_WTICK1=8'h02,
W_START=8'h03,
W_DEVICE7=8'h04,
W_DEVICE6=8'h05,
W_DEVICE5=8'h06,
W_DEVICE4=8'h07,
W_DEVICE3=8'h08,
W_DEVICE2=8'h09,
W_DEVICE1=8'h0a,
W_DEVICE0=8'h0b,
W_DEVACK=8'h0c,
W_ADDRES7=8'h0d,
W_ADDRES6=8'h0e,
W_ADDRES5=8'h0f,
W_ADDRES4=8'h10,
W_ADDRES3=8'h11,
W_ADDRES2=8'h12,
W_ADDRES1=8'h13,
W_ADDRES0=8'h14,
W_AACK=8'h15,
W_DATA7=8'h16,
W_DATA6=8'h17,
W_DATA5=8'h18,
W_DATA4=8'h19,
W_DATA3=8'h1a,
W_DATA2=8'h1b,
W_DATA1=8'h1c,
W_DATA0=8'h1d,
W_DACK=8'h1e,
WAIT_WTICK3=8'h1f,
R_START=8'h20,
R_DEVICE7=8'h21,
R_DEVICE6=8'h22,
R_DEVICE5=8'h23,
R_DEVICE4=8'h24,
R_DEVICE3=8'h25,
R_DEVICE2=8'h26,
R_DEVICE1=8'h27,
R_DEVICE0=8'h28,
R_DACK=8'h29,
R_DATA7=8'h2a,
R_DATA6=8'h2b,
R_DATA5=8'h2c,
R_DATA4=8'h2d,
R_DATA3=8'h2e,
R_DATA2=8'h2f,
R_DATA1=8'h30,
R_DATA0=8'h31,
R_NOACK=8'h32,
S_STOP=8'h33,
S_STOP0=8'h34,
S_STOP1=8'h35,
W_OPOVER=8'h36;
reg [7:0]i2c,next_i; //当前状态,下一状态
SCL同步
时钟的频率很高,读写数据不能以时钟周期为周期进行,设备进行响应和读写需要的时间远大于时钟周期,因此使用SCL同步方式来同 步时序。SCL周期是通过时钟周期实现的。
一个scl周期是30个时钟周期。使用div_cnt来记录时钟周期数,30个一次循环。以下只是时间单位 声明,SCL的具体实现在下方↓。
SCL周期:
|——————————
| ———————— |
clk0 clk7 clk15 clk22 clk29
scl_ls scl_lc scl_hs scl_hc scl_tick
reg [7:0]div_cnt; //时钟计数器
wire scl_tick;
//计数,一个时钟周期div_cnt+1
always @(posedge clk or negedge rstn)
if(!rstn) div_cnt <=8'd0;
else if((i2c==IDLE)|scl_tick) div_cnt <=8'd0;
else div_cnt<=div_cnt+1'b1;
//scl时间
wire scl_ls =(div_cnt==8'd0); //scl low
wire scl_lc = (div_cnt==8'd7); //scl low center
wire scl_hs =(div_cnt==8'd15); //scl high
wire scl_hc = (div_cnt==8'd22); //scl high center
assign scl_tick = (div_cnt==8'd29); //一个周期结束
状态更新
//状态
always @(posedge clk or negedge rstn)
if(!rstn) i2c <=0;
else i2c <= next_i;
读写命令的判断
读写命令是通过端口输入write_op和read_op确定的,这两个信号是低电平有效,用了wr_op和rd_op两个寄存器把输入的write_op和 read_op取反,这样如果有读或写命令,wr_op或rd_op为1,复位和操作结束(wr_opover)时都要清零,接下来就用wr_op和rd_op判断是否读 写了,这里仅仅是把原来低电平有效的信号替换为两个高电平有效信号。
reg wr_op,rd_op; //读写操作
always @ (posedge clk or negedge rstn)
if(!rstn) wr_op <= 0;
else if (i2c==IDLE) wr_op <= ~write_op;
else if(i2c==W_OPOVER) wr_op <=1'b0;
always @(posedge clk or negedge rstn)
if(!rstn) rd_op <= 0;
else if (i2c==IDLE) rd_op <= ~read_op;
else if(i2c==W_OPOVER) rd_op <=1'b0;
wire d5ms_over; //等待
下一状态的判断
Byte Write : START + DEVICE +ACK + ADDR + ACK + DATA + ACK + STOP
Random Read : START + DEVICE + ACK +ADDR + ACK+START + DEVICE + DATA + NO ACK + STOP
下一状态的更新是在scl_tick(每30个clk),上面下划线划出的部分是相同的,无论读写,一开始的状态更新都是按照上面下划线的顺 序依次更新状态,这时候的器件地址都是10100000(write),到了ADDR的ACK,即W_AACK时会根据wr_op和rd_op决定接下来进入怎样的 状态,wr_op会开始到状态W_DATA读数据;rd_op会到WAIT_WTICK3,然后继续START。操作结束后需要等待一个信号d5ms_over才能回到 空闲,控制器件工作的频率不要太高。
[email protected](*)
case (i2c)
IDLE: begin next_i = IDLE;if(wr_op|rd_op) next_i = WAIT_WTICK0;end //有读写操作跳出空闲状态
//wait tick
WAIT_WTICK0:begin next_i = WAIT_WTICK0;if(scl_tick) next_i=WAIT_WTICK1;end
WAIT_WTICK1:begin next_i = WAIT_WTICK1;if(scl_tick) next_i = W_START;end
//START:SCL=1,SDA=1->0(scl_lc)
W_START:begin next_i=W_START;if(scl_tick) next_i=W_DEVICE7;end
//DEVICE ADDRESS(1010_000_0(WRITE))
W_DEVICE7:begin next_i = W_DEVICE7;if(scl_tick) next_i=W_DEVICE6;end
W_DEVICE6:begin next_i = W_DEVICE6;if(scl_tick) next_i=W_DEVICE5;end
W_DEVICE5:begin next_i = W_DEVICE5;if(scl_tick) next_i=W_DEVICE4;end
W_DEVICE4:begin next_i = W_DEVICE4;if(scl_tick) next_i=W_DEVICE3;end
W_DEVICE3:begin next_i = W_DEVICE3;if(scl_tick) next_i=W_DEVICE2;end
W_DEVICE2:begin next_i = W_DEVICE2;if(scl_tick) next_i=W_DEVICE1;end
W_DEVICE1:begin next_i = W_DEVICE1;if(scl_tick) next_i=W_DEVICE0;end
W_DEVICE0:begin next_i = W_DEVICE0;if(scl_tick) next_i=W_DEVACK;end
//ACK
W_DEVACK:begin next_i=W_DEVACK;if(scl_tick) next_i=W_ADDRES7;end
//WORD ADDRESS
W_ADDRES7 :begin next_i = W_ADDRES7;if(scl_tick) next_i=W_ADDRES6;end
W_ADDRES6 :begin next_i = W_ADDRES6;if(scl_tick) next_i=W_ADDRES5;end
W_ADDRES5 :begin next_i = W_ADDRES5;if(scl_tick) next_i=W_ADDRES4;end
W_ADDRES4 :begin next_i = W_ADDRES4;if(scl_tick) next_i=W_ADDRES3;end
W_ADDRES3 :begin next_i = W_ADDRES3;if(scl_tick) next_i=W_ADDRES2;end
W_ADDRES2 :begin next_i = W_ADDRES2;if(scl_tick) next_i=W_ADDRES1;end
W_ADDRES1 :begin next_i = W_ADDRES1;if(scl_tick) next_i=W_ADDRES0;end
W_ADDRES0 :begin next_i = W_ADDRES0;if(scl_tick) next_i=W_AACK;end
//ACK
W_AACK:begin next_i = W_AACK;
if(scl_tick&wr_op) next_i=W_DATA7; //wr_op即写命令,开始写数据
else if(scl_tick&rd_op) next_i=WAIT_WTICK3; //rd_op读命令,则下一状态为WAIT_WTICK3
end
//WRITE DATA[7:0]
W_DATA7:begin next_i=W_DATA7;if(scl_tick)next_i=W_DATA6;end
W_DATA6:begin next_i=W_DATA6;if(scl_tick)next_i=W_DATA5;end
W_DATA5:begin next_i=W_DATA5;if(scl_tick)next_i=W_DATA4;end
W_DATA4:begin next_i=W_DATA4;if(scl_tick)next_i=W_DATA3;end
W_DATA3:begin next_i=W_DATA3;if(scl_tick)next_i=W_DATA2;end
W_DATA2:begin next_i=W_DATA2;if(scl_tick)next_i=W_DATA1;end
W_DATA1:begin next_i=W_DATA1;if(scl_tick)next_i=W_DATA0;end
W_DATA0:begin next_i=W_DATA0;if(scl_tick)next_i=W_DACK;end
//ACK
W_DACK:begin next_i=W_DACK; if(scl_tick) next_i=S_STOP;end
//Current Address Read
//START: SCL=1,SDA=1->0(scl_lc)
WAIT_WTICK3:begin next_i=WAIT_WTICK3; if(scl_tick) next_i=R_START;end
R_START:begin next_i=R_START; if(scl_tick)next_i=R_DEVICE7;end
//DEVICE ADDRESS(1010_000_1(READ))
R_DEVICE7:begin next_i=R_DEVICE7; if(scl_tick) next_i=R_DEVICE6;end
R_DEVICE6:begin next_i=R_DEVICE6; if(scl_tick) next_i=R_DEVICE5;end
R_DEVICE5:begin next_i=R_DEVICE5; if(scl_tick) next_i=R_DEVICE4;end
R_DEVICE4:begin next_i=R_DEVICE4; if(scl_tick) next_i=R_DEVICE3;end
R_DEVICE3:begin next_i=R_DEVICE3; if(scl_tick) next_i=R_DEVICE2;end
R_DEVICE2:begin next_i=R_DEVICE2; if(scl_tick) next_i=R_DEVICE1;end
R_DEVICE1:begin next_i=R_DEVICE1; if(scl_tick) next_i=R_DEVICE0;end
R_DEVICE0:begin next_i=R_DEVICE0; if(scl_tick) next_i=R_DACK;end
//ACK
R_DACK:begin next_i=R_DACK;if(scl_tick) next_i=R_DATA7;end
//READ DATA[7:0], SDA:input
R_DATA7:begin next_i=R_DATA7;if(scl_tick) next_i=R_DATA6;end
R_DATA6:begin next_i=R_DATA6;if(scl_tick) next_i=R_DATA5;end
R_DATA5:begin next_i=R_DATA5;if(scl_tick) next_i=R_DATA4;end
R_DATA4:begin next_i=R_DATA4;if(scl_tick) next_i=R_DATA3;end
R_DATA3:begin next_i=R_DATA3;if(scl_tick) next_i=R_DATA2;end
R_DATA2:begin next_i=R_DATA2;if(scl_tick) next_i=R_DATA1;end
R_DATA1:begin next_i=R_DATA1;if(scl_tick) next_i=R_DATA0;end
R_DATA0:begin next_i=R_DATA0;if(scl_tick) next_i=R_NOACK;end
//NO ACK
R_NOACK:begin next_i=R_NOACK;if(scl_tick) next_i=S_STOP;end
//STOP
S_STOP:begin next_i=S_STOP;if(scl_tick) next_i=S_STOP0;end
S_STOP0:begin next_i=S_STOP0;if(scl_tick) next_i=S_STOP1;end
S_STOP1:begin next_i=S_STOP1;if(scl_tick) next_i=W_OPOVER;end
//WAIT write_op=0,read_op=0;
W_OPOVER:begin next_i = W_OPOVER;if(d5ms_over)next_i=IDLE;end //操作结束回到空闲状态
default:begin next_i= IDLE;end
endcase
SCL同步实现
空闲,等待,操作结束,start开始等状态下SCL都是高电平,因此不需要clr_scl对SCL清零。另外clr_scl只在scl_ls(scl的低电平开始)处 才置1,把scl清0,在15个clk周期的scl_hs处,再把scl拉高,就实现了SCL周期。
//SCL
assign clr_scl=scl_ls&(i2c!=IDLE)&(i2c!=WAIT_WTICK0)& //clr_scl,scl置0信号
(i2c != WAIT_WTICK1)&(i2c!=W_START)&(i2c!=R_START)
&(i2c!=S_STOP0)&(i2c!=S_STOP1)&(i2c!=W_OPOVER);
always @(posedge clk or negedge rstn)
if(!rstn) scl <= 1'b1; //复位,scl为高电平
else if(clr_scl) scl <= 1'b0; //scl 1->0
else if(scl_hs) scl <=1'b1; //scl 0->1,high start,clk15
SDA实现
代码后半都是SDA实现的部分,因为太长所以一段一段分析。
下面的一段是实现SDA的控制信号声明,这些信号在对应的状态且scl在低电平的中心时置1,告诉SDA该怎么做,i2c_reg用来暂存scl上 的数据,i2c_rlf是在读写数据时用的,使用的部分在下一段代码。
//SDA
reg [7:0]i2c_reg;
assign start_clr = scl_lc &((i2c==W_START)|(i2c==R_START)); //在scl low center开始读写操作
assign ld_wdevice = scl_lc&(i2c==W_DEVICE7); //加载器件地址
assign ld_waddres = scl_lc&(i2c==W_ADDRES7); //加载数据地址
assign ld_wdata= scl_lc&(i2c==W_DATA7); //加载数据
assign ld_rdevice = scl_lc&(i2c==R_DEVICE7); //读操作的器件地址
assign noack_set = scl_lc&(i2c==R_NOACK) ; //读操作完毕,主机发响应
assign stop_clr = scl_lc&(i2c==S_STOP);
assign stop_set = scl_lc&((i2c==S_STOP0)|(i2c==WAIT_WTICK3));
assign i2c_rlf =scl_lc&( //有读写则i2c_rlf
(i2c == W_DEVICE6)|
(i2c == W_DEVICE5)|
(i2c == W_DEVICE4)|
(i2c == W_DEVICE3)|
(i2c == W_DEVICE2)|
(i2c == W_DEVICE1)|
(i2c == W_DEVICE0)|
(i2c == W_ADDRES6)|
(i2c == W_ADDRES5)|
(i2c == W_ADDRES4)|
(i2c == W_ADDRES3)|
(i2c == W_ADDRES2)|
(i2c == W_ADDRES1)|
(i2c == W_ADDRES0)|
(i2c == W_DATA6)|
(i2c == W_DATA5)|
(i2c == W_DATA4)|
(i2c == W_DATA3)|
(i2c == W_DATA2)|
(i2c == W_DATA1)|
(i2c == W_DATA0)|
(i2c == R_DEVICE6)|
(i2c == R_DEVICE5)|
(i2c == R_DEVICE4)|
(i2c == R_DEVICE3)|
(i2c == R_DEVICE2)|
(i2c == R_DEVICE1)|
(i2c == R_DEVICE0));
接下来就是根据控制信号进行操作,把对应操作的数据放到i2c_reg里,准备向SDA线上传输,i2c_rlf为1时i2creg会左移一位,因为sda 是单位宽的,每次把i2creg的最高位送到sda上,因此左移就是一位一位把数据送到sda上。
[email protected](posedge clk or negedge rstn)
if(!rstn) i2c_reg <= 8'hff; //复位,高电平
else if(start_clr) i2c_reg <= 8'h00; //开始读写,sda输出
else if(ld_wdevice) i2c_reg <= {4'b1010,3'b000,1'b0}; //10100000 写
else if(ld_waddres) i2c_reg <= addr; //加载数据地址
else if(ld_wdata) i2c_reg <= write_data; //加载写入的数据
else if(ld_rdevice) i2c_reg <= {4'b1010,3'b000,1'b1}; //10100001 读
else if(noack_set) i2c_reg <= 8'hff; //NOACK
else if(stop_clr) i2c_reg <= 8'h00;
else if(stop_set) i2c_reg <= 8'hff;
else if(i2c_rlf) i2c_reg <= {i2c_reg[6:0],1'b0}; //左移
接下来是sda输出的控制,sda使能在主机写数据地址,数据时都是1,使能为1时器件靠sda输出i2creg的最高位。NOACK以外的其他 响应信号,以及读的数据,都是从机发到sda线上的,这时主机的sda使能为0,不可以发出数据。2、TestBench代码说明
assign sda_o = i2c_reg[7]; //sda
assign clr_sdaen = (i2c==IDLE)| //sda使能置0信号
(scl_lc&(
(i2c==W_DEVACK)|
(i2c==W_AACK)|
(i2c==W_DACK)|
(i2c==R_DACK)|
(i2c==R_DATA7)));
assign set_sdaen = scl_lc&( //sda使能置1信号
(i2c==WAIT_WTICK0)|
(i2c==W_ADDRES7)|
(i2c==W_DATA7)|
(i2c==WAIT_WTICK3)|
(i2c==S_STOP)|
(i2c==R_NOACK));
reg sda_en;
always @(posedge clk or negedge rstn)
if(!rstn) sda_en <= 0;
else if (clr_sdaen) sda_en <=0;
else if(set_sdaen) sda_en <= 1'b1;
assign sda= sda_en?sda_o: 1'bz; //sda使能为1时sda可工作
以下是读数据的操作,用sda_wr控制,在scl高电平的中心(数据稳定时)往read_data里读数据,左移补sda,就一位一位的用sda发的 数据更新了read_data,这时sda是从机在发数据。
assign sda_wr = scl_hc &( //读数据
(i2c==R_DATA7)|
(i2c==R_DATA6)|
(i2c==R_DATA5)|
(i2c==R_DATA4)|
(i2c==R_DATA3)|
(i2c==R_DATA2)|
(i2c==R_DATA1)|
(i2c==R_DATA0));
[email protected](posedge clk or negedge rstn)
if(!rstn) read_data <= 0;
else if(sda_wr) read_data <= {read_data[6:0],sda}; //左移读入数据
操作结束,等待
最后就是操作结束后的等待时间,d5ms_cnt用来记时钟周期,记满了就会把d5ms_over置1,在上面状态转换的部分,最后进入STOP状 态等待的就是这个信号,等到了这个信号,I2C就回到空闲状态了。
//op_done
assign op_done = (i2c == W_OPOVER); //操作结束
//Write Cycle(5ms)
//6MHZ = 166ns,5ms/166ns = 31
reg [12:0] d5ms_cnt;
always @(posedge clk or negedge rstn)
if(!rstn) d5ms_cnt <= 8'd0;
else if(i2c==IDLE) d5ms_cnt <= 8'd0;
else if(i2c==W_OPOVER) d5ms_cnt <= d5ms_cnt + 1'b1;
assign d5ms_over = (d5ms_cnt==13'h1FFF);
最后,这个模块里没有ACK处理的部分,只是在应该收到ACK的时候从sda读信号出来,没有进行判断,或许是交给主机来做的。
2、TestBench代码说明
TestBench主要代码如下:
initial
begin
clk = 0;
rstn = 0;
write_op=1'b1;
write_data=8'h00;
read_op=1'b1;
addr=0;
repeat(5) @(posedge clk);
rstn = 1'b1;
end
initial
begin
wait(rstn);
repeat(10) @(posedge clk);
write_op=1'b0;
addr = 8'h55;
write_data= 8'haa;
wait(op_done);
write_op=1'b1;
$display ($stime/1,"ns","Write:Addr(%h)=(%h)\n",addr,write_data);
repeat(100)@(posedge clk);
read_op=1'b0;
addr = 8'h55;
wait(op_done);
read_op=1'b1;
$display ($stime/1,"ns","Write:Addr(%h)=(%h)\n",addr,read_data);
repeat(1000) @(posedge clk);
$stop;
end
根据上面的代码发现,我们可以知道读写命令是通过端口输入write_op和read_op确定的。所以该程序先写再读,波形应该也是这样。
3、仿真波形说明(截图+文字标注)
SCL为高时,SDA为下降沿的时候,设备开始工作。先由主机写入器件地址,然后写入数据地址,每次写入后从机都会回复一个ACK信号表示收到。其中器件地址是从机EEPROM的地址1010000X,X为0表示写,1表示读,一开始写入器件地址时,X都是0。进行写操作,接下来只需要由主机发出数据就可以了,从机发出ACK响应回复收到。
进行读操作,重新写一遍器件地址,这次X就是1了,表示接下来要读数据了,从机读出数据,主机收到数据以后回复NOACK给从机表示收到数据。
三、实验总结
通过本次实验我学会了以下几个知识点:
- 掌握状态机描述方法;
- 能编写TestBench;
- 能用ModelSim进行仿真;
- 掌握I2C接口协议;
- 能较好的理解参考设计文件和测试文件;
- 能用ModelSim进行仿真,合理解释各个信号的作用;
- 使用Quartus建立“EEPROM读写代码”工程;
下载验证"EEPROM读写代码"功能;
经过几次的实验,不仅磨练了我的意志,坚定了我的信念,相信在未来的实验中同样可以获得很多的收获。
边栏推荐
- Mysql database (I)
- ucore lab 2
- Eigen User Guide (Introduction)
- Mysql的事务
- Global and Chinese market of DVD recorders 2022-2028: Research Report on technology, participants, trends, market size and share
- Global and Chinese markets of electronic grade hexafluorobutadiene (C4F6) 2022-2028: Research Report on technology, participants, trends, market size and share
- Opencv recognition of face in image
- UCORE lab1 system software startup process experimental report
- MySQL transactions
- Global and Chinese market of RF shielding room 2022-2028: Research Report on technology, participants, trends, market size and share
猜你喜欢
Investment operation steps
What to do when programmers don't modify bugs? I teach you
ucore lab6 调度器 实验报告
UCORE lab1 system software startup process experimental report
STC-B学习板蜂鸣器播放音乐
Réponses aux devoirs du csapp 7 8 9
[pytorch] simple use of interpolate
软件测试工作太忙没时间学习怎么办?
Daily code 300 lines learning notes day 9
Leetcode notes - dynamic planning -day6
随机推荐
[HCIA continuous update] working principle of static route and default route
What if software testing is too busy to study?
软件测试面试回答技巧
The maximum number of words in the sentence of leetcode simple question
CSAPP家庭作业答案7 8 9章
[pytorch] simple use of interpolate
Interview answering skills for software testing
China's county life record: go upstairs to the Internet, go downstairs' code the Great Wall '
Want to change jobs? Do you know the seven skills you need to master in the interview software test
Do you know the advantages and disadvantages of several open source automated testing frameworks?
In Oracle, start with connect by prior recursive query is used to query multi-level subordinate employees.
软件测试方法有哪些?带你看点不一样的东西
遇到程序员不修改bug时怎么办?我教你
软件测试Bug报告怎么写?
基于485总线的评分系统双机实验报告
How to build a nail robot that can automatically reply
How to do agile testing in automated testing?
HackTheBox-Emdee five for life
51 lines of code, self-made TX to MySQL software!
CSAPP家庭作業答案7 8 9章