【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十三:串口模块② — 接收

简介: 实验十三:串口模块② — 接收 我们在实验十二实现了串口发送,然而这章实验则要实现串口接收 ... 在此,笔者也会使用其它思路实现串口接收。 图13.1 模块之间的数据传输。 假设我们不考虑波特率,而且一帧数据之间的传输也只是发生在FPGA之间,即两只模块之间互转,并且两块模块都使用相同的时钟频率,结果如图13.1所示。

实验十三:串口模块② — 接收

我们在实验十二实现了串口发送,然而这章实验则要实现串口接收 ... 在此,笔者也会使用其它思路实现串口接收。

clip_image002

图13.1 模块之间的数据传输。

假设我们不考虑波特率,而且一帧数据之间的传输也只是发生在FPGA之间,即两只模块之间互转,并且两块模块都使用相同的时钟频率,结果如图13.1所示。只要成立上述的假设成立,串口传输不过是简单的数据传输活动而已,图中的发送模块经由TXD将一帧11位的数据发送至接收模块。

clip_image004

图13.2 发送与接收一帧数据。

至于两者之间的时序过程,则如图13.2所示 ... 发送方经由TXD,从T0~T10总共发送一帧为11位的数据,反之接收方则从T2~T9读取其中的8位数据而已(D为寄存器的暂存内容)。从图13.2当中,我们可以看见发送方,即TXD都是经由上升沿发送未来值,接收方D则是经由上升沿读取过去值。对此,Verilog可以这样描述,结果如代码13.1所示:

      //发送方
      reg [10:0]rTXD;
     always @(posedge CLOCK)
         case(i)
            0,1,2,3,4,5,6,7,8,9,10:      
            begin TXD <= rTXD[i]; i <= i + 1'b1; end
            ......
         endcase
 
      //接收方
      reg [7:0]D1;
     always @(posedge CLOCK)
         case(i)
           2,3,4,5,6,7,8,9:      
            begin D1[i] <= TXD; i <= i + 1'b1; end
            ......
         endcase

代码13.1

如代码13.1所示,发送方在步骤0~10一共发送一帧为11位的数据 ... 反之接收方,则在步骤2~9读取其中的数据[7:0]。心机重的朋友的一定会疑惑道,为什么笔者要换个角度去思考串口怎样接收呢?原因其实很简单,目的就是为了简化理解,脑补时序,实现精密控制。

对此,FPGA与其它设备互转数据,其实可以反映成两只模块正在互转数据,然而理想时序就是关键。因为Verilog无法描述理想以外的时序,对此所有时序活动都必须看成理想时序。

clip_image006

图13.3 FPGA接收一帧波特率为115200的数据。

当FPGA接收一帧数据为波特率115200之际,情况差不多如图13.3所示。50Mhz是FPGA的时钟源,也是一帧数据的采集时钟,RXD则是一帧数据的输入端。波特率为115200的一位数据经过50Mhz的时钟量化以后,每一位数据大约保持8.68us,即434个时钟。

串口传输没有自己的时钟信号,所以我们必须利用FPGA的时钟源“跟踪”每一位数据。对此,FPGA只能借用计数器“同步跟踪”而已,至于Verilog则可以这样描述,结果如代码13.2所示:

    0,1,2,3,4,5,6,7,8,9,10:  //同步跟踪中 ...        
    if( C1 == 434 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1; 

代码13.2

如代码13.2所示,所谓同步跟踪,就是利用计数器估计每一位数据 ... 期间,步骤0~10表示每一位数据,至于C1计数434个时钟则是同步跟踪中。其中 -1 考虑了步骤之间的跳转所耗掉的时钟。

clip_image008

图13.4 读取起始位。

我们都知道串口的一帧数据都是从拉低的起始位开始,然而为了完美尾行,亦即实现精密控时,起始位的读取往往都是关键。如图13.4所示,当我们在第一个时钟读取(采集)起始位的时候,由于Verilog的读取只能经过读取过去值而已,余下起始位还有433个时钟需要我们跟踪,为此Verilog可以这样描述,结果如代码13.3所示:

    0: 
    if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end         
         
    1: // stalk start bit
    if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end 
    else C1 <= C1 + 1'b1;

代码13.3

如代码13.3所示,步骤0用来检测起始位,如果RXD的电平为拉低状态,C1立即递增以示同步跟踪已经用掉一个时钟,同样也可以看成i进入下一个步骤用掉一个时钟。然而步骤1是用来跟踪余下的433个时钟,但是计数器C1不是从0开始计数,而是从1开始计算,因为C1在步骤已经递增的缘故。

clip_image010

图13.5 读取一帧数据当中的数据位。

一帧数据的跟踪结果与读取结果如图13.5所示 ... 除了起始位,我们使用了两个步骤采集并跟踪之余,接下来便用8个步骤数据一边跟踪一边采集所有数据位,然而采集的时候则是1/4周期,即每位数据的第108个时钟。最后的校验位及结束位则是跟踪而已。对此,Verilog 可以这样表示,结果如代码13.4所示:

    0: 
    if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end 
                     
    1: // start bit
    if( C1 == 434 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end 
    else C1 <= C1 + 1'b1;
                     
    2,3,4,5,6,7,8,9: 
    begin
        if( C1 == 108 ) D1[i-2] <= RXD;
        if( C1 == 434 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
        else C1 <= C1 + 1'b1;                           
    end
                 
    10,11: // parity bit & stop bit
    if( C1 == 434 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1;

代码13.4

如代码13.4所示,步骤0~1用来采集与跟踪起始位,步骤2~9则用来跟踪数据位,并且采集为1/4周期。步骤10~11则用来跟踪校验位于结束位。理解完毕以后,我们便可以开始建模了。

clip_image012

图13.6 实验十三的建模图。

图13.6是实验十三的建模图,rx_demo组合模块包含RX功能模块与核心操作。RX功能模块的左方链接至RXD顶层信号,它主要是负责一帧数据的接收,然后反馈给核心操作。核心操作则负责RX功能模块的使能工作,当它领取完成信号以后,变桨回收回来的数据再经由TXD顶层信号发送出去。

rx_funcmod.v

clip_image014

图13.7 RX功能模块的建模图。

图13.7是RX功能模块的建模图,左方链接至顶层信号RXD,右方则是问答信号还有8位的oData。

1.    module rx_funcmod
2.    (
3.         input CLOCK, RESET, 
4.         input RXD,
5.         input iCall,
6.         output oDone, 
7.         output [7:0]oData
8.    );
9.        parameter BPS115K2 = 9'd434, SAMPLE = 9'd108;
10.          

以上内容是相关的出入端声明,第9行则是波特率为115200的常量声明,其外还有采集的周期。

11.         reg [3:0]i;
12.         reg [8:0]C1;
13.         reg [7:0]D1;
14.         reg isDone;
15.         
16.         always @ ( posedge CLOCK or negedge RESET )
17.             if( !RESET )
18.                  begin
19.                         i <= 4'd0;
20.                         C1 <= 9'd0;
21.                         D1 <= 8'd0;
22.                         isDone <= 1'b0;
23.                    end

以上内容行是相关的寄存器声明,第17~22行则是这些寄存器的复位操作。

24.              else if( iCall )
25.                  case( i )
26.                         
27.                         0: 
28.                         if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end 
29.                         
30.                         1: // start bit
31.                         if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end 
32.                         else C1 <= C1 + 1'b1;
33.                         
34.                         2,3,4,5,6,7,8,9: //stalk and count 1~8 data's bit , sample data at 1/2 for bps
35.                         begin
36.                            if( C1 == SAMPLE ) D1[i-2] <= RXD;
37.                            if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
38.                            else C1 <= C1 + 1'b1;          
39.                         end
40.                         
41.                         10,11: // parity bit & stop bit
42.                         if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
43.                         else C1 <= C1 + 1'b1;
44.                         
45.                         12:
46.                         begin isDone <= 1'b1; i <= i + 1'b1; end
47.                         
48.                         13:
49.                         begin isDone <= 1'b0; i <= 4'd0; end
50.                    
51.                    endcase
52.                    

以上内容是核心操作。第24行的 if( iCall ) 表示该模块不使能便不工作。步骤0~1用来判断与跟踪起始位;步骤2~9用来跟踪并且读取当中的数据位;步骤10至11则是用来跟踪校验位与停止位而已。步骤12~13则用来反馈完成信号,以示一次性的接收工作已经完成。

53.        assign oDone = isDone;
54.        assign oData = D1;
55.        
56.    endmodule

以上内容是输出驱动声明。

rx_demo.v

rx_demo的连线布局请浏览回图13.6,至于核心操作的内容请浏览代码。

1.    module rx_demo
2.    (
3.         input CLOCK, RESET, 
4.         input RXD,
5.         output TXD
6.    );

以上内容是相关的出入端声明。

7.         wire DoneU1;
8.         wire [7:0]DataU1;
9.        
10.        rx_funcmod U1
11.         (
12.             .CLOCK( CLOCK ),
13.              .RESET( RESET ),
14.              .RXD( RXD ),    // < top
15.              .iCall( isRX ),    // < core
16.              .oDone( DoneU1 ),  // > core
17.              .oData( DataU1 )   // > core
18.         );
19.         

以上内容为是RX功能模块的实例化,第7~8是连线声明。

20.         parameter B115K2 = 9'd434, TXFUNC = 5'd16;
21.         
22.         reg [4:0]i,Go;
23.         reg [8:0]C1;
24.         reg [10:0]D1;
25.         reg rTXD;
26.         reg isRX;
27.         
28.         always @ ( posedge CLOCK or negedge RESET )
29.             if( !RESET )
30.                  begin 
31.                         i <= 5'd0;
32.                         C1 <= 9'd0;
33.                         D1 <= 11'd0;
34.                         rTXD <= 1'b1;
35.                         isRX<= 1'b0;
36.                    end

以上内容为相关的寄存器声明以及复位操作。第20行是波特率为115200常量声明之余还有伪函数的入口地址。第22~26行是相关的寄存器声明,第29~33行则是这些寄存器的复位操作。

37.              else
38.                  case( i )
39.                    
40.                         0:
41.                         if( DoneU1 ) begin isRX <= 1'b0; D1 <= { 2'b11,DataU1,1'b0 }; i <= TXFUNC; Go <= 5'd0; end
42.                         else isRX <= 1'b1; 
43.                         
44.                         /**********/
45.                         
46.                         16,17,18,19,20,21,22,23,24,25,26:
47.                         if( C1 == B115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
48.                         else begin rTXD <= D1[i - 16]; C1 <= C1 + 1'b1; end
49.                         
50.                         27:
51.                         i <= Go;
52.                        
53.                    endcase
54.                    

以上内容为核心操作。步骤16~27是发送一帧数据的伪函数,笔者直接将TX功能整合进来。步骤0则是用来接收完成反馈,并且准备好发送输数,然后i指向伪函数。

55.        assign TXD = rTXD;
56.                               
57.    endmodule

以上内容是相关的输出驱动声明。编译完毕便下载程序,串口调试助手设置为 115200 波特率,8位数据位,奇偶校验位随便,停止位1。事后,每当串口调试助手想FPGA发送什么数据,FPGA也会回馈串口调试助手,不过仅限于一帧又有间隔的数据而已。目前是实验十三还不能支持数据流的接收,因为实验十三没有空间缓冲数据流 ... 此外,核心操作没发送一帧数据也有一定的时间耽误。

细节一:完整的个体模块

实验十三的RX功能模块已经是完整的个体模块,可以直接拿来调用。

目录
相关文章
|
3月前
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的1024QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的1024QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同SNR条件下的性能测试。1024QAM调制将10比特映射到复平面上的1024个星座点之一,实现高效数据传输。硬件测试结果表明,在SNR=32dB和40dB时,系统表现出良好的性能。Verilog核心程序展示了各模块的连接与功能实现。
90 7
|
2月前
|
数据采集 移动开发 算法
【硬件测试】基于FPGA的QPSK调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现QPSK调制与软解调系统,包含Testbench、高斯信道、误码率统计模块,并支持不同SNR设置。硬件版本新增ILA在线数据采集和VIO在线SNR设置功能,提供无水印完整代码及测试结果。通过VIO分别设置SNR为6dB和12dB,验证系统性能。配套操作视频便于用户快速上手。 理论部分详细解析QPSK调制原理及其软解调实现过程,涵盖信号采样、相位估计、判决与解调等关键步骤。软解调通过概率估计(如最大似然法)提高抗噪能力,核心公式为*d = d_hat / P(d_hat|r[n])*,需考虑噪声对信号点分布的影响。 附Verilog核心程序代码及注释,助力理解与开发。
89 5
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的MSK调制解调系统系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现MSK调制解调系统,采用Verilog开发,包含同步模块、高斯信道模拟、误码率统计等功能。相比仿真版本,新增ILA数据采集与VIO在线SNR设置模块。通过硬件测试验证,展示不同SNR(如10dB和16dB)下的性能表现。研究聚焦软件无线电领域,优化算法复杂度以适应硬件限制,利用MSK恒定包络、相位连续等特性提升频谱效率。核心代码实现信号生成、调制解调、滤波及误码统计,提供完整的硬件设计与分析方案。
136 19
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4ASK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的4ASK调制解调系统的硬件测试版本,该系统包括testbench、高斯信道模块和误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置功能。通过VIO设置不同SNR(如15dB和25dB),实现了对系统性能的实时监测与调整。4ASK是一种通过改变载波幅度表示数据的数字调制方式,适用于多种通信场景。FPGA平台的高效性和灵活性使其成为构建高性能通信系统的理想选择。
106 17
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前开发的16QAM调制与软解调系统,增加了硬件测试功能。该系统包含FPGA实现的16QAM调制、软解调、高斯信道、误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置模块。通过硬件测试,验证了不同SNR条件下的系统性能。16QAM软解调通过比较接收信号采样值与16个调制点的距离,选择最近的调制点来恢复原始数据。核心Verilog代码实现了整个系统的功能,包括SNR设置、信号处理及误码率统计。硬件测试结果表明系统在不同SNR下表现良好,详细操作步骤可参考配套视频。
103 13
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4FSK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前的文章《基于FPGA的4FSK调制解调系统》,增加了ILA在线数据采集模块和VIO在线SNR设置模块,实现了硬件测试版本。通过VIO设置不同SNR(如10dB和20dB),并展示了ILA采集的数据结果。四频移键控(4FSK)是一种数字调制方法,利用四个不同频率传输二进制数据,具有较高的频带利用率和抗干扰性能。输入的二进制数据分为两组,每组两个比特,对应四个频率f1、f2、f3、f4,分别代表二进制组合00、01、10、11。调制过程中选择相应频率输出,并进行幅度调制以增强抗干扰能力。接收端通过带通滤波器提取信号并还原为原始二进制数据。
84 7
|
3月前
|
数据采集 算法 数据处理
【硬件测试】基于FPGA的256QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的256QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同信噪比(如30dB和40dB)的仿真测试,并提供配套操作视频。256QAM调制方案每个符号携带8比特信息,通过复数值星座图映射实现高效传输。Verilog代码展示了核心模块设计,包括SNR设置、数据处理和ILA测试分析,确保系统在实际硬件环境中的稳定性和性能。
56 2
|
4月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的16QAM基带通信系统硬件测试版本。该系统在仿真基础上增加了ILA在线数据采集和VIO在线SNR设置模块,支持不同信噪比(如15dB、25dB)的测试。16QAM是一种正交幅度调制方式,通过两路4ASK信号叠加实现,每个符号包含4比特信息。系统采用正交调幅法生成16QAM信号,并通过DAC转换为模拟信号。解调时使用正交相干解调,经低通滤波器恢复电平信号。开发板内完成发射与接收,无需定时同步模块。代码可移植至其他开发板,具体步骤见配套文档。
72 2
|
6月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16QAM调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本项目基于FPGA实现了16QAM基带通信系统,包括调制、信道仿真、解调及误码率统计模块。通过Vivado2019.2仿真,设置不同SNR(如8dB、12dB),验证了软解调相较于传统16QAM系统的优越性,误码率显著降低。系统采用Verilog语言编写,详细介绍了16QAM软解调的原理及实现步骤,适用于高性能数据传输场景。
316 69
|
4月前
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的2ASK调制解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍基于FPGA的2ASK调制解调系统,涵盖仿真效果、理论知识、Verilog核心程序及开发板使用说明。系统包含testbench、高斯信道模块和误码率统计模块,支持不同SNR设置。硬件测试版本增加了ILA在线数据采集和VIO在线SNR设置功能。2ASK调制通过改变载波振幅传输二进制信号,FPGA实现包括系统设计、Verilog编码、仿真测试和硬件部署。详细操作步骤见配套视频,代码适用于多种开发板,提供移植方法。
76 1