背景
我想要做的是能够从我的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
=============================================== ==========================
在我看来,这个设置应该做的是:
从ARM DMA引擎提交事务后,Zynq将使用GP0通过GP0向CDMA控制器发送命令。
CDMA控制器将在其从属AXI_LITE端口上接收命令,并通过HP3解释访问RAM的请求。
CDMA控制器将通过axi_mem_intercon移动数据,以便从M01_AXI上的hp3获取交易数据,并通过M00_AXI将其发送到BRAM控制器
BRAM控制器将接收AXI-4输入并将其转换为适当的BRAM端口,以将数据写入blk_mem_gen_0生成的BRAM
完成此操作后,CDMA将通过sys_concat发送一个中断,向DMA引擎表明其工作已完成。
将此hdl设计加载到PL结构后,我尝试通过内核模块将事务提交到DMA引擎。结果是超时,DMA引擎显然从未完成任务。
=============================================== ==========================
在我试图找出问题时,我已经做了这些观察:
尝试超时的写入事务后,我尝试了对同一DMA通道的读取事务,但配置为读取数据。我得到的是我试图写的所有数据。对我来说,这似乎表明DMA引擎正在写入某个地方,但是没有认识到任务的完成
有问题的BRAM是双端口RAM,另一端口读取BRAM中的数据并切换LED以反映数据。当我尝试这个写入事务时,LED没有切换,所以似乎DMA事务没有像BRAM那样进行切换
在查看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
我尝试编写一个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是如何工作的,特别是对于寻址,所以我很有可能错误地写了这个,这就是我的事务没有成功的原因。任何人都可以帮我纠正我的设计吗? }
答案 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:在任何情况下,如果可能的话,尽量使用裸机应用程序确保硬件正常。