精华内容
下载资源
问答
  • 正点原子FPGA连载】第二十九章频率计实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1
    2021-11-04 12:06:24

    1)实验平台:正点原子新起点V2开发板
    2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113
    2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
    3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016
    4)关注正点原子公众号,获取最新资料更新
    在这里插入图片描述

    第二十九章频率计实验

    数字频率计是一种基本的测量仪器,被广泛应用于航天、电子、测控等领域。基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低,在使用中有较大的局限性,而等精度频率计不但具有较高的测量精度,而且在整个频率区域能保持恒定的测试精度。本章我们通过新起点开发板搭建等精度频率计,学习等精度频率计的设计思想和实现方案。
    本章分为以下几个章节:
    2828.1简介
    28.2实验任务
    28.3硬件设计
    28.4程序设计
    28.5下载验证

    29.1简介
    频率测量在电子设计和测量领域中经常用到,因此对频率测量方法的研究在实际工程应用中具有重要意义。常用的频率测量方法有两种:周期测量法和频率测量法。周期测量法是先测量出被测信号的周期T,然后根据频率求出被测信号的频率。频率测量法是在时间t内对被测信号的脉冲数N进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。但是上述两种方法都会产生±1个基准时钟误差或被测时钟的误差,在实际应用中有一定的局限性。根据测量原理,很容易发现周期测量法适合于低频信号测量,频率测量法适合于高频信号测量,但二者都不能兼顾高低频率同样精度的测量要求。
    等精度测量的一个最大特点是测量的实际门控时间不是一个固定值,而是一个与被测信号有关的值,刚好是被测信号的整数倍。在计数允许时间内,同时对基准时钟和被测信号进行计数,再通过数学公式推导得到被测信号的频率。由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l周期误差,但是会产生对基准时钟±1周期的误差。等精度测量原理如图 29.1.1所示。
    在这里插入图片描述

    图 29.1.1 等精度测量原理
    从以上叙述的等精度的测量原理可以很容易得出如下结论:首先,被测信号频率clk_fx的相对误差与被测信号的频率无关;其次,增大测量时间段“软件闸门”或提高“标频”clk_fs,可以减小相对误差,提高测量精度;最后,由于一般提供基准时钟clk_fs的石英晶振稳定性很高,所以基准时钟的相对误差很小,可忽略。假设基准时钟的频率为100MHz,只要实际闸门时间大于或等于1s,就可使测量的最大相对误差小于或等于10^(-8),即精度达到1/100MHz。等精度测量的核心思想在于如何保证在实际测量门闸内被测信号为整数个周期,这就需要在设计中让实际测量门闸信号与被测信号建立一定的关系。基于这种思想,设计中以被测信号的上升沿作为开启门闸和关闭门闸的驱动信号,只有在被测信号的上升沿才将图 29.1.1中预置的“软件闸门”的状态锁存,因此在“实际闸门”Tx内被测信号的个数就能保证整数个周期,这样就避免普通测量方法中被测信号的±1的误差,但会产生高频的基准时钟信号的±l周期误差,由于基准时钟频率远高于被测信号,因此它产生的±1周期误差对测量精度的影响十分有限,特别是在中低频测量的时候,相较于传统的频率测量和周期测量方法,可以大大提高测量精度。
    等精度测频的原理图如图 29.1.2所示。如图中所示,预置软件闸门信号Gate是由新起点开发板的定时模块产生,gate的时间宽度对测频精度的影响较小,故可以在较大的范围内选择,GATE信号经被测时钟clk_fx同步化(图中的D触发器)到被测时钟域下。另外,为了方便处理,这里选择预置闸门信号的长度由参数GATE_TIME设置。图中的fs_cnt和fx_cnt是2个可控的32位高速计数器,fs_cnt_en和fx_cnt_en分别是其计数使能端,由同步化后的gate信号控制,基准时钟信号clk_fs从时钟输入端clk_fs输入,待测信号clk_fx从时钟输入端clk_fx输入。测量时,生成的gate信号,在被测时钟同步化后用来控制启动和关闭2个计数器,2个计数器分别对被测信号和基准时钟计数。若在一次实际闸门时间GATE_TIME中,计数器对被测信号的计数值为fx_cnt,对基准时钟的计数值为fs_cnt,而基准时钟的频率为CLK_FS,则被测信号的频率为clk_fx,则由公式
    在这里插入图片描述
    图 29.1.2 是新起点开发板实现功能的原理图。
    在这里插入图片描述

    图 29.1.2 新起点实现的功能的原理图
    29.2实验任务
    本次的实验任务是板载50MHz的时钟通过内部逻辑进行分频,来产生500KHz频率的信号,作为被测时钟,然后用Verilog HDL编写的等精度测量模块测量被测时钟,并通过数码管显示。
    29.3硬件设计
    本次实验只需将新起点开发板P6扩展口的两个IO使用跳帽或者杜邦线连接即可。本次实验将新起点开发板的N9引脚做为分频产生的时钟的输出端,P9引脚作为被测时钟的输入端,通过一根导线(杜邦线)或者跳帽进行连接。
    在这里插入图片描述

    图 29.3.1 硬件原理图
    由于端口引脚较多,这里仅给出部分管脚列表,如下表所示:
    表 29.3.1 等精度频率计实验管脚分配
    在这里插入图片描述

    XDC约束语句如下:
    set_location_assignment PIN_M2 -to sys_clk
    set_location_assignment PIN_M1 -to sys_rst_n
    set_location_assignment PIN_P9 -to clk_fx
    set_location_assignment PIN_N9 -to clk_out
    29.4程序设计
    根据实验任务,我们可以大致规划出系统的控制流程:首先我们设计一个测试时钟模块用于生成被测的时钟,然后用等精度频率计模块测量被测时钟的频率,并将测得的时钟频率值送入数码管显示模块进行显示。由此画出系统的功能框图如下所示:
    在这里插入图片描述

    图 29.4.1 等精度频率计实验系统框图
    由系统框图可知,FPGA部分包括四个模块:顶层模块(top_cymometer)、等精度频率计模块(cymometer)、时钟产生模块(test_pll)以及数码管显示模块(seg_led)。各模块功能如下:
    顶层模块(top_cymometer):顶层模块完成了对其它三个模块的例化,实现各模块之间的数据交互。时钟产生模块产生被测时钟输出,并从外部接入至等精度频率计模块,以进行频率测量,将测量的结果传输给数码管显示模块进行显示。顶层模块的原理图如下图所示:
    在这里插入图片描述

    图 29.4.2 顶层模块原理图
    等精度频率计模块(cymometer):等精度频率计模块测量输入的被测时钟的频率。并将测得的频率结果输出。
    时钟产生模块(test_pll):时钟产生模块产生被测的时钟。
    数码管显示模块(seg_led):用来驱动数码管将等精度频率计测得的时钟频率值在数码管上显示出来。
    顶层模块的代码如下:

    1   module top_cymometer(
    2       //system clock
    3       input                  sys_clk  ,    // 时钟信号
    4       input                  sys_rst_n,    // 复位信号
    5   
    6       //cymometer interface
    7       input                  clk_fx   ,    // 被测时钟
    8       output                 clk_out  ,    // 输出时钟
    9       //user interface
    10      output          [5:0]  sel      ,    // 数码管位选
    11      output          [7:0]  seg_led       // 数码管段选
    12  );
    13  
    14  //parameter define
    15  parameter    CLK_FS = 26'd50000000;      // 基准时钟频率值
    16  
    17  //wire define
    18  wire    [19:0]       data_fx;            // 被测信号测量值
    19  
    20  //*****************************************************
    21  //**                    main code
    22  //*****************************************************
    23  
    24  //例化PLL,生成待测试时钟500Khz
    25  test_pll    test_pll_inst (
    26      .inclk0           (sys_clk  ),
    27      .c0               (clk_out  )
    28      );
    29  
    30  //例化等精度频率计模块
    31  cymometer #(.CLK_FS(CLK_FS)              // 基准时钟频率值
    32  ) u_cymometer(
    33      //system clock
    34      .clk_fs      (sys_clk  ),            // 基准时钟信号
    35      .rst_n       (sys_rst_n),            // 复位信号
    36      //cymometer interface
    37      .clk_fx      (clk_fx   ),            // 被测时钟信号
    38      .data_fx     (data_fx  )             // 被测时钟频率输出
    39  );
    40      
    41  //例化数码管显示模块
    42  seg_led u_seg_led(
    43      //module clock
    44      .clk         (sys_clk  ),            // 数码管驱动模块的驱动时钟
    45      .rst_n       (sys_rst_n),            // 复位信号
    46      //seg_led interface
    47      .seg_sel     (sel      ),            // 数码管位选
    48      .seg_led     (seg_led  ),            // 数码管段选
    49      //user interface
    50      .data        (data_fx  ),            // 被测频率值
    51      .point       (6'd0     ),            // 数码管显示的点控制
    52      .en          (1'b1     ),            // 数码管驱动使能信号
    53      .sign        (1'b0     )             // 控制符号位显示
    54  );
    55  
    56  endmodule
    

    顶层代码主要完成对各模块的例化并实现模块信号间的交互。第15行的基准时钟频率值参数为基准时钟频率值,当用不同的基准时钟时修改此参数即可。
    等精度频率计模块的代码如下:

    1   module cymometer
    2   #(parameter    CLK_FS = 26'd50_000_000) // 基准时钟频率值
    3       (   //system clock
    4           input                 clk_fs ,     // 基准时钟信号
    5           input                 rst_n  ,     // 复位信号
    6   
    7           //cymometer interface
    8           input                 clk_fx ,     // 被测时钟信号
    9           output   reg [19:0]   data_fx      // 被测时钟频率输出
    10  );
    11  
    12  //parameter define
    13  localparam   MAX       =  6'd32;           // 定义fs_cnt、fx_cnt的最大位宽
    14  localparam   GATE_TIME = 16'd5_000;        // 门控时间设置
    15  
    16  //reg define
    17  reg                gate        ;           // 门控信号
    18  reg                gate_fs     ;           // 同步到基准时钟的门控信号
    19  reg                gate_fs_r   ;           // 用于同步gate信号的寄存器
    20  reg                gate_fs_d0  ;           // 用于采集基准时钟下gate下降沿
    21  reg                gate_fs_d1  ;           // 
    22  reg                gate_fx_d0  ;           // 用于采集被测时钟下gate下降沿
    23  reg                gate_fx_d1  ;           // 
    24  reg    [   63:0]   data_fx_t    ;          // 
    25  reg    [   15:0]   gate_cnt    ;           // 门控计数
    26  reg    [MAX-1:0]   fs_cnt      ;           // 门控时间内基准时钟的计数值
    27  reg    [MAX-1:0]   fs_cnt_temp ;           // fs_cnt 临时值
    28  reg    [MAX-1:0]   fx_cnt      ;           // 门控时间内被测时钟的计数值
    29  reg    [MAX-1:0]   fx_cnt_temp ;           // fx_cnt 临时值
    30  
    31  //wire define
    32  wire               neg_gate_fs;            // 基准时钟下门控信号下降沿
    33  wire               neg_gate_fx;            // 被测时钟下门控信号下降沿
    34  
    35  //*****************************************************
    36  //**                    main code
    37  //*****************************************************
    38  
    39  //边沿检测,捕获信号下降沿
    40  assign neg_gate_fs = gate_fs_d1 & (~gate_fs_d0);
    41  assign neg_gate_fx = gate_fx_d1 & (~gate_fx_d0);
    42  
    43  //门控信号计数器,使用被测时钟计数
    44  always @(posedge clk_fx or negedge rst_n) begin
    45      if(!rst_n)
    46          gate_cnt <= 16'd0; 
    47      else if(gate_cnt == GATE_TIME + 5'd20)
    48          gate_cnt <= 16'd0;
    49      else
    50          gate_cnt <= gate_cnt + 1'b1;
    51  end
    52  
    53  //门控信号,拉高时间为GATE_TIME个实测时钟周期
    54  always @(posedge clk_fx or negedge rst_n) begin
    55      if(!rst_n)
    56          gate <= 1'b0;
    57      else if(gate_cnt < 4'd10)
    58          gate <= 1'b0;     
    59      else if(gate_cnt < GATE_TIME + 4'd10)
    60          gate <= 1'b1;
    61      else if(gate_cnt <= GATE_TIME + 5'd20)
    62          gate <= 1'b0;
    63      else 
    64          gate <= 1'b0;
    65  end
    66  
    67  //将门控信号同步到基准时钟下
    68  always @(posedge clk_fs or negedge rst_n) begin
    69      if(!rst_n) begin
    70          gate_fs_r <= 1'b0;
    71          gate_fs   <= 1'b0;
    72      end
    73      else begin
    74          gate_fs_r <= gate;
    75          gate_fs   <= gate_fs_r;
    76      end
    77  end
    78  
    79  //打拍采门控信号的下降沿(被测时钟下)
    80  always @(posedge clk_fx or negedge rst_n) begin
    81      if(!rst_n) begin
    82          gate_fx_d0 <= 1'b0;
    83          gate_fx_d1 <= 1'b0;
    84      end
    85      else begin
    86          gate_fx_d0 <= gate;
    87          gate_fx_d1 <= gate_fx_d0;
    88      end
    89  end
    90  
    91  //打拍采门控信号的下降沿(基准时钟下)
    92  always @(posedge clk_fs or negedge rst_n) begin
    93      if(!rst_n) begin
    94          gate_fs_d0 <= 1'b0;
    95          gate_fs_d1 <= 1'b0;
    96      end
    97      else begin
    98          gate_fs_d0 <= gate_fs;
    99          gate_fs_d1 <= gate_fs_d0;
    100     end
    101 end
    102 
    103 //门控时间内对被测时钟计数
    104 always @(posedge clk_fx or negedge rst_n) begin
    105     if(!rst_n) begin
    106         fx_cnt_temp <= 32'd0;
    107         fx_cnt <= 32'd0;
    108     end
    109     else if(gate)
    110         fx_cnt_temp <= fx_cnt_temp + 1'b1;
    111     else if(neg_gate_fx) begin
    112         fx_cnt_temp <= 32'd0;
    113         fx_cnt   <= fx_cnt_temp;
    114     end
    115 end 
    116 
    117 //门控时间内对基准时钟计数
    118 always @(posedge clk_fs or negedge rst_n) begin
    119     if(!rst_n) begin
    120         fs_cnt_temp <= 32'd0;
    121         fs_cnt <= 32'd0;
    122     end
    123     else if(gate_fs)
    124         fs_cnt_temp <= fs_cnt_temp + 1'b1;
    125     else if(neg_gate_fs) begin
    126         fs_cnt_temp <= 32'd0;
    127         fs_cnt <= fs_cnt_temp;
    128     end
    129 end
    130 
    131 //计算被测信号频率
    132 always @(posedge clk_fs or negedge rst_n) begin
    133     if(!rst_n) begin
    134         data_fx_t <= 64'd0;
    135     end
    136     else if(gate_fs == 1'b0)
    137         data_fx_t <= CLK_FS * fx_cnt ;
    138 end
    139 
    140 always @(posedge clk_fs or negedge rst_n) begin
    141     if(!rst_n) begin
    142         data_fx <= 20'd0;
    143     end
    144     else if(gate_fs == 1'b0)
    145         data_fx <= data_fx_t / fs_cnt ;
    146 end
    147 
    148 endmodule 
    

    在前面的等精度频率计简介中,我们知道在等精度测量中需要一个闸门信号(门控信号),并且该闸门信号需要同步化到被测时钟域下。这里我们为了方便处理,用被测时钟控制闸门信号的产生,这样就避免了同步化处理,当然了,完全可以用基准时钟控制闸门信号的产生,不过这时产生的闸门信号我们需要同步化到被测时钟域下,这样做的目的是为了不让被测时钟计数产生周期的误差。门控时间由参数GATE_TIME设置,此处设为5000,需要说明的是该值越大测得的被测时钟频率值越精确,但测量时间也会相应的变慢一些。另外因为闸门信号是由被测时钟产生的,当测量频率较高的信号或者说信号频率大于10KHz(此值跟门控时间有关)时是不会有什么问题的,但当测量低频信号像Hz级这种,如果门控时间设置的大的话,测量时间就会非常长,此时可修改门控时间的值,为被测时钟频率的5~10倍即可,对于几十KHz及以上的时钟信号,门控时间的大小对测量速度的影响较小,频率越高影响越小,但对测量精度影响较大,因而在测量频率较高的信号时,建议增大门控时间。
    代码中为了防止复位对测量造成的干扰,门控信号在复位后延迟了10个被测信号的周期(第55~58行)。另外计算被测信号频率是在基准时钟下的门控信号为低电平时进行。
    建立了门控信号之后,我们需要通过门控信号分别使能基准时钟和被测时钟的计数。因为门控信号对基准时钟而言是异步信号,所以这里我们对门控信号进行了两次打拍处理得到基准频率下的门控信号gate_fs(代码第68行的always语句块)。在门控信号的下降沿将计数值寄存并清零计数寄存器。
    在取得数值后,我们需要计算被测信号的频率值,由于在计算周期内数值已不再发生变化(计数值已寄存),而且保留了足够的计算时间,所以可以不用FIFO进行异步处理。计算完之后,把所得的结果赋给寄存器变量data_fx,其数值的单位为Hz。
    到这里频率计实验的代码就讲解完了,关于数码管显示部分内容大家可以参考前面数码管显示的例程,这里不再作重复讲解。
    至此,我们的设计部分已基本完成,现在我们来做一下误差分析。
    (1-3)
    其中clk_fxe为被测频率信号的准确值。
    在测量中,由于clk_fx计数的起停时间都是由该信号的上升沿触发的,在闸门时间GATE_TIME内对clk_fx的计数fx_cnt无误差();对clk_fs的计数fs_cnt最多相差一个时钟的误差,即|Δfs_cnt|≤1,其测量频率如式(1-4):
    (1-4)
    将式(1-2)和(1-4)代入式(1-3),并整理如式
    (1-5)
    由上式可以看出,测量频率的相对误差与被测信号频率的大小无关,仅与闸门时间和基准时钟频率有关,即实现了整个测试频段的等精度测量。闸门时间越长,基准时钟频率越高,测频的相对误差就越小。基准时钟频率可由稳定度好、精度高的高频率晶体振荡器产生,在保证测量精度不变的前提下,提高基准时钟频率,可使闸门时间缩短,即提高测试速度。
    29.5下载验证
    编译工程并生成sof文件。将新起点开发板的N9引脚和P9引脚,用一根杜邦线或者跳帽连接起来,将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。
    下载完成后数码管上面显示“500000”,如下图所示,与时钟产生模块产生的时钟频率一致,等精度频率计实验下载验证成功。
    在这里插入图片描述

    图 29.5.2 实验结果

    更多相关内容
  • 正点原子 FPGA代码

    2019-05-12 23:21:06
    正点原子 FPGA代码
  • 正点原子FPGA静态时序分析与时序约束_V1.0
  • FPGA学习少不了的好资料
  • 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第二章实验平台简介 本章内容主要向大家简要介绍我们的实验平台:新起点FPGA开发板。通过本章的学习,你将对我们...

    1)实验平台:正点原子新起点V2开发板
    2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113
    2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
    3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016
    4)关注正点原子公众号,获取最新资料更新
    在这里插入图片描述
    第二章实验平台简介

    本章内容主要向大家简要介绍我们的实验平台:新起点FPGA开发板。通过本章的学习,你将对我们后面使用的实验平台有个快速的了解,为后面的学习做铺垫。
    本章包括以下几个部分:1.3
    22.1新起点FPGA开发板资源初探
    2.2新起点FPGA开发板资源说明

    2.1新起点FPGA开发板资源初探
    正点原子目前已经拥有多款 STM32、I.MXRT以及FPGA开发板,这些开发板常年稳居淘宝销量冠军,累计出货超过10W套。这款FPGA开发板,既适合于初学者入门FPGA,同时也适合有一定经验的FPGA工程师提升自己的开发水平。
    2.1.1新起点开发板资源
    首先,我们来看新起点FPGA开发板的资源图,如图 2.1.1所示:
    在这里插入图片描述

    图 2.1.1 新起点FPGA开发板资源图
    从图 2.1.1可以看出,新起点FPGA开发板的资源十分丰富,把FPGA EP4CE10的内部资源发挥到了极致,同时扩充了丰富的接口和功能模块,整个开发板显得十分大气。
    开发板的外形尺寸为90mm*128.3mm,板子的设计充分考虑了人性化设计,并结合正点原子多年的开发板设计经验,经过多次改进,最终确定了这样的设计。
    新起点FPGA开发板板载资源如下:
    主控芯片:EP4CE10F17C8N,封装:BGA256
    晶振:50Mhz
    FLASH:W25Q16,容量:16Mbit(2M字节)
    SDRAM:W9825G6KH-6,容量:256Mbit(32M字节)
    EEPROM:AT24C64,容量:64Kbit(8K字节)
    1个电源指示灯(蓝色)
    4个状态指示灯(DS0~DS3:红色)
    1个红外接收头,并配备一款小巧的红外遥控器
    1个无线模块接口,支持NRF24L01无线模块
    1路单总线接口,支持DS18B20/DHT11等单总线传感器
    1个ATK模块接口,支持正点原子蓝牙/GPS/MPU6050/RGB灯模块
    1个环境光传感器,采用AP3216C芯片
    1个标准的RGB TFT-LCD接口
    1个OLED/摄像头模块接口
    1个USB串口
    1个有源蜂鸣器
    1个SD卡接口(在板子背面)
    1个HDMI接口
    1个标准的JTAG调试下载口
    1组5V电源供应/接入口
    1组3.3V电源供应/接入口
    1个直流电源输入接口(输入电压范围:DC6~16V)
    1个RTC后备电池座,并带电池(在板子背面)
    1个RTC实时时钟,采用PCF8563芯片
    1个复位按钮,可作为FPGA程序执行的复位信号
    4个功能按钮
    1个电容触摸按键
    1个电源开关,控制整个开发板的电源
    两个20x2扩展口,共72个扩展IO口(除去电源和地)
    新起点FPGA开发板的特点包括:
    1)接口丰富。板子提供了丰富的标准外设接口,可以方便的进行各种外设的实验和开发。
    2)设计灵活。板上很多资源都可以灵活配置,以满足不同条件下的使用。其中芯片两侧引出两排24x2扩展口,共72个扩展IO口。
    3)资源充足。主控芯片采用自带414Kbit嵌入式RAM块的EP4CE10F17C8N,并外扩256Mbit(32M字节)SDRAM和64Kbit(8K字节)的EEPROM,满足大内存需求和大数据存储。板载HDMI接口、LCD接口、UART串口、环境光传感器以及其它各种接口芯片,满足各种不同应用的需求。
    4)人性化设计。各个接口都有丝印标注,且用方框框出,使用起来一目了然;部分常用外设大丝印标出,方便查找;接口位置设计合理,方便顺手。资源搭配合理,物尽其用。
    2.2新起点FPGA开发板资源说明
    新起点FPGA开发板资源说明分为两个部分:硬件资源说明和软件资源说明。
    2.2.1硬件资源说明
    新起点FPGA开发板不仅配备了丰富的硬件外设而且提供了大量的扩展IO,为了让大家对开发板整体的硬件资源有个清晰的了解,我们特地画出了新起点FPGA开发板硬件资源框图,如下图所示:
    在这里插入图片描述

    图 2.2.1 新起点资源框图
    EP4CE10F17C8N FPGA芯片包括8个IO Bank,IO Bank可以理解为是FPGA IO的一个集合,每个Bank的IO电压和特性是相同的。我们分别为不同Bank的IO连接了不同的外设,如图 2.1.1所示。
    我们再来看下EP4CE10F17C8N FPGA芯片的Bank在BGA芯片管脚上面的分布,如下图所示:
    在这里插入图片描述

    图 2.2.2 FPGA的Bank分布
    下面我们来给大家解读一下上图所示的IO分布图。
    EP4CE10F17C8N FPGA芯片共有256个IO(FBGA256封装),按照16行16列去分布的,又将这256个IO分成8个Bank,每个Bank上的所有IO必须保持相同的电压特性。从上图中可以看到每个Bank的颜色都不同,主要是方便我们去查找IO具体在哪个Bank,细心的同学可能还会发现这256个IO还有许多不同的符号或者字母标注,比如第A行第5列标注一个“Q”,第A行第6列标注一个“S”,甚至还有一些IO就是一些三角形圆形的符号。那么这些标注是什么意思呢,在这里我们用一张图给大家说明一下,如下图所示:
    在这里插入图片描述

    图 2.2.3 IO标识含义
    从上图可以看到每个符号后面都有自己的注释,比如第一个白色圆圈代表普通IO,字母“P、N”代表差分IO,在分配IO的时候就需要注意不能把差分信号分配到普通IO上,否则编译就会报错。因此我们在设计硬件电路或者编写软件工程的时候一定要注意引脚不能乱用。
    硬件资源说明:
    这里我们首先详细介绍新起点FPGA开发板的各个部分(图 2.1.1中的标注部分)的硬件资源,我们将按逆时针的顺序依次介绍。
    1)WIRELESS模块接口
    新起点FPGA开发板板载一个无线模块扩展接口,只要在该接口上插入NRF24L01模块,便可以实现无线通信,从而使我们板子具备了无线通信的功能。这里需要注意的是,两个开发板和两个无线模块同时工作才可以实现无线通信的功能;只有1个开发板或1个模块,是无法实现无线通信功能的。
    2)SD卡接口
    新起点FPGA开发板板载一个标准SD卡卡槽(TF卡),该卡槽在开发板的背面,可以插入SD卡,使用SPI/SDIO驱动方式去驱动SD卡,旨在满足海量数据的存储需求。
    3)引出IO口(总共有2处)
    新起点FPGA开发板板载两组IO扩展口:P6和P7。其中,P6和P7分别采用2*20排针引出,总共引出72个IO口(电源和地不算)。
    4)RGB TFT-LCD接口
    新起点FPGA开发板板载RGB LCD接口(LCD),可以连接各种正点原子的RGB LCD屏模块,并且支持触摸屏(电阻/电容屏都可以)。为了节省IO口,采用的是RGB565格式,虽然降低了颜色深度,但是节省了IO,且RGB565的数据格式,在程序上更通用一些。
    5)50Mhz晶振
    新起点FPGA开发板板载一个频率为50Mhz的晶振(XTAL),该晶振输出的时钟是FPGA的最原始的时钟,其它需要的各种频率的时钟都是在这个时钟的基础上利用PLL(锁相环)或者其它分频方法得到的。
    6)JTAG接口
    新起点FPGA开发板板载一个10针标准JTAG调试口(JTAG),该JTAG口直接可以和FPGA下载器(调试器)连接,用于下载程序或者对程序进行在线调试。
    7)USB转串口
    新起点FPGA开发板板载一个USB串口(USB_UART),之所以设计成USB串口,是出于现在电脑上串口正在消失,尤其是笔记本,几乎清一色的没有串口。所以板载了USB串口可以方便大家进行USB串口通信的试验。而在板子上并没有直接连接在一起,则是出于使用方便的考虑。同时这个USB接口还可以给开发板提供电源,但是其最大电流只有500mA,大家在做LCD显示实验或者高速AD/DA实验等对供电能力要求较高时,推荐大家使用DC6~16V电源输入接口。
    8)SDRAM
    新起点FPGA开发板板载一颗SDRAM芯片(U23),型号为:W9825G6KH,容量为256Mbit(32M字节),轻松应对各种大内存需求场景,比如摄像头图像数据存储、录音数据存储等。
    9)六位数码管
    新起点FPGA开发板板载一个6位共阳极数码管(SEGLED),该数码管提供了一种最简单直观的显示,比如显示温度值、光照强度等。
    10)OLED/摄像头模块接口
    新起点FPGA开发板板载一个OLED/摄像头模块接口(P1),如果是OLED模块,靠左插即可(右边两个孔位悬空)。如果是摄像头模块(正点原子提供),则刚好插满。通过这个接口,可以分别完成多个外部模块的相关实验。
    11)环境光传感器
    新起点FPGA开发板板载一个环境光传感器(U7),它可以作为环境光传感器和近距离传感器。通过该传感器,开发板可以感知周围环境光线的变化和接近距离,从而可以实现类似手机的自动背光控制。
    12)有源蜂鸣器
    新起点FPGA开发板板载一个蜂鸣器(BEEP),可以实现简单的报警/闹铃。
    13)红外接收头
    新起点FPGA开发板板载红外接收头(U11),可以实现红外遥控功能,通过这个接收头,可以接收市面常见的各种遥控器的红外信号,大家甚至可以自己实现万能红外解码。当然,如果应用得当,该接收头也可以用来传输数据。
    新起点FPGA开发板给大家配备了一个小巧的红外遥控器,该遥控器外观如图 2.2.1.1 所示:
    在这里插入图片描述

    图 2.2.4 红外遥控器
    14)RTC实时时钟
    新起点FPGA开发板板载一个RTC实时时钟芯片(U12),新起点FPGA开发板上的实时时钟芯片为PCF8563,PCF8563是PHILIPS公司推出的一款工业级多功能时钟/日历芯片,具有报警功能、定时器功能、时钟输出功能以及中断输出功能,能完成各种复杂的定时服务。
    15)单总线接口
    新起点FPGA开发板板载一个单总线接口(U9),该接口由4个镀金排孔组成,可以用来接DS18B20/DHT11等单总线传感器。在不需要用的时候,大家可以拆下上面的传感器,放到其他地方去用,使用上是十分方便灵活的。
    16)4个LED
    新起点FPGA开发板板载四个LED灯(DS0~DS3)。四个LED灯对于一般的应用足够了,在调试代码的时候,使用LED来指示程序执行状态,是非常不错的一个辅助调试方法。
    17)复位按钮
    新起点FPGA开发板板载一个复位按键(RESET),可以作为FPGA程序执行的复位信号,注意按键复位信号默认是高电平的,当复位按钮按下之后为低电平。
    18)4个按键
    新起点FPGA开发板板载4个机械式按键(KEY0~KEY3)是直接连接在FPGA的IO口上的,可以作为人机交互的输入信号。这4个按键信号默认都是高电平的,当按键被按下之后,按键信号变为低电平。
    19)电池接口
    新起点FPGA开发板板载RTC实时时钟的供电接口(BAT1),可以保证在PPGA开发板断电时,实时时钟仍然能够继续工作,这样的话,配置的日期与时间不会因FPGA开发板的断电而恢复到默认值。
    20)触摸按钮
    新起点FPGA开发板板载一个电容触摸输入按键(TPAD),利用电容充放电原理,实现触摸按键检测的功能。
    21)电源指示灯
    新起点FPGA开发板板载一颗蓝色的LED灯(PWR),用于指示电源状态。在电源开启的时候电源指示灯会处于点亮的状态,否则为熄灭的状态。通过这个LED,可以判断开发板的上电情况。
    22)ATK模块接口
    新起点FPGA开发板板载一个正点原子通用模块接口(U5),目前可以支持正点原子开发的GPS模块、蓝牙模块、MPU6050模块和全彩RGB灯模块等,直接插上对应的模块,就可以进行相关模块的开发。后续我们将开发更多兼容该接口的其他模块,实现更强大的扩展性能。
    23)3.3V电源输入/输出
    新起点FPGA开发板板载一组3.3V电源输入输出排针(23)(VOUT1),用于给外部提供3.3V的电源,也可以从外部接3.3V的电源给板子供电。大家在做实验的时候可能经常会为没有3.3V电源而苦恼不已,有了新起点FPGA开发板,你就可以很方便的拥有一个简单的3.3V电源(最大电流不能超过500mA)。
    24)5V电源输入/输出
    新起点FPGA开发板板载一组5V电源输入输出排针(2
    3)(VOUT2),该排针用于给外部提供5V 的电源,也可以从外部接5V的电源给板子供电。同样大家在实验的时候可能经常会为没有5V电源而苦恼不已,正点原子充分考虑到了大家的需求,有了这组5V排针,你就可以很方便的拥有一个简单的5V电源(USB供电的时候,最大电流不能超过500mA,外部供电的时候,最大可达1000mA)。
    25)电源开关
    新起点FPGA开发板板载一个电源开关(K1)。该开关用于控制整个开发板的供电,如果通过开关切断电源,则整个开发板都将断电,电源指示灯(PWR)会随着此开关的状态而亮灭。
    26)DC6~16V电源输入
    新起点FPGA开发板板载一个外部电源输入口(DC_IN),采用标准的直流电源插座。开发板板载了DC-DC芯片(MP2359),用于给开发板提供高效、稳定的5V电源。由于采用了DC-DC芯片,所以开发板的供电范围十分宽,大家可以很方便的找到合适的电源(只要输出范围在DC6~16V 的基本都可以)来给开发板供电。在耗电比较大的情况下,比如用到4.3寸屏/7寸屏/网口/高速AD/DA的时候,建议大家使用外部电源供电,可以提供足够的电流给开发板使用。
    27)HDMI接口
    新起点FPGA开发板板载一个HDMI接口(仅支持输出),该接口可以连接在带有HDMI接口的显示器上,FPGA通过HDMI接口来驱动显示器,使其显示出彩条、图片以及视频图像等。
    28)LCD接口
    新起点FPGA开发板板载MCU TFT-LCD模块接口(16位并口数据),兼容正点原子全系列LCD模块,包括:2.4寸、2.8寸、3.5寸、4.3寸和7寸等MCU TFT-LCD 模块,并且支持电阻/电容触摸功能。
    29)FPGA(EP4CE10)
    这是开发板的核心芯片(U14),型号为EP4CE10F17C8。该款芯片拥有10320个逻辑单元、414Kbits的嵌入式存储资源、23个18×18的嵌入式乘法器、2个通用锁相环、10个全局时钟网络、8个用户I/O BANK和最大179个用户I/O,是一款非常具有性价比的芯片。
    30)Flash(W25Q16)
    新起点FPGA开发板板载一块Flash芯片(U15),现在大规模的FPGA都是基于SRAM结构的,程序掉电后会丢失。因此,在FPGA上电后,需要一个外部芯片在短时间内将程序加载到FPGA硬件里面,并且这个外部芯片存储的程序在掉电后是不丢失的,这个外部芯片就是FPGA的配置芯片。配置芯片用于储存FPGA的程序,以保证FPGA在重新上电后仍能继续工作。新起点FPGA开发板的配置芯片型号为W25Q16(完全兼容EPCS16芯片),存储容量为16Mbit(2M字节)。
    31)EEPROM (AT24C64)
    新起点FPGA开发板板载一块EEPROM芯片(U6),容量为64Kbit,也就是8K字节。用于存储一些掉电不能丢失的重要数据,比如系统设置的一些参数等。有了这个就可以方便的实现掉电数据保存。
    2.2.2软件资源说明
    上面我们简单介绍了新起点FPGA开发板的硬件资源。接下来,我们将向大家简要介绍新起点FPGA开发板的软件资源。
    新起点FPGA开发板Verilog提供的标准例程多达49个,新起点FPGA开发板NIOS II提供的标准例程多达17个。我们提供的这些例程,全部都是原创自主开发,注释非常详细、代码风格统一、难易程度由浅入深,非常适合初学者入门。而其他家开发板的例程,要么注释比较少,要么工程文件管理不统一,对初学者来说可能很难入门。
    新起点FPGA开发板Verilog的例程列表如下表所示:
    表 2.2.1例程列表
    在这里插入图片描述

    从上表可以看出,正点原子 FPGA开发板的例程是非常丰富的,并且扩展了很多有价值的例程。各个例程的安排是循序渐进的,首先从最基础的流水灯开始,然后一步步深入,从简单到复杂,有利于大家的学习和掌握,所以,正点原子新起点FPGA开发板是非常适合初学者的。当然,对于想深入学习FPGA开发的朋友,正点原子新起点FPGA开发板也绝对是一个不错的选择。
    2.2.3新起点IO引脚分配
    表 2.2.2 IO引脚分配表
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    表格中列出来了除扩展口外,开发板上所有的IO引脚,扩展口上的引脚IO可以参考开发板的原理图或者直接查看开发板上的丝印标注。
    该表在:新起点开发板资料盘(A盘)\3_正点原子新起点FPGA开发板原理图文件夹下有提供Excel格式,方便大家查看。

    展开全文
  • 1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子...

    1)实验平台:正点原子新起点V2开发板
    2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113
    2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
    3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016
    4)关注正点原子公众号,获取最新资料更新
    在这里插入图片描述

    第一章FPGA简介

    FPGA(Field Programmable Gate Array),即现场可编程门阵列,它是一种半定制的数字集成电路。FPGA凭借其灵活性高、开发周期短、处理性能强(并行)等特点,广泛应用于通信、图像处理、医疗等领域。随着科技的进步,FPGA在人工智能、5G和自动驾驶等领域也有一席之地。本章节我们将会详细介绍什么是FPGA,让大家对FPGA有个初步的认识。

    本章包括以下两个部分:
    1.1初识FPGA
    1.2深度剖析FPGA
    1.1初识FPGA
    其实我很好奇当大家拿到我们的开发板,看到板子上镶嵌的那一块黑不溜秋的像饼干一样的控制芯片时,大家心里会想些什么。犹记当年我第一次见到这玩意时,忍不住用手在上面不停的抚摸,你还别说,这么贵的玩意摸起来手感真挺不错的,很有质感,可是没几分钟,新鲜劲一过我就开始犯愁了,我买的到底是个什么玩意儿,有啥用啊,我学它干嘛?现在回想起来感觉恍如昨日,感叹一句岁月不饶人啊,所以我在写这篇文章的时候就在想大家第一次拿到FPGA开发板后是啥反应,是不是像当初的我一样,乍见欣喜,然后满脑袋问号,迫切的想了解到底什么是FPGA呢,它有什么用呢,我学了它后又能干什么呢,以后有前途吗?莫急,听我娓娓道来。
    1.2FPGA是什么
    首先我们先来聊聊什么是FPGA,其实这个问题不好回答,简单点来说FPGA(Field Programmable Gate Array,即现场可编程门阵列)它是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路个数有限的缺点,这就是FPGA。我相信这种回答很少有人能够理解,因为它涉及到的专业名词和知识面是非常广泛的,我要是把这段话就作为对FPGA的简介一定会被大家痛骂,大家可能会觉得什么玩意儿,你这说的还不如我百度呢,糊弄我吧。也确实,我自己当初看到这句话时也是一脸懵,还是不明白自己手上拿的这个“黑块块”到底是个啥,所以接下来我准备好好跟大家唠唠你们手中的“黑块块”到底是个什么东西。
    我先给大家上一张图(图片来源于网络),如所示,这张图应该是一个电子类专业的学生作品。
    在这里插入图片描述

    图 1.2.1 面包板搭建数字时钟电路
    从图中我们可以看到该电路是一个数字时钟,里面有晶振、蜂鸣器、数码管,以及各种74 系列的小芯片,这些小芯片能够实现的功能也就相当于几个逻辑门,如果你亲自动手去搭建它,肯定会知道搭建该电路是非常麻烦的,一根线一根线去连接,不断对照原理图,生怕搭错一根线,搞不好心态就崩了。大家可以想一想,这仅仅是搭建一个简单的数字时钟就这么多跟线了,密密麻麻的,看起来就很复杂。如果我们想要实现更加复杂的功能,那么我们就要犯难了,因为我们需要使用几十个或者上百个这种专用小芯片来完成,这样就会使得电路板的布局、布线变得困难,还会极大的影响到整个系统的性能,而且搭出来的电路体积庞大,也不美观,实用性极差,所以这种方式毫无疑问是不行的。为了改变这种情况,大家就想到了一个办法,那就是通过专用集成电路(ASIC)来实现,我们可以将要实现的特定需求交给 ASIC 厂商,让他们设计出一个专用集成电路芯片,这样就可以解决这种问题了。比如说,我们把数字时钟功能要求交给 ASIC 厂商,ASIC 厂商就会根据数字时钟功能要求设计出一个专用集成电路芯片,这一个小小的芯片它其实就完成了我们数字时钟电路功能。这种方法虽然很好,但同时也会带来很多其他的问题,比如说,生成周期长,芯片难验证,芯片内部电路不可以更改等等问题。于是人们就开始不断地去探索,看看有没有什么办法既能让我很好的实现功能,又能解决定制电路的不足。
    在这里插入图片描述

    图 1.2.2 Xilinx A7系列FPGA芯片
    于是FPGA应运而生(如图 1.2.2),于 1985 年由 Xilinx 创始人之一 Ross Freeman 发明,属于可编程逻辑器件 PLD(Programmable Logic Device)的一种。真正意义上的第一颗FPGA 芯片 XC2064 为 Xilinx 所发明,这个时间差不多比著名的摩尔定律晚 20 年左右,但是 FPGA一经问世,后续的发展速度之快,超出大多数人的想象。为什么FPGA能如此迅速的发展呢,这与它本身独特的优越性密不可分。我们要知道一块专用的ASIC定制集成电路的芯片他在出厂前功能就已经定死了,就拿上面的数字时钟来举例,假如我现在拿到一块全新的数字时钟芯片,那么我只需要看看厂家给我提供的数据手册,看看它是怎么操作的,可能仅仅只需要给它通上电然后简单的配置一下它就能工作了。它的功能是不可更改的,就只能跑个数字时钟,而且它内部电路是啥样的我也不知道,虽然用起来简单,但是缺乏灵活性,但FPGA就不一样了,它在出厂的那一刻是不具备任何功能的,可以说就是一张白纸。你可以在这张白纸上肆意创作,你想要它实现数字时钟的功能没问题,通过特定的编辑语言,例如Verilog、VHDL等硬件描述语言将数字时钟的逻辑编写好,下载到FPGA内部,它就会生成一个数字时钟的电路,去完成数字时钟的功能。当你不想要这个功能了,没问题你可以随时将内部程序擦除,或者用一个新的设计去覆盖原有的设计。理论上我们可以用FPGA去生成一个任意我们想要的功能,正是基于这种强大的可编辑能力,FPGA近年来越来越受到市场的认可,在未来FPGA的适用范围必将越来越广阔。
    1.2.1FPGA有什么用
    跟大家聊完了什么是FPGA之后,我想大家应该对自己手中那个“黑方块”有了一定的主观印象,至少明白了它和普通芯片的区别了,那么接下来,另一个问题就出现了,FPGA我能用它做什么,我学会它之后在未来我可以从事哪些领域的工作。这个问题我觉得是大家最想要关注的问题,因为兴趣是最好的老师,如果你发现FPGA所能从事的领域你压根就不感兴趣,那么你去学习它就有可能是在浪费时间,比如你将来想当个会计,你想当个医生那你学习FPGA就没有什么必要了,当然也不排除你在学习过程中突然发现了它的魅力,从而喜欢上它。
    FPGA所能应用的领域大概可以分成六大类:
    1)通信领域:FPGA在通信领域的应用可以说是无所不能,得益于FPGA内部结构的特点,它可以很容易地实现分布式的算法结构,这一点对于实现无线通信中的高速数字信号处理十分有利。因为在无线通信系统中,许多功能模块通常都需要大量的滤波运算,而这些滤波函数往往需要大量的乘和累加操作。而通过FPGA来实现分布式的算术结构,就可以有效地实现这些乘和累加操作。尤其是Xilinx公司的FPGA内部集成了大量的适合通信领域的一些资源比如:基带处理(通道卡)、接口和连接功能以及RF(射频卡)三大类:
    (1)基带处理资源
    基带处理主要包括信道编解码(LDPC、Turbo、卷积码以及RS码的编解码算法)和同步算法的实现(WCDMA系统小区搜索等)。
    (2)接口和连接资源
    接口和连接功能主要包括无线基站对外的高速通信接口(PCI Express、以太网MAC、高速AD/DA接口)以及内部相应的背板协议(OBSAI、CPRI、EMIF、LinkPort)的实现。
    (3)RF应用资源
    RF应用主要包括调制/解调、上/下变频(WiMAX、WCDMA、TD-SCDMA以及CDMA2000系统的单通道、多通道DDC/DUC)、削峰(PC-CFR)以及预失真(Predistortion)等关键技术的实现。
    总而言之只要你FPGA学的好,在通信领域你绝对可以大展身手。
    在这里插入图片描述

    图 1.2.3 FPGA无线通信
    2)数字信号处理领域:在数字信号处理领域FPGA同样所向披靡,主要是因为它的高速并行处理能力。FPGA最大优势是其并行处理机制,即利用并行架构实现数字信号处理的功能。这一并行机制使得FPGA特别适合于完成FIR等数字滤波这样重复性的数字信号处理任务,对于高速并行的数字信号处理任务来说,FPGA性能远远超过通用DSP处理器的串行执行架构,还有就是它接口的电压和驱动能力都是可编程配置的不像传统的DSP需要受指令集控制,因为指令集的时钟周期的限制,不能处理太高速的信号,对于速率级为Gbps的LVDS之类信号就难以涉及。所以在数字信号处理领域FPGA的应用也是十分广泛的。
    在这里插入图片描述

    图 1.2.4 FPGA数字信号处理
    3)视频图像处理领域:随着时代的变换,人们对图像的稳定性、清晰度、亮度和颜色的追求越来越高,像以前的标清(SD)慢慢演变成高清(HD),到现在人们更是追求蓝光品质的图像。这使得处理芯片需要实时处理的数据量越来越大,并且图像的压缩算法也是越来越复杂,使得单纯的使用ASSP或者DSP已经满足不了如此大的数据处理量了。这时FPGA的优势就凸显出来了,它可以更加高效的处理数据,所以在图像处理领域在综合考虑成本后,FPGA也越来越受到市场的欢迎。
    在这里插入图片描述

    图 1.2.5 FPGA图像处理
    4)高速接口设计领域:其实看了FPGA在通信领域和数字信号处理领域的表现,我想大家也已应该猜到了在高速接口设计领域,FPGA必然也是有一席之地的。它的高速处理能力和多达成百上千个的IO决定了它在高速接口设计领域的独特优势。比如说我需要和PC端做数据交互,将采集到的数据送给PC机处理,或者将处理后的结果传给PC机进行显示。PC机与外部系统通信的接口比较丰富,如ISA、PCI、PCI Express、PS/2、USB等。传统的做法是对应的接口使用对应的接口芯片,例如PCI接口芯片,当我需要很多接口时我就需要多个这样的接口芯片,这无疑会使我们的硬件外设变得复杂,体积变得庞大,会很不方便,但是如果使用FPGA优势立马就出来了,因为不同的接口逻辑都可以在FPGA内部去实现,完全没必要那么多的接口芯片,在配合DDR存储器的使用,将使我们接口数据的处理变得更加得心应手。
    在这里插入图片描述

    图 1.2.6高速光纤接口眼图
    5)人工智能领域:如果大家比较喜欢关注科技板块的新闻的话最近一定会被5G通信和人工智能充斥眼球,确实21世纪已经不知不觉走到了2020年,在这20年间,人工智能迅速发展,5G的顺利研发也使人工智能如虎添翼,可以预见,未来必将是人工智能的天下。FPGA在人工智能系统的前端部分也是得到了广泛的应用,例如自动驾驶,需要对行驶路线、红绿灯、路障和行驶速度等各种交通信号进行采集,需要用到多种传感器,对这些传感器进行综合驱动和融合处理就可以使用FPGA。还有一些智能机器人,需要对图像进行采集和处理,或者对声音信号进行处理都可以使用FPGA去完成,所以FPGA在人工智能系统的前端信息处理上使用起来得心应手。
    在这里插入图片描述

    图 1.2.7 FPGA与人工智能
    6)IC验证领域:IC这个词大家可能一听到就觉得特别高深,不是凡人所能触及到的,而IC设计更是一些神人才能胜任的工作。不可否认的是IC设计门槛确实比较高,但是我们也没必要把它过于神话,其实简单点来讲我们可以拿PCB设计来与之比较,PCB是拿一个个元器件在印制线路板上去搭建一个特定功能的电路组合,而IC设计呢是拿一个个MOS管,PN节在硅基衬底上去搭建一个特定功能的电路组合,一个宏观一个微观。PCB如果设计废了大不了重新设计再打样也不会造成太大损失,但是如果IC设计废了再重新设计那损失就很惨重了,俗话说大炮一开,黄金万两,那么在IC领域光刻机一开黄金万两也不是吹的,光刻胶贵的要命,光刻板开模也不便宜,加上其他多达几百上千道工序,其中人力、物力、机器损耗、机器保养,绝对是让人肉疼的损失,所以IC设计都要强调一版成功。保证IC一版成功就要进行充分的仿真测试和FPGA验证,仿真验证是在服务器上面跑仿真软件进行测试,类似ModelSim/VCS软件;FPGA验证主要是把IC的代码移植到FPGA上面,使用FPGA综合工具进行综合、布局布线到最终生成bit文件,然后下载到FPGA验证板上面进行验证,对于复杂的IC我们还可以给他拆成几个部分功能去分别验证,每个功能模块放在一个FPGA上面,FPGA生成的电路非常接近真实的IC芯片。这样极大的方便我们IC设计人员去验证自己的IC设计。
    在这里插入图片描述

    图 1.2.8 华为麒麟芯片
    1.2.2FPGA的现状
    根据统计以及预测,在2013年全球FPGA的市场规模在45.63亿美元,至2018年全球FPGA的市场规模缓步增长至63.35亿美元。但随着目前5G时代的进展以及AI的推进速度,预计FPGA在2025年有望达到约125.21亿美元。对于全球FPGA的市场分布而言,FPGA的下游应用地区分布而言,目前最大的为亚太地区,其占比39.15%,北美占比33.94%,欧洲占比19.42%,而至2025年,亚太地区的占比将会继续的提高至43.94%,此间原因也主要因为下游应用市场在未来的主要增长大部分集中在亚太地区。按照FPGA下游应用来分拆FPGA的市场规模的话,可以看到对于2018年而言,通讯领域所用FPGA占据约40%,消费电子占据23%,为最大的应用下游;根据预测至2025年时最大的应用领域将是汽车,占比29%,而数据中心以及工业的占比也将直线上升至13%和19%(数据来源于中国产业信息网)。
    在这里插入图片描述

    图 1.2.9 FPGA全球市场规模走势
    看完了市场规模我们再来看看FPGA的生产厂商,我总结了目前国际市场是两大巨头和一群小弟,很遗憾的是我国的国产FPGA也是属于小弟一列,但是我相信随着时间的积累技术和经验的积累中国FPGA发展将会越来越好。其中两大巨头分别是Xilinx和Altera:
    Xilinx(赛灵思):它是全球领先的可编程逻辑完整解决方案的供应商。Xilinx研发、制造并销售范围广泛的高级集成电路、软件设计工具以及作为预定义系统级功能的IP(Intellectual Property)核。客户使用Xilinx及其合作伙伴的自动化软件工具和IP核对器件进行编程,从而完成特定的逻辑操作。Xilinx公司成立于 1984年,Xilinx首创了现场可编程逻辑阵列(FPGA)这一创新性的技术,并于1985年首次推出商业化产品。眼下Xilinx满足了全世界对 FPGA产品一半以上的需求。Xilinx产品线还包括复杂可编程逻辑器件(CPLD)。在某些控制应用方面CPLD通常比FPGA速度快,但其提供的逻辑资源较少。Xilinx可编程逻辑解决方案缩短了电子设备制造商开发产品的时间并加快了产品面市的速度,从而减小了制造商的风险。与采用传统方法如固定逻辑门阵列相比,利用Xilinx可编程器件,客户可以更快地设计和验证他们的电路。由于Xilinx器件是只需要进行编程的标准部件,客户不需要像采用固定逻辑芯片时那样等待样品或者付出巨额成本。Xilinx产品已经被广泛应用于从无线电话基站到DVD播放机的数字电子应用技术中。
    传统的半导体公司只有几百个客户,而Xilinx在全世界有7500多家客户及50000多个设计开端。其客户包括Alcatel、Cisco Systems、EMC、Ericsson、Fujitsu、Hewlett-Packard、IBM、Lucent Technologies、Motorola、NEC、Nokia、Nortel、Samsung、Siemens、Sony、Oracle以及Toshiba。目前Xilinx比较火的具有代表性的FPGA芯片有Spartan7系列、Artix7系列、Kintex7系列、Virtex7系列以及Zynq系列,其中Zynq系列内嵌了ARM核,可以实现嵌入式和FPGA的联合开发(想了解更多关于Zynq系列的内容可以参考正点原子领航者开发板资料),Spartan6系列、Artix7系列可以参考超越者和达芬奇开发板的资料。 (数据资料来源于网络)。
    在这里插入图片描述

    图 1.2.10 Xilinx公司logo
    Altera(阿尔特拉):它秉承了创新的传统,是世界上“可编程芯片系统”(SOPC)解决方案倡导者。Altera结合带有软件工具的可编程逻辑技术、知识产权(IP)和技术服务,在世界范围内为14000多个客户提供高质量的可编程解决方案。我们新产品系列将可编程逻辑的内在优势、灵活性、产品及时面市和更高级性能以及集成化结合在一起,专为满足当今大范围的系统需求而开发设计。在2015年,英特尔宣布以167亿美元收购FPGA厂商Altera,这是英特尔公司历史上规模最大的一笔收购。随着收购完成,Altera将成为英特尔旗下可编程解决方案事业部。Altera使用最广泛的是Cyclone系列FPGA芯片,我个人觉得它用的比较多的是Cyclone IV和Cyclone V系列的FPGA芯片,其中大家需要注意一下Cyclone V,因为该系列包括6种型号,有只含逻辑的E型号、3.125-Gbps收发器GX型号、5-Gbps收发器GT型号,还有集成了基于双核ARM®的硬核处理器系统(HPS)的SE、SX、STSoC型号。除了Cyclone系列,Altera公司还有Agilex系列Stratix系列、Arria系列、Max系列:
    Agilex系列:首款采用10纳米工艺和第二代英特尔 Hyperflex FPGA 架构,可将性能提升多达40%,将数据中心、网络和边缘计算应用的功耗降低40%。英特尔Agilex SoC FPGA还集成了四核Arm Cortex-A53处理器,可提供高集成系统级水平的开发,该系列属于超高性能的SoC芯片,一般用于高端市场。
    Stratix系列:这个系列也是属于高端高性能产品,拥有高密度、高性能和丰富的IO特性,可最大程度地提高系统带宽,实现多种多样的功能设计。主要应用于Open CL高性能计算、高速数据采集、高速串行通讯高频交互等领域。
    Arria系列:这个系列定位为中端产品,它兼顾性能和成本,是一款性价比非常高的FPGA芯片,它内存资源丰富,信号处理能力和数据运算性能相对来说都还不错,并且收发器速度高达 25.78Gbps,支持用户集成更多功能并最大限度地提高系统带宽。此外,Arria V 和英特尔 Arria 设备家族的 SoC 产品可提供基于 ARM 的硬核处理器系统(HPS),从而进一步提高集成度和节省更多成本。
    Max系列:这个系列是比较低端的,准确的说这个系列是CPLD产品,主要是应对成本敏感性的设计应用,虽然低端但是它功能也还是可圈可点的,它提供支持模数转换器 (ADC) 的瞬时接通双配置,和特性齐全的 FPGA 功能,尤其对各种成本敏感性的大容量应用进行了优化,要注意的是除了MAX 10以外,该系列的其他产品都是CPLD。
    在这里插入图片描述

    图 1.2.11 Intel公司旗下的Altera
    剩余的小弟们这里就不做过多介绍了,因为所有小弟们加在一起的市场份额只有一成左右,远不是两大巨头所能比的,在这里提一句我国的FPGA厂商主要有紫光同创、京微雅格、高云半导体、上海安路、西安智多晶等,但是同国外领先厂商相比,国产FPGA厂商不论从产品性能、功耗、功能上都有较大差距。革命尚未成功,同志们仍需努力。
    1.2.3FPGA的就业前景
    一路说下来我想大家们对于FPGA到底是什么,有什么用以及现状都有所了解了,那大家可能就要问了,学习FPGA就业前景怎么样呢?好找工作吗?我这里也很诚实,很真实的跟大家聊聊就业情况。其实相比较那些纯粹搞软件的程序员来讲呢,FPGA的就业面没有他们广,因为各行各业都需要软件信息技术的支持,哪怕你开个小超市,你还需要一个收银系统,而FPGA在适用面上就窄了一些,它大多用于图像算法、信号处理、IC验证、汽车控制等领域,不像软件开发那样各行各业都涉及到。但是有缺点就有优点,FPGA的两大巨头在不断的打造嵌入式与FPGA联合的开发模式,大量的提供IP核,使得FPGA的适用面越来越广,FPGA工程师的需求量与日剧增。在5G、虚拟现实和人工智能的冲击下,传统的微处理器在性能上越来越不能满足需求,这个时候FPGA的优势就尤为突出,我相信在未来FPGA一定会成为市场的主流。即使就目前而言FPGA工程师的福利待遇也是非常高的,如图 1.2.12所示我们可以看到FPGA工程师的平均薪资都已经达到了一万以上了,而软件工程师的薪资除了那些大牛级人物,普通程序员的薪资并没有你想象的那么高,所以在这里我非常衷心的希望大家好好学习FPGA,你们未来可期。
    在这里插入图片描述

    图 1.2.12月薪分布图
    1.3深度剖析FPGA
    我们在学习一个新的事物的时候一定要知其然还要知其所以然,前文我们都是表层的跟大家聊聊什么是FPGA,它能干什么,现状如何,就业前景咋样,让大家对FPGA有个直观的认识,下面我们将带领大家深度剖析FPGA的内部结构是什么样的,让大家更深层次的去认识FPGA。
    1.3.1FPGA的发展由来
    谈到FPGA的发展我们不妨先看看数字电路的发展,在数字集成电路中,门电路是最基本的逻辑单元,用以实现最基本的逻辑运算(与、或、非)和复合逻辑运算(与非、异或等)。与上述逻辑运算相对应,常用的门电路有与门、或门、非门、与非门、异或门等,其电路符号如下图所示:
    在这里插入图片描述

    图 1.3.1门电路符号
    在最初的数字逻辑电路中,每个门电路都是用若干个分立的半导体器件和电阻、电容连接而成的。不难想象,用这种单元电路组成大规模的数字电路是非常困难的,这就严重制约了数字电路的普遍应用。1961年,美国德州仪器公司(TI)率先将数字电路的元器件制作在同一片硅片上,制成了集成电路(Intergrated Circuits,IC),并迅速取代了分立器件电路。
    早期的数字逻辑设计需要设计师在一块电路板上或者如下图所示的面包板上用导线将多个芯片连接在一起。每个芯片包含一个或多个逻辑门,或者一些简单的逻辑结构(比如触发器或多路复用器等)。如下图中所示的芯片是在1960和1970年代,很多设计中都会使用的德州仪器7400系列的器件。

    在这里插入图片描述

    图 1.3.2使用74系列器件搭建的电路
    自20世纪60年代以来,随着集成电路工艺水平的不断进步,集成电路的集成度也不断提高。数字集成电路经历了从小规模集成电路(Small Scale Integrated circuit,SSI),到中规模集成电路(Medium Scale Integrated circuit,MSI),再到大规模集成电路(Large Scale Integrated circuit,LSI),然后是超大规模集成电路(Very Large Scale Integrated circuit,VLSI),以及甚大规模集成电路(Ultra Large Scale Integrated circuit,ULSI)的发展过程。今天我们已经可以把十分复杂的数字系统制作在一个很小的硅片上,构成“片上系统”。
    我们从逻辑功能的特点上将数字集成电路分类,可以分为通用型和专用型两类。前面介绍到的中、小规模集成电路(如74系列)都属于通用型数字集成电路。它们的逻辑功能都比较简单,而且是固定不变的。由于它们的这些功能在组成复杂数字系统时经常要用到,所以这些器件具有很强的通用性。
    从理论上来讲,用这些通用型的中、小规模集成电路可以组成任何复杂的数字系统。随着集成电路的集成度越来越高,如果能把所设计的数字系统做成一片大规模集成电路,则不仅能减小电路的体积、重量和功耗,而且可以使电路的可靠性大为提高。像这种为某种专门用途而设计的集成电路称为专用集成电路,即所谓的ASIC(Application Specific Integrated Circuit)。
    ASIC的使用在生产、生活中非常普遍,比如手机、平板电脑中的主控芯片都属于专用集成电路。
    在这里插入图片描述

    图 1.3.3 华为Mate 30手机中的麒麟990芯片
    虽然ASIC有诸多优势,但是在用量不大的情况下,设计和制造这样的专用集成电路不仅成本很高,而且设计制造的周期也很长。可编程逻辑器件(Programmable Logic Device,PLD)的出现成功解决了这个矛盾。
    可编程逻辑器件PLD是作为一种通用器件生产,但它的逻辑功能是由用户通过对器件进行编程来设定的。而且有些PLD的集成度很高,足以满足设计一般数字系统的需要。这样就可以由设计人员自行编程从而将一个数字系统“集成”在一片PLD上,做成“片上系统”(System on Chip,SoC),而不必去请芯片制造厂商设计和制作专用集成电路芯片了。
    最后,我们再来总结这三种数字集成电路之间的差异。通用型数字集成电路和专用集成电路内部的电路连接都是固定的,所以它们的逻辑功能也是固定不变的。而可编程逻辑器件则不同,它们内部单元之间的连接是通过“写入”编程数据来确定的,写入不同的编程数据就可以得到不同的逻辑功能。
    自20世纪70年代以来,PLD的研制和应用得到了迅速的发展,相继开发出了多种类型和型号的产品。PLD的发展历程如下图所示:
    在这里插入图片描述

    图 1.3.4 PLD的发展历程
    目前常见的PLD大体上可以分为SPLD(simple PLD,简单PLD)、CPLD(complex PLD,复杂PLD)和FPGA(field-programmable gate array,现场可编程门阵列)。SPLD中又可分为PLA、PAL和GAL几种类型。FPGA也是一种可编程逻辑器件,但由于在电路结构上与早期已经广为应用的PLD不同,所以采用FPGA这个名称,以示区别。
    通过对数字电路的学习我们知道,任何一个逻辑函数式都可以变换成与-或表达式,因而任何一个逻辑函数都能用一级与逻辑电路和一级或逻辑电路来实现。PLD最初的研制思想就来源于此。
    在这里插入图片描述

    图 1.3.5 PAL器件的基本电路结构
    上图是SPLD中PAL(可编程阵列逻辑)的电路结构图。通过对输入端(inputs)到与门之间的可编程阵列(programmable array)进行编程,利用PAL可以获得不同形式的组合逻辑函数。数字电路课程告诉我们,任何逻辑函数式都可以转化为若干乘积项(product tems)之和的形式,亦称“积之和”形式。通过对可编程阵列进行编程,与逻辑电路输出所需要的乘积项,再通过或逻辑电路将这些乘积项相加,就得到了最终的功能输出。然后该输出送给输出电路中的寄存器用于存储或者同步,当然也可以忽略寄存器直接输出。这就是PAL作为一种“可编程逻辑器件”能够实现不同逻辑功能的原理。
    通过扩展SPLD的概念就可以得到CPLD。CPLD是复杂可编程逻辑器件,相当于将多个PAL用可编程互联阵列(Programmable Interconnect Array,PIA)连接起来,形成一个大的PLD,如下图所示:
    在这里插入图片描述

    图 1.3.6 CPLD结构示意图
    上图中的Logic block(逻辑块)通常被称为逻辑阵列模块,或者LAB(Logic Array Block)。每个LAB相当于一个PAL电路,不同型号的CPLD器件可以包含十几个甚至上百个LAB。通过PIA将这些LAB连接起来,就可以构成规模更大的逻辑电路了。另外,在PAL中,I/O管脚是直接连接到逻辑的。而在CPLD中,I/O管脚是通过PIA从器件的主要逻辑中分离出来的。I/O管脚有它自己的控制逻辑,I/O控制单元可以根据需要将相应的引脚设置成输入、输出或双向工作模式。
    CPLD相对于SPLD最大的优势就是拥有更大的逻辑资源和布线的可能性。CPLD中LAB逻辑和PIA是完全可编程的,使得它具有在单芯片中非凡的设计灵活性。CPLD的I/O特性和功能也远比SPLD中简单的I/O更有价值。
    FPGA是在PAL、GAL和CPLD等可编程逻辑器件的基础上进一步发展的产物,但是FPGA和其前辈CPLD有着非常大的差异。我们用一张表格来罗列他们之间的差别如下表所示:
    表 1.3.1 FPGA与CPLD的差别
    在这里插入图片描述

    那为什么会产生这么大的差别呢,主要是由于FPGA的内部结构决定的,下面我们就来看看FPGA的内部结构。
    1.3.2FPGA的内部结构
    简化的FPGA基本结构由6部分组成,分别为可编程输入/输出单元、基本可编程逻辑单元、嵌入式块RAM、丰富的布线资源、底层嵌入功能单元和内嵌专用硬核等,如下图所示。
    在这里插入图片描述

    图 1.3.7 FPGA基本结构
    每个单元的基本概念介绍如下。
    1)可编程输入/输出单元
    输入/输出(Input/Ouput)单元简称I/O单元,它们是芯片与外界电路的接口部分,完成不同电气特性下对输入/输出信号的驱动与匹配需求,为了使FPGA具有更灵活的应用,目前大多数FPGA的I/O单元被设计为可编程模式,即通过软件的灵活配置,可以适配不同的电气标准与I/O物理特性;可以调整匹配阻抗特性、上下拉电阻、以及调整驱动电流的大小等。
    可编程I/O单元支持的电气标准因工艺而异,不同芯片商、不同器件的FPGA支持的I/O标准不同,一般来说,常见的电气标准有LVTTL,LVCMOS,SSTL,HSTL,LVDS,LVPECL和PCI等。值得一提的是,随着ASIC工艺的飞速发展,目前可编程I/O支持的最高频率越来越高,一些高端FPGA通过DDR寄存器技术,甚至可以支持高达2Gbit/s的数据数率。
    2)基本可编程逻辑单元
    基本可编程逻辑单元是可编程逻辑的主体,可以根据设计灵活地改变其内部连接与配置,完成不同的逻辑功能。FPGA一般是基于SRAM工艺的,其基本可编程逻辑单元几乎都是由查找表(LUT,Look Up Table)和寄存器(Register)组成。FPGA内部查找表一般为4输入,查找表一般完成纯组合逻辑功能。FPGA内部寄存器结构相当灵活,可以配置为带同步/异步复位或置位,时钟使能的触发器,也可以配置成锁存器,FPGA依赖寄存器完成同步时序逻辑设计。一般来说,比较经典的基本可编程逻辑单元的配置是一个寄存器加一个查找表,但是不同厂商的寄存器与查找表也有一定的差异,而且寄存器与查找表的组合模式也不同。例如,Altera可编程逻辑单元通常被称为LE(Logic Element),由一个寄存器加一个LUT构成。Altera大多数FPGA将10个LE有机地组合在一起,构成更大的功能单元——逻辑阵列模块(LAB,Logic Array Block),LAB中除了LE还包含LE之间的进位链,LAB控制信号,局部互联线资源,LUT级联链,寄存器级联链等连线与控制资源。Xilinx可编程逻辑单元叫Slice,它是由上下两个部分组成,每个部分都由一个寄存器加一个LUT组成,被称为LC(Logic Cell,逻辑单元),两个LC之间有一些共用逻辑,可以完成LC之间的配合与级联。Lattice的底层逻辑单元叫PFU(Programmable Function Unin,可编程功能单元),它是由8个LUT和8~9个寄存器构成,当然这些可编程逻辑单元的配置结构随着器件的不断发展也在不断更新,最新的一些可编程逻辑器件常常根据需求设计新的LUT和寄存器的配置比率,并优化其内部的连接构造。
    学习底层配置单元的LUT和寄存器比率的一个重要意义在于器件选型和规模估算。很多器件手册上用器件的ASIC门数或等效的系统门数表示器件的规模。但是由于目前FPGA内部除了基本可编程逻辑单元外,还包含丰富的嵌入式RAM,PLL或DLL,专用Hard IP Core(如PCIE、Serdes硬核)等,这些功能模块也会等效出一定规模的系统门,所以用系统门权衡基本可编程逻辑单元的数量是不准确的,常常混淆设计者。比较简单科学的方法是用器件的寄存器或LUT的数量衡量。例如,Xilinx的Spartan系列的XC3S1000有15360个LUT,而Lattice的EC系列LFEC15E也有15360个LUT,所以这两款FPGA的可编程逻辑单元数量基本相当,属于同一规模的产品。同样道理,Altera的Cyclone IV器件族的EP4CE10的LUT数量是10320个,就比前面提到的两款FPGA规模略小。需要说明的是,器件选型是一个综合性的问题,需要将设计的需求、成本、规模、速度等级、时钟资源、I/O特性、封装、专用功能模块等诸多因素综合考虑进来。
    3)嵌入式块RAM
    目前大多数FPGA都有内嵌的块RAM(Block RAM),FPGA内部嵌入可编程RAM模块,大大地拓展了FPGA的应用范围和使用灵活性。FPGA内嵌的块RAM一般可配置为单口RAM,双口RAM,伪双口RAM,CAM,FIFO等常用存储结构。RAM的概念和功能读者应该非常熟悉,在此不再赘述。FPGA中其实并没有专用的ROM硬件资源,实现ROM的思路是对RAM赋予初值。所谓CAM,即内容地址存储器,CAM这种存储器在其每个存储单元都包含了一个内嵌的比较逻辑,写入CAM的数据会和其内部存储的每一个数据进行比较,并返回与端口数据相同的所有内部数据的地址。概括的讲,RAM是一种根据地址读,写数据的存储单元;而CAM和RAM恰恰相反,它返回的是端口数据相同的所有内部地址。CAM的应用也十分广泛,比如在路由器中的交换表等。FIFO是先进先出队列的存储结构。FPGA内部实现RAM,ROM,CAM,FIFO等存储结构都可以基于嵌入式块RAM单元,并根据需求自动生成相应的粘合逻辑以完成地址和片选等控制逻辑。
    不同器件商或不同器件族的内嵌块RAM的结构不同,Xilinx常见的块RAM大小是4kbit和18kbit两种结构,Lattice常用的块RAM大小是9KBIT,Altera的块RAM最灵活,一些高端器件内部同时含有3种块RAM结构,分别是M512 RAM,M4K RAM,M9K RAM。
    需要补充的一点是,除了块RAM,还可以灵活地将LUT配置成RAM,ROM,FIFO等存储结构,这种技术被称为分布式RAM。根据设计需求,块RAM的数量和配置方式也是器件选型的一个重要标准。
    4)丰富的布线资源
    布线资源连通FPGA内部的所有单元,而连线的长度和工艺决定着信号在连线上的驱动能力和传输速度。FPGA芯片内部有着丰富的布线资源,这些布线资源根据工艺、长度、宽度和分布位置的不同而划分为4类不同的类别:
    第一类是全局布线资源,用于芯片内部全局时钟和全局复位/置位的布线;
    第二类是长线资源,用以完成芯片Bank间的高速信号和第二全局时钟信号的布线;
    第三类是短线资源,用于完成基本逻辑单元之间的逻辑互连和布线;
    第四类是分布式的布线资源,用于专有时钟、复位等控制信号线。
    在实际中设计者不需要直接选择布线资源,布局布线器可自动地根据输入逻辑网表的拓扑结构和约束条件选择布线资源来连通各个模块单元。从本质上讲,布线资源的使用方法和设计的结果有直接的关系。
    5)底层嵌入功能单元
    底层嵌入功能单元的概念比较笼统,这里我们指的是那些通用程度较高的嵌入式功能模块,比如PLL(Phase Locked Loop)、DLL(Delay Locked Loop)、DSP、CPU等。随着FPGA的发展,这些模块被越来越多地嵌入到FPGA的内部,以满足不同场合的需求。
    目前大多数FPGA厂商都在FPGA内部集成了DLL或者PLL硬件电路,用以完成时钟的高精度、低抖动的倍频、分频、占空比调整、相移等功能。目前,高端FPGA产品集成的DLL和PLL资源越来越丰富,功能越来越复杂,精度越来越高。Altera芯片集成的是PLL,Xilinx集成的是DLL,Lattice的新型FPGA同时集成了PLL与DLL以适应不同的需求。Altera芯片的PLL模块分为增强型PLL和快速PLL等。Xilinx芯片DLL的模块名称为CLKDLL,在高端FPGA中,CLKDLL的增强型模块为DCM。这些时钟模块的生成和配置方法一般分为两种,一种是在HDL代码和原理图中直接例化,另一种是在IP核生成器中配置相关参数,自动生成IP。另外可以通过在综合、实现步骤的约束文件中编写约束文件来完成时钟模块的约束。
    越来越多的高端FPGA产品将包含DSP或CPU等软处理核,从而FPGA将由传统的硬件设计手段逐步过渡到系统级设计平台。例如Altera的Stratix IV、Stratix V等器件族内部集成了DSP core,配合同样逻辑资源,还可实现ARM、MIPS、NIOS II等嵌入式处理系统;Xilinx的Virtes II和Virtex II pro系列FPGA内部集成了Power PC450的CPU Core和MicroBlaze RISC处理器Core;Lattice的ECP系列FPGA内部集成了系统DSP Core模块,这些CPU或DSP处理模块的硬件主要由一些加、乘、快速进位链、Pipelining和Mux等结构组成,加上用逻辑资源和块RAM实现的软核部分,就组成了功能强大的软运算中心。这种CPU或DSP比较适合实现FIR滤波器、编码解码、FFT等运算密集型运用。FPGA内部嵌入CPU或DSP等处理器,使FPGA在一定程度上具备了实现软硬件联合系统的能力,FPGA正逐步成为SOPC的高效设计平台。Altera的系统级开发工具是SOPC Buider和DSP Builder,专用硬件结构与软硬件协同处理模块等;Xilinx的系统设计工具是EDK和Platform Studio;Lattice的嵌入式DSP开发工具是Matlab的Simulink。
    6)内嵌专用硬核
    这里的内嵌专用硬核与前面的底层嵌入单元是有区分的,这里讲的内嵌专用硬核主要指那些通用性相对较弱,不是所有FPGA器件都包含硬核。我们称FPGA和CPLD为通用逻辑器件,是区分于专用集成电路(ASIC)而言的。其实FPGA内部也有两个阵营:一方面是通用性较强,目标市场范围很广,价格适中的FPGA;另一方面是针对性较强,目标市场明确,价格较高的FPGA。前者主要指低成本FPGA,后者主要指某些高端通信市场的可编程逻辑器件。
    1.3.3Cyclone IV系列芯片简介
    Altera 的 Cyclone IV系列FPGA器件巩固了Cyclone系列在低成本、低功耗FPGA市场的领导地位。并且Cyclone IV器件旨在用于大批量,成本敏感的应用,使系统设计师在降低成本的同时又能够满足不断增长的带宽要求。
    Cyclone IV器件系列是建立在一个优化的低功耗工艺基础之上,并提供以下两种型号:
    ■ Cyclone IV E—最低的功耗,通过最低的成本实现较高的功能性
    ■ Cyclone IV GX—最低的功耗,集成了3.125 Gbps收发器的最低成本的FPGA
    下面我们对Cyclone IV FPGA芯片的主要特点做了一个罗列:
    ■ 低成本、低功耗的 FPGA 架构:
    ■ 6 K到150 K的逻辑单元
    ■ 高达6.3 Mb的嵌入式存储器
    ■ 高达360个18 × 18乘法器,实现DSP处理密集型应用
    ■ 协议桥接应用,实现小于1.5 W的总功耗
    ■ Cyclone IV GX器件提供高达八个高速收发器以支持:
    ■ 高达3.125 Gbps的数据速率
    ■ 8B/10B编码器/解码器
    ■ 8-bit或者10-bit位物理介质附加子层 (PMA) 到物理编码子层 (PCS) 接口
    ■ 字节串化器/解串器 (SERDES)
    ■ 字对齐器
    ■ 速率匹配FIFO
    ■ 公共无线电接口 (CPRI) 的TX位滑块
    ■ 电路空闲
    ■ 动态通道重配置以实现数据速率及协议的即时修改
    ■ 静态均衡及预加重以实现最佳的信号完整性
    ■ 每通道150mW的功耗
    ■ 灵活的时钟结构以支持单一收发器模块中的多种协议
    ■ Cyclone IV GX器件对PCI Express (PIPE)(PCIe)Gen 1提供了专用的硬核IP:
    ■ ×1,×2,和×4通道配置
    ■ 终点和根端口配置
    ■ 高达256-byte的有效负载
    ■ 一个虚拟通道
    ■ 2 KB重试缓存
    ■ 4 KB接收 (Rx) 缓存
    ■ Cyclone IV GX 器件提供多种协议支持:
    ■ PCIe (PIPE) Gen 1×1,×2,和×4 (2.5 Gbps)
    ■ 千兆以太网 (1.25 Gbps)
    ■ CPRI (高达3.072 Gbps)
    ■ XAUI (3.125 Gbps)
    ■ 三倍速率串行数字接口 (SDI)(高达2.97 Gbps)
    ■ 串行 RapidIO(3.125 Gbps)
    ■ Basic 模式 (高达3.125 Gbps)
    ■ V-by-One(高达3.0 Gbps)
    ■ DisplayPort(2.7 Gbps)
    ■ 串行高级技术附件 (Serial Advanced Technology Attachment (SATA))(高达3.0 Gbps)
    ■ OBSAI(高达3.072 Gbps)
    ■ 高达532个用户I/O
    ■ 高达840 Mbps发送器 (Tx),875 Mbps Rx的LVDS接口
    ■ 支持高达200MHz的DDR2 SDRAM接口
    ■ 支持高达167 MHz的QDRII SRAM和DDR SDRAM
    ■ 每器件中高达8个锁相环 (PLLs)
    ■ 支持商业与工业温度等级
    为了方便大家去选型,这里将Cyclone IV 系列器件的资源表给大家贴出来,如下图所示:
    在这里插入图片描述

    图 1.3.8 Cyclone IV器件资源表
    在这里插入图片描述

    图 1.3.9 Cyclone IV器件资源表
    总而言之Cyclone IV系列芯片是一款功能相对完善,成本相对较低的高性价比的FPGA芯片,并且经过了市场的长期检验,深受广大工程师的喜爱。
    在这里插入图片描述

    图 1.3.10 EP4CE10芯片
    1.3.4Altera芯片的命名规则
    一路看下来相信大家已经了解了什么是FPGA并且也知道了我们新起点上的芯片型号是EP4CE10F17C8N,那么大家是否知道这个命名的含义呢,这里我就以Altera的官方文档来给大家做个简单的介绍,方便大家以后自己去选型的时候可能会用得着这个小知识。
    我们先来看下我从官方文档中截的图(图 1.3.10),从这张图中我们可以看到它是以Cyclone IV系列的芯片为例的:
    在这里插入图片描述

    图 1.3.10 Xilinx芯片命名规则示意图
    EP4C:Cyclone IV家族;
    E:逻辑资源增强型版本;
    40:逻辑资源等级,数字越大逻辑资源越丰富;
    F:封装类型;
    29:引脚数量等级,数字越大引脚数量越多;
    C:温度等级;
    8:速度等级,数字越小速度越快;
    N:可选的一个后缀,其中N代表无铅包装发货。
    所以对照这个规则我们E10新起点上搭载的就是一块Altera(Intel)公司Cyclone IV系列的FPGA芯片,它拥有接近于10k的逻辑资源,速度等级为8,采用FBGA的封装类型,一共拥有256个IO引脚。

    展开全文
  • 4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十六章 UART串口通信实验 串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字

    1)实验平台:正点原子领航者ZYNQ开发板
    2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
    3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-301505-1-1.html
    4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016
    5)关注正点原子公众号,获取最新资料更新
    在这里插入图片描述

    第十六章 UART串口通信实验

    串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字节分成一位一位的形式在一条数据线上逐个传送,其特点是通信线路简单,但传输速度较慢。因此串口广泛应用于嵌入式、工业控制等领域中对数据传输速度要求不高的场合。本章我们将使用ZYNQ开发板上的UART串口完成上位机与ZYNQ PL的通信。
    本章包括以下几个部分:
    1.1 UART串口简介
    1.2 实验任务
    1.3 硬件设计
    1.4 程序设计
    1.5 下载验证

    1.1 UART串口简介
    串行通信分为两种方式:同步串行通信和异步串行通信。同步串行通信需要通信双方在同一时钟的控制下,同步传输数据;异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。
    UART是一种采用异步串行通信方式的通用异步收发传输器(universal asynchronous receiver-transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。
    UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收。UART在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如图 7.5.13.1所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。校验位分为奇校验和偶校验,用于检验数据在传输过程中是否出错。奇校验时,发送方应使数据位中1的个数与校验位中1的个数之和为奇数;接收方在接收数据时,对1的个数进行检查,若不为奇数,则说明数据在传输过程中出了差错。同样,偶校验则检查1的个数是否为偶数。
    在这里插入图片描述

    图 7.5.13.1 异步串行通信数据格式
    UART通信过程中的数据格式及传输速率是可设置的,为了正确的通信,收发双方应约定并遵循同样的设置。数据位可选择为5、6、7、8位,其中8位数据位是最常用的,在实际应用中一般都选择8位数据位;校验位可选择奇校验、偶校验或者无校验位;停止位可选择1位(默认),1.5或2位。串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bps(位/秒),常用的波特率有9600、19200、38400、57600以及115200等。
    在设置好数据格式及传输速率之后,UART负责完成数据的串并转换,而信号的传输则由外部驱动电路实现。电信号的传输过程有着不同的电平标准和接口规范,针对异步串行通信的接口标准有RS232、RS422、RS485等,它们定义了接口不同的电气特性,如RS-232是单端输入输出,而RS-422/485为差分输入输出等。
    RS232接口标准出现较早,可实现全双工工作方式,即数据发送和接收可以同时进行。在传输距离较短时(不超过15m),RS232是串行通信最常用的接口标准,本章主要介绍针对RS-232标准的UART串口通信。
    RS-232标准的串口最常见的接口类型为DB9,样式如图 7.5.13.2所示,工业控制领域中用到的工控机一般都配备多个串口,很多老式台式机也都配有串口。但是笔记本电脑以及较新一点的台式机都没有串口,它们一般通过USB转串口线(图 7.5.13.3)来实现与外部设备的串口通信。
    在这里插入图片描述

    图 7.5.13.2 DB9接口
    在这里插入图片描述

    图 7.5.13.3 USB串口线
    DB9接口定义以及各引脚功能说明如图 7.5.13.4所示,我们一般只用到其中的2(RXD)、3(TXD)、5(GND)引脚,其他引脚在普通串口模式下一般不使用,如果大家想了解,可以自行百度下。
    在这里插入图片描述

    图 7.5.13.4 DB9接口定义
    1.2 实验任务
    本节实验任务是上位机通过串口调试助手发送数据给Zynq,Zynq PL端通过RS232串口接收数据并将接收到的数据发送给上位机,完成串口数据环回。
    1.3 硬件设计
    领航者ZYNQ开发板上RS232串口部分的原理图如下所示:
    在这里插入图片描述

    图 7.5.13.1 领航者RS232串口原理图
    由于ZYNQ PL端串口输入输出引脚为TTL电平,用3.3V代表逻辑“1”,0V代表逻辑“0”;而计算机串口采用RS-232电平,它是负逻辑电平,即-15V-5V代表逻辑“1”,+5V+15V代表逻辑“0”。因此当计算机与ZYNQ通信时,需要加电平转换芯片SP3232,实现RS232电平与TTL电平的转换。
    从图 7.5.13.1中可以看到,SP3232芯片端口的U2_RX和U2_TX并没有直接和ZYNQ的引脚相连接,而是连接到了P1排针上。RS232串口和RS485串口共用P1排针的UART2_TX和UART2_RX,而UART2_TX和UART2_RX是直接和ZYNQ的引脚相连接的。在使用时,使用跳线帽选择与ZYNQ相连接的串口类型,这样的设计方式实现了有限IO的复用。因此,在做RS232的通信实验时,需要使用杜邦线或者跳线帽将U2_RX和UART2_TX连接在一起,U2_TX和UART2_RX连接在一起。
    本实验中,系统时钟、按键复位以及串口的接收、发送端口的管脚分配如下表所示:
    表 16.3.1 串口通信实验管脚分配
    信号名 方向 管脚 端口说明 电平标准

    sys_clk	input	U18	系统时钟,50M	LVCMOS33
    sys_rst_n	input	N16	系统复位,低有效	LVCMOS33
    uart_rxd	input	K14	串口接收	LVCMOS33
    uart_txd	output	M15	串口发送	LVCMOS33
    

    对应的XDC约束语句如下所示:

    create_clock -period 20.000 -name clk [get_ports sys_clk]
    set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
    set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
    set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports uart_rxd]
    set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports uart_txd]
    

    1.4 程序设计
    根据实验任务,我们不难想象本系统应该有一个串口接收模块,用来接收上位机发送的数据;还要有一个串口发送模块,用于将数据发回上位机;另外还应该有一个对数据进行环回控制的模块,它负责把从串口接收模块接收到的数据送给串口发送模块,以实现串口数据的环回。由此可以画出本次实验的系统框图,如下所示:
    在这里插入图片描述

    图 7.5.13.1 系统框图
    由系统总体框图可知,ZYNQ PL部分包括四个模块,顶层模块、接收模块、发送模块和数据环回模块。其中在顶层模块中完成对另外三个模块的例化,顶层模块原理图如下所示:
    在这里插入图片描述

    图 7.5.13.2 顶层模块原理图
    在图 7.5.13.2中,uart_recv为串口接收模块,从串口接收端口uart_rxd来接收上位机发送的串行数据,并在一帧数据接收结束后给出通知信号uart_done。
    uart_send为串口发送模块,以uart_en为发送使能信号。uart_en的上升沿将启动一次串口发送过程,将uart_din接口上的数据通过串口发送端口uart_txd发送出去。
    uart_loop模块负责完成串口数据的环回功能。它在uart_recv模块接收完成后,将接收到的串口数据发送到uart_send模块,并通过send_en接口给出一个上升沿,以启动发送过程。
    在编写代码之前,我们首先要确定串口通信的数据格式及波特率。在这里我们选择串口比较常用的一种模式,数据位为8位,停止位为1位,无校验位,波特率为115200bps。则传输一帧数据的时序图如下图所示:
    在这里插入图片描述

    图 7.5.13.3 串口通信时序图
    顶层模块的代码如下:

    1  module uart_loopback_top(
    2      input           sys_clk,            //外部50M时钟
    3      input           sys_rst_n,          //外部复位信号,低有效
    4  
    5      input           uart_rxd,           //UART接收端口
    6      output          uart_txd            //UART发送端口
    7      );
    8  
    9  //parameter define
    10 parameter  CLK_FREQ = 50000000;         //定义系统时钟频率
    11 parameter  UART_BPS = 115200;           //定义串口波特率
    12     
    13 //wire define   
    14 wire       uart_recv_done;              //UART接收完成
    15 wire [7:0] uart_recv_data;              //UART接收数据
    16 wire       uart_send_en;                //UART发送使能
    17 wire [7:0] uart_send_data;              //UART发送数据
    18 wire       uart_tx_busy;                //UART发送忙状态标志
    19 
    20 //*****************************************************
    21 //**                    main code
    22 //*****************************************************
    23 
    24 //串口接收模块     
    25 uart_recv #(                          
    26     .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
    27     .UART_BPS       (UART_BPS))         //设置串口接收波特率
    28 u_uart_recv(                 
    29     .sys_clk        (sys_clk), 
    30     .sys_rst_n      (sys_rst_n),
    31     
    32     .uart_rxd       (uart_rxd),
    33     .uart_done      (uart_recv_done),
    34     .uart_data      (uart_recv_data)
    35     );
    36 
    37 //串口发送模块    
    38 uart_send #(                          
    39     .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
    40     .UART_BPS       (UART_BPS))         //设置串口发送波特率
    41 u_uart_send(                 
    42     .sys_clk        (sys_clk),
    43     .sys_rst_n      (sys_rst_n),
    44      
    45     .uart_en        (uart_send_en),
    46     .uart_din       (uart_send_data),
    47     .uart_tx_busy   (uart_tx_busy),
    48     .uart_txd       (uart_txd)
    49     );
    50     
    51 //串口环回模块    
    52 uart_loop u_uart_loop(
    53     .sys_clk        (sys_clk),             
    54     .sys_rst_n      (sys_rst_n),           
    55    
    56     .recv_done      (uart_recv_done),   //接收一帧数据完成标志信号
    57     .recv_data      (uart_recv_data),   //接收的数据
    58    
    59     .tx_busy        (uart_tx_busy),     //发送忙状态标志      
    60     .send_en        (uart_send_en),     //发送使能信号
    61     .send_data      (uart_send_data)    //待发送数据
    62     );
    63     
    64 endmodule
    

    在顶层模块中完成了对其余各个子模块的例化。需要注意的是,顶层模块中第10、11行定义了两个变量:系统时钟频率CLK_FREQ与串口波特率UART_BPS,使用时可以根据不同的系统时钟频率以及所需要的串口波特率设置这两个变量。我们可以尝试将串口波特率UART_BPS设置为其他值(如9600),在模块例化时会将这个变量传递到串口接收与发送模块中,从而实现不同速率的串口通信。
    串口接收模块的代码如下所示:

    1   module uart_recv(
    2       input             sys_clk,                  //系统时钟
    3       input             sys_rst_n,                //系统复位,低电平有效
    4       
    5       input             uart_rxd,                 //UART接收端口
    6       output  reg       uart_done,                //接收一帧数据完成标志
    7       output  reg [7:0] uart_data                 //接收的数据
    8       );
    9       
    10  //parameter define
    11  parameter  CLK_FREQ = 50000000;                //系统时钟频率
    12  parameter  UART_BPS = 9600;                    //串口波特率
    13  localparam  BPS_CNT  = CLK_FREQ/UART_BPS;       //为得到指定波特率,
    14                                                  //需要对系统时钟计数BPS_CNT次
    15  //reg define
    16  reg        uart_rxd_d0;
    17  reg        uart_rxd_d1;
    18  reg [15:0] clk_cnt;                             //系统时钟计数器
    19  reg [ 3:0] rx_cnt;                              //接收数据计数器
    20  reg        rx_flag;                             //接收过程标志信号
    21  reg [ 7:0] rxdata;                              //接收数据寄存器
    22  
    23  //wire define
    24  wire       start_flag;
    25  
    26  //*****************************************************
    27  //**                    main code
    28  //*****************************************************
    29  //捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
    30  assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    
    31  
    32  //对UART接收端口的数据延迟两个时钟周期
    33  always @(posedge sys_clk or negedge sys_rst_n) begin 
    34      if (!sys_rst_n) begin 
    35          uart_rxd_d0 <= 1'b0;
    36          uart_rxd_d1 <= 1'b0;          
    37      end
    38      else begin
    39          uart_rxd_d0  <= uart_rxd;                   
    40          uart_rxd_d1  <= uart_rxd_d0;
    41      end   
    42  end
    43  
    44  //当脉冲信号start_flag到达时,进入接收过程           
    45  always @(posedge sys_clk or negedge sys_rst_n) begin         
    46      if (!sys_rst_n)                                  
    47          rx_flag <= 1'b0;
    48      else begin
    49          if(start_flag)                          //检测到起始位
    50              rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
    51                                                  //计数到停止位中间时,停止接收过程
    52          else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))
    53              rx_flag <= 1'b0;                    //接收过程结束,标志位rx_flag拉低
    54          else
    55              rx_flag <= rx_flag;
    56      end
    57  end
    58  
    59  //进入接收过程后,启动系统时钟计数器
    60  always @(posedge sys_clk or negedge sys_rst_n) begin         
    61      if (!sys_rst_n)                             
    62          clk_cnt <= 16'd0;                                  
    63      else if ( rx_flag ) begin                   //处于接收过程
    64          if (clk_cnt < BPS_CNT - 1)
    65              clk_cnt <= clk_cnt + 1'b1;
    66          else
    67              clk_cnt <= 16'd0;                   //对系统时钟计数达一个波特率周期后清零
    68      end
    69      else                                            
    70          clk_cnt <= 16'd0;                       //接收过程结束,计数器清零
    71  end
    72  
    73  //进入接收过程后,启动接收数据计数器
    74  always @(posedge sys_clk or negedge sys_rst_n) begin         
    75      if (!sys_rst_n)                             
    76          rx_cnt  <= 4'd0;
    77      else if ( rx_flag ) begin                   //处于接收过程
    78          if (clk_cnt == BPS_CNT - 1)             //对系统时钟计数达一个波特率周期
    79              rx_cnt <= rx_cnt + 1'b1;            //此时接收数据计数器加1
    80          else
    81              rx_cnt <= rx_cnt;       
    82      end
    83       else
    84          rx_cnt  <= 4'd0;                        //接收过程结束,计数器清零
    85  end
    86  
    87  //根据接收数据计数器来寄存uart接收端口数据
    88  always @(posedge sys_clk or negedge sys_rst_n) begin 
    89      if ( !sys_rst_n)  
    90          rxdata <= 8'd0;                                     
    91      else if(rx_flag)                            //系统处于接收过程
    92          if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
    93              case ( rx_cnt )
    94               4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
    95               4'd2 : rxdata[1] <= uart_rxd_d1;
    96               4'd3 : rxdata[2] <= uart_rxd_d1;
    97               4'd4 : rxdata[3] <= uart_rxd_d1;
    98               4'd5 : rxdata[4] <= uart_rxd_d1;
    99               4'd6 : rxdata[5] <= uart_rxd_d1;
    100              4'd7 : rxdata[6] <= uart_rxd_d1;
    101              4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
    102              default:;                                    
    103             endcase
    104         end
    105         else 
    106             rxdata <= rxdata;
    107     else
    108         rxdata <= 8'd0;
    109 end
    110 
    111 //数据接收完毕后给出标志信号并寄存输出接收到的数据
    112 always @(posedge sys_clk or negedge sys_rst_n) begin        
    113     if (!sys_rst_n) begin
    114         uart_data <= 8'd0;                               
    115         uart_done <= 1'b0;
    116     end
    117     else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
    118         uart_data <= rxdata;                    //寄存输出接收到的数据
    119         uart_done <= 1'b1;                      //并将接收完成标志位拉高
    120     end
    121     else begin
    122         uart_data <= 8'd0;                                   
    123         uart_done <= 1'b0; 
    124     end    
    125 end
    126 
    127 endmodule
    

    串口接收模块程序中29至42行是一个经典的边沿检测电路,通过检测串口接收端uart_rxd的下降沿来捕获起始位。一旦检测到起始位,输出一个时钟周期的脉冲start_flag,并进入串口接收过程。串口接收状态用rx_flag来标志,rx_flag为高标志着串口接收过程正在进行,此时启动系统时钟计数器clk_cnt与接收数据计数器rx_cnt。
    由第13行的公式BPS_CNT = CLK_FREQ/UART_BPS可知,BPS_CNT为当前波特率下,串口传输一位所需要的系统时钟周期数。因此clk_cnt从零计数到BPS_CN-1时,串口刚好完成一位数据的传输。由于接收数据计数器rx_cnt在每次clk_cnt计数到BPS_CN-1时加1,因此由rx_cnt的值可以判断串口当前传输的是第几位数据。第87行至第109行就是根据clk_cnt的值将uart接收端口的数据寄存到接收数据寄存器对应的位,从而实现接收数据的串并转换。其中第92行选择clk_cnt计数至BPS_CNT/2时寄存接收端口数据,是因为计数到数据中间时的采样结果最稳定。
    程序中需要额外注意的地方是串口接收过程结束条件的判定,由第52行可知,在计数到停止位中间时,标志位rx_flag就已经拉低。这样做是因为虽然此时一帧数据传输还没有完成(停止位只传送到一半),但是数据位已经寄存完毕。而在连续接收数据时,提前半个波特率周期结束接收过程可以为检测下一帧数据的起始位留出充足的时间。
    我们使用上位机通过串口向开发板发送16进制数55,在串口接收过程中ILA抓取的波形图如下所示:
    在这里插入图片描述
    在这里插入图片描述

    图 7.5.13.4 串口接收过程波形图
    图 7.5.13.4中红色的触发线标识出了串口接收端uart_rxd的起始位,在整个接收过程中rx_flag保持为高电平,同时rx_cnt对串口数据进行计数。当rx_cnt计数到9时,串口数据接收完成,uart_done拉高,同时uart_data给出接收到的数据。从图中可以看到,接收模块能够正确接收串口数据并完成串并转换。
    串口发送模块代码如下所示:

    ![1   module uart_send(
    2       input         sys_clk,                  //系统时钟
    3       input         sys_rst_n,                //系统复位,低电平有效
    4       
    5       input         uart_en,                  //发送使能信号
    6       input  \[7:0\]  uart_din,                 //待发送数据
    7       output        uart_tx_busy,             //发送忙状态标志      
    8       output  reg   uart_txd                  //UART发送端口
    9       );
    10      
    11  //parameter define
    12  parameter  CLK_FREQ = 50000000;            //系统时钟频率
    13  parameter  UART_BPS = 9600;                //串口波特率
    14  localparam  BPS_CNT  = CLK_FREQ/UART_BPS;   //为得到指定波特率,对系统时钟计数BPS_CNT次
    15  
    16  //reg define
    17  reg        uart_en_d0; 
    18  reg        uart_en_d1;  
    19  reg \[15:0\] clk_cnt;                         //系统时钟计数器
    20  reg \[ 3:0\] tx_cnt;                          //发送数据计数器
    21  reg        tx_flag;                         //发送过程标志信号
    22  reg \[ 7:0\] tx_data;                         //寄存发送数据
    23  
    24  //wire define
    25  wire       en_flag;
    26  
    27  //*****************************************************
    28  //**                    main code
    29  //*****************************************************
    30  //在串口发送过程中给出忙状态标志
    31  assign uart_tx_busy = tx_flag;
    32  
    33  //捕获uart_en上升沿,得到一个时钟周期的脉冲信号
    34  assign en_flag = (~uart_en_d1) & uart_en_d0;
    35  
    36  //对发送使能信号uart_en延迟两个时钟周期
    37  always @(posedge sys_clk or negedge sys_rst_n) begin         
    38      if (!sys_rst_n) begin
    39          uart_en_d0 <= 1'b0;                                  
    40          uart_en_d1 <= 1'b0;
    41      end                                                      
    42      else begin                                               
    43          uart_en_d0 <= uart_en;                               
    44          uart_en_d1 <= uart_en_d0;                            
    45      end
    46  end
    47  
    48  //当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
    49  always @(posedge sys_clk or negedge sys_rst_n) begin         
    50      if (!sys_rst_n) begin                                  
    51          tx_flag <= 1'b0;
    52          tx_data <= 8'd0;
    53      end 
    54      else if (en_flag) begin                 //检测到发送使能上升沿                      
    55              tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
    56              tx_data <= uart_din;            //寄存待发送的数据
    57          end
    58                                              //计数到停止位结束时,停止发送过程
    59          else if ((tx_cnt == 4'd9) && (clk_cnt == BPS_CNT -(BPS_CNT/16))) begin                                        
    60              tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
    61              tx_data <= 8'd0;
    62          end
    63          else begin
    64              tx_flag <= tx_flag;
    65              tx_data <= tx_data;
    66          end 
    67  end
    68  
    69  //进入发送过程后,启动系统时钟计数器
    70  always @(posedge sys_clk or negedge sys_rst_n) begin         
    71      if (!sys_rst_n)                             
    72          clk_cnt <= 16'd0;                                  
    73      else if (tx_flag) begin                 //处于发送过程
    74          if (clk_cnt < BPS_CNT - 1)
    75              clk_cnt <= clk_cnt + 1'b1;
    76          else
    77              clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
    78      end
    79      else                             
    80          clk_cnt <= 16'd0;                   //发送过程结束
    81  end
    82  
    83  //进入发送过程后,启动发送数据计数器
    84  always @(posedge sys_clk or negedge sys_rst_n) begin         
    85      if (!sys_rst_n)                             
    86          tx_cnt <= 4'd0;
    87      else if (tx_flag) begin                 //处于发送过程
    88          if (clk_cnt == BPS_CNT - 1)         //对系统时钟计数达一个波特率周期
    89              tx_cnt <= tx_cnt + 1'b1;        //此时发送数据计数器加1
    90          else
    91              tx_cnt <= tx_cnt;       
    92      end
    93      else                              
    94          tx_cnt  <= 4'd0;                    //发送过程结束
    95  end
    96  
    97  //根据发送数据计数器来给uart发送端口赋值
    98  always @(posedge sys_clk or negedge sys_rst_n) begin        
    99      if (!sys_rst_n)  
    100         uart_txd <= 1'b1;        
    101     else if (tx_flag)
    102         case(tx_cnt)
    103             4'd0: uart_txd <= 1'b0;         //起始位 
    104             4'd1: uart_txd <= tx_data\[0\];   //数据位最低位
    105             4'd2: uart_txd <= tx_data\[1\];
    106             4'd3: uart_txd <= tx_data\[2\];
    107             4'd4: uart_txd <= tx_data\[3\];
    108             4'd5: uart_txd <= tx_data\[4\];
    109             4'd6: uart_txd <= tx_data\[5\];
    110             4'd7: uart_txd <= tx_data\[6\];
    111             4'd8: uart_txd <= tx_data\[7\];   //数据位最高位
    112             4'd9: uart_txd <= 1'b1;         //停止位
    113             default: ;
    114         endcase
    115     else 
    116         uart_txd <= 1'b1;                   //空闲时发送端口为高电平
    117 end
    118 
    119 endmodule](https://img-blog.csdnimg.cn/842cce3cdd674420a3a0c7638134dae1.png)
         
    

    串口发送模块与串口接收模块异曲同工,代码中也给出了详尽的注释,此处不再赘述。需要注意的是,在程序的59行,我们将tx_flag提前1/16个停止位拉低,是为了确保发送模块发送数据的时间略小于接收模块接收数据的时间,否则当连续传输大量数据时,发送数据的时间会不断累积,最终导致在做串口环回实验时丢失数据。
    尽管串口发送数据只是接收数据的反过程,理论上在传输的时间上是一致的,考虑到我们模块里计算波特率会有较小的偏差,并且串口对端的通信设备(如电脑等)收发数据的波特率同样可能会出现较小的偏差,因此这里为了确保环回实验的成功,这里将发送模块的停止位略微提前结束。
    需要说明的是,较小偏差的波特率在串口通信时是允许的,同样可以保证数据可靠稳定的传输。
    另外我们在代码的第31行将用于标志串口发送过程的tx_flag信号赋值给uart_tx_busy,并通过模块端口输出。这样其他模块就可以通过检测uart_tx_busy信号是否为低电平,从而判断串口发送模块是否处于空闲状态。若uart_tx_busy为高电平,那么uart_send正处于发送过程,外部模块需要等待当前发送过程结束之后,才能通过uart_en信号的上升沿来启动新的发送过程。
    图 7.5.13.5为串口发送过程中ILA抓取的波形图,我们使用开发板通过串口向上位机向发送16进制数55。图中绿色的触发线标识出了串口发送使能信号uart_en的上升沿。在检测到uart_en的上升沿后,en_flag会拉高一个时钟周期,此时将uart_din端口上的待发送数据寄存到tx_data中,并进入串口发送过程。
    在整个发送过程中tx_flag保持为高电平,tx_cnt对串口数据进行计数,同时tx_data的各个数据位依次通过串口发送端uart_txd发送出去。当tx_cnt计数到9时,串口数据发送完成,开始发送停止位。在一个波特率周期的停止位发送完成后,串口发送过程结束,uart_tx_busy信号拉低,表明串口发送模块进入空闲状态。
    在这里插入图片描述

    图 7.5.13.5 串口发送过程波形图
    从图 7.5.13.5中可以看出串口发送模块能够完成并串转换并正确发送串口数据。
    在介绍完串口的接收和发送模块后,最后我们来看一下串口环回模块的代码:

    1  module uart_loop(
    2      input             sys_clk,                   //系统时钟
    3      input            sys_rst_n,                 //系统复位,低电平有效
    4       
    5      input            recv_done,                 //接收一帧数据完成标志
    6      input      [7:0] recv_data,                 //接收的数据
    7       
    8      input            tx_busy,                   //发送忙状态标志      
    9      output reg       send_en,                   //发送使能信号
    10     output reg [7:0] send_data                  //待发送数据
    11     );
    12 
    13 //reg define
    14 reg recv_done_d0;
    15 reg recv_done_d1;
    16 reg tx_ready;
    17 
    18 //wire define
    19 wire recv_done_flag;
    20 
    21 //*****************************************************
    22 //**                    main code
    23 //*****************************************************
    24 
    25 //捕获recv_done上升沿,得到一个时钟周期的脉冲信号
    26 assign recv_done_flag = (~recv_done_d1) & recv_done_d0;
    27                                                  
    28 //对发送使能信号recv_done延迟两个时钟周期
    29 always @(posedge sys_clk or negedge sys_rst_n) begin         
    30     if (!sys_rst_n) begin
    31         recv_done_d0 <= 1'b0;                                  
    32         recv_done_d1 <= 1'b0;
    33     end                                                      
    34     else begin                                               
    35         recv_done_d0 <= recv_done;                               
    36         recv_done_d1 <= recv_done_d0;                            
    37     end
    38 end
    39 
    40 //判断接收完成信号,并在串口发送模块空闲时给出发送使能信号
    41 always @(posedge sys_clk or negedge sys_rst_n) begin         
    42     if (!sys_rst_n) begin
    43         tx_ready  <= 1'b0; 
    44         send_en   <= 1'b0;
    45         send_data <= 8'd0;
    46     end                                                      
    47     else begin                                               
    48         if(recv_done_flag)begin                 //检测串口接收到数据
    49             tx_ready  <= 1'b1;                  //准备启动发送过程
    50             send_en   <= 1'b0;
    51             send_data <= recv_data;             //寄存串口接收的数据
    52         end
    53         else if(tx_ready && (~tx_busy)) begin   //检测串口发送模块空闲
    54             tx_ready <= 1'b0;                   //准备过程结束
    55             send_en  <= 1'b1;                   //拉高发送使能信号
    56         end
    57     end
    58 end
    59 
    60 endmodule 
    

    uart_loop模块的代码比较简单,首先代码的25至38行实现了上升沿检测功能。当检测到recv_done信号的上升沿时,recv_done_flag输出一个时钟周期的高电平,标志着串口接收模块接收到了一帧数据。在代码的48至52行,在判断到recv_done_flag为高电平时,寄存接收到的数据recv_data到send_data中;同时将tx_ready信号拉高,表示已经准备好了待发送的数据。另外还要将send_en信号拉低,为接下来产生一个上升沿作准备。
    uart_loop模块还有一个输入信号tx_busy,它是由串口发送模块所输出,该信号为高电平表示串口发送模块正处于发送过程中。在代码的第53行,当tx_ready信号为高电平时,如果检测到tx_busy为低电平,则说明串口发送模块处于空闲状态。此时将send_en信号拉高,由此产生一个上升沿,以启动串口发送模块的发送过程,将寄存到send_data中的数据发送出去。于此同时,将tx_ready信号拉低,等待下一个串口接收数据的到来。
    1.5 下载验证
    编译工程并生成比特流.bit文件。接下来我们下载程序,验证上位机与开发板通过RS232串口进行串口数据环回功能。
    首先我们需要准备一个图 7.5.13.3所示的USB转串口线,将USB接口一端插入电脑上的USB口,另一端DB9接口与开发板上的COM2接口相连接,并将P1排针上的两个跳帽按照如下图所示的方式连接:
    在这里插入图片描述

    图 7.5.13.1 串口连接和P1跳线帽连接
    接下来分别连接JTAG接口和电源线,并打开电源开关。
    注意上位机第一次使用USB转串口线与FPGA开发板连接时,需要安装USB串口驱动。在开发板随附的资料中找到“6_软件资料/1_软件/CH340驱动(USB串口驱动)”的文件夹,双击打开文件夹中的“SETUP.EXE”进行安装,驱动安装界面如图 7.5.13.2所示。界面中提示INF文件为CH341SER.INF,我们不需要理会(CH341,CH340驱动是共用的),直接点安装即可。
    在这里插入图片描述

    图 7.5.13.2 USB串口驱动驱动安装界面
    开发板电源打开后,将本次实验的bit文件下载到开发板中。
    接下来打开串口助手。串口助手是上位机中用于辅助串口调试的小工具,可以选择安装使用开发板随附资料中“6_软件资料/1_软件/串口调试助手”文件夹中提供的XCOM串口助手。在上位机中打开串口助手XCOM V2.0,如下图所示:
    在这里插入图片描述

    图 7.5.13.3 串口助手操作界面
    在串口助手中选择与开发板相连接的CH340虚拟串口,具体的端口号(这里是COM4)需要根据实际情况选择,可以在计算机设备器中查看,如下图所示:
    在这里插入图片描述

    图 7.5.13.4 电脑的设备管理器窗口
    在串口助手中设置波特率为115200,数据位为8,停止位为1,无校验位,最后确认打开串口。
    串口打开后,在发送文本框中输入数据“5A”并点击发送,可以看到串口助手中接收到数据“5A”,如图 7.5.13.3所示。串口助手接收到的数据与发送的数据一致,说明程序所实现的串口数据环回功能验证成功。

    展开全文
  • 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第三章硬件资源详解 本章,我们将向大家详细介绍正点原子新起点FPGA开发板各部分的硬件原理图,让大家对该开发板...
  • 1)实验平台:正点原子领航者ZYNQ...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十五章 IP核之FIFO实验 FIFO的英文全称是First In First Out,即先进先出
  • 1)实验平台:正点原子...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十七章 RS485串口通信实验 RS-485是针对UART串口的一种接口标准,它定义了串行通信系统
  • 目前用CPLD(复杂可编程逻辑器件)和 FPGA(现场可编程逻辑门阵列)来进行ASIC设计是最为流行的方式之一,它们的共性是都具有用户现场可编程特性,都支持边界扫描技术,但两者在集成度、速度以及编程方式上具有...
  • 1)实验平台:正点原子领航者...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第一章 ZYNQ简介 ZYNQ是赛灵思公司(Xilinx)推出的新一代全可编程片上系统(APSoC)
  • 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第四十五章FLASH读写实验 FLASH存储器又称闪存,是一种长寿命的非易失性(在断电情况下仍能保持所存储的数据
  • 4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第三十三章 以太网ARP测试实验 在以太网中,一个主机和另一个主机进行通信,必须要知道目的主机的MA
  • 4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第二十二章 HDMI方块移动实验 在HDMI彩条显示实验中,我们成功地在显示器上显示出了静态的彩条图
  • 1)实验平台:正点原子...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第二十章 LCD触摸屏实验 触摸屏(Touch Panel)又称为触控屏、触控面板,是一种可接收触头
  • 1)实验平台:正点原子...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十九章 RGB LCD字符和图片显示实验 我们在“RGB LCD彩条显示实验”中成功的在正点原子的
  • 1)实验平台:正点原子领航者ZYNQ开发板 ...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十三章 IP核之MMCM/PLL实验 PLL的英文全称是Phase Locked Loop,即锁相
  • 正点原子FPGA连载】第十四章串口通信实验-摘自【正点原子】新起点之FPGA开发指南-V2.1 fpga开发.pdf
  • 1)实验平台:正点原子...3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第四章Quartus II软件的安装和使用 Quartus II是Altera公司的综合性FPGA开发软件,可以
  • 正点原子FPGA连载】第九章按键控制LED灯实验-摘自【正点原子】新起点之FPGA开发指。。。 fpga开发.pdf
  • 1)实验平台:正点原子领航者ZYNQ...4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十四章 IP核之RAM实验 RAM的英文全称是Random Access Memory,即随机存取
  • 4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第十二章 呼吸灯实验 呼吸灯最早由苹果公司发明并应用于笔记本睡眠提示上,其一经展出,立刻吸引众多科技
  • 本章我们同样通过LED灯流水实验,带你进入FPGA的精彩世界。 本章包括以下几个部分: 88.1简介 8.2实验任务 8.3硬件设计 8.4程序设计 8.5下载验证 8.1简介 LED,又名发光二极管。LED灯工作电流很小(有的仅零点几毫安...
  • 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第四十六章SD卡读写测试实验 SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备。它具有体积小、传输速度快、...
  • 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 第二十一章UART串口通信实验 串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字节分成一位...
  • 4)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 5)关注正点原子公众号,获取最新资料更新 第二十五章 频率计实验 数字频率计是一种基本的测量仪器,被广泛应用于航天、电子、测控等领域。基于传统
  • 最新正点原子FPGA开发板及外围电路模块protel99原理图库PCB封装库+AD集成库, 3.5TFTLCD封装库.IntLib ATK-4.3' TFTLCD电容触摸屏模块_V1.2.IntLib ATK-4342 4.3寸RGB屏模块封装库.IntLib ATK-7016&7084 7寸RGB屏...
  • 串口是“串行接口”的简称,即采用串行通信方式的接口。...更多详细内容请参考《正点原子开拓者FPGA开发指南》,以下链接可免费下载该文档及源码: http://openedv.com/thread-281143-1-1.html  
  • b站正点原子的SDRAM源代码,基本上符合对于SDRAM的要求

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,319
精华内容 527
关键字:

正点原子fpga

友情链接: CHAP06.rar