该串口收发模块有串口发送模块,串口接收模块,波特率生成模块,发送数据fifo模块,接收数据的fifo模块组成。
默认配置下,要求输入的参考时钟为50MHz,输入输出的波特率默认配置为115200.该设置体现在波特率生成模块中。
整体的设计框架如下:
端口定义如下:
端口名 | 方向 | 描述 |
---|---|---|
Clk | Input | 主时钟,默认频率为50MHz |
Rst_n | Input | 复位信号,低有效 |
RsRx | Input | 串口接收端口 |
RSTx | Output | 串口发送端口 |
Tx_data_in[7:0] | Input | tx端要发送的1字节数据 |
Rx_data_out[7:0] | output | rx端口接收到的1字节数据 |
Tx_wen | Input | 发送数据的写入使能信号 |
Rx_ren | Input | 接收数据的读取使能信号 |
Uart_irq | output | 串口中断信号,为高时标志着rx接收到了有效的数据 |
该模块的使用:
发送数据:
将要发送的数据放置到Tx_data_in[7:0]总线上,同时将Tx_wen置为高,下一个时钟时,该数据会写进tx_fifo中。如要发送多字节数据,则重复上述步骤,每个时钟向TX_FIFO中发送一个字节的数据,tx_fiof的默认深度为256,可以储存256个字节的数据,则一次最多可以发送256字节数据。
接收数据:
接收到一个字节的有效数据时,该字节立即在Rx_data_out[7:0]端口输出,此时中断信号Uart_irq为高时,读取输出端口的数据,同时将Rx_ren置一个时钟的高电平即可 。 。
1,波特率计数模块
在波特率生成模块中,生成发送和接收数据的采样时钟,该采样时钟为波特率的16倍频时钟。count_reg 是分频计数器。27为波特率设置为115200时的时钟分频参数。
设置一个可配置参数 Baud_rate,便可以再顶层例化模块中通过该参数来改变串口的波特率。参数值和对应的波特率如下表所示。默认情况下,配置参数为6,对应的波特率设置为115200.
分频计数器的参数计算如下:
分频参数 = 主时钟频率/(波特率*16)。
设置为其他常用波特率时,该参数的值为下表:
波特率 | 计算的分频参数 | 实际的分频参数 | 配置参数 |
---|---|---|---|
1200 | 2604.2 | 2604 | 1 |
2400 | 1302.1 | 1302 | 2 |
4800 | 651.0 | 651 | 3 |
9600 | 325.5 | 325 | 4 |
38400 | 81.4 | 81 | 5 |
115200 | 27.1 | 27 | 6 |
2,fifo模块
tx_fifo和rx_fifo 都是例化的自定义的fifo模块。该fifo模块预留有参数接口,可以通过改变该参数来改变fifo的深度和数据宽度。
fifo模块用于临时储存串口发送和接收的数据,进行跨时钟预的数据储存。若不使用fifo来暂存数据,由于串口发送数据相对缓慢,则要连续发送多个字节的数据时,必须等待上一个字节发送完成后才能发送下一个字节,则主模块便要不断等待。使用fifo后,便可以将连续多个字节的数据一次性发送到fifo中,发送模块便会自动读取fifo中的数据进行发送,主模块便可以空闲。
接收模块的fifo同理。将接收到的多个数据暂时储存在fifo中,在读取时便可以一次性连续读取多个字节的数据。
当往fifo中写入数据时,写入的第一个字节的数据就会在R_out[7:0]端口输出。将rd信号置高时,读指针指向下一个地址,在下一个时钟将输出下一个字节数据。
fifo模块的配置参数和端口定义如下:
定义了一个名为array_reg的内存阵列,该内存阵列的储存深度由参数AWIDTH决定,储存的深度等于 2^AWIDTH.fifo的数据宽度等于DWIDTH。
在串口模块例化该fifo模块时,将AWIDTH配置为8,DWIDTH也配置为8。即例化了一个数据宽度为8,储存深度为256的fifo模块。
发送数据fifo:
要通过tx端口向其他串口设备发送数据,首先将要发送的数据放置到Tx_data_in[7:0]总线上,同时将Tx_wen置为高,下一个时钟时,该数据会写进tx_fifo中。如要发送多字节数据,则重复上述步骤,每个时钟向TX_FIFO中发送一个字节的数据,tx_fiof的默认深度为64,可以储存64个字节的数据,则一次最多可以发送64字节数据。当数据储存到TX_FIFO中后,fifo的空标志位(empty)不等于零,令发送模块的开发发送标志位(tx_start)等于 ~empty,则当fifo内储存有要发送的数据时,tx_start信号为1,此时,发送模块从TX_FIFO中读取一字节的数据。待这一字节的数据发送完成后,继续读取fifo内储存的下一个发送数据。直至将fifo内储存的数据全部读取完后,empty等于1,tx_start等于0,发送模块不再发送数据。
接收数据fifo:
当接收到rx端口的有效数据时,接收到的数据会临时储存在rx_fifo中,第一个字节的数据就会在Rx_data_out[7:0]端口输出。中断信号 uart_irq 时rx_fifo的空标志位的取反,此时中断信号 uart_irq 为高,标志这接收到了有效的数据。此时将Rx_ren置为高,读指针指向下一个数据的地址,在下一个时钟将输出下一个字节数据。连续将Rx_ren置为高,则可读出储存在rx_fifo中的接收到的数据,并从Rx_data_out[7:0]端口输出,直到fifo中的数据被读完。
故当tx_fifo里每接收到一个数据时,中断信号为高即标志着接收到了数据,同时在接收到的数据就在Rx_data_out[7:0]端口输出。如果每接收到一个有效数据就立即读取,则必须同时发送一个周期的Rx_ren高信号,使得读地址指针指向下一个读地址,以便当接收到新的数据时,也能立即输出。
如果等待接收多个字节的数据才读取的话,此时输出端口直接输出第一个字节的地址,当将Rx_ren信号置高时,每一个时钟输出一个接收到的数据,直到fifo中的数据被读完。
3,发送模块
发送模块的端口如下:
当 信号 tx_start 为高时,该模块将此时端口 d_in[7:0]输入的数据按照预定的波特率将该字节的数据从端口tx发送出去, 波特率时钟 b_tick 指定了该模块的波特率。等到该字节数据发送完成后,tx_done信号被置为一个时钟的高电平。tx_done信号连接到tx_fifo的读端口,当tx_done为高时,fifo的读指针指向下一个地址,如果下一个地址还储存有数据,输出端口输出储存在下一个地址中的数据,同时empty信号为0,串口发送模块将继续发送数据。当下一个地址还没有数据时,empty输出为高,数据发送停止。
4,接收模块
接收模块的端口如下:
当该模块从rx端口接收到一个有效的字节数据后,rx_done会置高一个时钟,同时接收到的数据从端口dout[7:0]输出。rx_done连接到rx_fifo的写使能端口,接收到的数据将写入到rx_fifo中。
5,模块测试
通过电脑端串口向FPGA发送数据,FPGA端RX模块接收到数据后再将该数据通过串口在发送到电脑端。
我们连续发送了字符串“123”,在接收端也同样接收到了字符串“123”。
这是接收到的三个字符采样得到的时序图。
如下图,当接收到一个字节数据后,uart_irq信号会置高,同时接收到的数据就立刻在rx_data_out[7:0]端口输出。然后将rx_ren信号置高一个时钟,让读地址指针指向下一个地址,则当再次接收到一个新的数据时,该数据也能马上输出。