基于fpga uart学习笔记
2018年7月24日
uart 接收 部分测试成功,多谢开源骚客 邓堪文老师 ,想学的同学可以微信公众号搜索开源骚客
好啦!言归正传。
1.先附上老师的时序图,自己有点懒不想画,rx_t、rx_tt、rx_ttt分别对应源码中的rx_r1、rx_r2、rx_r2。
认真理解时序图,代码具体怎么实现就好理解了。
2.需要说明的是baud_cnt这个计数器,他是波特率的计数器,计数原理了解这个公式
3.剩下的就自己结合一下源码
1 `define SIM 2 3 module uart_rx( 4 //system signale 5 input sclk , 6 input s_rst_n , 7 //uart interface 8 input rs232_rx , 9 //other 10 output reg [7:0] rx_data , 11 output reg po_flag 12 13 ); 14 15 //-----------------------------------------------------------------\ 16 //***********Difine Parameter and Internal signals***************** 17 //-----------------------------------------------------------------/ 18 `ifndef SIM 19 localparam BAUD_END = 5207 ; 20 `else 21 localparam BAUD_END = 55 ; 22 `endif 23 localparam BAUD_M = BAUD_END/2-1 ; 24 localparam BIT_END = 8 ; 25 26 27 reg rx_r1 ; 28 reg rx_r2 ; 29 reg rx_r3 ; 30 reg rx_flag ; 31 reg [12:0] baud_cnt ; 32 reg bit_flag ; 33 reg [3:0] bit_cnt ; 34 35 //==================================================================\ 36 //****************Main Code ********************************* 37 //==================================================================/ 38 39 //捕获起始位下降沿 40 assign rx_neg = ~rx_r2 & rx_r3; 41 42 always @(posedge sclk ) begin 43 rx_r1 <= rs232_rx; 44 rx_r2 <= rx_r1; 45 rx_r3 <= rx_r2; 46 end 47 48 //接收数据标志 49 always @(posedge sclk or negedge s_rst_n) begin 50 if(s_rst_n == 1'b0) 51 rx_flag <= 1'b0; 52 else if(rx_neg == 1'b1) 53 rx_flag <= 1'b1; 54 else if(bit_cnt == 4'd0 && baud_cnt == BAUD_END) 55 rx_flag <= 1'b0; 56 end 57 58 //波特率生成 59 always @(posedge sclk or negedge s_rst_n ) begin 60 if(s_rst_n == 1'b0) 61 baud_cnt <= 13'd0; 62 else if(baud_cnt == BAUD_END) 63 baud_cnt <= 13'd0; 64 else if(rx_flag == 1'b1) 65 baud_cnt <= baud_cnt + 1'b1; 66 else 67 baud_cnt <= 13'd0; 68 end 69 70 //位接收有效 71 always @(posedge sclk or negedge s_rst_n) begin 72 if(s_rst_n == 1'b0) 73 bit_flag <= 1'b0; 74 else if (baud_cnt == BAUD_M) 75 bit_flag <= 1'b1; 76 else 77 bit_flag <= 1'b0; 78 end 79 80 //位计数 81 always @(posedge sclk or negedge s_rst_n) begin 82 if(s_rst_n == 1'b0) 83 bit_cnt <= 4'd0; 84 else if(bit_flag == 1'b1 && bit_cnt == BIT_END ) 85 bit_cnt <= 4'd0; 86 else if(bit_flag == 1'b1) 87 bit_cnt <= bit_cnt + 1'b1; 88 89 end 90 91 //串转并 92 always @(posedge sclk or s_rst_n) begin 93 if(s_rst_n == 1'b0) 94 rx_data <= 8'd0; 95 else if (bit_flag == 1'b1 && bit_cnt >= 4'd1) 96 rx_data <= {rx_r2, rx_data[7:1]}; 97 end 98 //一位接收完成 99 always @(posedge sclk or s_rst_n) begin 100 if(s_rst_n == 1'b0) 101 po_flag <= 1'b0; 102 else if(bit_cnt == BIT_END && bit_flag == 1'b1) 103 po_flag <= 1'b1; 104 else 105 po_flag <= 1'b0; 106 end 107 108 endmodule
4.源码这儿需要理解一下 `ifndef ,`else,`endif。这个是预编译处理,详情可以看这位大佬
https://blog.csdn.net/hision_fpgaer/article/details/50909653
5.测试文件,这里需要理解tast使用,以及外部数据文件的的用法(第26行)以及将文件里的数据如何存入二维数组中,tx_data文件就是一般的文本文件,这里设计的技巧太多,可以自己去查询一下。
1 `timescale 1ns/1ns 2 module tb_uart_rx; 3 4 reg sclk; 5 reg s_rst_n; 6 reg rs232_tx; 7 8 wire po_flag; 9 wire [7:0] rx_data; 10 11 reg [7:0] mem_a[4:0]; 12 13 initial begin 14 sclk = 1; 15 s_rst_n = 0; 16 rs232_tx = 1; 17 #100 18 s_rst_n = 1; 19 #100 20 tx_tyte(); 21 end 22 23 always # 10 sclk = ~sclk; 24 25 26 initial $readmemh("./tx_data.txt",mem_a); 27 28 task tx_tyte(); 29 integer i ; 30 for(i = 0;i < 4; i = i +1) begin 31 tx_bit(mem_a[i]); 32 end 33 34 endtask 35 36 37 task tx_bit( 38 input [7:0] data 39 ); 40 integer i; 41 for(i = 0; i < 10; i = i+1)begin 42 case(i) 43 0: rs232_tx <= 1'b0; 44 1: rs232_tx <= data[0]; 45 2: rs232_tx <= data[1]; 46 3: rs232_tx <= data[2]; 47 4: rs232_tx <= data[3]; 48 5: rs232_tx <= data[4]; 49 6: rs232_tx <= data[5]; 50 7: rs232_tx <= data[6]; 51 8: rs232_tx <= data[7]; 52 9: rs232_tx <= 1'b1; 53 endcase 54 #560; 55 end 56 endtask 57 58 uart_rx uart_rx_inst( 59 //system signale 60 .sclk (sclk ), 61 .s_rst_n (s_rst_n ), 62 //uart interface 63 .rs232_rx (rs232_tx ), 64 //other 65 .rx_data (rx_data ), 66 .po_flag (po_flag ) 67 68 ); 69 70 71 endmodule
总结一些自己,大一下学期期末左右接触到fpga,自己就爱好电子设计,大一一来就学了51单片机,下学期看着自己同学都报班32,学的都很好,而自己呢还在玩51,弄3D打印机,那个时候挺迷的。
后来不小心看到了fpga,自己仔细去查了,也与32做了比较,斟酌了很久,最后还是下决心学fpga,但是那个我是什么处境呢,同级的一起玩的32都会做很多东西了,自己有小小羞耻感,关键是学校没有人学fpga或者说没有人学的可以的,如果要学的话只能孤军奋战。
后来还是下决心买了板子,自学了一段时间,刚好暑假国赛,我也参加了,打击很大啊,最后还用51做,太丢人了。国赛完,我就自己瞎学fpga,一直因为对fpga的真正的喜爱,以及他那强大而又神秘能力支撑着我学到现在。
刚开始都是看着大佬们的博客一路学习过来,这学期终于翻身了开始自己写博客了,虽然技术含量有点低,哈哈哈,但是还是很开心。到现在差不多学fpga一年了,说实话fpga也让我害怕,不光是她太难驾驭还有的是没啥成就,看其他人啪啪啪的一下子做一堆东西,而自己控制个舵机都吃力。
现在这个暑假,马上又要大三了,趁着时间很多,好好重头在干一次,或许注定是孤独的,我爱你fpga,希望你也爱我,啦啦啦啦啦啦啦!!!!!!!!!!!!!!
完工回去睡觉,fpga等我明天再来宠幸你!
2018年7月26日
uart发送部分以及收发整合,其实是昨天就完事儿了,有事给耽搁了,今天再补来得及。
先说发送部分
1.还是先看时序图,信号都不用解释,直接看图。
2.仔细的同学发现bit_flag这个信号和接收的不一样,这次是baud_cnt波特率计数器记完再触发,而接收的是计数到一半触发,这两种方式作用相同,只是后者稳定一下,自己也可以改。
下面附上接收的源码
1// `define SIM 2 module uart_tx( 3 //system signal 4 input sclk , 5 input s_rst_n , 6 //uart interface 7 output reg rs232_tx , 8 //other 9 input tx_trig , 10 input [7:0] tx_data 11 ); 12 13 //-----------------------------------------------------------------\ 14 //***********Difine Parameter and Internal signals***************** 15 //-----------------------------------------------------------------/ 16 17 `ifndef SIM 18 localparam BAUD_END = 5207 ; 19 `else 20 localparam BAUD_END = 56 ; 21 `endif 22 23 localparam BAUD_M = BAUD_END/2-1 ; 24 localparam BIT_END = 8 ; 25 26 reg [7:0] tx_data_r ; 27 reg tx_flag ; 28 reg [12:0] baud_cnt ; 29 reg bit_flag ; 30 reg [3:0] bit_cnt ; 31 32 33 //==================================================================\ 34 //****************Main Code ********************************* 35 //==================================================================/ 36 //tx_data_r 37 always @(posedge sclk or negedge s_rst_n) begin 38 if(s_rst_n == 1'b0) 39 tx_data_r <= 8'd0; 40 else if (tx_trig == 1'b1 && tx_flag == 1'b0) 41 tx_data_r <= tx_data; 42 end 43 44 //tx_flag 45 always @(posedge sclk or negedge s_rst_n) begin 46 if(s_rst_n == 1'b0) 47 tx_flag <= 1'b0; 48 else if(tx_trig == 1'b1 ) 49 tx_flag <= 1'b1; 50 else if (bit_cnt == BIT_END && bit_flag == 1'b1) 51 tx_flag <= 1'b0; 52 end 53 54 //波特率计数器 55 always @(posedge sclk or negedge s_rst_n) begin 56 if(s_rst_n == 1'b0) 57 baud_cnt <= 13'd0; 58 else if (baud_cnt == BAUD_END) 59 baud_cnt <= 13'd0; 60 else if(tx_flag == 1'b1) 61 baud_cnt <= baud_cnt +1'b1; 62 else 63 baud_cnt <= 13'd0; 64 end 65 66 //bit_flag 67 always @(posedge sclk or negedge s_rst_n) begin 68 if(s_rst_n == 1'b0) 69 bit_flag <= 1'b0; 70 else if(baud_cnt == BAUD_END) 71 bit_flag <= 1'b1; 72 else 73 bit_flag <= 1'b0; 74 end 75 76 //bit_cnt 77 always @(posedge sclk or negedge s_rst_n) begin 78 if(s_rst_n == 1'b0) 79 bit_cnt <= 4'd0; 80 else if(bit_flag == 1'b1 && bit_cnt == BIT_END) 81 bit_cnt <= 4'd0; 82 else if (bit_flag == 1'b1) 83 bit_cnt <= bit_cnt +1'b1; 84 85 end 86 87 //rs232_tx 88 always @(posedge sclk or negedge s_rst_n) begin 89 if(s_rst_n == 1'b0) 90 rs232_tx <= 1'b1; 91 else if(tx_flag == 1'b1) 92 case(bit_cnt) 93 0: rs232_tx <= 1'b0; 94 1: rs232_tx <= tx_data_r[0]; 95 2: rs232_tx <= tx_data_r[1]; 96 3: rs232_tx <= tx_data_r[2]; 97 4: rs232_tx <= tx_data_r[3]; 98 5: rs232_tx <= tx_data_r[4]; 99 6: rs232_tx <= tx_data_r[5]; 100 7: rs232_tx <= tx_data_r[6]; 101 8: rs232_tx <= tx_data_r[7]; 102 default:rs232_tx <= 1'b1; 103 endcase 104 else 105 rs232_tx <= 1'b1; 106 end 107 108 endmodule
3.下面附上接收部分的激励源码
1 `timescale 1ns/1ns 2 3 module tb_uart_tx; 4 5 reg sclk; 6 reg s_rst_n; 7 reg tx_trig; 8 reg [7:0] tx_data; 9 wire rs232_tx; 10 //----------------------------------difine system signales----------------- 11 initial begin 12 sclk = 1; 13 s_rst_n = 0; 14 #100 15 s_rst_n = 1; 16 end 17 18 always #10 sclk = ~sclk; 19 20 //----------------------------------------------------------------------- 21 initial begin 22 tx_data <= 8'd0; 23 tx_trig <= 0; 24 25 #200 26 tx_trig <= 1'b1; 27 tx_data <= 8'h55; 28 #20 29 tx_trig <= 1'b0; 30 31 #20000 32 tx_trig <= 1'b1; 33 tx_data <= 8'h78; 34 #20 35 tx_trig <= 1'b0; 36 37 #20000 38 tx_trig <= 1'b1; 39 tx_data <= 8'h53; 40 #20 41 tx_trig <= 1'b0; 42 43 end 44 45 uart_tx uart_tx_inst( 46 //system signal 47 .sclk (sclk ), 48 .s_rst_n (s_rst_n ), 49 //uart interface 50 .rs232_tx (rs232_tx ), 51 //other 52 .tx_trig (tx_trig ), 53 .tx_data (tx_data ) 54 ); 55 56 endmodule
最后收发整合前面接收和发送部分都做好的话,这个就很简单了,但是这儿注意一个细节,把模块第一行的 ” `define SIM“给注释掉,这个是仿真用的,不然烧写到板卡不对
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 module uart_top( 2 //system signals 3 input sclk , 4 input s_rst_n , 5 //UART Interface 6 input rs232_rx , 7 output wire rs232_tx 8 ); 9 10 //-----------------------------------------------------------------\ 11 //***********Difine Parameter and Internal signals***************** 12 //-----------------------------------------------------------------/ 13 wire [7:0] rx_data ; 14 wire tx_trig ; 15 //==================================================================\ 16 //****************Main Code ********************************* 17 //==================================================================/ 18 19 uart_rx uart_rx_inst( 20 //system signale 21 .sclk (sclk ), 22 .s_rst_n (s_rst_n ), 23 //uart interface 24 .rs232_rx (rs232_rx ), 25 //other 26 .rx_data (rx_data ), 27 .po_flag (tx_trig ) 28 29 ); 30 31 32 uart_tx uart_tx_inst( 33 //system signal 34 .sclk (sclk ), 35 .s_rst_n (s_rst_n ), 36 //uart interface 37 .rs232_tx (rs232_tx ), 38 //other 39 .tx_trig (tx_trig ), 40 .tx_data (rx_data ) 41 ); 42 43 44 endmodule
uart学习到此为止了,已完成