[X]关闭
 专注集成电路FPGA应用生态推广
 微信公众号
米联客
开启左侧

09UART串口接收驱动设计

[复制链接]
uisrc 发表于 2022-7-9 17:36:20 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
 
软件版本:Anlogic -TD5.6.1-64bit
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述
UART串口通信是应用非常广泛的一种串行异步通信方式,常用的异步串口包括RS232\RS482\RS485。
RS232的逻辑1的电平为-3~-15V,逻辑0的电平为+3~+15V,下图是老式的DB9串口线。
09UART串口接收驱动设计-1.png
标准的DB9接口定义如下:
序号
DB9公头
DB9母头
1
CD
载波检测
CD
载波检测
2
RXD
接收端接收
TXD
发送端发送数据
3
TXD
发送数据
RXD
接收端接收数据
4
DTR
数据终端就绪
DTR
数据终端就绪
5
GND
系统接地
GND
系统接地
6
DSR
数据准备就绪
DSR
数据准备就绪
7
RTS
发送请求
CTS
清除请求
8
CTS
清除发送
RTS
发送请求
9
RI
振铃指示器
RI
振铃指示器


实际上一般RS232只使用到TXD RXD两个信号。
09UART串口接收驱动设计-2.png
    RS485/422采用差分信号负逻辑,逻辑"1"以两线间的电压差为-(2~6)V表示;逻辑"0"以两线间的电压差为+(2~6)V表示,由于采用差分方式可以具有更高的速度和更强的抗干扰能力,具有更远的传输距离。由于RS485/RS422更多出现在工业场合,因此一般采用接线端子方式接线
    老式DB9串口基本上已经消失了,但是UART串口更加广泛的实用,比如我们常见的USB串口,就是通过一颗芯片实现了通过USB接口芯片,实现了以TTL电平方式的UART串口通信。数据通过USB接口进行传输,通过UART串口芯片完成USB协议到UART串口协议的相互转换。

在完成本实验前,请确保已经完成前面的实验,包括已经掌握以下能力:
1:完成了TD软件安装
2:完成了modelsim安装以及TD库的编译
3:掌握了TD仿真环境的设置
4:掌握了modesim通过do文件启动仿真

实验目的:
1:实现UART串口发送控制器的设计
2:实现主程序中调用串口发送控制器发送字符"HELLO FPGA"
3:实用modelsim完成仿真验证
4:编译并且固化程序到FPGA验证
2UART接收驱动设计1:系统框图
如下图所示,米联客设计的UART发送控制器包含4个主要模块:波特率发生器、抗干扰过采样模块、起始位检测模块,移位模块。
09UART串口接收驱动设计-3.png
2:UART接收时序
下图中,UART串口通信数据格式包括1bit起始位、8bits数据位、1bit停止位,不包含奇偶校验位。
09UART串口接收驱动设计-4.png

上图中,对接收数据进行过采样,对一个波特率位的数据以8倍波特率采样,并且判断其中7次。多次采样可以提高总线的抗干扰能力。

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

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

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

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

奇偶校验:用于校对数据,对于UART通信,可以根据实际情况选择是否需要支持奇偶校验
3:驱动接口时序图
米联客设计了一种通用简洁的驱动接口,包含以下信号:
xxx_rdata:接收的数据
xxx_rvalid:接收的有效数据
这里xxx代表了uart
09UART串口接收驱动设计-5.png
4:驱动源码
代码如下:
`timescale 1ns / 1ns

module uiuart_rx#
(
parameter integer  BAUD_DIV     = 10416
)
(
input clk_i,
input uart_rx_rstn_i,
input uart_rx_i,
output [7:0] uart_rdata_o,
output uart_rvalid_o
);

localparam  BAUD_DIV_SAMP = (BAUD_DIV/8)-1;

wire bps_en       ;
wire samp_en      ;
wire bit_cap_done ;
wire uarx_rx_done ;
wire bit_data     ;
wire uart_rx_int  ;

reg [13:0]  baud_div = 14'd0;
reg [13:0]  samp_cnt = 14'd0;
reg [4 :0]  uart_rx_i_r = 5'd0;
reg [3 :0]  bit_cnt=4'd0;
reg [3 :0]  cap_cnt=4'd0;
reg [4 :0]  rx_bit_tmp = 5'd0;
reg [7 :0]  rx_data = 8'd0;

reg bps_start_en_r = 1'b0;
reg bit_cap_done_r = 1'b0;
reg bps_start_en,start_check_done,start_check_failed;

assign bps_en       =   (baud_div == (BAUD_DIV - 1'b1));
assign samp_en      =   (samp_cnt == (BAUD_DIV_SAMP - 1'b1 ));
assign bit_cap_done =   (cap_cnt  == 3'd7);
assign uarx_rx_done =   (bit_cnt  == 9)&&(baud_div == BAUD_DIV >> 1);//received bits finished half the baud rate time earlier

assign bit_data     =   (rx_bit_tmp < 5'd15) ? 0 : 1;
assign uart_rx_int  =   uart_rx_i_r[4] | uart_rx_i_r[3] | uart_rx_i_r[2] | uart_rx_i_r[1] | uart_rx_i_r[0];

assign uart_rdata_o   =   rx_data;
assign uart_rvalid_o  =   uarx_rx_done;  

//baud rate generator
always@(posedge clk_i)begin
    if(bps_start_en && baud_div < BAUD_DIV)
        baud_div <= baud_div + 1'b1;
    else
        baud_div <= 14'd0;
end

//8x oversampling, divider
always@(posedge clk_i)begin
    if(bps_start_en && samp_cnt < BAUD_DIV_SAMP)   
        samp_cnt <= samp_cnt + 1'b1;
    else
        samp_cnt <= 14'd0;
end

//uart rx bus asynchronous to Synchronous
always@(posedge clk_i)begin
    uart_rx_i_r <= {uart_rx_i_r[3:0],uart_rx_i};
end

//start check
always@(posedge clk_i)begin
    if(uart_rx_rstn_i == 1'b0 || uarx_rx_done || start_check_failed)
        bps_start_en    <= 1'b0;
    else if((uart_rx_int == 1'b0)&(bps_start_en==1'b0))
        bps_start_en    <= 1'b1;
end

always@(posedge clk_i)begin
        bps_start_en_r    <= bps_start_en;
end

always@(posedge clk_i)begin
    if(uart_rx_rstn_i == 1'b0 || start_check_failed)begin
        start_check_done    <= 1'b0;
        start_check_failed  <= 1'b0;
    end   
    else if(bps_start_en == 1'b1&&bps_start_en_r == 1'b0) begin
        start_check_done    <= 1'b0;
        start_check_failed  <= 1'b0;
    end
    else if((bit_cap_done&&bit_cap_done_r==1'b0)&&(start_check_done == 1'b0))begin
        start_check_failed <= bit_data ? 1'b1 : 1'b0;
        start_check_done   <= 1'b1;
    end   
end

//bits counter
always@(posedge clk_i)begin
    if(uart_rx_rstn_i == 1'b0 || uarx_rx_done || bps_start_en == 1'b0)
        bit_cnt   <= 4'd0;  
    else if(bps_en)
        bit_cnt <= bit_cnt + 1'b1;   
end

//sample bits
always@(posedge clk_i)begin
    if(uart_rx_rstn_i == 1'b0 || bps_en == 1'b1 || bps_start_en == 1'b0) begin
        cap_cnt     <= 4'd0;
        rx_bit_tmp  <= 5'd15;
    end
    else if(samp_en)begin
        cap_cnt     <= cap_cnt + 1'b1;
        rx_bit_tmp  <= uart_rx_i_r[4] ? rx_bit_tmp + 1'b1 :  rx_bit_tmp - 1'b1;
    end
end

always@(posedge clk_i)
    bit_cap_done_r <= bit_cap_done;
//shift rx bit data
always@(posedge clk_i)begin
    if(uart_rx_rstn_i == 1'b0 || bps_start_en == 1'b0)
        rx_data  <= 8'd0;  
    else if(start_check_done&&(bit_cap_done&&bit_cap_done_r==1'b0)&&bit_cnt < 9)
        rx_data  <= {bit_data,rx_data[7:1]};
end

endmodule


4FPGA工程
fpga工程的创建过程不再重复,如有不清楚的请看前面实验,这里以型号为EG4D20EG176的FPGA作为演示demo
09UART串口接收驱动设计-6.png
米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹
01_rtl:放用户编写的rtl代码
02_sim:仿真文件或者工程
03_ip:放使用到的ip文件
04_pin:放fpga的pin脚约束文件或者时序约束文件
05_boot:放编译好的bit或者bin文件(一般为空)
06_doc:放本一些相关文档(一般为空)
09UART串口接收驱动设计-7.png
3Modelsim仿真1:准备工作
再次提醒,在进行modelsim仿真前,请提前完成,如果有不清楚的,以下3步请看前面课程内容:
1:完成了modelsim安装以及TD库的编译
2:掌握了TD仿真环境的设置
3:掌握了modesim通过do文件启动仿真

对于向执行什么级别的仿真,就执行对应的HDL2Bit Flow
当 HDL2Bit Flow 运行至 Read Design 这一步时,可执行 Behavioral Simulation;
当 HDL2Bit Flow 运行至 Optimize RTL 这一步时,可执行 Post-RTL Simulation;
当 HDL2Bit Flow 运行至 Optimize Gate 这一步时,可执行 Post-Gate Simulation;
当 HDL2Bit Flow 运行至 Optimize Routing 这一步时,可执行 Post-Route Simulation。
以执行Behavioral Simulation仿真来说,只要执行Read Design 这一步,如下图
右击FPGA Flow中 Read Design,Rerun
09UART串口接收驱动设计-8.png
2:产生do文件
在tool菜单中选择simulation
09UART串口接收驱动设计-9.png
我们这里也是选择已经编写好的仿真测试文件
09UART串口接收驱动设计-10.png
仿真测试文件源码如下:
`timescale 1ns / 1ns

module uart_top_TB;

reg   sysclk_i;
reg   uart_rx_i;
wire  [7:0]uart_rx_data_o;
wire  uart_rvalid_o;
reg   uart_rx_rstn_i;

uart_top u_uart_top
(
.sysclk_i       (sysclk_i),
.uart_rx_rstn_i (uart_rx_rstn_i),
.uart_rx_i      (uart_rx_i),
.uart_rx_data_o (uart_rx_data_o),
.uart_rvalid_o  (uart_rvalid_o)

);

parameter FREQ      = 25000000;
parameter BAUD      = 115200;
parameter TBAUD     = FREQ/BAUD*40;

initial
begin
      sysclk_i  = 0;
      uart_rx_i = 1'b1;
      uart_rx_rstn_i = 1'b0;
      #200 // Wait 200 ns for global reset to finish
      uart_rx_rstn_i = 1'b1;
      #200 // Wait 200 ns for global reset to finish
        #TBAUD
        uart_rx_i = 1'b1;
        #TBAUD
        uart_rx_i = 1'b0;//start
        //1001_0101
        #TBAUD
        uart_rx_i = 1'b1;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b1;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b1;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b1;        
         #TBAUD
        uart_rx_i = 1'b1;//stop            
         #808320
        //00000101
        uart_rx_i = 1'b0;//start
        #TBAUD
        uart_rx_i = 1'b1;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b1;
         #TBAUD
        uart_rx_i = 1'b0;
         #TBAUD
        uart_rx_i = 1'b0;
          #TBAUD
        uart_rx_i = 1'b0;
          #TBAUD
        uart_rx_i = 1'b0;
          #TBAUD
        uart_rx_i = 1'b0;        
           #TBAUD
        uart_rx_i = 1'b1;//stop  

           #808320
      //10000100
        uart_rx_i = 1'b0;//start
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b1;
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b0;
        #TBAUD
        uart_rx_i = 1'b1;         
        #TBAUD
        uart_rx_i = 1'b1;//stop                    
end
always
    begin
        #20 sysclk_i = ~sysclk_i;
    end

endmodule


可以看到产生的do文件中,自动添加了仿真文件、库的路径
09UART串口接收驱动设计-11.png
3:启动modelsim仿真
09UART串口接收驱动设计-12.png
09UART串口接收驱动设计-13.png
09UART串口接收驱动设计-14.png
输入do fpga_prj_behavioral_sim.do
09UART串口接收驱动设计-15.png
启动后,右击需要观察的信号,添加到波形窗口
09UART串口接收驱动设计-16.png
设置restart
09UART串口接收驱动设计-17.png
设置运行100ms(如果运行时间太长可以修改小一些)
09UART串口接收驱动设计-18.png
09UART串口接收驱动设计-19.png
本实验只完成仿真演示,在下一个实验中完成uart收发环路实验。

附录:常见问题1联系方式
米联客官方社区:www.uisrc.com

米联客社区FPGA/SOC QQ群:
群1:516869816         群2:543731097
群3:86730608         群4:34215299

技术微信:18951232035
技术电话:18951232035

官方微信公众号(新微信公众号):
09UART串口接收驱动设计-20.jpg
2售后
1、7天无理由退货(人为原因除外)
2、质保期限:本司产品自快递签收之日起,提供一年质保服务(主芯片,比如FPGA 或者CPU等除外)。
3、维修换货,需提供淘宝订单编号或合同编号,联系销售/技术支持安排退回事宜。
售后维修请登录工单系统:https://www.uisrc.com/plugin.php?id=x7ree_service
4、以下情形不属于质保范畴。
A:由于用户使用不当造成板子的损坏:比如电压过高造成的开发板短路,自行焊接造成的焊盘脱落、铜线起皮 等
B:用户日常维护不当造成板子的损坏:比如放置不当导致线路板腐蚀、基板出现裂纹等
5、质保范畴外(上方第4条)及质保期限以外的产品,本司提供有偿维修服务。维修仅收取器件材料成本,往返运 费全部由客户承担。
6、寄回地址,登录网页获取最新的售后地址:https://www.uisrc.com/t-1982.html
3销售
天猫米联客旗舰店:https://milianke.tmall.com
京东米联客旗舰店:https://milianke.jd.com/
米联客生态淘宝店:https://milianke.taobao.com

销售电话:18921033576

公司地址:常州溧阳总部:常州溧阳市中关村吴潭渡路雅创高科智造谷10-1幢楼
南京研发基地:南京市栖霞区仙林大道181号5幢1820室
4在线视频5软件下载6经验分享7官方博文
越努力越幸运!加油!
 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


12关注

65粉丝

548帖子

热门图文
排行榜
作者专栏

关注我们:微信订阅号

官方微信公众号

官方微信公众号

客服服务热线:

0519-80699907

常州-总部:常州溧阳市中关村吴潭渡路雅创高科智造谷10-1幢楼

南京-分部:南京市栖霞区仙林大道181号5幢2220/2221室

邮编:213300 Email:tjy@uisrc.com

Copyright   ©2020-2026 内容版权归©UISRC.COM    ( 苏ICP备19046771号-2 )