跳转至

ROM IP核使用方法

参考链接

FPGA实验课8:ROM(IP核)使用实例_fpga的rom的ip如何调用-CSDN博客

Kimi人工智能

1. FPGA中位宽和深度的概念

  1. 位宽(Bit Width)
  2. 想象一下,你有一条高速公路,这条高速公路有多个车道。位宽就是指这些车道的数量。比如,一个32位宽的寄存器就像是有32个车道的高速公路,可以同时让32辆车并排行驶。在FPGA中,位宽越大,意味着可以同时处理更多的数据,从而提高计算速度。
  3. 深度(Depth)
  4. 现在,想象你有一座多层的停车场。深度就是指这座停车场有多少层。比如,一个深度为1024的存储器就像是有1024层的停车场,每一层都可以停放一辆车。在FPGA中,深度越大,意味着可以存储更多的数据。

总结一下:

  • 位宽:一次操作可以处理的数据量。位宽越大,数据处理能力越强。
  • 深度:可以存储的数据总量。深度越大,存储容量越大。

2. ROM IP核的使用方法

2.1 仿真结果

rom_ip.v

module ROM_IP(
    input sys_clk,
    input sys_rst_n,

    // TLC5620的引脚
    output  wire            da_clk      ,   // 时钟信号
    output  wire            da_data     ,   // 数据信号
    output  wire            da_ldac     ,   // LDAC信号
    output  wire            da_load     ,   // LOAD信号
     output  wire    [7:0]    wave

);


// rom地址控制模块
reg [12:0] addr;
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        addr <= 13'd0;
    else if(addr == 13'd4095)
        addr <= 13'd0;
    else 
        addr <= addr + 1'd1;
end

// 实例化ROM IP核
rom rom_inst (
    .address ( addr ),
    .clock   ( sys_clk ),
    .q       ( wave )
    );


// 实例化tlc5620驱动模块
tlc_5620 tlc_5620_inst
(
    .CLOCK_50(sys_clk),     // 系统时钟
    .RST_N(sys_rst_n),      // 复位信号
    .da_enable(1'b1),       // 使能信号,始终使能
    .da_range(1'b0),        // 输出范围选择,根据需要设置
    .da0_data(wave),        // 将dac_data连接到DA0通道
    .da1_data(8'b0),        // 其他通道暂时不使用,置为0
    .da2_data(8'b0),        // 其他通道暂时不使用,置为0
    .da3_data(8'b0),        // 其他通道暂时不使用,置为0
    .SCK(da_clk),           // 连接到外部引脚
    .SDI(da_data),          // 连接到外部引脚
    .LOAD(da_load)          // 连接到外部引脚
);
// TLC5620的LDAC信号通常需要保持低电平以更新输出电压
assign da_ldac = 1'b0;
endmodule

tlc_5620.v

module tlc_5620
(
    input CLOCK_50,
    input RST_N,
    //
    input da_enable,
    input da_range, // 0, 1倍参考电压; 1, 2倍参考电压
    input [7:0] da0_data, // 0~255
    input [7:0] da1_data, // 0~255
    input [7:0] da2_data, // 0~255
    input [7:0] da3_data, // 0~255
    // 
    output reg SCK,
    output reg SDI,
    output reg LOAD
);

function integer log2(input integer n);
    integer i;
    for(i=0; 2**i <=n; i=i+1) log2=i+1;
endfunction

/**************************************
* 生成140ns的tick时钟
**************************************/
reg [log2(7):1]cnt_140ns;
always@(posedge CLOCK_50, negedge RST_N) 
    if(!RST_N) cnt_140ns <= 0;
    else begin
        if(cnt_140ns < 6) 
            cnt_140ns <= cnt_140ns + 1'b1;
        else cnt_140ns <= 0;
    end
wire tick_140ns = (cnt_140ns == 6) ? 1 : 0;

/**************************************
* 根据tick时钟生成da基准计数器
**************************************/
reg [log2(48):1] da_ref_cnt; // [0,47]
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_ref_cnt <= 0;
    else begin
        if(!da_enable) da_ref_cnt <= 0;
        else begin
            if(tick_140ns) begin
                if(da_ref_cnt < 47) 
                    da_ref_cnt <= da_ref_cnt + 1'b1;
                else da_ref_cnt <= 0;
            end
        end
    end
wire tick_6720ns = (da_ref_cnt == 47) ? 1 : 0;

reg [1:0] da_sel_cnt;
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_sel_cnt <= 2'b0;
    else if (tick_6720ns) begin
        if(da_sel_cnt < 3)
            da_sel_cnt <= da_sel_cnt + 1'b1;
        else da_sel_cnt <= 2'b0;
    end

/**************************************
* 根据基准计数器生成串行信号
**************************************/
reg [7:0] da_data;
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_data <= 8'b0;
    else begin
        case(da_sel_cnt)
            2'b00: da_data <= da0_data;
            2'b01: da_data <= da1_data;
            2'b10: da_data <= da2_data;
            2'b11: da_data <= da3_data;
        endcase
    end

always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) begin
        SCK <= 0;
        SDI <= 0;
        LOAD <= 0;
    end
    else begin
        if(tick_140ns) begin
            // 生成SCK信号
            case(da_ref_cnt)
                2,6,10,14,18,22,26,30,34,38,42: SCK <= 1;
                4,8,12,16,20,24,28,32,36,40,44: SCK <= 0;
                default : ; // 缺省不操作
            endcase
            // 生成LOAD信号
            case(da_ref_cnt)
                0: LOAD <= 1;
                46: LOAD <= 0;
                default : ; // 缺省不操作
            endcase
            // 送入串型数据
            case(da_ref_cnt)
                3,4: SDI <= da_sel_cnt[1];
                7,8: SDI <= da_sel_cnt[0];
                11,12: SDI <= da_range;
                15,16: SDI <= da_data[7];
                19,20: SDI <= da_data[6];
                23,24: SDI <= da_data[5];
                27,28: SDI <= da_data[4];
                31,32: SDI <= da_data[3];
                35,36: SDI <= da_data[2];
                39,40: SDI <= da_data[1];
                43,44: SDI <= da_data[0];
                default : SDI <= 1'b1;
            endcase
        end
    end

endmodule