07、安路SparkRoad国产FPGA测评【学习篇】串口回环实验
[复制链接]
本帖最后由 1nnocent 于 2022-7-30 09:10 编辑
该例程实现串口回环实验,FPGA 实时监测 uart_rx 信号是否有数据, 若接收到 PC 端发送的数据, 则把接收到的数据通过 uart_tx 返回给 PC 端。先下载程序试下效果,发现PC端发送数据时,没有现象,检查了原理图和管脚约束文件发现是管脚约束时例程使用的不是USB对应的引脚,通过原理图可知TX_RX对应的引脚分别为F16_E16。
修改引脚后功能正常。
先看下一步串口通讯的数据格式:首先是起始位,空闲时为高电平,起始位时拉低电平,之后是数据位,校验位和停止位,停止位时拉高电平。
例程顶层模块的输入接口为25MHz时钟,外部复位(对应中间的按键)、输入引脚(rx_引脚)、输出引脚(tx_引脚)。
波特率设置模块(波特率为9600,时钟周期40ns_):其中bps_start是uart_tx引脚捕获的起始位信号,clk_bps位波特率采样中点。
module speed_setting
#(
parameter BPS_SET = 96, // 波特率
parameter CLK_PERIORD = 40 // 系统时钟周期 40ns(25MHz)
)
(
input clk, // 25MHz 系统时钟
input rst_n, // 系统复位
input bps_start, // 捕获起始信号的脉冲信号
output clk_bps // 波特率采样中点脉冲信号
);
`define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET) // 10_000_000/`CLK_PERIORD/96;
`define BPS_PARA_2 (`BPS_PARA/2) // BPS_PARA/2;
reg [12:0] cnt; // 为得到指定的波特率,需要对系统时钟进行计数
reg clk_bps_r; // 接收过程标志信号 寄存器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 13'd0;
else if((cnt == `BPS_PARA) || !bps_start) // 捕获起始信号后开始波特率计数
cnt <= 13'd0; // 计时到指定波特率次数后清零
else
cnt <= cnt + 1'b1; // 否则计数器自加
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_bps_r <= 1'b0;
else if(cnt == `BPS_PARA_2)
clk_bps_r <= 1'b1; // 波特率采样中点标志
else
clk_bps_r <= 1'b0;
end
assign clk_bps = clk_bps_r;
endmodule
rx_接收模块:该模块捕获下降沿时使用的四个寄存器uart_rx0、uart_rx1、uart_rx2、uart_rx3,捕获的下降沿用于产生波特率模块。该模块主要功能是接收数据,把rx_引脚上的数据进行串转并的功能。
module my_uart_rx
(
input clk, // 25MHz 系统时钟
input rst_n, // 系统复位
input uart_rx, // uart_rx 输入引脚
output [7:0] rx_data, // uart_rx 接收数据
output rx_int, // 接收过程标志信号
input clk_bps, // 波特率采样中点
output bps_start // 捕获的起始位脉冲信号
);
//----------------------------------------------------------------
reg uart_rx0,uart_rx1,uart_rx2,uart_rx3; // 起始位下降沿信号寄存器
wire neg_uart_rx;
always @ (posedge clk or negedge rst_n) // 起始位下降沿信号寄存
begin
if(!rst_n)
begin
uart_rx0 <= 1'b0;
uart_rx1 <= 1'b0;
uart_rx2 <= 1'b0;
uart_rx3 <= 1'b0;
end
else
begin
uart_rx0 <= uart_rx;
uart_rx1 <= uart_rx0;
uart_rx2 <= uart_rx1;
uart_rx3 <= uart_rx2;
end
end
assign neg_uart_rx = uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0; // 捕获起始位下降沿信号
//----------------------------------------------------------------
reg bps_start_r; // 起始位脉冲信号寄存器
reg [3:0] num;
reg rx_int; // 接收过程标志信号
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
bps_start_r <= 1'bz;
rx_int <= 1'b0;
end
else if(neg_uart_rx)
begin // 捕获起始位下降沿
bps_start_r <= 1'b1; // 起始位脉冲信号置一
rx_int <= 1'b1; // 接收过程标志信号置一
end
else if(num == 4'd9)
begin // 接收到停止位
bps_start_r <= 1'b0; // 起始位脉冲信号置零
rx_int <= 1'b0; // 接收过程标志信号置零
end
end
assign bps_start = bps_start_r;
//----------------------------------------------------------------
reg [7:0] rx_data_r; // 接收数据寄存器
reg [7:0] rx_temp_data; // 临时接收数据寄存器
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rx_temp_data <= 8'd0;
num <= 4'd0;
rx_data_r <= 8'd0;
end
else if(rx_int)
begin // 接收过程标志信号为一时
if(clk_bps) // 波特率采样中点时,寄存接收数据
begin
num <= num+1'b1;
case (num)
4'd1: rx_temp_data[0] <= uart_rx; //寄存接收数据0bit
4'd2: rx_temp_data[1] <= uart_rx; //寄存接收数据1bit
4'd3: rx_temp_data[2] <= uart_rx; //寄存接收数据2bit
4'd4: rx_temp_data[3] <= uart_rx; //寄存接收数据3bit
4'd5: rx_temp_data[4] <= uart_rx; //寄存接收数据4bit
4'd6: rx_temp_data[5] <= uart_rx; //寄存接收数据5bit
4'd7: rx_temp_data[6] <= uart_rx; //寄存接收数据6bit
4'd8: rx_temp_data[7] <= uart_rx; //寄存接收数据7bit
default: ;
endcase
end
else if(num == 4'd9)
begin
num <= 4'd0; // 停止位时,清零接收数据计数器
rx_data_r <= rx_temp_data; // 寄存临时接收数据寄存器的数据
end
end
end
assign rx_data = rx_data_r;
endmodule
发送模块,该模块的功能主要是将接收的数据进行并转串,并发送给PC端。发送模块与接受模块不同的地方是需要发送起始位和停止位。
module my_uart_tx
(
input clk, // 系统时钟
input rst_n, // 复位信号
input [7:0] rx_data, // 接收到的数据
input rx_int, // 接收过程标志信号
output uart_tx, // uart_tx 输出引脚
input clk_bps, // 波特率采样中点
output bps_start // 捕获的结束位脉冲信号
);
//---------------------------------------------------------
reg rx_int0,rx_int1,rx_int2; // 接收过程标志信号寄存器
wire neg_rx_int; // 接收过程标志信号下降沿
always @ (posedge clk or negedge rst_n) // 寄存接收过程标志信号
begin
if(!rst_n)
begin
rx_int0 <= 1'b0;
rx_int1 <= 1'b0;
rx_int2 <= 1'b0;
end
else
begin
rx_int0 <= rx_int;
rx_int1 <= rx_int0;
rx_int2 <= rx_int1;
end
end
assign neg_rx_int = ~rx_int1 & rx_int2; // 捕获接收过程标志信号
//---------------------------------------------------------
reg [7:0] tx_data; // 发送的数据
reg bps_start_r;
reg tx_en; // 发送数据使能
reg [3:0] num;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
bps_start_r <= 1'bz;
tx_en <= 1'b0;
tx_data <= 8'd0;
end
else if(neg_rx_int)
begin // 捕获到接收过程标志信号
bps_start_r <= 1'b1;
tx_data <= rx_data; // 将接收到的数据送到发送模块
tx_en <= 1'b1; // 发送数据使能置一
end
else if(num == 4'd10)
begin // 结束
bps_start_r <= 1'b0;
tx_en <= 1'b0;
end
end
assign bps_start = bps_start_r;
//---------------------------------------------------------
reg uart_tx_r;
always @ (posedge clk or negedge rst_n) // 将接收到的数据进行并转串
begin
if(!rst_n)
begin
num <= 4'd0;
uart_tx_r <= 1'b1;
end
else if(tx_en)
begin
if(clk_bps)
begin
num <= num+1'b1;
case (num)
4'd0: uart_tx_r <= 1'b0; // 起始位
4'd1: uart_tx_r <= tx_data[0]; // 寄存发送数据bit0
4'd2: uart_tx_r <= tx_data[1]; // 寄存发送数据bit1
4'd3: uart_tx_r <= tx_data[2]; // 寄存发送数据bit2
4'd4: uart_tx_r <= tx_data[3]; // 寄存发送数据bit3
4'd5: uart_tx_r <= tx_data[4]; // 寄存发送数据bit4
4'd6: uart_tx_r <= tx_data[5]; // 寄存发送数据bit5
4'd7: uart_tx_r <= tx_data[6]; // 寄存发送数据bit6
4'd8: uart_tx_r <= tx_data[7]; // 寄存发送数据bit7
4'd9: uart_tx_r <= 1'b1; // 停止位
default: uart_tx_r <= 1'b1;
endcase
end
else if(num == 4'd10)
num <= 4'd0;
end
end
assign uart_tx = uart_tx_r;
endmodule
历程运行效果:
|