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; }
-
-
-
-
- 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
- )
- (
- input clk,
- input rst_n,
- input bps_start,
- output clk_bps
- );
-
- `define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET)
- `define BPS_PARA_2 (`BPS_PARA/2)
-
- reg [12:0] cnt;
- reg clk_bps_r;
- reg [2:0] uart_ctrl;
-
- 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;
-
这个程序使用了一个计数器,而不是一个标准状态机,这点根据个人的喜好了,计数器的优点是资源占用少,但是可配置性差,不是很灵活,状态机的缺点是结构复杂。这就是看各自的喜好了。本次测试到此为止,希望大家多多指正。
|