zedboard如何从PL端控制DDR读写(五)

  有了前面的一堆铺垫。现在终于开始正式准备读写DDR了,开发环境:VIVADO2014.2 + SDK。

  一、首先要想在PL端通过AXI去控制DDR,我们必须要有一个AXI master,由于是测试,就不自己写了,直接用package IP生成,方法如下:

  1.选择package IP工具

  

  2.创建新的AXI外设

  

  3.接口类型选择Full,模式选择master,如果你不关心里面的详细实现过程,那么直接finish就好了。(后面我们会继续分析里面的过程)

  

  

  二、创建好了IP,自然要加入到IP库里,如图,在IP Catalog空白处右键,设置,把刚刚生成IP的路径放进去:

  

  三、接下来创建BD块,把整个硬件系统搭建好:

  

  需要指出的是,由于我们需要用到HP,所以在zynq的配置里面把HP勾选上,任选一个通道就行

  

   四、然后校验正确性,产生输出文件,创建BD块顶层,这都是套路,一路走下来就行。如果你想在调试里看到产生的AXI信号,那么需要对AXI标记一下debug

   

   五、综合,set up debug,然后生成比特流,并将其导入到SDK;在SDK里跑个hello world 就行,主要目的是用CPU去把DDR控制器初始化。

  到这里整个过程基本就结束了,接下来看仿真波形:

  

   放大一点,可以看到每次地址的步进长度是十进制的64,这是因为我们的突发长度设置的是16,位宽为32bit。

   

  但是问题来了,我们在上一节里面说过,有一部分地址是连到了OCM的,那么这一部分地址是多少呢?UG585里给出了如下说明:

  

  我们是从全0地址开始写数据的,然而全0的地址刚好分配到了OCM,这TM就很尴尬了。一开始想让程序运行的时间长一点,这样地址是不是就可以跑到0x0008_0000了?然而并没有什么用,因为地址只跑到00001000就停止了,如图:

  

  还记得前面打包AXI IP时候我们说过要分析其过程吗?其实那里就已经挖了一个坑了,具体见代码:

   

  这是AXI的写数据状态机,(可以看到,官方也是用一段式状态机来实现整个时序的,印证了前面三段式状态机不好实现的说法),从写状态到读状态的跳变是由writes_done信号来控制的,那么这个writes_done又是怎么产生的呢?继续看代码:

  

  writes_done是由write_burst_counter的高位进位来控制的,再继续找write_burst_counter:

  

  在这个计数器里有一个很关键的位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);

  

  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里面写数据,我们还需要对代码进行修改。
  到这里离成功就已经不远了
原文地址:https://www.cnblogs.com/christsong/p/5689283.html