目录
- 实验内容
- 串口接收模块
- 模块框图
- 时序波形
- 仿真结果
- 顶层模块设计
- 模块框图
- 时序波形
- 代码调整
- 仿真结果
- 上板测试
实验内容
- 将接收到的数据发送出去,实现串口回环。
串口发送的内容 FPGA上板项目(五)——UART测试,串口发送 已做过阐述,本篇文章在此基础上实现串口接收功能 ,完成串口回环。
串口接收模块
模块框图
引脚 | 方向 | 位宽 | 说明 |
---|---|---|---|
clk | in | 1 | 时钟 |
rst_n | in | 1 | 同步低复位 |
rx_pin | in | 1 | 接收端引脚 |
rx_ready | in | 1 | 接收端准备标志位 |
rx_data | out | 8 | 接收数据 |
rx_valid | out | 1 | 接收数据有效标志位 |
-
rx_ready:tx_ready 为高时表示开始接收数据,可以理解为使能信号。
-
rx_valid:表征 tx_data 的有效性,为高时代表此帧数据已经串并转换完成。
时序波形
状态变量分析:
- IDLE:空闲状态,等待下一次接收。
- START:接收起始位。
- DATA:接收数据位。
- STOP:接收停止位。
时序图说明:
- 为了避免错过下一帧数据的接收,STOP 状态的计数只进行半个周期。
- RX_BITS 是对 RX_2 信号的采样,在每比特数据传输时的中间时刻进行。
仿真结果
对编写的 HDL 代码进行仿真,仿真时序图如下。逐个信号进行比对后,可以看出,仿真结果与预想的时序波形相同。
下面检验比特信息是否正确,对上面的波形图进行比特位截取。rx_pin 的数据为 1000 0100,将顺序取反后为 0010 0001,下图中 rx_data 的显示格式为无符号十进制数,即 0010 0001 对应的十进制 33。
顶层模块设计
实验内容回顾:将接收到的数据发送出去,实现串口回环
模块框图
时序波形
代码调整
调整前代码:
- 状态机部分:
STOP: beginif(baud_cnt == BAUD_CNT_MAX) beginstate <= IDLE;endend
- tx_ready 赋值部分:
always@(posedge clk) beginif(!rst_n) begintx_ready <= 1'b1;endelse if(state == IDLE) begintx_ready <= ~tx_valid;endelse if(state == STOP && baud_cnt == BAUD_CNT_MAX) begintx_ready <= 1'b1;end
end
代码做调整前的仿真结果如上图
- 现象:接收到了四个字符,但是回环过程只发送了第一、三两个字符。
- 分析:我的代码设定是,tx_pin 发送停止位时,BAUD_CNT 要达到 BAUD_CNT_MAX,tx_ready 才会被拉高,发送数据的状态才可以从 STOP 变为 IDLE,才可开启下一次发送。这会导致发送数据所用时钟周期比接收数据所用时钟周期多一个,会使得发送模块错过第二个字符的 valid 信号。
- 本质问题:下一个发送字符的 valid 信号拉高时,上一个字符还在 STOP 状态,没有进入 IDLE 状态。
- 解决思路:减小发送过程中 STOP 状态的维持时间,可以与接收过程中 STOP 状态的维持时间保持一致(BAUD_CNT_MAX / 2)
调整后代码:
- 状态机部分:
STOP: beginif(baud_cnt == BAUD_CNT_MAX / 2) beginstate <= IDLE;endend
- tx_ready 赋值部分:
always@(posedge clk) beginif(!rst_n) begintx_ready <= 1'b1;endelse if(state == IDLE) begintx_ready <= ~tx_valid;endelse if(state == STOP && baud_cnt == BAUD_CNT_MAX / 2) begintx_ready <= 1'b1;end
end