问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 108 人浏览分享

开启左侧

[MILIANPAI-F01-EG4D]FPGA程序设计基础实验连载-10 UART串口发送驱动设计

[复制链接]
108 0
安路-FPGA课程
安路课程: 基础入门 » 新手入门实验
安路系列: EG4
本帖最后由 UT发布 于 2025-4-10 16:04 编辑

软件版本:TD_5.6.4_Release_97693
操作系统:WIN11 64bit
硬件平台:适用安路(Anlogic)FPGA
登录米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述

本章将学习 UART 通信的原理及其硬件电路设计,并使用FPGA实现UART串口发送控制器的设计,实现主程序中调用串口发送控制器发送字符HELLO FPGA”。

在完成本实验前,请确保已经完成前面的实验,包括已经掌握以下能力:

1:完成了TD软件安装

2:完成了modelsim安装以及TD库的编译

3:掌握了TD仿真环境的设置

4:掌握了modelsim通过do文件启动仿真


实验目的:

1:实现UART串口发送控制器的设计

2:实现主程序中调用串口发送控制器发送字符“HELLO FPGA”

3:实用modelsim完成仿真验证

4:编译并且固化程序到FPGA验证

1.1 UART串口简介

UART串口通信是应用非常广泛的一种串行异步通信方式,常用的接口标准规范有RS232、RS422、RS485。

RS-232标准的串口最常见的接口类型为DB9(DB9 接口详细定义见上一课),但是笔记本电脑以及较新一点的台式机都没有DB9串口,它们一般通过 USB 转串口线来实现与外部设备的串口通信。比如我们常见的USB串口,就是通过USB接口芯片,实现了以TTL电平方式的UART串口通信。数据通过USB接口进行传输,通过UART串口芯片完成USB协议到UART串口协议的相互转换。

image.jpg image.jpg
                            DB9接口                      USB串口线

由于传统的DB9接口体积较大,会占用开发板过多空间,在开发板上我们采用的是Mini USB 接口,另一端直接和电脑 USB 相连。

image.jpg
          Mini USB串口线

1.2 硬件电路分析

CP2104是单芯片USBUART桥接器控制器,它将RS-232/RS-485设计升级到USB提供了一种简单的解决方案,以更新RS-232/RS-485设计到USB使用最小的组件和PCB空间。在许多现有RS-232设计中,如果要将设计从 RS-232升级到USB,只需将 RS-232电平转换器更换为CP2104 即可。

image.jpg
2UART发送驱动设计
2.1系统框图

本次实验使用FPGA来实现UART通信中的数据发送部分,将数据发给上位机。本实验共有两个模块,分别为顶层模块uart_top和发送驱动模块uiuart_tx

发送驱动模块uiuart_tx

在开始编写串口发送驱动前,我们需要了解以下概念:

波特率UART采用异步通信方式,数据收发双方只有在同一波特率才能正常通信。波特率代表了UART完成1个时间单位数据位或者控制位的时间。通常,我们需要对系统时钟进行分频来产生正确的波特率,所以计算分频系数尤为重要,比如系统时钟是25_000_000HZ,波特率是115200,那么分频系数为=25000000/115200-1。

起始位UART数据总线由高电平变低电平并且持续1个波特率时间代表数据的起始。

数据位每个数据位占用1个波特率时间,本文实验发送1BYTE字节需要占用8个波特率时间。

停止位如果没有奇偶校验位,数据位结束后,保持1/1.5/2个波特率的高电平代表了停止位。

奇偶校验用于校对数据,对于UART通信,可以根据实际情况选择是否需要支持奇偶校验。

下图中,UART串口通信数据格式包括1bit起始位、8bits数据位、1bit停止位,不包含奇偶校验位。

image.jpg

当检测到发送数据请求,即I_uart_wreq为高时,发送使能(bps_start_en)拉高,代表传输开始,拉高发送忙状态标志(O_uart_wbusy),以此来告诉其它功能模块不要发送数据的过程中更新发送的数据。根据板子的传输速率,传输1bit需要的时间由计数器(baud_div)控制,计满拉高发送时能(bps_en),代表已发送1bitbaud_div0并重新计数,直到所有数据发送完成。串口发送模块将数据并转串,因此需要一个移位模块,用移位计数器tx_cnt控制并行数据依次传输,每发送一个bit1,计满清0,代表数据发送完毕。

根据以上分析,米联客设计的UART发送控制器包含3个主要模块:波特率发生器,发送使能模块,移位模块,其中移位模块中包含了移位计数器和移位控制器。串口发送模块的输入信号主要有系统时钟、系统复位以及发送使能信号和待发送数据,输出信号主要有发送忙状态标志和串口发送总线。

image.jpg

顶层模块uart_top


uart_top模块将并行数据数据(uart_wdata)转成串行数据,并通过UART发送驱动模块,将数据通过uart发送串行总线(O_uart_tx)发回上位机。顶层模块uart_top需要个输入的端口为系统时钟输出为串口发送端口

数据发送状态机:


初始化内存,将要发送的数据按字节顺序寄存在uart_tx_buf[0:11]里,当发送请求拉高(状态0),通过发送驱动模块开始由低位到高位传送uart_tx_buf里的数据,发送一字节数据时,uart_wbusy信号拉高,等待uart_wbusy信号拉低(状态1),说明上一个字节发送完毕。uart_wbusy信号拉低后index计数器加1(状态2),再重新等待发送请求(状态0)发送的下一个字节,直到数据发送结束。数据发送结束后进入时间延迟状态(状态3),延时计数完成后重新回到状态0

image.jpg
2.2 驱动接口时序图

米联客设计了一种通用简洁的驱动接口,包含以下信号:

xxx_wreq:数据发送请求

xxx_wdata:需要发送的数据

xxx_wbusy:数据发送忙状态指示

这里xxx代表了uart

image.jpg
2.3 驱动源码
  1. module uiuart_tx#
  2. (
  3. parameter integer BAUD_DIV     = 216 //设置采样系数(时钟/采样率-1),便于外部修改
  4. )
  5. (
  6.         input       I_clk,
  7.     input       I_uart_rstn,
  8.         input       I_uart_wreq,//发送数据请求
  9.     input [7:0] I_uart_wdata,//发送数据
  10.     output      O_uart_wbusy,//发送状态忙,即是否正在发送数据
  11.         output      O_uart_tx//发送总线
  12. );
  13. localparam UART_LEN = 4'd10;//设置uart发送的bit数量为10,代表1bit起始位,8bits数据,1bit停止位
  14. wire        bps_en ;//发送使能
  15. reg         uart_wreq_r   = 1'b0;//寄存一次发送数据请求
  16. reg         bps_start_en    = 1'b0;//波特率计数器启动使能,也是发送启动使能
  17. reg [13:0]  baud_div        = 14'd0;//波特率计数器
  18. reg [9 :0]  uart_wdata_r  = 10'h3ff;//寄存10bit数据(1+8+1)
  19. reg [3 :0]  tx_cnt          = 4'd0;//计数已经发送出多少位数据
  20. assign O_uart_tx = uart_wdata_r[0];//从低位开始输出,且总线上的数据始终为uart_wdata_r[0]
  21. assign O_uart_wbusy = bps_start_en;//发送启动使能有效时,处于发送忙状态
  22. // uart tx Baud rate divider
  23. assign bps_en = (baud_div == BAUD_DIV);//产生一次发送使能信号,条件是baud_div == BAUD_DIV,波特率计数达成
  24. //波特率计数器
  25. always@(posedge I_clk )begin
  26.     if((I_uart_rstn== 1'b0) || (I_uart_wreq==1'b1&uart_wreq_r==1'b0))begin
  27.         baud_div <= 14'd0;
  28.     end
  29.     else begin
  30.         if(bps_start_en && baud_div < BAUD_DIV)//发送使能为1时,进行波特率计数
  31.             baud_div <= baud_div + 1'b1;
  32.         else
  33.             baud_div <= 14'd0;
  34.     end
  35. end
  36. always@(posedge I_clk)begin
  37.     uart_wreq_r <= I_uart_wreq;//寄存一次发送请求
  38. end
  39. //UART transmit enable ,Support gapless continuous enable
  40. always@(posedge I_clk)begin
  41.     if(I_uart_rstn == 1'b0)
  42.         bps_start_en    <= 1'b0;
  43.     else if(I_uart_wreq==1'b1&uart_wreq_r==1'b0)
  44.         bps_start_en    <= 1'b1;
  45.     else if(tx_cnt == UART_LEN)
  46.         bps_start_en    <= 1'b0;
  47.     else
  48.         bps_start_en    <= bps_start_en;
  49. end
  50. //UART transmiter BIT counter
  51. always@(posedge I_clk)begin
  52.     if(((I_uart_rstn== 1'b0) || (I_uart_wreq==1'b1&uart_wreq_r==1'b0))||(tx_cnt == 10))
  53.         tx_cnt <=4'd0;//复位、启动发送、发送完成,重置tx_cnt
  54.     else if(bps_en && (tx_cnt < UART_LEN))
  55.         tx_cnt <= tx_cnt + 1'b1;//tx_cnt计数器,每发送一个bit加1
  56. end
  57. //uart send controller shift control
  58. always@(posedge I_clk)begin
  59.     if((I_uart_wreq==1'b1&uart_wreq_r==1'b0))
  60.         //寄存需要发送的数据,包括1bit起始位,8bits数据,1bit停止位
  61.         uart_wdata_r  <= {1'b1,I_uart_wdata[7:0],1'b0};
  62.     else if(bps_en && (tx_cnt < (UART_LEN - 1'b1)))//shift 9 bits
  63.         //并串转换,将并行数据依次传输
  64.         uart_wdata_r <= {uart_wdata_r[0],uart_wdata_r[9:1]};
  65.     else
  66.         uart_wdata_r <= uart_wdata_r;
  67. end   
  68. endmodule
复制代码

顶层模块uart_top代码如下:

  1. module uart_top
  2. (
  3. input I_sysclk,  //系统时钟输入
  4. output O_uart_tx  //UART串口发送总线
  5. );
  6. wire     uart_rstn; //内部同步复位
  7. wire     uart_wbusy;//UART发送驱动器正忙
  8. reg      t1s_dly_en;//1S延迟
  9. reg[1:0] S_UART_TX;//UART 发送状态机
  10. reg[3:0] tx_index;//发送index计数器
  11. reg      uart_wreq;//UART发送请求
  12. reg[7:0] uart_wdata;//UART发送数据寄存器
  13. reg[7:0] uart_tx_buf[0:11];//发送缓存
  14. reg [15:0]rst_cnt = 16'd0;//复位计数器
  15. reg [24:0]delay_cnt = 25'd0;//延迟计数器
  16. assign uart_rstn = rst_cnt[15];
  17. //Power-on Reset Delay
  18. always @(posedge I_sysclk)begin
  19.     rst_cnt <= (rst_cnt[15] == 1'b0) ? (rst_cnt + 1'b1) : rst_cnt ;
  20. end
  21. //帧延迟计数器
  22. always @(posedge I_sysclk)begin
  23.         if(t1s_dly_en == 1'b0)
  24.             delay_cnt <= 25'd0;
  25.     else
  26.             delay_cnt <= delay_cnt + 1'b1;
  27. end
  28. //数据发送状态机
  29. //初始化uart_tx_buf,hello fpga等字符共计12 BYTES,以及其他寄存器
  30. always @(posedge I_sysclk)begin
  31.     if(uart_rstn==1'b0)begin
  32.         uart_tx_buf[0]  <=8'h48;//h
  33.         uart_tx_buf[1]  <=8'h45;//e
  34.         uart_tx_buf[2]  <=8'h4c;//l
  35.         uart_tx_buf[3]  <=8'h4c;//l
  36.         uart_tx_buf[4]  <=8'h4f;//o
  37.         uart_tx_buf[5]  <=8'h20;//space
  38.         uart_tx_buf[6]  <=8'h46;//f
  39.         uart_tx_buf[7]  <=8'h50;//p
  40.         uart_tx_buf[8]  <=8'h47;//g   
  41.         uart_tx_buf[9]  <=8'h41;//a      
  42.         uart_tx_buf[10]  <=8'h0d;//Enter
  43.         uart_tx_buf[11]  <=8'h0a;//newline
  44.         //各寄存器清零
  45.         uart_wdata    <= 8'd0;
  46.         uart_wreq     <= 1'b0;
  47.         S_UART_TX       <= 2'd0;
  48.         t1s_dly_en      <= 1'b0;
  49.         tx_index        <= 4'd0;
  50.     end
  51.     else begin
  52.         case(S_UART_TX)
  53.         0:begin
  54.             if(!uart_wbusy)begin//When the bus is not busy, request to send
  55.                 uart_wdata <= uart_tx_buf[tx_index];//准备发送数据,发送tx_index所指向的数据
  56.                 uart_wreq <= 1'b1;//设置uart_wreq为高电平,请求发送数据
  57.             end
  58.             else begin//当总线忙
  59.                 uart_wreq <= 1'b0; //重置uart_wreq
  60.                 S_UART_TX <= 2'd1;//进入下一状态
  61.             end
  62.         end
  63.         1:begin//该状态等待总线空闲
  64.             S_UART_TX <= (uart_wbusy == 1'b0) ? 2'd2: S_UART_TX;
  65.         end
  66.         2:begin//更新tx_index计数器
  67.             if(tx_index < 11)begin//每一帧发送11个字节
  68.                 tx_index <= tx_index + 1'b1; //tx_index+1计数
  69.                 S_UART_TX  <= 2'd0;//进入下一状态
  70.             end
  71.             else begin//如果tx_index==11 代表所有数据发送完毕
  72.                 tx_index   <= 4'd0;//重置tx_index
  73.                 t1s_dly_en <= 1'b1;//1s延迟计数器开始计数
  74.                 S_UART_TX  <= 2'd3;//下一状态
  75.             end
  76.         end
  77.         3:begin//1s延迟计数器计数
  78.             //这里的1S不是精确的,仅以delay_cnt[24]最高位作为判断可以节省逻辑资源
  79.             if(delay_cnt[24] == 1'b1)begin
  80.                 S_UART_TX <= 2'd0;  
  81.                 t1s_dly_en <= 1'b0;
  82.             end
  83.             else
  84.                S_UART_TX <= S_UART_TX;   
  85.         end        
  86.         endcase
  87.     end   
  88.    
  89. end
  90. //例化UART 发送驱动器模块   
  91. uiuart_tx#
  92. (
  93. .BAUD_DIV(25000000/115200 -1) //波特率计算,BAUD_DIV = 系统时钟/波特率-1
  94. )
  95. uart_tx_u
  96. (
  97. .I_clk(I_sysclk),
  98. .I_uart_rstn(uart_rstn),
  99. .I_uart_wreq(uart_wreq),
  100. .I_uart_wdata(uart_wdata),
  101. .O_uart_wbusy(uart_wbusy),
  102. .O_uart_tx(O_uart_tx)
  103. );
  104.    
  105. endmodule
复制代码
3FPGA工程

fpga工程的创建过程不再重复,如有不清楚的请看前面实验

image.jpg

米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹

01_rtl:放用户编写的rtl代码

02_sim:仿真文件或者工程

03_ip:放使用到的ip文件

04_pin:fpgapin脚约束文件或者时序约束文件

05_boot:放编译好的bit或者bin文件(一般为空)

06_doc:放本一些相关文档(一般为空)

image.jpg
4Modelsim仿真
4.1准备工作

Modelsim仿真的创建过程不再重复,如有不清楚的请看前面实验


仿真测试文件源码如下:

  1. module uart_top_tb;
  2. reg I_sysclk;
  3. wire O_uart_tx;
  4. uart_top u_uart_top
  5. (
  6. .I_sysclk  (I_sysclk),
  7. .O_uart_tx  (O_uart_tx)
  8. );
  9. initial begin
  10. I_sysclk = 0;
  11. #100;           
  12. end
  13. always  #20 I_sysclk = ~I_sysclk;
  14.    
  15. endmodule
复制代码
4.2启动modelsim仿真

启动后,右击需要观察的信号,添加到波形窗口

image.jpg

设置restart

image.jpg

设置运行100ms(如果运行时间太长可以修改小一些)

image.jpg
image.jpg
5下载演示

下载程序前,先确保FPGA工程已经编译。

5.1硬件连接

(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)

请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

image.jpg
5.2运行结果

我们采用米联客开发的串口工具进行验证:

image.jpg





























您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

295

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版