xilinx FPGA 串口设计笔记 在设计中, 需要用 FPGA 读取 GPS 内部的信息,GPS 的通信方式为串口, 所以在 FPGA 中移植了串口程序 本次移植的程序源代码是特权的串口程序, 本以为移植应该很快就能完成, 但其中还是出了一写小问题, 耽误了不少的时间, 下面将问题进行一个总结! 以下是串口的时序 : 在设计中, 耽误时间最长的问题就是数据老是出错, 为了找出问题的所在, 用示波器观察了 一下串口发送的数据! 串口发送的软件如图所示 :
通过定时发送 hex 数据 :0x55, 如图 : 其中绿色的为电脑发送的串口数据波形, 紫色为波特率发生器产生的读数据的触发脉冲, 也就是说在上升沿的时候读取串口信号的数据, 从图可以看出, 在每个数据的中间段,FPGA 对信号进行了读取, 也就是说 FPGA 的波特率设置是没有问题的 为了进一步的验证, 又发了一次 0xaa, 进行了一次对比 通过定时发送 hex 数据 :0xaa, 如图 :
通过上面的测试可知, 程序设计的波特率以及读写数据的时序是没有问题的, 但是在读数据的时候依然出现错误 在此过程中, 发了两个数据进行验证 通过定时发送 hex 数据 :0xff,0xff 如图 : 在通过发送两个数据后发现, 串口发送的一个数据的位数为 10 位, 1bit 下降沿的起始位 +8bit 的数据位 +1bit 的停止位 也就是说串口发送的数据长度不是固定的, 在没有校验位的情况下, 其长度为 10bit, 而特权的程序的, 他的串口设置的读取长度为 12bit, 这样也就造成了数据的错位, 最终导致数据的整体出错!! 在对程序进行了修改过发现, 程序运行正常
module wi125_time( input clk, // 48MHz 主时钟 input rst_n, // 低电平复位信号 input wi125_uart_rx, // RS232 接收数据信号 output wi125_data_ok, output[7:0] wi125_rx_data, output ww ); //---------------------------------- 串口波特率设置 ---------------------------------// // 功能 : 将串口的波特率设置为 38400bps //---------------------------------------------------------- reg[12:0] cnt; // 分频计数 reg clk_bps; // 波特率时钟寄存器 reg bps_start; if(!rst_n) cnt <= 13'd0; else if((cnt == 1250)!bps_start) cnt <= 13'd0; // 波特率计数清零 else cnt <= cnt+1'b1; // 波特率时钟计数启动 if(!rst_n) clk_bps <= 1'b0; else if(cnt == 625) clk_bps <= 1'b1; // clk_bps_r 高电平为接收数据位的中间采样点, 同时也作为发送数据的数据改变点 else clk_bps <= 1'b0; assign ww=clk_bps; //---------------------------------- 串口波特率设置 ---------------------------------// // 功能 : 将串口的波特率设置为 38400bps //---------------------------------------------------------- reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; // 接收数据寄存器, 滤波用 wire neg_rs232_rx; // 表示数据线接收到下降沿 reg rx_int1,rx_int2; if(!rst_n) rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; rs232_rx3 <= 1'b0; rx_int1 rx_int2 <= 1'b0; <= 1'b0;
else rs232_rx0 <= wi125_uart_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2; rx_int1 <= rx_int; rx_int2 <= rx_int1; // 下面的下降沿检测可以滤掉 <20ns-40ns 的毛刺 ( 包括高脉冲和低脉冲毛刺 ), // 这里就是用资源换稳定 ( 前提是我们对时间要求不是那么苛刻, 因为输入信号打了好几拍 ) //( 当然我们的有效低脉冲信号肯定是远远大于 40ns 的 ) assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; // 接收到下降沿后 neg_rs232_rx 置高一个时钟周期 assign wi125_data_ok = rx_int2&~rx_int1; //---------------------------------------------------------------- reg[3:0] num; // 移位次数 reg rx_int; // 接收数据中断信号, 接收到数据期间始终为高电平 if(!rst_n) bps_start <= 1'bz; rx_int <= 1'b0; else if(neg_rs232_rx) // 接收到串口接收线 rs232_rx 的下降沿标志信号 bps_start <= 1'b1; // 启动串口准备数据接收 rx_int <= 1'b1; // 接收数据中断信号使能 else if(num==4'd10) // 接收完有用数据信息 bps_start <= 1'b0; // 数据接收完毕, 释放波特率启动信号 rx_int <= 1'b0; // 接收数据中断信号关闭 //----------------------------------------------------------------
reg[7:0] rx_data_r; 至下一个数据来到 //---------------------------------------------------------------- reg[7:0] rx_temp_data; // 串口接收数据寄存器, 保存直 // 当前接收数据寄存器 if(!rst_n) rx_temp_data <= 8'd0; num <= 4'd0; rx_data_r <= 8'd0; else if(rx_int) // 接收数据处理 if(clk_bps) // 读取并保存数据, 接收数据为一个起始位,8bit 数据,1 或 2 个结束位 num <= num+1'b1; case (num) 4'd1: rx_temp_data[0] <= wi125_uart_rx; // 锁存第 0bit 4'd2: rx_temp_data[1] <= wi125_uart_rx; // 锁存第 1bit 4'd3: rx_temp_data[2] <= wi125_uart_rx; // 锁存第 2bit 4'd4: rx_temp_data[3] <= wi125_uart_rx; // 锁存第 3bit 4'd5: rx_temp_data[4] <= wi125_uart_rx; // 锁存第 4bit 4'd6: rx_temp_data[5] <= wi125_uart_rx; // 锁存第 5bit 4'd7: rx_temp_data[6] <= wi125_uart_rx; // 锁存第 6bit 4'd8: rx_temp_data[7] <= wi125_uart_rx; // 锁存第 7bit default: ; case else if(num == 4'd10) // 我们的标准接收模式下只有 1+8+1(2)=10bit 的有效数据 num <= 4'd0; // 接收到 STOP 位后结束,num 清零 rx_data_r <= rx_temp_data; // 把数据锁存到数据寄存器 rx_data 中 assign wi125_rx_data = rx_data_r; module