SparkRoad测评(7)-FPGA串口测试
[复制链接]
安路的开发板上是带有USB2UART模块的,这个模块是通过板子上的单片机与USB转串口相连接的,打开自带的例程6_uart_loopback自接运行是不可以的。因为默认的引脚是不接在UART2USB的线上的,所以必须将引脚设定到USB2UART指定的引脚上。
1、打开项目uart.al,文件mini_EG4S20BG256.adc
2、修改文件的指定资源。uart_tx E16、uart_rx F16
set_pin_assignment {ext_clk_25m} { LOCATION = K14; }
set_pin_assignment {ext_rst_n} { LOCATION = L12; } ##KEY_C
##set_pin_assignment {uart_tx} { LOCATION = C11; }
##set_pin_assignment {uart_rx} { LOCATION = B15; }
set_pin_assignment {uart_tx} { LOCATION = E16; }
set_pin_assignment {uart_rx} { LOCATION = F16; }
3、将项目综合后,烧入板子就可以实验了。
这个说明一下实验中的项目文件,speed_setting.v这个文件是用来修改波特率的。这里有两个文件对应的是收发两个设置
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 //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; //波特率时钟寄存器
reg [2:0] uart_ctrl; //uart波特率选择寄存器
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; //clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点
else
clk_bps_r <= 1'b0;
end
assign clk_bps = clk_bps_r;
endmodule
只要修改parameter BPS_SET = 96, //波特率 其中的96就可以了,其实的参数行是:`define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET) //10_000_000/`CLK_PERIORD/96;
别的就不要动了。其实主要的就是一个“分频器”
下面我们来分析一下串口的发送文件,my_uart_tx.v
module my_uart_tx
(
input clk,
input rst_n,
input [7:0] rx_data,
input rx_int,
output uart_tx,
input clk_bps,
output bps_start
);
//---------------------------------------------------------
reg rx_int0,rx_int1,rx_int2; //rx_int信号寄存器
wire neg_rx_int; //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; //捕捉到下降沿后,neg_rx_int拉高保持一个主时钟周期
//---------------------------------------------------------
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
这个文件让人看了有点疑惑,主要是这里面多了一步,将收到的数据转出到tx_data的过程,这个过程真不应该写到这个模块中,我的建议是写到顶层的文件中的状态机当中。
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
接下来是输出的主要部分。
//---------------------------------------------------------
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;
这个程序使用了一个计数器,而不是一个标准状态机,这点根据个人的喜好了,计数器的优点是资源占用少,但是可配置性差,不是很灵活,状态机的缺点是结构复杂。这就是看各自的喜好了。本次测试到此为止,希望大家多多指正。
|