uart部分
SOC中一般必不可少uart串口,是异步收发(不用同一个时钟信号)传输接口,且只能一个bit一个bit进行传输。
标准传输一个字符需要1bit(起始位)+7bit(数据位)+1bit(校验位)+1bit(结束位),也就是说传输一个标准的字符需要传输十位,将在后面详细介绍。
波特率:谈到波特率之前先说一下比特率,譬如比特率为9600意味着每秒传输9600个bit,两相调制时波特率和比特率相同,导致很多人以为这是一个东西,当四相调制或八相调制乃至16时时,比特率就是波特率的2倍和三、四倍。所谓波特率,就是传输码元的速率,当四相调制时,就需要两个比特来表示一个码元了,以此类推。过于复杂的电磁环境不宜使用过高的波特率,波特率高了意味着每个bit时间短了,在这样的环境容易出错。
uart 协议传输图
传输数据位包括以下几个部分:
1,空闲位:
UART协议规定,当总线处于空闲状态时信号线的状态为‘1’即高电平,表示当前线路上没有数据传输。
2,起始位:
每开始一次通信时发送方先发出一个逻辑”0”的信号(低电平),表示传输字符的开始。因为总线空闲时为高电平所以开始一次通信时先发送一个明显区别于空闲状态的信号即低电平。
3,数据位:
起始位之后就是我们所要传输的数据,数据位可以是5、6、7、8,9位等,构成一个字符(一般都是8位)。如ASCII码(7位),扩展BCD码(8位)。先发送最低位,最后发送最高位,使用低电平表示‘0’高电平表示‘1’完成数据位的传输。
4,奇偶校验位:
数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。校验位其实是调整个数,串口校验分几种方式:
1)无校验(no parity)。
2)奇校验(odd parity):如果数据位中“1”的数目是偶数,则校验位为“1”,如果“1”的数目是奇数,校验位为“0”。
3)偶校验(even parity):如果数据为中“1”的数目是偶数,则校验位为“0”,如果为奇数,校验位为“1”。
4)mark parity:校验位始终为1(不常用)。
5)parity:校验位始终为0(不常用)。
那么利用uart进行Verilog编程时我们需要定义哪些输入输出端口呢。
发送部分;clk(时钟),rstn(复位),en(使能),uart_tx(输出信号端),还有一个8位片上输入数据端wdata_in_uart,最后传输完成还有一个完成标志,代码入下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/05/26 16:10:58
// Design Name:
// Module Name: uart_send
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_send #(
parameter freq=50000000, //trime frequncy
parameter bps=9600 //baud fre
)(
input clk,
input rstn,
input [7:0] wdata_i_uart,
input tx_en,
output reg uart_tx, //output send data (a time a bit)
output send_done
);
localparam bps_cnt=freq/bps;
reg tx_flag;//send flag
reg [15:0] bps_cnt_reg;
reg [3:0] tx_cnt;
reg [7:0] tx_data;
//
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
bps_cnt_reg<=16'b0;
tx_cnt<=4'b0;
end
else if(bps_cnt_reg<bps_cnt-1'b1) begin
bps_cnt_reg<= bps_cnt_reg+1'b1;
tx_cnt<=tx_cnt+1'b1;
end
else begin
bps_cnt_reg<= 16'b0;
tx_cnt<=tx_cnt;
end
end
//
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
tx_flag<=1'b0;
tx_data<=8'b0;
end
else if(tx_en)begin
tx_flag<=1'b1;
tx_data<=wdata_i_uart;
end
else if((tx_cnt==4'h9)&&(bps_cnt==bps_cnt_reg/2)) begin
tx_flag<=1'b0;
tx_data<=8'b0;
end
else begin
tx_flag<=tx_flag;
tx_data<=tx_data;
end
end
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
uart_tx<=1'b1;
end
else begin
if(tx_flag)begin
case(tx_cnt)
4'd0:uart_tx<=1'b0; //begin data
4'd1:uart_tx<=tx_data[0];
4'd2:uart_tx<=tx_data[1];
4'd3:uart_tx<=tx_data[2];
4'd4:uart_tx<=tx_data[3];
4'd5:uart_tx<=tx_data[4];
4'd6:uart_tx<=tx_data[5];
4'd7:uart_tx<=tx_data[6];
4'd8:uart_tx<=tx_data[7];
4'd9:uart_tx<=1'b1;//stop data
4,b10:send_done<=1'b1;
default:begin uart_tx<=1'b0; send_done<=1'b1; end
endcase
end
else begin
uart_tx<=1'b1;
end
end
end
endmodule
接收part
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/05/26 20:52:54
// Design Name:
// Module Name: uart_recv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
uart rx module
module uart_recv #(
parameter bps=9600,
parameter freq=50000000 //clock freq
)(
input clk,
input rstn,
input uart_rx,
output reg [7:0] tx_data,
output reg rx_done,
input write_uart
);
localparam bps_cnt=freq/bps;
wire start_flag;
reg uart_rxd1;
reg uart_rxd2;
reg rx_flag;
reg [3:0] rx_cnt;
reg [15:0] bps_cnt_reg;
reg [7:0] reg_data;
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
uart_rxd1<=0;
uart_rxd2<=0;
end
else begin
uart_rxd1<=uart_rx;
uart_rxd2<=uart_rxd1;
end
end
//
assign start_flag=uart_rxd2&(~uart_rxd1);
//
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
rx_flag<=1'b0;
end
else if(start_flag)begin
rx_flag<=1'b1;
end
else if((bps_cnt_reg==bps_cnt/2)&(rx_cnt==4'd9)) begin
rx_flag<=1'b0;
end
else
rx_flag<=rx_flag;
end
///
always@(posedge clk or negedge rstn) begin
if(!rstn) begin
bps_cnt_reg<=16'b0;
rx_cnt<=4'b0;
end
else if(rx_flag)begin
if(bps_cnt_reg<bps_cnt-1'b1)begin//一个数据传输周期长度为50000000/9600个周期
bps_cnt_reg<=bps_cnt_reg+1'b1;
rx_cnt<=rx_cnt;
end
else begin
bps_cnt_reg<=16'b0;
rx_cnt<=rx_cnt+1'b1;
end
end
else begin
bps_cnt_reg<=16'b0;
rx_cnt<=4'b0;
end
end
always@(posedge clk or negedge rstn) begin
if(!rstn)begin
reg_data<=8'b0;
rx_done<=1'b0;
end
else if(rx_flag)
case(rx_cnt)
4'd0:begin reg_data[1]<=uart_rx; rx_done<=1'b0; end
4'd1:reg_data[2]<=uart_rx;
4'd2:reg_data[3]<=uart_rx;
4'd3:reg_data[4]<=uart_rx;
4'd4:reg_data[5]<=uart_rx;
4'd5:reg_data[6]<=uart_rx;
4'd6: begin reg_data[6]<=uart_rx; rx_done<=1'b0; end
4'd7:begin reg_data[7]<=uart_rx; rx_done<=1'b1; end
4'd8:begin rx_done<=1'b0; end
default: rx_done<=1'b0;
endcase
else
reg_data<=reg_data;
end
always@(posedge clk or negedge rstn) begin
if(!rstn)begin
tx_data<=8'b0;
end
else if(!write_uart)begin
tx_data<=reg_data;
end
//
end
endmodule
uart—top模块,由于这是挂靠在SOC总线下,所以有地址,多位数据总线,这里的总线需要将数据分为四块,依次发出和写入,本次分为四块。代码详情如下
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/05/26 22:15:05
// Design Name:
// Module Name: uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//address number is 32'b0000_0000-32'b0fffffff
module uart_top #(
parameter bps=9600,
parameter freq=50000000
)(
input clk,
input rstn,
input write,
output wire uart_tx, //slave
input wire[31:0]tx_data_indata,
output reg [31:0] rx_data_outdata,
input wire uart_rx_in_slave,
output wire sign_done,
input [31:0] addr_i_uart//master
);
reg write_reg;
reg [31:0] tx_data_in_reg;
wire [31:0] rx_data_out_wire;
reg [2:0]cnt_tx;
reg [2:0]cnt_rx;
wire [7:0] tx_data;
reg [7:0] rx_data;
wire uart_tx_salve;
//assign rx_data_out_wire=rx_data_out;
reg [31:0]tx_data_in;
reg sign_in_out;
always@(posedge clk) begin
if(!rstn) begin
tx_data_in<=32'b0;
rx_data_outdata<=32'b0;
end
else if(sign_in_out==1)begin
tx_data_in<=tx_data_indata;
rx_data_outdata<=tx_data_in_reg;
end
end
///
always@(posedge clk) begin
if(!rstn) begin
cnt_tx<=0;
tx_data_in_reg<=32'b0;
rx_data<=0;
end
else if(sign_done) begin
cnt_tx<=cnt_tx+1'b1;
tx_data_in_reg<={tx_data_in_reg[31:8],tx_data};
tx_data_in<=tx_data_in>>8;
rx_data<=tx_data_in[7:0];
if(cnt_tx==3'b100) begin
sign_in_out=1;
end
else begin
sign_in_out=0;
end
end
else if(cnt_tx>3'b100) begin
cnt_tx<=0;
tx_data_in_reg<=32'b0;
rx_data<=0;
end
end
localparam reg_csr=8'h00;
localparam reg_br=8'h04; //r=response
localparam reg_datar=8'h08;
wire reg_csr_w;
wire reg_br_w;
wire reg_data_w;
assign reg_csr_w=(reg_csr==addr_i_uart[7:0]);
assign reg_br_w=(reg_br==addr_i_uart[7:0]);
assign reg_data_w=(reg_datar==addr_i_uart[7:0]);
///recv module
uart_recv #(
.bps(bps),
.freq(freq) //clock freq
)uart_recv_inst(
.clk(clk),
.rstn(rstn),
.uart_rx(uart_rx_in_slave), //input
.tx_data(tx_data), //output
.rx_done(sign_done),
.write_uart(write)
);
///
uart_send #(
.freq(freq), //trime frequncy
.bps(bps) //baud fre
)uart_send_inst(
.clk(clk),
.rstn(rstn),
.wdata_i_uart(rx_data),//input
.tx_en(write),
.uart_tx(uart_tx), //output send data (a time a bit)
.send_done(sign_done)
);
endmodule