基于FPGA器件实现UART适应自顶向下的设计

可编程逻辑

1366人已加入

描述

UART(通用异步收发器)是广泛使用的串行数据传输协议。UART允许在串行链路上进行全双工的通信。专用的UART集成电路如8250,8251,NS16450等已经相当复杂,有些含有许多辅助的模块(如FIF0),在实际应用中,往往只需要用到UART的几个基本功能,使用专用芯片会造成资源浪费和成本提高,我们可以将所需要的UART功能集成到FPGA内部,从而简化了整个系统电路,提高了可靠性、稳定性和灵活性。

l 、UART简介

基本的UART通信只需要两条信号线(RXD,TXD)就可以完成数据的相互通信,接收与发送是全双工形式,其中TXD是UART发送端,RXD是UART接收端。UART的基本特点是:在信号线上有2种状态,可分别用逻辑1(高电平)和逻辑0(低电平)来区分。在发送器空闲时,数据线应保持在逻辑高电平状态。发送器是通过发送起始位而开始一个字符传送,起始位使数据线处于逻辑0状态,提示接收器数据传输即将开始。数据位一般为8位一个字节的数据(也有6位、7位的情况),低位(LSB)在前,高位(MSB)在后。校验位一般用来判断接收的数据位有无错误,一般是奇偶校验。停止位在最后,用以标志一个字符传送的结束,它对应于逻辑1状态。UART数据帧格式如表1所示。

FPGA

2 、UART功能实现

基于FPGA的UART由3个子模块组成:波特率发生器模块;发送模块;接收模块。

2.1 波特率发生器模块

波特率发生器实际上就是一个分频器。波特率发生器的功能是产生和RS-232通信所采用的波特率同步的时钟,这样才能按照RS-232串行通信的时序要求进行数据接收或发送。实现波特率时钟的基本思路就是设计一个计数器,该计数器工作在速度很高的系统时钟下,当计数到某数值时将输出置为高电平,再计数一定数值后将输出置为低电平,如此反复就能得到所需的波特率时钟。例如FPGA的系统时钟为50MHz,RS-232通信的波特率为9600,则波特率时钟的每个周期约相当于5208个系统时钟的周期。假如要得到占空比为50%的波特率时钟,只要使计数器在计数到5208 50%=2604时将输出置为高电平,之后在计数到5208时输出低电平并重新计数,就能得到和9600波特率同步的时钟。

波特率发生器VHDL实现的关键代码如下:

entity baud is

Port (clk,resetb:in std_logic;

bclk:out std_logic);

end baud;

architecture Behavioral of baud is

begin

process(clk,resetb)

variable cnt:integer;

begin

if resetb=‘1’ then cnt:=0; bclk《=‘0’; --复位

elsif rising_edge(clk) then

if cnt》=208 then cnt:=0; bclk《=‘1’; --设置分频系数

else cnt:=cnt+1; bclk《=‘0’;

end if;

end if;

end process;

end Behavioral;

Modelsim下的仿真波形如图1所示。

FPGA

2.2 发送模块

在发数据寄存器被写入一帧数据之后,发送过程被启动。发送过程启动后,发送串行移位寄存器被启动。同时发送使能标志被清空。首先发送的是起始位,同时启动发数据计算器,记录发送数据的个数。根据工作模式寄存器的要求,将要发送的一帧数据串行发送出去,如果需要校验,则产生校验位并发送出去。最后需要发送的是停止位,根据停止位个数的要求,发送停止位。最后设置发送完毕标志位。图2为发送模块状态机示意图。

FPGA

图2 发送状态机示意图

发送模块VHDL程序关键代码如下:

architecture Behavioral of transfer is

type states is (x_idle,x_start,x_wait,x_shift,x_stop); --定义各子状态

signal state:states:=x_idle;

signal tcnt:integer:=0;

begin

process(bclkt,resett,xmit_cmd_p,txdbuf) --主控时序、组合进程

variable xcnt16:std_logic_vector(4 downto 0):=“00000”; --定义中间变量

variable xbitcnt:integer:=0;

variable txds:std_logic;

begin

if resett=‘1’ then state《=x_idle; txd_done《=‘0’; txds:=‘1’; --复位

elsif rising_edge(bclkt) then

case state is

when x_idle=》 --状态1,等待数据帧发送命令

if xmit_cmd_p=‘1’ then state《=x_start; txd_done《=‘0’;

else state《=x_idle;

end if;

when x_start=》 --状态2,发送信号至起始位

if xcnt16》=“01111” then state《=x_wait; xcnt16:=“00000”;

else xcnt16:=xcnt16+1; txds:=‘0’; state《=x_start;

end if;

when x_wait=》 --状态3,等待状态

if xcnt16》=“01110” then

if xbitcnt=framlent then state《=x_stop; xbitcnt:=0;

else state《=x_shift;

end if;

xcnt16:=“00000”;

else xcnt16:=xcnt16+1; state《=x_wait;

end if;

when x_shift=》txds:=txdbuf(xbitcnt); xbitcnt:=xbitcnt+1; state《=x_wait; --状态4,将待发数据进行并串转换

when x_stop=》 --状态5,停止位发送状态

if xcnt16》=“01111” then

if xmit_cmd_p=‘0’ then state《=x_idle; xcnt16:=“00000”;

else xcnt16:=xcnt16; state《=x_stop;

end if; txd_done《=‘1’;

else xcnt16:=xcnt16+1; txds:=‘1’; state《=x_stop;

end if;

when others=》state《=x_idle;

end case;

end if;

txd《=txds;

end process;

end Behavioral;

UART发送器的仿真波形如图3所示。

FPGA

2.3 接收模块

在接收数据寄存器被读出一帧数据或系统开始工作之后,接收过程被启动。接收过程启动之后,等待检测起始位。检测到有效的起始位后,根据高于数据速率的时钟同步开始接收数据。根据数据位数的设定,计数器统计接收位数。一帧数据接收完毕之后,如果使用校验位,则检测校验位,否则接收停止位。停止位接收完毕,则设定接收状态寄存器中接收完毕寄存器,同时产生接收中断,通知控制器读取。接收状态机的实现与发送部分类似,限于篇幅,在这里不再叙述。

在具体实现接收部分电路的时候,我们采用的是基于高速多倍率采样的方法。比如将采样速率设置在三倍信息速率上,就是以三倍于波特率的频率对接收引脚Rx进行采样,这样既保证检测到“起始位”,又可以调整采样的时间间隔。将有效数据位的采样点控制在码元的中间1/3处,最大限度地减少误码,提高接收的准确性。图4是该方法的示意图,在图中为了分析方便,将起始位和部分数据位放大,把每个信息位分为三等份,每等份的时间宽度设为TS 。以三倍频对信息位进行采样时,每个信息位都将可能被采样到三次。当处于空闲状态并检测起始位时,尽管每次具体的采样点会在S0区。检测到起始位低电平后,间隔4×TS时间,正好是第一位数据位的中间1/3部分S1区,即箭头所指部位。此后的数据位、校验位和停止位的采样间隔都是3×TS,当所有采样点均落在码元的中间1/3部分时,采样数据最可靠。

FPGA

3 、结束语

用FPGA实现UART功能,可以减小系统的面积,降低系统的功耗,提高系统的稳定性,这种硬件软件化的方法已经成为当今电子设计领域中的主导趋势。在实际应用中,我们将文中实现的UART电路作为一个功能块嵌入到一个FPGA实现的数据采集与处理系统中,成功地实现了和远端PC机间的异步串行通信。实验证明了该UART电路设计简单、工作稳定。

本文作者创新观点:本文将UART系统结构进行了模块化分解,使之适应自顶向下的设计方法,并采用状态机对核心电路部分进行了描述,使控制逻辑直观简单,大幅度提高了设计效率,特别是对接收电路采用了高速多倍率采样法进行实现,降低了误码率,使采样数据更为可靠。

责任编辑:gt

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分