UART是最常用的串行通信方式,几乎每一款MCU或者处理器都有UART。但是很多MCU的UART都没有带硬件FIFO,而一般嵌入式处理器的UART都带硬件FIFO,可是FIFO的深度常见的是8、16或者32。在一些较大数据包的传输场合,带较大深度FIFO的UART,可以有效提高传输效率和降低CPU的负担。FPGA具有较大容量的嵌入式RAM,适合组成FIFO,比如ALTERA的FPGA,利用Quartus II里的MegaWizard Plug-In Manager工具,很方便就可以生成可定制深度和位宽的FIFO。为构建带FIFO的UART提供有利条件。本文介绍的是一种包含512字节FIFO并且带并行总线的UART设计。
图1
如图1所示,就是一种用FPGA设计的UART 结构图。采用常用的并行总线作为与主机通信的接口,可直接与CPU总线对接。通过总线操作,可以直接访问控制寄存器、状态寄存器和读写数据寄存器。写数据寄存器与发送FIFO相连,总线每写入一个数据,就会相应增加到发送FIFO中。如果使能了发送使能控制位,发送逻辑就会从发送FIFO读出数据到发送移位寄存器,串行数据从TXD发出。同样,如果使能了接收使能控制位,当接收逻辑收到一个数据时,就写入接收FIFO,接收FIFO读端口的第一个字节被映射到读数据寄存器。这样总线每读出一个字节,就相当于从接收FIFO读出一个字节。
该UART还带有接收中断功能,只要设定了中断触发值寄存器,当接收FIFO数据个数达到中断触发值时,就会从INT引脚产生中断信号,通知主机。
波特率的设定是通过设定分频值寄存器,产生波特率时钟。UART采用16倍波特率的采样时钟,所以波特率Baud = sysclk/16/(分频值+1)。由于收发是异步的,所以发送逻辑和接收逻辑使用不同的时钟产生模块。
图2
采用自顶而下的模块化设计方法,分为总线控制、发送逻辑、接收逻辑、时钟产生、发送FIFO、接收FIFO以及FIFO读写控制模块。在Quartus II里综合出来的顶层RTL如图2。
表1
地址 |
寄存器 |
描述 |
读写 |
0x00 |
FIFO |
W:发送FIFO; R:接收FIFO |
R/W |
0x01 |
分频值 |
Baud = sysclk/16/(分频值+1) |
W |
0x02 |
中断触发值 |
当接收FIFO有效个数≥中断触发值时,触发中断 |
W |
0x03 |
状态寄存器 |
Bit0:接收FIFO空; Bit1:接收FIFO满; Bit2:发送FIFO空; Bit3:发送FIFO满; Bit4:接收FIFO有效个数第8位; Bit5:接收FIFO有效个数第9位; Bit6~ Bit7:保留 |
R |
0x04 |
接收FIFO有效个数 |
接收FIFO有效个数0~7位; |
R |
0x05 |
控制寄存器 |
Bit0:发送FIFO清空位; Bit1:接收FIFO清空位; Bit2:接收使能位; Bit3:发送使能位; Bit4~Bit7:保留 |
W |
总线可操作的内部寄存器以及描述见表1所示。在本例中,发送和接收FIFO的深度都是512字节。发送FIFO和接收FIFO共用了地址0x00。UART使用1位起始位、8位数据位和1位停止位。
使用modelsim进行UART的功能仿真。仿真的方法是采用UART自发自收的方式,把RXD连接到TXD。先通过总线设置好UART的控制寄存器,使能发送和接收,设定中断触发值为5,然后往发送FIFO写入从0x55~0x5e的10个字节。经过一段时间后,读取接收FIFO的数据个数,然后依次把接收到的数据读出。仿真结果见如图3、4、5。
图3
图3是整个仿真截图,可以看到,当写入数据之后,txd引脚就开始输出串行数据,依次是0x55~0x5e。同时数据从rxd输入到接收逻辑,也就是每发送一个数据就相应接收到相同的一个数据。当发送完5个字节后,int_out信号置为高,此时产生中断。
图4
图4是仿真开始时的截图,总线依次写入了中断触发值为5;分频值为1,也就是波特率为主时钟的1/32;清空发送和接收FIFO,并使能了发送和接收;然后依次写入0x55~0x5e到发送FIFO,txd开始有波形,表示开始发送数据。
图5
图5是仿真的末期截图,总线先读取接收FIFO有效数据个数为10,然后依次从接收FIFO读出的数据为0x55~0x5e,说明接收到了发送的10个字节。说明功能仿真通过。
用户125281 2015-9-30 12:56