选题缘由:前几天在黑金时序篇的陪伴下,对FIFO进行了大致的掌握,今天看特权同学的深入浅玩转FPGA进阶实验五:基于FIFO的串口发送机设计,想自己总该动手练练,总看别人的code也能学到东西,但那终究不是自己的,当自己独自面对时,会冒出不少原本看似没有问题的问题。可喜的是这次竟然没遇到多大困难,一个小时多一点写好代码,解决问题不到十分钟,然后搞定!难道自己水平有所提高了,哈哈!
本实验RTL图:
本实验实现如下功能:Data_gene模块每隔1s产生一个递增的8位数(在助手里边以16进制方式显示),然后每隔1s wrreq发送一个高电平,写入FIFO,本实验FIFO采用8 wide,256deepth,但是这个深度似乎是没有作用的,后边再解释。受黑金大大影响,发送模块采用仿顺序写法,并引出了Start_sig和Done_sig,Start_sig和FIFO的empty相连,一旦FIFO不为空,则启动串口发送过程,一旦完成发送则马上使能读FIFO,因此FIFO里边的数据就是进来一个马上发送出去的过程,因此深度在这里是无意义的……再说FIFO,FIFO是用向导生成的,在第一页选了同步读写时钟,第二页选择保留empty输出,第四页选择关闭电路保护,上面说“如不需要,数据溢出以及数据不足将不会被检查,如此以提高系统性能”,不明白的是,如果不检查下溢,怎么会输出empty?目前实验没问题,就先不纠结了。确实有时候很多细节要理清头绪,需要花太多的时间。
“时序分析”:起始时刻--FIFO为空,empty输出为1,232模块停止,1s时刻在,wrreq赋值为1,Data_out赋值为1,下一个CLk时刻,wrreq赋值为0,但非阻塞赋值的特性使得FIFO写入一个Data_out的值,即1。此时FIFO不再为空,empty为0,232模块开始运行,但由于此刻FIFO没有输出,所以232模块运行但无发送数据,232发送完,Send_done产生一个高电平,读FIFO使能,此刻,FIFO有输出,但empty输出变为1(FIFO空),232模块停止,Q一直保持第一次的输出数据:1。约1s后,数据生成模块产生新的数据2读进FIFO,empty为0,232模块使能,将1发送出去,产生完成信号。。如此往复。也即:232模块发出Send_done后,离下次真正232发送数据的间隔为1s。
下面给出2个.v文件及顶层的纯组合.v文件(FIFO文件就不给了):
1 module Data_gene(Clk,Rstn,wrreq,Data_out); 2 3 input Clk,Rstn; 4 output wrreq; 5 output [7:0] Data_out; 6 7 parameter T1s=26'd49_999_999; 8 9 reg [25:0] i;10 reg [7:0] Data;11 reg wrreq;12 always@(posedge Clk or negedge Rstn)13 if(!Rstn)14 begin15 Data<=1'b0;16 wrreq<=1'b0;17 end18 else if(i==T1s)19 begin20 wrreq<=1'b1;21 i<=1'b0;22 Data<=Data+1'b1;23 end24 else25 begin26 i<=i+1'b1;27 wrreq<=1'b0;28 end29 30 assign Data_out=Data;31 endmodule
刚连接好各模块后进行的第一次实验时,发现串口助手并非接收到的是每隔1s的一个递增的2位16进制数,后来看RTL图,猛然意识到自己在程序中始终赋予wrreq为1,那么FIFO以及发送模块都是在系统Clk的拍子下,不停的读入FIFON多个相同的数,然后在发送模块不停的发送N多个相同的数……果断在一秒时赋予wrreq值为1,其他时刻均为0,问题完美解决!
1 module rx_232(Clk,Rstn,Data_in,Start_sig,Done_sig,Send_data); 2 3 input Clk,Rstn,Start_sig; 4 input [7:0] Data_in; 5 output Done_sig,Send_data; 6 7 reg isDone,Send_out; 8 9 /**********************************************/10 parameter Bps_9600=13'd5208;11 reg [12:0] count;12 always@(posedge Clk or negedge Rstn)13 if(!Rstn)14 count<=1'b0;15 else if(!Start_sig)16 if(count==Bps_9600)17 count<=1'b0;18 else19 count<=count+1'b1;20 else21 count<=1'b0;22 /**********************************************/23 reg [3:0] i;24 25 always@(posedge Clk or negedge Rstn)26 if(!Rstn)27 begin28 i<=1'b0;29 Send_out<=1'b0;30 isDone<=1'b0;31 end32 else33 case(i)34 0:if(count==Bps_9600) i<=i+1'b1;//Idle35 else Send_out<=1'b1;36 1:if(count==Bps_9600) i<=i+1'b1;//Startbit37 else Send_out<=1'b0;38 2,3,4,5,6,7,8,9:39 if(count==Bps_9600) i<=i+1'b1;//Zerobit to Sevenbit40 else Send_out<=Data_in[i-2];41 42 10:if(count==Bps_9600) i<=i+1'b1;//Checkout random43 else Send_out<=1'b0;44 11:if(count==Bps_9600) i<=i+1'b1;//Stopbit45 else Send_out<=1'b1;46 12:begin isDone<=1'b1;i<=i+1'b1;end47 13:begin isDone<=1'b0;i<=1'b0;end48 endcase 49 50 /**********************************************/51 assign Done_sig=isDone;52 assign Send_data=Send_out;53 54 endmodule 55 56 57
波特率为9600bps,含有一位校验位。
1 module FIFO_232(Clk,Rstn,Send_data); 2 input Clk,Rstn; 3 output Send_data; 4 5 wire wrreq; 6 wire [7:0] Data_out; 7 8 Data_gene U1( 9 .Clk(Clk),10 .Data_out(Data_out),11 .Rstn(Rstn),12 .wrreq(wrreq)13 );14 15 wire Done_sig,Start_sig;16 wire [7:0]Data_in;17 18 FIFO U2(19 .clock ( Clk ),20 .data ( Data_out ),21 .rdreq ( Done_sig ),22 .wrreq ( wrreq ),23 .empty ( Start_sig ),24 .q ( Data_in )25 );26 27 rx_232 U3(28 .Clk(Clk),29 .Rstn(Rstn),30 .Data_in(Data_in),31 .Start_sig(Start_sig),32 .Done_sig(Done_sig),33 .Send_data(Send_data)34 );35 36 endmodule
这个真的是纯组合模块…… 由于实例化的时候,不是实例化了一个文件,而是涉及多个模块之间的相互连接,那么wire连接线类型在这里边体现的淋漓尽致……
最后给出串口助手图,下边的tx就像是秒针那样加一……
这些都是基础的、粗略的、思路简单的…… 要走的路还有很长,离1W小时还有很远,但不放弃,终有一天可达到……
↖(^ω^)↗