简介
今天购买了AXLINX AX7020的开发板,从今天开始每一个例程都要做文档记录,为自己加油。
本实验,基于ALINX AX7020开发板,芯片为xc7z020clg400-2。开发板输入时钟为50MHz。
1.UART协议介绍
UART是一种通用串行数据总线,用于异步通信。UART能实现双向通信,在嵌入式设计中,常用于主机与辅助设备通信。UART包括RS232、RS449、RS423等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。而RS232等式对应各种异步串行通信口的接口标准和总线标准,它们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。实际上是属于通信网络中的物理层(最底层)的概念,与通信协议并没有关系。
UART传输中,相关名词解释如下:
(1)波特率:每秒钟发送的符号数
(2)起始位:先发出一个逻辑0的信号,表示传输数据的开始
(3)数据位:衡量通信中实际数据位的参数。标准的数据位可以是5、7、8位,从最低位开始传输
(4)奇偶校验位:UART发送时,检查发送数据中1的个数,自动在奇偶校验位上添上1或0,用于发送数据的校验
数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。就比如传输“A”(01000001)为例:
当为奇数校验:“A”字符的8个bit位中有两个1,那么奇偶校验位为1才能满足1的个数为奇数(奇校验);
当为偶数校验:“A”字符的8个bit位中有两个1,那么奇偶校验位为0才能满足1的个数为偶数(偶校验);
(5)停止位:数据结束的标志,可以是1位、1.5位、2位的高电平
(6)空闲位:处于逻辑1的状态,表示当前线路上无数据传输
2.UART传输时序
**发送数据过程:**空闲状态,线路处于高电平,当收到发送数据指令后,拉低电平一个数据位的时间,接着数据按低位到高位依次发送,数据位发送完毕,接着发送奇偶校验位和停止位,停止位为高电平,一帧数据发送结束;
**接收数据过程:**空闲状态,线路处于高电平,当检测到线路的下降沿,说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后接着接收奇偶校验位并比较,看奇偶校验位是否正确,如果正确则通知接收端设备准备接收数据;
2.UART工程设计
UART_TOP模块中共包含三个子模块:
1、Baud_Clock模块用来产生115200的波特率时钟;
2、RX模块为接收(receive)模块,输入信号rx_pin为接收的序列数据,rx_ready为接收端的反压信号,只有当ready信号为高时才会输出rx_data数据,rx_valid用来表明什么时候rx_data有效。rx_erro输出接收的rx_pin序列的奇偶校验是否正确,0表示正确,1表示错误,若检验到错误,会要求发送端重发。
3、TX模块为发送(transmission)模块,输入信号为tx_data并行信号,tx_valid表示tx_data的有效性,tx_ready表示当前发送模块是否空闲;tx_pin为输出的串行数据,tx_erro为检错重发信号,当受到erro=1时就把ready=1拉高,重新发送上一次的数据;
3.RX模块(receive)
`timescale 1ns/1ps
module rx_control(
input clk,//50MHz
input rst_n,
input baud_clk,
input rx_pin,
output rx_erro,
input rx_ready,
output rx_valid,
output [6:0] rx_data
);
parameter IDLE = 4'b0001, RECEIVE = 4'b0010,
END = 4'b0100, ERRO = 4'b1000;
reg [3:0] state_curt; //current state
reg [3:0] state_next; //next state
reg [3:0] count;
reg [7:0] data;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
state_curt <= IDLE;
end
always@(posedge baud_clk)
begin
state_curt <= state_next;
end
always@(*)
begin
case(state_curt)
IDLE:
if(rx_pin==0)
state_next <= RECEIVE;
RECEIVE:
if(count==7)
begin
if((^data)==0)
state_next <= END;
else
state_next <= ERRO;
end
else
state_next <= state_next;
END:
if(rx_ready)
state_next <= IDLE;
else
state_next <= END;
ERRO:
state_next <= IDLE;
default :
state_next <= IDLE;
endcase
end
always@(posedge baud_clk)
begin
if(state_curt==RECEIVE)
count <= count +1'b1;
else
count <= 32'd0;
end
always@(posedge baud_clk)
begin
if(state_curt==RECEIVE)
begin
data[7] <= rx_pin;
data[6:0] <= data[7:1];
end
else
begin
if(state_curt==END | state_curt==ERRO)
data <= data;
else
data <= 8'b0;
end
end
assign rx_erro = (state_curt == ERRO)? 1'b1:1'b0;
assign rx_data = (state_curt == END )? data[6:0]:7'b0;
assign rx_valid= (state_curt == END )? 1'b1:1'b0;
endmodule
4.TX模块(transmission)
`timescale 1ns/1ps
module tx_control(
input clk,
input rst_n,
input baud_clk,
input tx_erro,
output reg tx_pin,
input tx_valid,
input [6:0] tx_data,
output tx_ready
);
parameter IDLE = 4'b0001, START = 4'b0010,
SEND = 4'b0100, END = 4'b1000;
reg [3:0] state_curt;
reg [3:0] state_next;
reg [7:0] data;
reg [7:0] r_data;
reg [3:0] count;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
state_curt <= IDLE;
end
always@(posedge baud_clk)
begin
state_curt <= state_next;
end
always@(*)
begin
case(state_curt)
IDLE:
if((tx_valid==1'b1)&(tx_erro==1'b0))
begin
state_next <= START;
r_data <= tx_data;
end
else
state_next <= IDLE;
START:
state_next <= SEND;
SEND:
if(count==3'd7)
state_next <= END;
else
state_next <= SEND;
END:
if((tx_valid==1'b1)&(tx_erro==1'b0))
begin
state_next <= START;
r_data <= tx_data;
end
else
state_next <= IDLE;
default:
state_next <= IDLE;
endcase
end
always@(posedge baud_clk)
begin
if(state_curt==SEND)
count <= count + 1'b1;
else
count <= 4'b0;
end
assign tx_ready = ((state_curt==IDLE)|(state_curt==END))? 1'b1:1'b0;
always@(posedge baud_clk)
begin
if(state_next==START)
begin
tx_pin <= 1'b0;
data[6:0] <= r_data;
data[7] <= ^r_data;
end
else
begin
if(state_next==SEND)
begin
tx_pin <= data[0];
data[6:0] <= data[7:1];
end
else
tx_pin <= 1'b1;
end
end
endmodule
5.Baud_Clock模块
`timescale 1ns/1ps
module baud_clock(
input clk,
input rst_n,
output baud_clk
);
parameter CLK_FRE = 32'd50;
parameter BAUD_RATE = 32'd115200;//波特率:1s传输的二进制码元个数
parameter CNT_NUM = CLK_FRE * 1000_000 / BAUD_RATE;
reg [31:0] count;
reg b_clk;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
count <= 32'd0;
b_clk <= 0;
end
else
begin
if(count == CNT_NUM-1)
begin
count <= 32'd0;
b_clk <= 1;
end
else
begin
count <= count + 32'd1;
b_clk <= 0;
end
end
end
assign baud_clk = b_clk;
endmodule