• 基于 Cyclone IV 在 Quartus 中配置 IP 核中的 PLL 与 RAM 的详细步骤


    本文内容:基于 Cyclone IV在 Quartus 中配置 IP 核中的 PLL 、 RAM 与 FIFO 的详细步骤

    一、配置 PLL

    • 在我看来哈,PLL 的作用就是将输入时钟通过倍频分频相位偏移设置占空比等操作,将输入的时钟信号转变为另外一种形式的时钟信号,这个主要看自己的需求

    1.1 参数配置

    • 首先需要新建一个工程,在工程里面配置 PLL
    • 在【IP Catalog】界面的搜索框中输入【PLL】,双击【ALTPLL】即可
      在这里插入图片描述
    • 如果没有【IP Catalog】界面,在【View】中可以设置
      在这里插入图片描述
    • 点击【…】选择 IP 核的保存路径
      在这里插入图片描述
    • 最好新建一个 ip 文件夹,输入文件名后保存(图中有文件,是之前加的)
      在这里插入图片描述
    • 再点击【OK】
      在这里插入图片描述
    • Cyclone IV 选择 8 通道、50 MHz(细心的兄弟会发现左边的 PLL_demo 有 c0 - c3 多个输出,但是自己的界面只有个 c0 ,没关系,这是后面才配置出来的,我这个是配置好的)
      在这里插入图片描述
    • 勾选上【Create ‘locked’ output】
      在这里插入图片描述
    • 默认即可
      在这里插入图片描述
    • 默认即可
      在这里插入图片描述
    • 默认即可
      在这里插入图片描述
    • 主要的配置界面如下:
      在这里插入图片描述
      Clock multiplication factor——时钟倍频参数
      Clock division factor——时钟分频参数
      Clock phase shift——时钟相位偏移参数
      Clock duty cycle(%)——时钟占空比
    • 这里我们让每一个输出设置一种参数类型来看看实际的效果
    • 首先让 c0 设置倍频参数为 2,可以看到它的时钟频率变为了 100 MHz,再点击【Next>】
      在这里插入图片描述
    • c1 让它分频参数设为 2 ,可以看到它的频率变为了 25 MHz,再点【Next>】
      在这里插入图片描述
    • c2 相位偏移设为 90,单位是 deg,表示角度,也就是偏移了 π/2 个时钟周期,除了角度还有时间单位 ns、ps
      在这里插入图片描述
    • c3 时间占空比设为 20,之后可以具体看看是什么样子
      在这里插入图片描述
    • c4 我就没有勾选上了,因为就那么四个参数,没必要再搞一个 c4 输出了
      在这里插入图片描述
    • 继续点击【Next>】
      在这里插入图片描述
    • 勾选上【PLL_demo_inst.v】,这个可以生成相应的模块调用格式
      在这里插入图片描述

    1.2 仿真测试

    `timescale 1ns/1ns
    
    module tb_pll;
    
    // Parameter definition
        parameter       CYC_CLK             = 20            ;
    
    // Drive signal
        reg                                 tb_clk          ;
        reg                                 tb_rst_n        ;
    
    // Observation signal
        wire                                c0              ;
        wire                                c1              ;
        wire                                c2              ;
        wire                                c3              ;
        wire                                locked          ;
    
    
    // Module calls
        PLL_demo	PLL_demo_inst (
            /*input */  .inclk0             (tb_clk     ),
        	/*input */  .areset             (~tb_rst_n  ),
        	/*output*/  .c0                 (c0         ),
        	/*output*/  .c1                 (c1         ),
        	/*output*/  .c2                 (c2         ),
        	/*output*/  .c3                 (c3         ),
        	/*output*/  .locked             (locked     )
    	);
        
    
    // System initialization
        initial tb_clk = 1'b1;
        always #10 tb_clk = ~tb_clk;
    
        initial begin
            tb_rst_n = 1'b0;
            #20;
            tb_rst_n = 1'b1;
    
            #(500 * CYC_CLK);
    
            $stop;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 在【Simulation】选择 Test Benches 中,选择哪一个仿真文件,就会仿真哪个,同时还要设置相应的顶层模块熬
      在这里插入图片描述
    • 仿真结果如下:
      在这里插入图片描述
    • 可以看到
      c0 倍频,频率高了,时钟周期短了
      c1 分频,频率低了,时钟周期长了
      c2 相位偏移,右移了 π/2 个时钟周期
      c3 设置占空比 20,高电平区间占一个时钟周期 20%
    • 这就是 PLL 的作用,将输出的 clock 时钟信号转变为其它类型的时钟信号

    二、配置 RAM

    2.1 参数配置

    • 同样在【IP Catalog】搜索 RAM,选择 1-PORT 单端口的,2-PORT 表示双端口,学会了单端口那么双端口也依葫芦画瓢就会了
      在这里插入图片描述
    • 同样的操作步骤
      在这里插入图片描述
    • 这里表示一个数据字节为 8 bits,共 256 个字节,Auto 自动配置即可,勾选 Single clock 表示单个时钟信号控制输入输出就行
      在这里插入图片描述
    • 勾选上 q 也就是数据输出,同时勾选上复位信号 aclr 和读使能信号 rden
      在这里插入图片描述
    • 这里设置 Don’t Care 即可
      在这里插入图片描述
    • 在这里使用一个 hex 文件初始化 RAM,看下面怎么创建 hex 文件
      在这里插入图片描述
    • 切回 Quartus 主界面,点击【File】→【New…】
      在这里插入图片描述
    • 点击【Hexadecimal (Intel-Format) File】创建在这里插入图片描述
    • 新建的文件,里面是没有数据,选中所有的字节,右键点击【Custom Fill Cells…】
      在这里插入图片描述
    • Starting address:开始地址
      Ending address:结束地址
      Starting value:初始值
      Increment:递增操作
      by:步长
    • 最后点击 OK
      在这里插入图片描述
    • 保存到 prj 下面,一定要是 prj 下面!!!
      在这里插入图片描述
    • 回到刚刚的窗口,添加 hex 文件到 RAM 中
      在这里插入图片描述
    • 再点击【Next>】
      在这里插入图片描述
    • 最后勾选上【inst】即可
      在这里插入图片描述

    2.2 仿真测试

    • 仿真代码如下:
    `timescale 1ns/1ns
    
    module tb_ram;
    
    // Parameter definition
        parameter       CYC_CLK             = 20            ;
    
    // Drive signal
        reg                                 tb_clk          ;
        reg                                 tb_rst_n        ;
        reg             [ 7:0]              address         ;
        reg             [ 7:0]              data            ;
        reg                                 rden            ;
        reg                                 wren            ;
    
    // Observation signal
        wire            [ 7:0]              q_out           ;
    
    // Module calls
        RAM_demo	RAM_demo_inst (
            .clock                          (tb_clk         ),
    	    .aclr                           (~tb_rst_n      ),
    	    .address                        (address        ),
    	    .data                           (data           ),
    	    .rden                           (rden           ),
    	    .wren                           (wren           ),
    	    .q                              (q_out          )
    	);
    
    // System initialization
        initial tb_clk = 1'b1;
        always #10 tb_clk = ~tb_clk;
    
        initial begin
            address = 8'd25;
            data = 8'd51;
            rden = 1'b0;
            wren = 1'b0;
            tb_rst_n = 1'b0;
            #20;
            tb_rst_n = 1'b1;
    
            // 读操作
            rden = 1'b1;
            repeat (256) begin
                address = address + 8'd1;
                #(CYC_CLK);
            end
            rden = 1'b0;
    
            #(500 * CYC_CLK);
    
            // 写操作
            wren = 1'b1;
            repeat (256) begin
                data = data + 8'd2;
                address = address + 8'd1;
                #(CYC_CLK);
            end
            wren = 1'b0;
    
            #(500 * CYC_CLK);
    
            // 读操作
            rden = 1'b1;
            repeat (256) begin
                address = address + 8'd1;
                #(CYC_CLK);
            end
            rden = 1'b0;
    
            #(500 * CYC_CLK);
    
            $stop;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 记得设置仿真文件
      在这里插入图片描述
    • 仿真结果:
      在这里插入图片描述
    • 第一段读操作是读的 hex 文件设置的内容,写操作写入新的数据,第二个读操作,读取的是写入的新数据

    三、配置 FIFO

    3.1 参数配置

    • FIFO 其实就是一个队列,先进先出的原则
    • 同样的,输入 FIFO/fifo 双击
      在这里插入图片描述
    • 选择存储路径
      在这里插入图片描述
    • 看自己的选择勾选与设置
      在这里插入图片描述
    • 默认设置即可
      在这里插入图片描述
    • 按照下图自己需要进行配置
      在这里插入图片描述
    • 默认就行
      在这里插入图片描述
    • 没勾选
      在这里插入图片描述
    • 一直到这一步,勾选个 inst 即可,生成个模块调用语句而已
      在这里插入图片描述

    3.2 仿真测试

    • 这里使用一个 Verilog 顶层模块调用 FIFO,并不断地写数据,同时不断地读数据
    • 再写一个仿真测试文件来看看仿真波形

    fifo_top.v

    module fifo_top (
        input                               clk             ,
        input                               rst_n           ,
        
        output          [15:0]              q               ,
        output                              rdempty         ,
        output          [ 7:0]              rdusedw         ,
        output                              wrfull          ,
        output          [ 8:0]              wrusedw         
    );
    
    // Parameter definition
        
    
    // Signal definition
        reg             [ 7:0]              data            ;
        reg                                 rdreq           ;
        reg                                 wrreq           ;
        
    
    // Module calls
        FIFO_512_8	FIFO_512_8_inst (
        	/*input           */    .aclr       (~rst_n  ),// 复位信号,高电平有效
        	/*input     [ 7:0]*/    .data       (data    ),// 写数据,8bits
        	/*input           */    .rdclk      (clk     ),// 读时钟信号
        	/*input           */    .rdreq      (rdreq   ),// 读使能信号,高电平读
        	/*input           */    .wrclk      (clk     ),// 写时钟信号
        	/*input           */    .wrreq      (wrreq   ),// 写使能信号,高电平写
        	/*output    [15:0]*/    .q          (q       ),// 读数据,16bits
        	/*output          */    .rdempty    (rdempty ),// 读空使能,表示读的时候队列中是否为空,1表示空,0表示非空
        	/*output    [ 7:0]*/    .rdusedw    (rdusedw ),// 读余量,表示读的时候队列中有多少个16bits的数据
        	/*output          */    .wrfull     (wrfull  ),// 写满使能,表示写的时候队列中是否写满了,1表示满,0表示非满
        	/*output    [ 8:0]*/    .wrusedw    (wrusedw ) // 写余量,表示写的时候队列中有多少个8bits的数据 
        );
        
    // Logic description
        // 读使能
        always @(posedge clk or negedge rst_n) begin
            if (!rst_n) begin
                rdreq <= 'd0;
            end
            else if (rdempty) begin
                rdreq <= 'd0;
            end
            else begin
                rdreq <= 'd1;
            end
        end
    
        // 写使能
        always @(posedge clk or negedge rst_n) begin
            if (!rst_n) begin
                wrreq <= 'd0;
            end
            else if (wrfull) begin
                wrreq <= 'd0;
            end
            else begin
                wrreq <= 'd1;
            end
        end
    
        // 写数据
        always @(posedge clk or negedge rst_n) begin
            if (!rst_n) begin
                data <= 'd20;
            end
            else if (wrreq) begin
                if (data >= 255) begin
                    data <= 0;
                end
                else begin
                    data <= data + 'd2;
                end
            end
            else begin
                data <= 'd20;
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 仿真文件

    tb_fifo.v

    `timescale 1ns/1ns
    
    module tb_fifo;
    
    // Parameter definition
        parameter       CYC_CLK             = 20            ;
    
    // Drive signal
        reg                                 tb_clk          ;
        reg                                 tb_rst_n        ;
    
    // Observation signal
        wire 	        [15:0]              tb_q            ;
    	wire 	                            tb_rdempty      ;
    	wire 	        [ 7:0]              tb_rdusedw      ;
    	wire 	                            tb_wrfull       ;
    	wire 	        [ 8:0]              tb_wrusedw      ;
    
    // Module calls
        fifo_top U_fifo_top(
            /*input                 */  .clk            (tb_clk     ),
            /*input                 */  .rst_n          (tb_rst_n  ),
            /*output          [15:0]*/  .q              (tb_q       ),
            /*output                */  .rdempty        (tb_rdempty ),
            /*output          [ 7:0]*/  .rdusedw        (tb_rdusedw ),
            /*output                */  .wrfull         (tb_wrfull  ),
            /*output          [ 8:0]*/  .wrusedw        (tb_wrusedw )
        );
    
    // System initialization
        initial tb_clk = 1'b1;
        always #10 tb_clk = ~tb_clk;
    
        initial begin
            tb_rst_n = 1'b0;
            #20;
            tb_rst_n = 1'b1;
    
            #(200 * CYC_CLK);
    
            $stop;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 仿真结果
      在这里插入图片描述
    • 可以看到队列先进先出的原则
    • 但是读余量前面一段时间为 0 ,但是明明有数据,结果却为了,过了几个时钟周期后才变成 1
    • 应该是由于写数据到 M9K 中这个过程需要时间,过了几个时钟周期后,读余量才检测到有数据,才读取数据
  • 相关阅读:
    强大的JTAG边界扫描(2):BSDL文件介绍
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    【智能家居项目】裸机版本——项目介绍 | 输入子系统(按键) | 单元测试
    三种获取URL参数值的方法
    探究Spring Boot中@PostConstruct注解的使用场景
    半小时了解SQL注入漏洞?(注入方式大全+绕过大全)
    异行星低代码平台--第三方插件对接:企业微信平台对接(二)
    Java 面试题:如何保证集合是线程安全的? ConcurrentHashMap 如何实现高效地线程安全?
    [自研开源] MyData 数据集成之数据过滤 v0.7.2
    怎样开发智能合约中的时间锁
  • 原文地址:https://blog.csdn.net/ssj925319/article/details/126116213