2

背景:

我想做的是能够从我的 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 Engine 指示其工作已完成。

将此 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,所以我相信我对我正在寻找的中断的理解是正确的。因此,由于某种原因,它没有在处理器上注册该中断。

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

基于此,我相信我的这个 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

我编写设备树条目的尝试如下:

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 的工作原理,特别是寻址方式,所以我很有可能写错了,这就是我的交易没有成功的原因。谁能帮我纠正我的设计?}

4

1 回答 1

2

在设备树中声明 IP 核是不够的。您还必须声明您的 DMA 客户端,就像赛灵思在 CDMA测试客户端中所做的那样:

 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 测试客户端来源

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 内核中保留频道。此外,请确保不要使用xilinxdma_request_channel()内核 >= 4.0 中不支持的内容,否则将无法正确保留通道,传输将无法完成,并且 DMA 将超时且无中断。我不确定观察 1,它可能是一种缓存效果。尝试使用dma_alloc_coherent()而不是kmalloc().

PS:无论如何,如果可能,请尝试使用裸机应用程序确保您的硬件正常。

于 2017-01-21T15:25:44.300 回答