UART(UniversalAnynchrONousReceiverTransmitter,通用异步接收发送器)是广泛应用的串行数据传输协议之一,其应用范围遍及计算机外设、工控自动化等场合。虽然 USB 传输协议比 UART 协议有更高的性能,但电路复杂开发难度大,并且大多数的微处理器只集成了 UART,因此 UART 仍然是目前数字系统之间进行串行通信的主要协议。

 

随着 FPGA 的广泛应用,经常需要 FPGA 与其他数字系统进行串行通信,专用的 UART 集成电路如 8250,8251 等是比较复杂的,因为专用的 UART 集成电路既要考虑异步的收发功能,又要兼容 RS232 接口设计,在实际应用中,往往只需要用到 UART 的基本功能,使用专用芯片会造成资源浪费和成本提高。可以将所需要的 UART 功能集成到 FPGA 内部,实现 FPGA 与其他数字系统的直接通信,从而简化了整个系统电路,提高了可靠性、稳定性和灵活性。


1 UART 简介

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

 

图 1 UART 数据帧格式

 

2 UART 功能实现

UART 可以分解为 3 个子模块:波特率发生器模块;发送模块;接收模块。UART 的功能主要由 VHDL 硬件描述语言编程,图 2 是编译后生成的图元 SCI,它包括了 UART 的最主要的部分,即发送模块和接收模块。SCI 的外部口线可分为 3 类:

 

一是与数字系统的接口,包括数据 DATA[7.0],片选 CS,读写 RD、WR,状态 RDFULL、TDEMPTY. 这部分接口完成的功能是将待发送的数据写入 SCI 或从 SCI 读出已接收到的数据。

 

二是串行通信接口 2 条线 RXD、TXD,其中 RXD 是接收数据线、TXD 是发送数据线,因此,SCI 实现的是全双工通信的设计。

 

三是系统控制线 RESET、CLK,RESET 为模块复位输入,CLK 为模块时钟输入,通信的波特率由 CLK 来决定(实际的波特率是 CLK/4)。

 

图 2 UART 的图元模块结构

 

RDFULL、TDEMPTY 为两个状态标志位,RDFULL 为输入寄存器满标志,高电平表示已经接收到一个有效数据并存储到输入数据寄存器中,当 CS、RD 有效将数据读出后变为低电平无效。

 

TDEMPTY 为输出寄存器空标志,高电平表示由 CS、WR 有效写入到输出寄存器的数据已经发送完毕,可以向输出寄存器写入另外待发送的数据,低电平时表示数据目前正在发送中。

 

2.1 发送模块设计

发送模块由发送控制进程、写数据进程、并 / 串转换进程、状态操作进程等进程构成。其中,最主要的是发送控制进程,在发送控制进程中声明了一个 6 比特的变量 scit_v,由它的取值(状态机)状态来控制整个发送过程。scit_v 被分为高四位的 sh_t 和低两位的 sl_,tscit_v 在系统复位后被赋初值 28(011100B),每来一个时钟 scit_v 增量,每来四个时钟 sh_t 增量,当 sh_t 为 0111B 时发送起始位,sh_t 为 1000~1111B 时发送 8 比特的数据。下面给出的是发送控制进程和发送接收数据进程的原代码:

 

----- 数据发送控制进程 -----

 

PROCESS(clk,reset)

variablescit_v:integerrange0to63;

variablescit_s:STd_LOGIC_vector(tdownto0);

BEGIN

IF(reset=0‘)’THEN

scit_v:=0;--“000000”

ELSIF(clkE‘VENTANDclk=1’)‘THEN

IF(scit_v<=27)THEN

IF(tdEMPTY_s=0’‘ANDwr=1’)‘THEN

scit_v:=28;--sci_v=“011100”

ELSE

scit_v:=0;

ENDIF;

ELSE

scit_v:=scit_v+1;

ENDIF;

ENDIF;

scit_s:=conv_std_logic_vector(scit_v,6);

scit<=TO_STDULOGICVECTOR(scit_s);

ENDPROCESS;

 

------ 数据的串行发送 -----

 

PROCESS(sh_t)

BEGIN

CASEsh_tIS

WHEN“0111”=>txd<=0’;‘

WHEN“1000”=>txd<=din_latch(0);

WHEN“1001”=>txd<=din_latch(1);

WHEN“1010”=>txd<=din_latch(2);

WHEN“1011”=>txd<=din_latch(3);

WHEN“1100”=>txd<=din_latch(4);

WHEN“1101”=>txd<=din_latch(5);

WHEN“1110”=>txd<=din_latch(6);

WHEN“1111”=>txd<=din_latch(7);

WHENOTHERS=>txd<=1’;‘

ENDCASE;

ENDPROCESS;

 

图 3 给出的是发送数据的仿真图。当 CS 和 WR 有效时写入数据 55H,同时 EMPTY 被置成无效状态,开始数据的发送,从图中可以看到 TXD 上电平的变化过程,当发送结束后 EMPTY 变为有效。

 

图 3 发送数据的仿真波形

 

2.2 接收模块设计

UART 接口模块由接收控制进程、读数据进程、接收数据串 / 并转换进程、状态操作进程等进程构成。

 

在接收控制进程中同样声明了一个 6 比特的变量 scir_v,由它的取值(状态机)状态来控制整个接收过程。其控制过程同发送模块相似,这里不再赘述。下面给出的是接收数据进程的源代码:

 

---- 接收行数据的串 / 转换进程 ---

 

PROCESS(clk,reset)

BEGIN

IF(reset=0’)‘THEN

d_fb<=“00000000”;

ELSIF(clkE’VENTANDclk=0‘)’THEN

IF((sh_r>=“1000”)AND(sh_r<=“

1111”)AND(sl_r=“01”))THEN

d_fb(7)<=rxd;

FORiIN0TO6LOOP

d_fb(i)<=d_fb(i+1);--d_fb(0)被移

出;d_fb(7)被移空

ENDLOOP;

ENDIF;

ENDIF;

ENDPROCESS;

 

图 4 给出的是接收数据的仿真图。当 rxd 出现低电平后便启动一次接收过程,当 8 比特的数据接收完毕后,rxd 变为高电平,同时将 RDFULL 信号置为高电平有效,RDFULL 有效表示接收寄存器已经存储了一个刚刚接收到的数据,当 CS 和 RD 有效时将数据(实际接收到的数据是 2AH)读出,同时 RDFULL 被置成无效状态。

 

图 4 接收数据的仿真波形

 

2.3 波特率发生器模块

波特率发生器实际是一个分频器,分频器的输出连接到 SCI 的 CLK 输入端,且应为实际波特率的 4 倍频。因为在发送和接收控制进程中,状态机由一个 6 比特的寄存器(cit_v、cir_v)的高 4 位(sh_r、sh_t)进行控制,而高 4 位的状态改变需要 4 个 CLK 时钟(低 2 位向高 4 位进位)。当 SCI 与 SCI 进行通信时,通信双方波特率选择一致即可,当 SCI 同 MCU 通信时,SCI 的波特率选择同 MCU 定时器的溢出率即可,当 SCI 需要同 PC 通信时,才将 SCI 的波特率定制成:1.2Kbps,2.4Kbps,4.8Kbps 直到 115.2Kbps,这时要求 SCI 的晶体振荡频率要足够高来满足波特率的匹配,或采用(11.0592 或 22.1184MHz)的特殊晶体来满足特率的匹配要求。

 

3 结论

将 SCI 下载到 EPF10K10 芯片中,40MHz 有源晶振没有进行分频直接驱动 SCI 模块,用 ICL57176 进行 RS485 转换,用 100m 的网线进行了 SCI 与 SCI 之间全双工通信。测试结果表明波特率达到 10Mbps 时通信是正确的。