Vivado与Matlab联合生成.coe文件使用ROM生成正弦波及滤波输出例程 && 用ROM生成正弦波仿真看不是标准波形bug解决

本文介绍两个问题

1.如何使用matlab生成正弦波的.coe文件并在Vivado中使用ROM例化输出正弦波,设计滤波器对正弦波滤波。

2.ROM生成的正弦波波形是乱的,不平滑问题的解决。

使用matlab生成正弦波.coe文件

depth = 4096; %存储器的单元数4096

widths = 16; %数据宽度为16位

fidc = fopen('sine.coe','wt'); %给文件起名字

fprintf(fidc , 'memory_initialization_radix=%d;\nmemory_initialization_vector=\n',10);

for x = 1 : depth-1

fprintf(fidc,'%d,\n',round((2^(widths-1)-1)*sin(2*pi*(x-1)/4096)+2^(widths-1)));

end % 加上直流分量2^(widths-1) 保证值为正范围为(1,2^16-1)

fprintf(fidc,'%d;\n',round((2^(widths-1)-1)*sin(2*pi*(depth-1)/4096)+2^(widths-1)));

fclose(fidc);

 设置存储器也就是Vivado中的ROM核的深度为4096,数据位宽为16,使用fidc作为文件标识符打开或新建一个名为sine.coe的文件并准备写入,设置数据进制为10,依次向fidc文件写入正弦波的值。给正选波加上直流分量2^(widths-1)是为了保证输出值是正数,并且范围为(1,2^16-1)。最最后使用fclose(fidc)来关闭文件,以确保数据正确保存并释放系统资源。

保存运行后,会在跟此matlab脚本文件同一文件夹内生成.coe文件

然后在Vivado中单击IP Catalog搜索Rom 双击Distributed Memory Generator

Distributed Memory Generator 适用与数据量较少的情况,如果数据量较大深度较大推荐使用下面的Block Memory Genertor。

如下图所示 配置ROM 深度为4096,数据宽度为16

输入输出都选择寄存

如下图所示,点击按钮选中使用matlabn生成的那个.coe文件

进制设为10进制,点击OK

接下来创建一个design source文件

代码如下

`timescale 1ns / 1ps

module rom(
    input clk,  //100M
    input rst,
    output [15:0] data_3M,
    output [15:0] data_19M
    

    );

parameter fre_word1 = 12'd122;// fre_word = f_out * 2^N / fclk   N为累加器位宽
                                    //N 为地址的位宽  实际122.8,不四舍五入
parameter fre_word2 = 12'd778;

reg [11:0] addr_sin_3m;
reg [11:0] addr_sin_19m;

//相位累加器
always @(posedge clk or rst)
begin
    if(!rst)begin
        addr_sin_3m <= 12'd0;
        addr_sin_19m <= 12'd0;
    end
    else begin
        addr_sin_3m <= addr_sin_3m + fre_word1;
        addr_sin_19m <= addr_sin_19m + fre_word2;
    end
end
    
wire [11:0] addra1 = addr_sin_3m[11:0];
wire [11:0] addra2 = addr_sin_19m[11:0];
 
 
    
dist_mem_gen_0 Rom_3M (
.a(addra1),
.clk(clk),
.qspo(data_3M)
);

dist_mem_gen_0 Rom_19M (
.a(addra2),
.clk(clk),
.qspo(data_19M)
);  

  
    
endmodule

代码中将上面我们创建的ROM IP核例化了两次分别命名为Rom_3M和Rom_19m

需要注意的是频率步进字fre_word = f_out * 2^N / fclk 的计算,其中fout代表想要输出的频率,例如我这里想输出3M那么fout = 3*10^6,fclk是代码中使用的时钟,我的时钟是100M,那么fclk = 100*10^6,N代表累加器的位宽,在这里就是ROM的地址端口的位宽如下图为12位,那么要输出3M频率的正弦波,我的频率步进字fre_word = 3*10^6 * 2^12/ 100*10^6 = 122.88,取122。输出19M同理。

接下来创建一个simulation sources文件

代码如下

`timescale 1ns / 1ps

module rom_sim();

reg clk;
reg rst;
wire [15:0] data_3M;
wire [15:0] data_19M;
wire [39:0] wave_out;  //要看 IP端口的位数,而不是Summary中的 Output Width
reg [16:0] wave_sum;   //3M正弦波和19M正弦波相加
wire [16:0] wave_inn;  //将3M和19M的合除以4
wire [15:0] wave_in;   //将wave_inn的结果截取16位,符合fir滤波器ip核的input width
wire s_axis_data_tready;
wire m_axis_data_tvalid;


always #5 clk = ~clk;

always@ (posedge clk or rst)begin
    if(!rst)
        wave_sum = 17'd0;
    else begin
        wave_sum = data_3M + data_19M;
    end
end
 
assign    wave_inn =  wave_sum>>2;  //除以四
assign    wave_in = wave_inn[15:0];

initial begin
    clk = 1'b0;
    rst = 1'b0;
    #1 rst = 1'b1;
end

rom rom_inst(
    .clk(clk),
    .rst(rst),
    .data_3M(data_3M),
    .data_19M(data_19M)
);

fir_compiler_0 fir (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(1'b1),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),  // output wire s_axis_data_tready
  .s_axis_data_tdata(wave_in),    // input wire [15 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(wave_out)    // output wire [39 : 0] m_axis_data_tdata
);



endmodule

如图测试代码中例化了一个FIR滤波器,这个滤波器的.coe文件由matlab滤波器产生,测试代码中"wave_inn =  wave_sum>>2; " 3m和19m合路信号为什么相加后要除以4下面来解释。

下面介绍使用matlab生成FIR滤波器系数文件

 首先打开matlab,如图所示点击APP - 显示更多

下拉找到如图所示滤波器设计工具,别的matlab版本也叫Fliter Designer

按照下图所示配置FIR模式设为最小二乘法,Fs采样时钟设为100Mhz,这个要跟Vivado中的时钟设为一致,通带频率Fpass设为8M,即允许8Mhz以下的信号通过,截止频率Fstop设为15Mhz

如下图点击左侧按钮,设置滤波器算法为定点,分子字长设为16位,即为输入数据宽度

点击输入/输出,可以看到滤波器的输入范围为(-1,1),超出这个范围会出错。因此在我们输入数据位宽为16位的情况下,输入应该是(-2^16 +1,2^16 - 1),并且输入时是带符号数,即最高位是符号位,在matlab中我们的正弦波值为加上直流分量的值round((2^(widths-1)-1)*sin(2*pi*(x-1)/4096)+2^(widths-1)));值的范围是(1,2^16 -1),这个值代表无符号数的值,要除以2将最高位的符号位空出来才能表示有符号数,否则会出错,因此单路rom出来的正弦波要除以2才能送入滤波器,那么两路rom出来的正弦波加一块要除以4才能送入滤波器。

点击应用后,点击目标生成XILINX系数指定文件名生成.coe文件

接下来在Vivado中找到fir滤波器ip核

双击配置fir ip核,点击下图所示按钮将刚才生成的滤波器.coe文件导入

将采样频率和时钟频率都设为100m

输入宽度设为16位,数据类型为signed

最终配置结果如下所示

点击OK,ip核即配置完成

回到我们的sim文件,点击Run Simlaution

打开ModelSim文件,如下图所示设置波形为进制为Decimal,模拟波形

发现data_3m和data_19m的波形不太对,原因是因为他们没有除以2之前还代表无符号数,因此将他们和wave_sum的数据类型改成unsigned后波形正常,而wave_out和wave_in本来就是有符号数因此波形表示正常,如图所示,3M和19M信号进入滤波器后成功将高频信号滤除,留下3M的信号。

  • 33
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值