-
在设计FPGA时,多运用模块化的思想取设计模块,将某一功能设计成module。
-
设计之前要先画一下模块设计图,列出输入输出接口,再进一步设计内部功能。
-
状态机要画图,确定每个状态和状态之间怎么切换。状态用localparam定义。
-
顶层向下传递的要定义为wire,底层向上传递的要定义为reg。
-
根据时序将每一个时钟周期进行按步分解。对于通讯协议要对每条线仔细分析。
-
每个模块要用一个tb测试
-
testbench例子
always #10 Clk = ~Clk;initial beginClk = 1;Rst_n = 0;Cmd = 6'b000000;Go = 0;Tx_DATA = 8'd0;#2001;Rst_n = 1;#2000;//写数据操作,往EEPROM器件的B1地址写数据DA//第一次:起始位+EEPROM器件地址(7位)+写方向(1位)Cmd = STA | WR;Go = 1;Tx_DATA = 8'hA0 | 8'd0;//写方向@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;//第二次:写8位EEPROM的寄存器地址Cmd = WR;Go = 1;Tx_DATA = 8'hB1;//写地址B1@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;//第三次:写8位数据 + 停止位Cmd = WR | STO;Go = 1;Tx_DATA = 8'hda;//写数据DA@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;#5000000; //仿真模型的两次操作时间间隔//读数据操作,从EEPROM器件的B1地址读数据//第一次:起始位+EEPROM器件地址(7位)+写方向(1位)Cmd = STA | WR;Go = 1;Tx_DATA = 8'hA0 | 8'd0;//写方向@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;//第二次:写8位EEPROM的寄存器地址Cmd = WR;Go = 1;Tx_DATA = 8'hB1;//写地址B1@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;//第三次:起始位+EEPROM器件地址(7位)+读方向(1位)Cmd = STA | WR;Go = 1;Tx_DATA = 8'hA0 | 8'd1;//读方向@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;//第四次:读8位数据 + 停止位Cmd = RD | STO;Go = 1;@ (posedge Clk);#1;Go = 0;@ (posedge Trans_Done);#200;#2000;$stop;end
-
每个模块要建立一个testbench
-
时钟分频
//系统时钟采用50MHzparameter SYS_CLOCK = 50_000_000;//SCL总线时钟采用400kHzparameter SCL_CLOCK = 400_000;//产生时钟SCL计数器最大值localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK/4 - 1;reg [19:0]div_cnt;reg en_div_cnt;always@(posedge Clk or negedge Rst_n)if(!Rst_n)div_cnt <= 20'd0;else if(en_div_cnt)beginif(div_cnt < SCL_CNT_M)div_cnt <= div_cnt + 1'b1;elsediv_cnt <= 0;endelsediv_cnt <= 0;wire sclk_plus = div_cnt == SCL_CNT_M;
-
串转并
reg[7:0]Rx_DATA;
Rx_DATA <= {Rx_DATA[6:0],i2c_sdat};
-
命令可以选择使用独热码编码
localparam
IDLE = 7'b0000001, //空闲状态
GEN_STA = 7'b0000010, //产生起始信号
WR_DATA = 7'b0000100, //写数据状态
RD_DATA = 7'b0001000, //读数据状态
CHECK_ACK = 7'b0010000, //检测应答状态
GEN_ACK = 7'b0100000, //产生应答状态
GEN_STO = 7'b1000000; //产生停止信号
-
亚稳态
跨时钟域信号传输;异步信号采集;复位电路。
在FPGA系统中,如果数据传输中不满足触发器的Tsu和Th不满足,或者复位过程中复位信号的释放相对于有效时钟沿的恢复时间(recovery time)不满足,就可能产生亚稳态,此时触发器输出端Q在有效时钟沿之后比较长的一段时间处于不确定的状态,在这段时间里Q端在0和1之间处于振荡状态,而不是等于数据输入端D的值。这段时间称为决断时间(resolution time)。经过resolution time之后Q端将稳定到0或1上,但是稳定到0或者1,是随机的,与输入没有必然的关系。
异步信号采集
always@(posedge clk or posedge reset)if(reset)beginuart_rx_sync1 <= 1'b0;uart_rx_sync2 <= 1'b0;endelse beginuart_rx_sync1 <= uart_rx;uart_rx_sync2 <= uart_rx_sync1;
end
边沿检测
//下降沿检测
always@(posedge clk or posedge reset)
if(reset)beginuart_rx_reg1 <= 1'b0;uart_rx_reg2 <= 1'b0;
end
else beginuart_rx_reg1 <= uart_rx_sync2;uart_rx_reg2 <= uart_rx_reg1;
endassign uart_rx_nedge = !uart_rx_reg1 & uart_rx_reg2;