如何在Xilinx CDMA的设备中进行寻址工作?

时间:2016-08-10 18:27:05

标签: xilinx device-tree zynq

背景

我想要做的是能够从我的ARM处理器写入Zynq 7000上的BRAM。

为此,我有以下组件:

-M_AXI_GP0 on PS7 connects to S_AXI_LITE on axi_cdma_0 through an AXI Interconnect

-cdma_introut on axi_cdma_0 connects to IRQ_F2P on PS7 through sys_concat, input 11. This means that this maps to Interrupt 87 on PS7.

-M_AXI on axi_cdma_0 connects to S00_AXI on axi_mem_intercon

-M01_AXI on axi_mem_intercon connects to S_AXI_HP3 on PS7

-M00_AXI on axi_mem_intercon connects to S_AXI on axi_bram_ctrl_0

-BRAM_PORTA on axi_bram_ctrl_0 connects to BRAM_PORTA on blk_mem_gen0

=============================================== ==========================

在我看来,这个设置应该做的是:

  1. 从ARM DMA引擎提交事务后,Zynq将使用GP0通过GP0向CDMA控制器发送命令。

  2. CDMA控制器将在其从属AXI_LITE端口上接收命令,并通过HP3解释访问RAM的请求。

  3. CDMA控制器将通过axi_mem_intercon移动数据,以便从M01_AXI上的hp3获取交易数据,并通过M00_AXI将其发送到BRAM控制器

  4. BRAM控制器将接收AXI-4输入并将其转换为适当的BRAM端口,以将数据写入blk_mem_gen_0生成的BRAM

  5. 完成此操作后,CDMA将通过sys_concat发送一个中断,向DMA引擎表明其工作已完成。

  6. 将此hdl设计加载到PL结构后,我尝试通过内核模块将事务提交到DMA引擎。结果是超时,DMA引擎显然从未完成任务。

    =============================================== ==========================

    在我试图找出问题时,我已经做了这些观察:

    1. 尝试超时的写入事务后,我尝试了对同一DMA通道的读取事务,但配置为读取数据。我得到的是我试图写的所有数据。对我来说,这似乎表明DMA引擎正在写入某个地方,但是没有认识到任务的完成

    2. 有问题的BRAM是双端口RAM,另一端口读取BRAM中的数据并切换LED以反映数据。当我尝试这个写入事务时,LED没有切换,所以似乎DMA事务没有像BRAM那样进行切换

    3. 在查看cat / proc / interrupts时,我可以看到几个中断,但不能看到GIC 87.如前所述,我使用的中断线进入IRQ concat块的输入11。我可以确认进入输入12的中断线确实对应于来自/ proc / interrupts的GIC 88,所以我相信我对我正在寻找哪个中断的理解是正确的。因此,由于某种原因,它没有在处理器上注册该中断。

    4. =============================================== ==========================

      基于此,我相信我对这个CDMA的设备进入是不正确的。

      在Vivado中,我可以在地址编辑器中看到这些条目(为简洁起见省略了一些条目):

      sys_ps7
          Data(32 address bits:0x40000000 [1G])
              axi_cdma_0                S_AXI_LITE    Reg    0x43C0_0000    64K    0x43C0_FFFF
      
      
      axi_cdma_0
          Data(32 address bits : 4G)
              axi_bram_ctrl_0           S_AXI         Mem0   0xC000_0000    4K    0xC000_0FFF
              sys_ps7                   S_AXI_HP3     HP3... 0x0000_0000    1G    0x3FFF_FFFF
      

      我尝试编写一个devicetree条目如下:

      axi-cdma@43C00000{
          #dma-cells = <0x1>;
          compatible = "tst,axi-cdma-ctrl-1.00.a";
          reg = <0x10000000 0x1000>;
          interrupts = <0x0 0x37 0x4>;
          interrupt-parent = <0x1>;
      
          dma-channel@C0000000{
              buswidth = <0x20>;
          }
      

      在我的内核模块中添加此条目之前,甚至无法注册事务通道,现在确实如此,所以我相当确定内核接受此条目至少足以分配DMA通道。但是,我不太了解devicetree是如何工作的,特别是对于寻址,所以我很有可能错误地写了这个,这就是我的事务没有成功的原因。任何人都可以帮我纠正我的设计吗?     }

1 个答案:

答案 0 :(得分:1)

在设备树中声明IP核是不够的。您还必须声明您的DMA客户端,就像Xilinx在CDMA test client中所做的那样:

 cdmatest_1: cdmatest@1 {
              compatible ="xlnx,axi-cdma-test-1.00.a";
              dmas = <&axi_cdma_0 0>;
              dma-names = "cdma";
 } ;  

dmas字段中,axi_cdma_0引用CDMA IP内核和0其第一个dma频道,如设备目录中所定义:

 axi_cdma_0: dma@4e200000 {
              #dma-cells = <1>;
              clock-names = "s_axi_lite_aclk", "m_axi_aclk";
              clocks = <&clkc 15>, <&clkc 15>;
              compatible = "xlnx,axi-cdma-1.00.a";
              interrupt-parent = <&intc>;
              interrupts = <0 31 4>;
              reg = <0x4e200000 0x10000>;
              xlnx,addrwidth = <0x20>;
              xlnx,include-sg ;
              dma-channel@4e200000 {
                      compatible = "xlnx,axi-cdma-channel";
                      interrupts = <0 31 4>;
                      xlnx,datawidth = <0x20>;
                      xlnx,device-id = <0x0>;
                      xlnx,include-dre ;
                      xlnx,max-burst-len = <0x10>;
              };
 };

之后,您应该将您的客户端注册为平台驱动程序。再次,来自CDMA测试客户端source

static const struct of_device_id xilinx_cdmatest_of_ids[] = {
    { .compatible = "xlnx,axi-cdma-test-1.00.a", },
    { }
 };

 static struct platform_driver xilinx_cdmatest_driver = {
     .driver = {
         .name = "xilinx_cdmatest",
         .owner = THIS_MODULE,
         .of_match_table = xilinx_cdmatest_of_ids,
     },
     .probe = xilinx_cdmatest_probe,
     .remove = xilinx_cdmatest_remove,
 };

 static int __init cdma_init(void)
 {
     return platform_driver_register(&xilinx_cdmatest_driver);
 }

请注意设备树的compatible字段和平台驱动程序定义,这些字符串必须匹配。如果您不这样做,dma_request_slave_channel()无法从您的CDMA IP核保留一个频道。此外,请确保您使用xilinx内核&gt; = 4.0不支持的dma_request_channel()并且无法正确保留频道,传输将无法完成,DMA将超时打断。我不确定观察1,它可能是缓存效果。尝试使用dma_alloc_coherent()代替kmalloc()

PS:在任何情况下,如果可能的话,尽量使用裸机应用程序确保硬件正常。