基于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“给注释掉,这个是仿真用的,不然烧写到板卡不对
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学习到此为止了,已完成