MiZ702学习笔记13——ZYNQ通过AXI-Lite与PL交互
在《MiZ702学习笔记7——尝试自制带总线IP》,我曾提到了AXI4-Lite的简单用法,驱动了下流水灯,只涉及到了写总线。今天,我想利用之前的VGA模块,将AXI4-Lite的读写都应用上。这篇文章主要是思想的介绍,以及AXI4-Lite读的方法。一些细节请先阅读《MiZ702学习笔记7——尝试自制带总线IP》。
具体思路为如下框图所示:
所以这次,我们需要两条AXI4-Lite总线,一条负责给VGA模块提供RGB数据(写),一条读取VGA模块提供的扫描的坐标信息(读)。
点击下图中的加号,就能为我们额外的添加一条AXI4-Lite总线:
因此在我们的IP工程里可以看到两套总线框架:
IP打包好之后是这个样子:
我们将S00这条总线作为写数据用,将S01作为读数据总线。当然一条总线是既可以读也可以写的,但是VGA这个工程决定了读和写必须是同行进行的不可复用。
其他的就和之前讲到一样了,接下来AXI4-Lite的读和写。PL为了和PS通讯,是需要一些逻辑去支持的。而这些逻辑在我们生成AXI4-Lite IP的时候,vivado就帮我们自动生成了。我们要做的部分很少,只需要增改一些内容即可,就如《MiZ702学习笔记7——尝试自制带总线IP》提到的那样。
这个工程中,对于总线的写而言就是给VGA模块送去RGB数据,“写”我们只需要增加自己的逻辑即可:
reg [11:0]rlcd_rgb;
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
rlcd_rgb <= 12'd0;
end
else
begin
rlcd_rgb <= S_AXI_WDATA[11:0];
end
end
assign lcd_rgb = rlcd_rgb;
对于总线的读而言,我们需要将框架进行稍微的改动:
//写总线测试修改!!!!!!!!!
wire[31:0]wlcd_xy;// = {10'd0,lcd_xy};
assign wlcd_xy = {10'd0,lcd_xy};
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
always @(*)
begin
// Address decoding for reading registers
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0 : reg_data_out <= wlcd_xy;//slv_reg0;
2'h1 : reg_data_out <= slv_reg1;
2'h2 : reg_data_out <= slv_reg2;
2'h3 : reg_data_out <= slv_reg3;
default : reg_data_out <= 0;
endcase
end
这里其实,也就改了一个地方,本来是reg_data_out <= slv_reg0;被我改成了reg_data_out <= wlcd_xy;这样就能通过总线读取wlcd_xy的值了。
在回到这张框架图:
到这了,我们的AXI IP已经具备了和ZYNQ以及VGA交互的能力,它就是PS和PL之间的桥梁,现在我们只差一个VGA IP,而这个IP就是个普通IP,没错就是《MiZ702学习笔记12——封装一个普通的VGA IP》讲的那样,我们将程序稍加修改,在进行IP打包,就能得到。
最后,我们分别添加这几个IP,进行连线就完成了硬件的搭建。其实我提一些细节。
我们配置下ZNYQ的输出时钟:
其中FCLK0一般添加zynq核时是默认引出的,这里主要是给AXI4-Lite IP提供时钟,大小我设置是250M,再高就提示出错了。
FCLK1将其设置为25M,主要给VGA IP提供时钟,应为VGA扫描是25M。
硬件平台准备好之后,就可以开始SDK的编程了。首先,我们得根据地址访问到AXI4-Lite IP,通过xparameter.h这个头文件可以得知S00这条总线的地址:
/* Definitions for driver MYVGAIP */
#define XPAR_MYVGAIP_NUM_INSTANCES 1
/* Definitions for peripheral MYVGAIP_0 */
#define XPAR_MYVGAIP_0_DEVICE_ID 0
#define XPAR_MYVGAIP_0_S00_AXI_BASEADDR 0x43C00000
#define XPAR_MYVGAIP_0_S00_AXI_HIGHADDR 0x43C0FFFF
但是头文件并未看到S01这条总线的地址,不过可以猜想,S00总线宽带是32位的,且首地址是0x43C00000,那么如果地址是连续的总线S01的首地址应该就是0x43C1ffff。
通过查看system.hdf可以确定以上推测是正确的:
于是定义如下:
#define RGB_AXI_BASEADDR 0x43C00000
#define LCDXY_AXI_BASEADDR 0x43C10000
首先进行彩条的测试,先通过Xil_In32,这个函数读总线,得到VGA模块输出的坐标值。其中低11位是Y坐标的值,高11位是X坐标的值:
temp = Xil_In32(LCDXY_AXI_BASEADDR);
lcd_ypos = temp & 0x7ff;
lcd_xpos = (temp>>11) & 0x7ff;
就可以测试横向彩条:
//横向彩条
if (lcd_ypos >= 0 && lcd_ypos < (V_DISP/8)*1)
Xil_Out32(RGB_AXI_BASEADDR, RED);
else if(lcd_ypos >= (V_DISP/8)*1 && lcd_ypos < (V_DISP/8)*2)
Xil_Out32(RGB_AXI_BASEADDR, GREEN);
else if(lcd_ypos >= (V_DISP/8)*2 && lcd_ypos < (V_DISP/8)*3)
Xil_Out32(RGB_AXI_BASEADDR, BLUE);
else if(lcd_ypos >= (V_DISP/8)*3 && lcd_ypos < (V_DISP/8)*4)
Xil_Out32(RGB_AXI_BASEADDR, WHITE);
else if(lcd_ypos >= (V_DISP/8)*4 && lcd_ypos < (V_DISP/8)*5)
Xil_Out32(RGB_AXI_BASEADDR, BLACK);
else if(lcd_ypos >= (V_DISP/8)*5 && lcd_ypos < (V_DISP/8)*6)
Xil_Out32(RGB_AXI_BASEADDR, YELLOW);
else if(lcd_ypos >= (V_DISP/8)*6 && lcd_ypos < (V_DISP/8)*7)
Xil_Out32(RGB_AXI_BASEADDR, CYAN);
else if(lcd_ypos >= (V_DISP/8)*7 && lcd_ypos < (V_DISP/8)*8)
Xil_Out32(RGB_AXI_BASEADDR, ROYAL);
结果和想象中一样完美~~~
接下来测试,总线彩条:
//竖向扫描有点问题,
if (lcd_xpos >= 0 && lcd_xpos < (H_DISP/8)*1)
Xil_Out32(RGB_AXI_BASEADDR, RED);
else if(lcd_xpos >= (H_DISP/8)*1 && lcd_xpos < (H_DISP/8)*2)
Xil_Out32(RGB_AXI_BASEADDR, GREEN);
else if(lcd_xpos >= (H_DISP/8)*2 && lcd_xpos < (H_DISP/8)*3)
Xil_Out32(RGB_AXI_BASEADDR, BLUE);
else if(lcd_xpos >= (H_DISP/8)*3 && lcd_xpos < (H_DISP/8)*4)
Xil_Out32(RGB_AXI_BASEADDR, WHITE);
else if(lcd_xpos >= (H_DISP/8)*4 && lcd_xpos < (H_DISP/8)*5)
Xil_Out32(RGB_AXI_BASEADDR, BLACK);
else if(lcd_xpos >= (H_DISP/8)*5 && lcd_xpos < (H_DISP/8)*6)
Xil_Out32(RGB_AXI_BASEADDR, YELLOW);
else if(lcd_xpos >= (H_DISP/8)*6 && lcd_xpos < (H_DISP/8)*7)
Xil_Out32(RGB_AXI_BASEADDR, CYAN);
else
Xil_Out32(RGB_AXI_BASEADDR, ROYAL);
结果就不想想象中那么完美了:
我们发现彩条的边缘有锯齿,这是为什么呢?原因是横向彩条的扫描依据是lcd_ypos的值,纵向彩条的扫描依据是lcd_xpos。而VGA扫描是水平扫描,这意味着X的更新频率是Y更新频率的N倍。
也就是说AXI4-Lite的读写速度跟上了lcd_ypos的变化,却没能完全跟上lcd_xpos的值。
有的读者可能要发问了,之前给AXI4-Lite IP提供了250M的时钟吗,而VGA扫描才25M,怎么可能速度上跟不上?
这只能说AXI4-Lite本身,并不适合做大量传输数据这件事。AXI4-Lite只适合做一些简单的IO控制,配置寄存器用。
还记得在选择总线类型的时候吗?
我们选择的是Lite,其实还有其他类型可选,如:AXI4,以及AXIStream类型。这些就是我们接下来的任务了。
最近,路飞开4档了,实在太帅了,我最终的目的本来是想将他显示在VGA上的,奈何一开始选错了总线类型,只能将就着看了:
总结:
虽然最终的结果不算成功,但是过程还是能学到不少东西,这里例子可以很好的体现ZYNQ的优势:
1、利用PL部分驱动VGA,充分的发挥FPGA的优势。为PS分担的不小的任务。
2、利用PS完成数据的提供,数据方便存储,且更加多变,正好弥补了FPGA这方面的缺点。
接下来的教程里,就开始探究AXI4以及AXIStream,必将完善次项目,就到这里吧。东莞今天居然下雪了,不说了拿电吹风取暖去了。明天回家了,祝我一路顺风吧~~
工程文件,待会上传~~~
MiZ702学习笔记13——ZYNQ通过AXI-Lite与PL交互的更多相关文章
- MiZ702学习笔记12——封装一个普通的VGA IP
还记得<MiZ702学习笔记(番外篇)--纯PL VGA驱动>这篇文章中,用verilog写了一个VGA驱动.我们今天要介绍的就是将这个工程打包成一个普通的IP,目的是为后面的一篇文章做个 ...
- Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法
Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法 这篇笔记将介绍如何使用Ext.Net GridPanel 中使用Sorter. 默认情况下,Ext.Net GridP ...
- SQL反模式学习笔记13 使用索引
目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引. 索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...
- golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换
golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...
- springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定
springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...
- Python3+Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)'''from sel ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
- python 学习笔记 13 -- 经常使用的时间模块之time
Python 没有包括相应日期和时间的内置类型.只是提供了3个相应的模块,能够採用多种表示管理日期和时间值: * time 模块由底层C库提供与时间相关的函数.它包括一些函数用于获取时钟时间和处 ...
- 【干货】Html与CSS入门学习笔记1-3
从23号开始用了4天时间看完了<Head First Html与CSS>这本书,本书讲解方式深入浅出,便于理解,结合习题,便于记忆,是一本不错的入门书.下面是本书的学习笔记: 一.认识HT ...
随机推荐
- Android应用集成支付宝接口的简化
拿到支付宝接口的andriod demo后有点无语,集成一个支付服务而已,要在十几个java类之间引用来引用去,这样不仅容易导致应用本身代码结构的复杂化,调试起来也很累,于是操刀改造之: 该删的删,该 ...
- Cocos2dx 3.0 过渡篇(二十九)globalZOrder()与localZOrder()
前天非常难得的加班到八点...为什么说难得呢?由于平时我差点儿就没加班过.六点下班后想走就走,想留就留.率直洒脱.不拘一格.尽显男儿本色.程序猿,就是这么自信! -----------这篇博客的标题本 ...
- A*算法解决八数码问题 Java语言实现
0X00 定义 首先要明确一下什么是A*算法和八数码问题? A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法也是一种启发性的算法,也是解决许多搜索问题的有效算法.算法中的距离估 ...
- .net中的多线程
一.多线程的概念 什么是进程呢?当一个程序开始运行时,它就是一个进程,进程所指包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的,线程是程序中的一个执行流, ...
- IOS 应用 退出的一个小方法
AppDelegate * app=(AppDelegate *)[[UIApplication sharedApplication]delegate]; UIWindow *window = app ...
- 【AsyncTask整理 2】 AsyncTask方法代码演示
Android SDK为我们提供了一个后台任务的处理工具AsyncTask.AsyncTask就是一个封装过的后台任务类顾名思义就是异步任务,方便我们维护,Android开发网提示这样的好处可以解决一 ...
- 【开源项目5】测滑菜单MenuDrawer的使用以及解析
在安卓中左右侧滑菜单的使用用的比ios多得多,可能是谷歌带的头吧,几乎所有的谷歌应用都有侧滑菜单.谷歌没有开放这个源码,在一个成熟的开源代码出现之前,大家都是各自为战,偶尔能看到一个勉强实现了的.Me ...
- cocoapods 卸载,重装,高版本的使用
今天清理下电脑,发现自己电脑上的cocoapods经常出现的一个问题就是一些经常用的第三方库cocoapods搜不到,比如SDWebImage,然后就鼓捣了一下 $pos list 命令发现M 以后的 ...
- android 中对于采用okhttp时获取cookie并放入webview实现跳过登陆显示页面的功能
最近项目需要将网页的一些信息展示到app当中,由于采用的是okhttp进行网络的访问,并采用了cookie对于每次的访问请求都做了验证,所以在加入webview显示网页的时候会需要进行一下验证,为了跳 ...
- OC之protocol监听器的实现
画图 图解 代码 总结 一.画图 本人画了一个图(字体和画图水平请忽略) 二.图解 1.首先我们上边是一个按钮的类,按钮当中包括了一条线,这个线是什么呢? 其实难理解就难理解到这条线上了 1⃣️这条线 ...