matlab处理数据并显示图形的能力很强,调试的时候会将FPGA的数据通过ILA抓取数据并存成csv的格式,然后在通过matlab进行读取并处理,最终做出图形,这里就多了很多手动控制的环节,如果大部分内容不变,可以做成一套完整的自动化控制程序,就减少了手动操作的麻烦。
依然是参考某呼上的文章:
matlab调用vivado tcl脚本——数据采集卡验证方法V1.0
然后一步一步自己探索着做。
matlab通过jtag2axi 这个IP控制LED的部分可以翻看我前边的文章。接下来要做的是如果控制数据存储。选择的方案是使用IPI图形设计界面,使用AXI Bram Controller控制Bram的读写,写数据通道使用dds产生波形数据,然后通过自己写的AXI主控模块,将dds产生的波形数据存储到bram里边,然后matlab通过jtag2axi IP读取存储的数据,bram何时存储通过matlab控制jtag2axi 控制gpio给出一个控制信号。
如下图:

模块1控制模块2生产存储数据的命令:led[0]一个上升沿开启数据存储。
控住模块4收到模块2的输出端口led[0]的上升沿,开始256个数据的存储(为啥是256个,因为AXI4 FULL的INCR模式,每次最大长度是256个)。
模块3根据模块4的指令,将模块4的数据存储到BRAM里。
然后matlab通过模块1控制模块3将数据读取,并读取的数据写入data.txt文件。
matlab通过读取data.txt文件,并显示数据的时域波形和频谱图。
matlab的控制,作图使用app designer 进行设计,图示如下:

左上角的按钮执行指令:
system('vivado -mode batch -source {t1.tcl}');
t1.tcl的代码如下:
#硬件相关
open_hw_manager
connect_hw_server
open_hw_target
current_hw_device [get_hw_devices xc7a35t_0]
refresh_hw_device [lindex [get_hw_devices xc7a35t_0] 0]
#执行读写任务
#1.使用前必须reset
reset_hw_axi [get_hw_axis hw_axi_1]
#2.先创建事务
create_hw_axi_txn wr_txn [get_hw_axis hw_axi_1] -address 40000000 -data {00000003} -len 1 -type write
#3.再执行事务
run_hw_axi [get_hw_axi_txns wr_txn]
#4.执行完事务需要删除事务,事务名删除之前不可重复
delete_hw_axi_txn [get_hw_axi_txns wr_txn ]
#LED :2'b00:
create_hw_axi_txn wr_txn [get_hw_axis hw_axi_1] -address 40000000 -data {00000000} -len 1 -type write
run_hw_axi [get_hw_axi_txns wr_txn]
delete_hw_axi_txn [get_hw_axi_txns wr_txn ]
#读取文件:
create_hw_axi_txn -force rd_txn [get_hw_axis hw_axi_1] -address c0000000 -len 256 -type read
run_hw_axi rd_txn
set data [report_hw_axi_txn rd_txn]
#将文件写入txt:
set fid [open "data.txt" w]
for {set i 1} {$i<[expr 256*3/2]} {incr i} {
if {[expr $i%3]!=0} {
puts $fid [lindex $data $i]
}
}
close $fid
delete_hw_axi_txn [get_hw_axi_txns rd_txn ]
#LED :2'b01:文件写入txt完毕点亮第二个LED
create_hw_axi_txn wr_txn [get_hw_axis hw_axi_1] -address 40000000 -data {00000002} -len 1 -type write
run_hw_axi [get_hw_axi_txns wr_txn]
delete_hw_axi_txn [get_hw_axi_txns wr_txn ]
#硬件相关
close_hw_manager
tcl中的相关指令网上搜索有很多教程的,这里不赘述,仅提一下踩到的坑:
for命令后边的{}这种大括号,相邻的大括号之间需要加空格!空格!空格!
数据是256个,为什么tcl里长度是256*3/2,因为tcl读出的数据格式如下:
地址i 数据1 数据2
地址i+1 数据1 数据2
...
所以整体读出的数据会多处一半的地址,所以这里len+len/2=len*3/2个index。
app右上角的按钮执行的是读取数据,数据截取,数据hex2dec,2的补码向整形数据转换,做FFT,并画图,代码如下:
fid = fopen('data.txt','r');
C = textscan(fid,'%s'); fclose all; s_data = [C{1}]; % data_len=256; s_data_5to8 = strings([1,data_len]); for i=1:data_len s_data_5to8(i)=s_data{i,1}(5:8);%截取5到8位并存入s_data_5to8 end t=hex2dec(s_data_5to8);%二进制转化为十进制 for i=1:data_len if(t(i)>32767) t(i)=t(i)-65536; end end % fs=50; N=data_len; F=fs/2*linspace(0,1,N/2+1); win=hanning(N)'; fft_sig=fft(t.*win); amp = 20*log10((abs(fft_sig))/(N/2)); % plot(app.UIAxes,F,amp(1:N/2+1)); plot(app.UIAxes2,t);
这样就完成了整个过程,最终数据显示如下:

数据没有归一化,数据点数较少,即便加窗函数频谱显示也很差。
项目优点:自动化程度较高,中间无需人工干涉。不同任务可以执行不同的tcl脚本。
项目缺点:限于AXI数据每次burst长度的限制,每次最多存储256个连续的数据,多次AXI burst之间并不能背靠背,导致相邻帧数据并不连续,无法存储多帧连续数据,当然,这可以通过写数据之前加处理代码解决,但是这个增加了系统复杂度,并不符合IPI 模块搭建的理念。
我自己的AXI主控模块4,代码在下一篇里讲述。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删