Zynq开发实践(FPGA之uart发送)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
fpga作为独立的模块,本身肯定有很多的优势,当然也有缺点,价格就是缺点。不过fpga很少是独立使用的,它得和其他嵌入式板子通信,或者是直接和pc进行通信。通信的方法很多,有uart、iic和spi,这几种是经常出现的方式。这里面最简单的就是uart,因为它比较简单,发送就是tx,接收就是rx。
1、uart的波特率
uart的发送频率一般都不快,从4800到115200都可以。当然,也可以发送得更快一点,比如说115200的2倍、4倍等等,这需要看接收方支不支持。
2、发送的格式
uart空闲状态一般是拉高。一次uart可以发送一个字节,发送的时候有起始位、数据位、校验位、停止位四个部分。校验位大部分不添加,所以就是剩下来的三个部分。其中数据位一般是8位为主,起始位是0,停止位是1。数据位也是从低到高,一个bit、一个bit发送。
3、一般先开发发送功能
针对各种通信协议,我们一般都是先开发发送功能。发送验证好了,就可以继续验证接收功能。比如,这个时候就可以通过回环发送的形式,验证发送模块是不是ok。这样借助于回环检测,就可以把发送和接收都验证好了。
4、串口发送的实现
整个串口发送是从计数器开始的,因为发送的频率不同,所以需要确认发送的时候,计数器的大小是多少,
always@(posedge clk or negedge rst)if(!rst)counter <= 16'h0;else if(state != 3'h0) beginif(counter != `BAUD_CNT)counter <= counter + 1;elsecounter <= 16'h0;end
至于状态机切换,直接根据串口的发送顺序,用传统的三段式方法去编写即可,
// state machinealways@(posedge clk or negedge rst)if(!rst)state <= 3'h0;elsestate <= next_state;// about next_statealways@(*)if(!rst)next_state = 3'h0;else if(state == 3'h0 && out_valid)next_state = 3'h1; // first bitelse if(state == 3'h1 && counter == `BAUD_CNT)next_state = 3'h2; // send dataelse if(state == 3'h2 && num == 7 && counter == `BAUD_CNT)next_state = 3'h3; // send stopelse if(state == 3'h3 && counter == `BAUD_CNT)next_state = 3'h0;elsenext_state = state;
发送数据的时候由于需要计数处理,所以要对num进行计数,
// num of sending signalalways@(posedge clk or negedge rst)if(!rst)num <= 3'h0;else if(state == 3'h2 && counter == `BAUD_CNT)num <= num + 1;
最后就是依次发送数据,并且及时通知接收端当前可以继续发送其他数据了,
// about sending dataalways@(posedge clk or negedge rst)if(!rst)out_data <= 8'd0;else if(state == 3'h0 && out_valid)out_data <= data;// tx signalalways@(*)if(!rst)tx = 1'b1;else if(state == 3'h1)tx = 1'b0;else if(state == 3'h2)tx = out_data[num];elsetx = 1'b1;// about statusalways@(posedge clk or negedge rst)if(!rst)accept_status <= 1'b1;else if(state !=3'h0 )accept_status <= 1'b0;elseaccept_status <= 1'b1;
5、测试和验证
验证部分,直接使用testbench即可,首先我们先准备一个testbench文件,
`timescale 1ns/1ps
module test();reg rst;
reg clk;
reg out_valid;
reg[7:0] data;
wire tx;
wire accept_status;initialbeginrst = 1;clk = 0;out_valid = 0;data = 48;#12 rst = 0;#21 rst = 1;#30 out_valid = 1;#50 out_valid = 0;#10000 $finish;endinitial
beginwhile(1)clk = #5 !clk;
enduart_tx uart_tx(.rst(rst),.clk(clk),.out_valid(out_valid),.data(data),.tx(tx),.accept_status(accept_status));initial
begin$dumpfile("hello.vcd");$dumpvars(0, test);
endendmodule
接下来的工作就和之前一样,直接仿真运行,查看波形即可,