zedboard如何从PL端控制DDR读写(五)
2018-02-04 11:10
302 查看
有了前面的一堆铺垫。现在终于开始正式准备读写DDR了,开发环境:VIVADO2014.2 + SDK。
一、首先要想在PL端通过AXI去控制DDR,我们必须要有一个AXI master,由于是测试,就不自己写了,直接用package IP生成,方法如下:
1.选择package IP工具
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170233388-393194464.png)
2.创建新的AXI外设
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170348201-337035582.png)
3.接口类型选择Full,模式选择master,如果你不关心里面的详细实现过程,那么直接finish就好了。(后面我们会继续分析里面的过程)
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170453154-1063647221.png)
二、创建好了IP,自然要加入到IP库里,如图,在IP Catalog空白处右键,设置,把刚刚生成IP的路径放进去:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170955826-1562562212.png)
三、接下来创建BD块,把整个硬件系统搭建好:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171148326-34631202.png)
需要指出的是,由于我们需要用到HP,所以在zynq的配置里面把HP勾选上,任选一个通道就行
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171340779-1956811265.png)
四、然后校验正确性,产生输出文件,创建BD块顶层,这都是套路,一路走下来就行。如果你想在调试里看到产生的AXI信号,那么需要对AXI标记一下debug
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171706966-109829999.png)
五、综合,set up debug,然后生成比特流,并将其导入到SDK;在SDK里跑个hello world 就行,主要目的是用CPU去把DDR控制器初始化。
到这里整个过程基本就结束了,接下来看仿真波形:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720172430904-15741397.png)
放大一点,可以看到每次地址的步进长度是十进制的64,这是因为我们的突发长度设置的是16,位宽为32bit。
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720173054326-1098756974.png)
但是问题来了,我们在上一节里面说过,有一部分地址是连到了OCM的,那么这一部分地址是多少呢?UG585里给出了如下说明:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720174245482-983235499.png)
我们是从全0地址开始写数据的,然而全0的地址刚好分配到了OCM,这TM就很尴尬了。一开始想让程序运行的时间长一点,这样地址是不是就可以跑到0x0008_0000了?然而并没有什么用,因为地址只跑到00001000就停止了,如图:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720174828982-1377775574.png)
还记得前面打包AXI IP时候我们说过要分析其过程吗?其实那里就已经挖了一个坑了,具体见代码:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175249982-1990559804.png)
这是AXI的写数据状态机,(可以看到,官方也是用一段式状态机来实现整个时序的,印证了前面三段式状态机不好实现的说法),从写状态到读状态的跳变是由writes_done信号来控制的,那么这个writes_done又是怎么产生的呢?继续看代码:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175550388-519525330.png)
writes_done是由write_burst_counter的高位进位来控制的,再继续找write_burst_counter:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175704685-1156076218.png)
在这个计数器里有一个很关键的位C_NO_BURSTS_REQ ,在代码的低179行,它的定义如下:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175951201-1417627011.png)
本文转自:http://www.cnblogs.com/christsong/p/5689283.html
一、首先要想在PL端通过AXI去控制DDR,我们必须要有一个AXI master,由于是测试,就不自己写了,直接用package IP生成,方法如下:
1.选择package IP工具
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170233388-393194464.png)
2.创建新的AXI外设
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170348201-337035582.png)
3.接口类型选择Full,模式选择master,如果你不关心里面的详细实现过程,那么直接finish就好了。(后面我们会继续分析里面的过程)
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170453154-1063647221.png)
二、创建好了IP,自然要加入到IP库里,如图,在IP Catalog空白处右键,设置,把刚刚生成IP的路径放进去:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720170955826-1562562212.png)
三、接下来创建BD块,把整个硬件系统搭建好:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171148326-34631202.png)
需要指出的是,由于我们需要用到HP,所以在zynq的配置里面把HP勾选上,任选一个通道就行
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171340779-1956811265.png)
四、然后校验正确性,产生输出文件,创建BD块顶层,这都是套路,一路走下来就行。如果你想在调试里看到产生的AXI信号,那么需要对AXI标记一下debug
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720171706966-109829999.png)
五、综合,set up debug,然后生成比特流,并将其导入到SDK;在SDK里跑个hello world 就行,主要目的是用CPU去把DDR控制器初始化。
到这里整个过程基本就结束了,接下来看仿真波形:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720172430904-15741397.png)
放大一点,可以看到每次地址的步进长度是十进制的64,这是因为我们的突发长度设置的是16,位宽为32bit。
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720173054326-1098756974.png)
但是问题来了,我们在上一节里面说过,有一部分地址是连到了OCM的,那么这一部分地址是多少呢?UG585里给出了如下说明:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720174245482-983235499.png)
我们是从全0地址开始写数据的,然而全0的地址刚好分配到了OCM,这TM就很尴尬了。一开始想让程序运行的时间长一点,这样地址是不是就可以跑到0x0008_0000了?然而并没有什么用,因为地址只跑到00001000就停止了,如图:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720174828982-1377775574.png)
还记得前面打包AXI IP时候我们说过要分析其过程吗?其实那里就已经挖了一个坑了,具体见代码:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175249982-1990559804.png)
这是AXI的写数据状态机,(可以看到,官方也是用一段式状态机来实现整个时序的,印证了前面三段式状态机不好实现的说法),从写状态到读状态的跳变是由writes_done信号来控制的,那么这个writes_done又是怎么产生的呢?继续看代码:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175550388-519525330.png)
writes_done是由write_burst_counter的高位进位来控制的,再继续找write_burst_counter:
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175704685-1156076218.png)
在这个计数器里有一个很关键的位C_NO_BURSTS_REQ ,在代码的低179行,它的定义如下:
localparam integer C_NO_BURSTS_REQ = C_MASTER_LENGTH-clogb2((C_M_AXI_BURST_LEN*C_M_AXI_DATA_WIDTH/8)-1);
![](https://images2015.cnblogs.com/blog/957523/201607/957523-20160720175951201-1417627011.png)
C_M_AXI_BURST_LEN我们设置的是16,C_M_AXI_DATA_WIDTH是32,clogb2可以理解为计算以2为底的某个数的对数,那么最后得到的C_NO_BURSTS_REQ = 6;也就是说write_burst_counter的位宽是7为,当最高位为1时,写数据停止。也就是只会发生64次写数据,之后计数器和写地址就会归零。那么64次写数据乘以每次突发长度16再乘以位宽4个字节,最后得到的数值是4096,换算成16进制刚好是0x00001000。 所以要想真正的往DDR里面写数据,我们还需要对代码进行修改。到这里离成功就已经不远了
本文转自:http://www.cnblogs.com/christsong/p/5689283.html
相关文章推荐
- zedboard如何从PL端控制DDR读写(三)——AXI-FULL总线调试
- zedboard如何从PL端控制DDR读写(四)
- zedboard如何从PL端控制DDR读写(六)
- zedboard如何从PL端控制DDR读写(七)
- Zedboard 如何从PL端控制DDR3(二)--AXI4总线
- 采用FPGA IP实现DDR的读写控制的设计与验证
- Zedboard & Zynq 图像采集 视频开发 (三) AXI4总线读写DDR
- 如何对读写的网格部件字段进行只读控制
- 如何对读写的网格部件字段进行只读控制
- 软件项目如何控制需求蔓延(下)---老吴说产品
- winform 如何控制输入法
- 在sendmail里如何控制邮箱大小
- 如何更好地控制input输入框的高度(1)[
- latex 表格如何精细控制行高,行距,行与行之间的距离
- OpenStack Horizon: Controlling the Cloud Using Django (如何使用Django控制Openstack Horizon)
- 当不可信小应用程序或应用程序在 Web 浏览器中运行时,我应当如何控制?
- 如何控制Yahoo! Slurp蜘蛛的抓取频度
- 如何更好的控制apache的内存
- 如何使DB2控制中心的字体好看些
- Dalvik——如何控制vm