软件版本:Anlogic -TD5.9.1-DR1_ES1.1
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板
板卡获取平台:https://milianke.tmall.com/
登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
前面两课,我们完成了我们发送程序的测试,成功给PC主机发送了"HELLO FPGA"的信息,主机显示接收成功。但是我们串口接收的程序仅仅是通过我们模拟仿真,虽然仿真结果达到了期望,但是不能直接上板测试难免差强人意。所以我们不妨将我们串口UART接收程序以及发送程序连接起来,做到能将PC端通过USB发送过来的数据接收,然后将接收到的数据再通过发送程序返回给我们的PC机。
在完成本实验前,请确保已经完成前面的实验,包括已经掌握以下能力:
1:完成了TD软件安装
2:完成了modelsim安装以及TD库的编译
3:掌握了TD仿真环境的设置
4:掌握了modesim通过do文件启动仿真
实验目的:
1:实现UART串口发送控制器的设计
2:实现主程序中调用串口发送控制器发送字符"HELLO FPGA"
3:实用modelsim完成仿真验证
4:编译并且固化程序到FPGA验证
1.1 UART收发环路简介
电脑USB口和FPGA串口通信示意图:
一般RS232只使用到TXD和RXD两个信号,两个设备之间的TXD和RXD必须交叉连接,例如对于PC的TX 要和FPGA的RX连接,同样PC的RX要和FPGA的TX连接才可以正常通信。
1.2硬件电路分析
参照 "UART串口发送驱动设计"硬件电路分析部分
2 UART收发环路程序设计
在完成以下实验前,请确保已经完成了"UART串口发送实验"和"UART串口接收实验"
2.1系统框图
上位机通过串口发送数据到FPGA开发板的UART数据接收模块,将串口接收端口(I_uart_rx)的串行数据解析回并行数据输出,再将并行数据作为输入给数据发送模块,UART数据发送模块将并行数据转成串行数据发送回上位机。通过串口发送端口(O_uart_tx)把数据发回到串口芯片,之后数据在串口调试助手上打印,实现环路测试。需要注意的是,数据并不是一直有效的,所以将UART数据接收模块的数据有效信号(O_uart_rvalid)接入到UART数据发送模块的发送数据请求信号(I_uart_wreq),当接收的信号有效时,触发UART数据发送模块,就可以发送接收的有效数据。对于发送驱动模块中的O_uart_wbusy信号,不需要使用,因为这里uart发送模块是被动发送。
2.2驱动源码
顶层模块只需要调用uart的首发模块驱动接口。并且设置uart_rdata和uart_wdata互联,uart_wreq和uart_rvalid互联。
1 `timescale 1ns / 1ns //仿真时钟刻度和精度 2 3 module uart_top 4 ( 5 input I_sysclk,//系统时钟输入 6 input I_uart_rx,//uart rx接收信号 7 output O_uart_tx //uart tx发送信号 8 ); 9 10 localparam SYSCLKHZ = 25_000_000; //系统输入时钟 11 12 reg [11:0] rstn_cnt = 0;//上电后延迟复位 13 wire uart_rstn_i;//内部复位信号 14 wire uart_wreq,uart_rvalid; 15 wire [7:0]uart_wdata,uart_rdata; 16 17 assign uart_wreq = uart_rvalid;//用uart rx接收数据有效的uart_rvalid信号,控制uart发送模块的发送请求 18 assign uart_wdata = uart_rdata; //接收的数据给发送模块发送 19 assign uart_rstn_i = rstn_cnt[11];//延迟复位设计,用计数器的高bit控制复位 20 21 //同步计数器实现复位 22 always @(posedge I_sysclk)begin 23 if(rstn_cnt[11] == 1'b0) 24 rstn_cnt <= rstn_cnt + 1'b1; 25 else 26 rstn_cnt <= rstn_cnt; 27 end 28 29 //例化uart 发送模块 30 uiuart_tx# 31 ( 32 .BAUD_DIV(SYSCLKHZ/115200-1) 33 ) 34 uart_tx_u 35 ( 36 .I_clk(I_sysclk),//系统时钟输入 37 .I_uart_rstn(uart_rstn_i), //系统复位 38 .I_uart_wreq(uart_wreq), //uart发送驱动的写请求信号,高电平有效 39 .I_uart_wdata(uart_wdata), //uart发送驱动的写数据 40 .O_uart_wbusy(),//uart 发送驱动的忙标志 41 .O_uart_tx(O_uart_tx)//uart 串行数据发送 42 ); 43 44 //例化uart 接收 45 uiuart_rx# 46 ( 47 .BAUD_DIV(SYSCLKHZ/115200-1) 48 ) 49 uiuart_rx_u 50 ( 51 .I_clk(I_sysclk), //系统时钟输入 52 .I_uart_rstn(uart_rstn_i),//系统复位 53 .I_uart_rx(I_uart_rx), //uart 串行数据接收 54 .O_uart_rdata(uart_rdata), //uart 接收数据 55 .O_uart_rvalid(uart_rvalid)//uart 接收数据有效,当O_uart_rvalid =1'b1 O_uart_rdata输出的数据有效 56 ); 57 58 endmodule
3 FPGA工程
fpga工程的创建过程不再重复,如有不清楚的请看前面实验,具体的FPGA型号以对应的开发板上芯片为准
米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹
01_rtl:放用户编写的rtl代码
02_sim:仿真文件或者工程
03_ip:放使用到的ip文件
04_pin:放fpga的pin脚约束文件或者时序约束文件
05_boot:放编译好的bit或者bin文件(一般为空)
06_doc:放本一些相关文档(一般为空)
4 Modelsim仿真
4.1准备工作
Modelsim仿真的创建过程不再重复,如有不清楚的请看前面实验
仿真测试文件源码如下:
1 `timescale 1ns/1ns //定义仿真时间刻度/精度 2 3 module sim_top_tb(); 4 5 localparam BPS = 'd115200 ; //波特率 6 localparam CLK_FRE = 'd25_000_000 ; //系统频率 7 localparam CLK_TIME = 'd250_000_000 /CLK_FRE; //计算系统时钟周期,以ns为单位 8 localparam BIT_TIME = 'd250_000_000 / BPS ; //计算出传输每个bit所需要的时间以ns为单位 9 localparam NUM_BYTES = 3; //需要发送的BYTES 10 11 reg I_sysclk; //系统时钟 12 reg bsp_clk ; //波特率时钟 13 reg uart_tx; //uart 数据发送,该信号接入到,FPGA的uart 接收 14 wire uart_rx; //uart 数据接收,该信号接入到,FPGA的uart 发送 15 reg [8*NUM_BYTES-1:0] uart_send_data; //需要发送的数据 16 reg [7:0] uart_send_data_r; //寄存每次需要发送的BYTE 17 18 integer i,j; 19 20 //例化顶层模块 21 uart_top uart_top_inst 22 ( 23 .I_sysclk(I_sysclk), 24 .I_uart_rx(uart_tx), 25 .O_uart_tx(uart_rx) 26 ); 27 28 //仿真初始化 29 initial begin 30 31 //初始化REG寄存器 32 I_sysclk =0; 33 bsp_clk = 0; 34 uart_tx = 1; 35 i=0; 36 j=0; 37 38 uart_send_data =0; 39 uart_send_data_r =0; 40 41 #20000;//延迟20000ns,等待uart测试代码中的复位延迟 42 43 uart_send_data[(0*8) +: 8] = 8'b1001_0101;//初始化需要发送的第1个BYTE 44 uart_send_data[(1*8) +: 8] = 8'b0000_0101;//初始化需要发送的第2个BYTE 45 uart_send_data[(2*8) +: 8] = 8'b1000_0100;//初始化需要发送的第3个BYTE 46 47 //uart tx 发送数据 48 for(i=0; i<NUM_BYTES;i=i+1) 49 begin 50 51 uart_send_data_r = uart_send_data[(i*8) +: 8];//寄存需要发送的数据到寄存器 52 $display("uart_send_data : 0x%h",uart_send_data_r);//打印准备发送的数据 53 54 @(posedge bsp_clk); //发送起始位1bit 55 uart_tx = 1'b0; 56 57 for(j=0;j<8;j=j+1)begin//发送数据8bits 58 @(posedge bsp_clk); //发送 59 uart_tx = uart_send_data_r[j]; 60 end 61 62 @(posedge bsp_clk);//发送停止位1bit 63 uart_tx = 1'b1; 64 65 end 66 @(posedge bsp_clk); 67 #200 $finish; 68 end 69 70 always #(CLK_TIME/2) I_sysclk = ~I_sysclk; //产生主时钟 71 always #(BIT_TIME/2) bsp_clk = ~bsp_clk; //产生波特率时钟 72 73 74 endmodule
4.2启动modelsim仿真
启动后,右击需要观察的信号,添加到波形窗口
设置restart
设置运行2.2ms(如果时间太长需要找下数据位置,时间太短需要继续跑直到波形出来)
5下载演示
下载程序前,先确保FPGA工程已经编译。
5.1硬件连接
(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)
请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)