安路FPGA FIFO IP核使用小程序

项目概述

在学习sdram的使用的时候需要用到FIFO,不想重头写一个了,决定直接用安路的FIFO IP,之前没有用过,对它的功能用法还不太了解,所以写一个小工程来学习一下。项目功能设定为:一秒的时钟脉冲内向FIFO发送数据,从0开始一直到255,然后直接从FIFO中读出数据,发送到数码管进行显示,并单独引出一个一秒亮一秒灭的LED与其进行对比,判断功能完整性。
开发板:安路EG4S20BG256,cortex-M0内核。
编译环境:安路TD5.6.2版本。
在这里插入图片描述
为了简便,采用同步FIFO,输入输出共用一个时钟,输入输出都采用8位宽,1024深度。

程序层级

在这里插入图片描述

顶层代码

module fifo_ctrl(
    input         clk,
    input         rst,    //用于复位,连接key1

    output [3:0]  digitalCS,
    output [7:0]  digitalDATA,
    output        LED
);

wire empty_flag;
wire full_flag;
wire we,re;
reg  [8:0] di;
reg  [8:0] do;


// 1秒周期时钟
reg [25:0] counter;
wire clk_1Hz;

reg clk_1Hz_reg;
// 计数器逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        counter <= 26'd0;
        clk_1Hz_reg <= 1'b0;
    end else if (counter == 26'd49_999_999) begin // 50,000,000 - 1
        counter <= 26'd0;
        clk_1Hz_reg <= ~clk_1Hz_reg; // 翻转时钟输出
    end else begin
        counter <= counter + 1'b1;
    end
end

assign clk_1Hz = clk_1Hz_reg;

//半秒时钟脉冲
reg [24:0] counter_half;
wire clk_2Hz;

reg clk_2Hz_reg;
// 计数器逻辑
always @(posedge clk or posedge rst) begin
    if (rst) begin
        counter_half <= 26'd0;
        clk_2Hz_reg <= 1'b0;
    end else if (counter_half == 25'd24_999_999) begin // 25,000,000 - 1
        counter_half <= 26'd0;
        clk_2Hz_reg <= ~clk_2Hz_reg; // 翻转时钟输出
    end else begin
        counter_half <= counter_half + 1'b1;
    end
end

assign clk_2Hz = clk_2Hz_reg;

// 数据生成器
reg [7:0] data_to_write;

always @(posedge clk_2Hz or posedge ret) begin
    if (rst)
        data_to_write <= 8'd0;
    else
        data_to_write <= data_to_write + 8'd1;
end


wire [7:0] fifo_data_in, fifo_data_out;
// assign we = clk_1Hz & ~full_flag;  // 每秒写入一次,如果FIFO不满
assign we = (counter_half == 25'd24_999_999) & ~full_flag; // 每秒写入一次,如果FIFO不满
assign re = ~empty_flag;           // 只要FIFO不空就持续读取

assign LED = clk_1Hz; // 1Hz闪烁LED



fifo u_fifo(
    .rst         (rst),
	.di          (data_to_write), 
    .clk         (clk), 
    .we          (we),
	.do          (fifo_data_out), 
    .re          (re),     
	.empty_flag  (empty_flag),
	.full_flag   (full_flag)  
);


// 三位数码管显示控制
Digitron_NumDisplay display_controller (
    .CLK(clk),
    .Result(fifo_data_out),
    .Digitron_Out(digitalDATA),
    .DigitronCS_Out(digitalCS)
);


endmodule

这里必须要强调一下,在程序初期,我试图直接将1Hz的时钟脉冲进行数据发送,但这样的结果是数码管2秒才会变换一个数字,是因为程序里设定1Hz脉冲上升沿才会发送数据,这中间的间隔实际上就变成了2s,因此,后来我又写了一个2Hz的脉冲,这时在上升沿发送数据就对了。

三位数码管显示代码

module Digitron_NumDisplay
(
    input wire CLK,
    input wire [7:0] Result,
    output wire [7:0] Digitron_Out,
    output wire [3:0] DigitronCS_Out
);
    parameter T250K = 16'd16666; // 调整为3kHz刷新率 (50MHz / 3000Hz ≈ 16666)
    reg [15:0] Count;
    reg [1:0] cnt;
    reg [3:0] W_DigitronCS_Out;

    always @(posedge CLK)
    begin
        if (Count == T250K)
        begin
            Count <= 16'd0;
            cnt <= cnt + 1'b1;
        end
        else
            Count <= Count + 1'b1;
    end

    always @(cnt)
    begin
        case (cnt)
            2'b00: W_DigitronCS_Out = 4'b1110; // 个位
            2'b01: W_DigitronCS_Out = 4'b1101; // 十位
            2'b10: W_DigitronCS_Out = 4'b1011; // 百位
            default: W_DigitronCS_Out = 4'b1111; // 全不选
        endcase
    end

    reg [3:0] SingleNum;
    reg [7:0] W_Digitron_Out;

    parameter   _0 = 8'b0011_1111, _1 = 8'b0000_0110, _2 = 8'b0101_1011,
                _3 = 8'b0100_1111, _4 = 8'b0110_0110, _5 = 8'b0110_1101,
                _6 = 8'b0111_1101, _7 = 8'b0000_0111, _8 = 8'b0111_1111,
                _9 = 8'b0110_1111;

    wire [7:0] hundreds;
    wire [7:0] tens;
    wire [7:0] ones;

    assign hundreds = Result / 100;
    assign tens = (Result % 100) / 10;
    assign ones = Result % 10;

    always @(*)
    begin
        case(W_DigitronCS_Out)
            4'b1110: SingleNum = ones;
            4'b1101: SingleNum = tens;
            4'b1011: SingleNum = hundreds;
            default: SingleNum = 4'd0;
        endcase

        case(SingleNum)
            0:  W_Digitron_Out = _0;
            1:  W_Digitron_Out = _1;
            2:  W_Digitron_Out = _2;
            3:  W_Digitron_Out = _3;
            4:  W_Digitron_Out = _4;
            5:  W_Digitron_Out = _5;
            6:  W_Digitron_Out = _6;
            7:  W_Digitron_Out = _7;
            8:  W_Digitron_Out = _8;
            9:  W_Digitron_Out = _9;
            default: W_Digitron_Out = 8'b0000_0000;
        endcase
    end

    assign Digitron_Out = W_Digitron_Out;
    assign DigitronCS_Out = W_DigitronCS_Out;

endmodule

运行结果

在这里插入图片描述
程序顺利运行。这里用到了三位数码管以及一个LED,数码管一秒一计数,LED两秒闪灭一周期,用来与FIFO读出的数据进行对比,判断FIFO读出的效果。经过实际测试,数码管正常显示,计数到255即发生反转,功能正常。

总结

哦!万能的Chatgpt以及Claude!他们几乎能帮我写出全部的代码!

另外,总的来看,同步FIFO IP核的使用并不复杂,这里不再考虑内部RAM的构建,因此带来了极大的方便。数据读出也很迅速,毕竟在50MHz时钟下人眼也几乎无法判断LED与数码管之间是否有延迟。
在写程序之前,我对FIFO的输入时钟clk不太理解,认为对FIFO的读入与读出会与这个clk信号有直接联系,但实测来看,如果仅用IP的话看起来并没有什么关系,这里只要把它和系统时钟连在一起就好了,不过要注意,如果自己写FIFO,时钟还是很重要的,尤其对于异步FIFO而言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值