# [Unet] CDMA details ## CDMA vs DMA ### 1. 為何要使用CDMA或是DMA ? #### Answers: CDMA和DMA是為了處理CPU掛載的AXI接口內存內部的數據傳輸。 那為何不要直接使用CPU內部的AXI,而要再透過一個CDMA或是DMA? 因為若是想要使用CPU端的DDR的話就必須使用CDMA來操作,最主要使因為ZYNQ並沒有AXI Master的接口,只有Slave (S_AXI_HP0)。 ![](https://hackmd.io/_uploads/r1loGFfgT.png) 圖1-1.DMA和CDMA的用處 ![](https://hackmd.io/_uploads/H175-Fflp.png) 圖1-2.AXI CDMA接口與參數設置。 **S_AXI_LITE連接到ZYNQ,M_AXI連接到BRAM controller,SG不太會使用到所以通常不接,類似下圖。** ![](https://hackmd.io/_uploads/rkvaXtGga.png) 圖1-3. CPU與CDMA的接法 **為何不會使用到SG port?** SG全名為Scatter Gather(分散收集)。 在DMA傳輸數據的過程中,要求source physical address和target physical address要是連續的,但是在某些系統中,例如IA architecture,連續的Memory address在physical addrss不一定會是連續的,所以導致DMA要分成很多次傳輸才能完成。SG port即是將目標地址全部收集起來再一次做傳輸,這樣效率比較高。 ### 2. DMA和CDMA之間的差別 ? #### Answer: DMA : ![](https://hackmd.io/_uploads/BkuAYEUWp.png) CDMA : 從BRAM到DDR的資料傳輸 ### 3. Address editor ![image](https://hackmd.io/_uploads/HkObE-1E6.png) ![image](https://hackmd.io/_uploads/Hy2HNbk4T.png) ### 4. Block Diagram ![image](https://hackmd.io/_uploads/rJnxLqKrp.png) Pink is BRAM8~15 to AXI_interconnect Light blue to CPU's S_AXI_HP3 Red to CDMA ![image](https://hackmd.io/_uploads/H1fDHWyVa.png) Light blue is BRAM0~7 to AXI_interconnect Deep Green is to CPU ### 5. SDK ![image](https://hackmd.io/_uploads/HJWnt5tBp.png) ![image](https://hackmd.io/_uploads/ryh6DqYBp.png) #### C code 詳細內容 : :::spoiler ```clike= //#include <stdio.h> //#include "platform.h" #include "xil_printf.h" #include "xparameters.h" #include "xaxicdma.h" #include "xil_cache.h" #include "xil_io.h" #define PL_BRAM_Addr 0xC0000000 #define PL_BRAM_Addr2 0xC2000000 #define BUFF_LEN 3136 //28*28*4 XAxiCdma_Config *axi_cdma_cfg; XAxiCdma axi_cdma; static int SourceAddr = 0x11000000; static int DestAddr = 0x12000000; static int DestAddr2 = 0x12000070; int main() { // init_platform(); print("Initial start......\n\r"); int Status; int *SrcPtr; int *DestPtr; SrcPtr = (int*)SourceAddr; DestPtr = (int*)DestAddr; //u32 *rx_buffer = (u32 *) PS_OCM_Addr; //u32 *tx_buffer = (u32 *) PL_BRAM_Addr; // static int Array_0[28][28]; //static int Array_1[28][28]; int i,j; for (i=0;i<28;i++){ for (j=0;j<28;j++){ Array_0[i][j] = (i*28+j); //Array_1[i][j] = 0; } } for (i=0;i<28;i++){ for (j=0;j<28;j++){ SrcPtr[i*28+j] = Array_0[i][j]; DestPtr[i*28+j] = 0; } } printf("Original SRC_DDR DATA\n\r"); for(i=0;i<28*1;i++){ printf("%d %d at %x\n\r",i,SrcPtr[i],&SrcPtr[i]); } printf("-------------------------------------------------\n\r"); printf("Original DEST_DDR DATA\n\r"); for(i=0;i<28*1;i++){ printf("%d %d at %x\n\r",i,DestPtr[i],&DestPtr[i]); } int *tx_buffer = (int *) SrcPtr; int *rx_buffer = (int *) PL_BRAM_Addr; int *rx_buffer1 = (int *) PL_BRAM_Addr2; u32 *tx_buffer1 = (u32 *) PL_BRAM_Addr; u32 *rx_buffer2 = (u32 *) DestAddr; u32 *tx_buffer2 = (u32 *) PL_BRAM_Addr2; u32 *rx_buffer3 = (u32 *) DestAddr2; // printf("%d %d\n\r",SrcPtr[55],2*28); // for(i=0;i<28;i++){ // printf("%d %d at %d\n\r",i,SrcPtr[i],&SrcPtr[i]); // } // Set up the AXI CDMA printf("--Set up the AXI CDMA from DDR to BRAM0\n\r"); axi_cdma_cfg = XAxiCdma_LookupConfig(XPAR_AXICDMA_0_DEVICE_ID); if (!axi_cdma_cfg) { printf("AXAxiCdma_LookupConfig failed\n\r"); } Status = XAxiCdma_CfgInitialize(&axi_cdma, axi_cdma_cfg, axi_cdma_cfg->BaseAddress); if (Status == XST_SUCCESS ){ printf("XAxiCdma_CfgInitialize succeed\n\r"); } printf("--Disable Interrupt of AXI CDMA\n\r"); XAxiCdma_IntrDisable(&axi_cdma, XAXICDMA_XR_IRQ_ALL_MASK); if (XAxiCdma_IsBusy(&axi_cdma)) { printf("AXI CDMA is busy...\n\r"); while (XAxiCdma_IsBusy(&axi_cdma)); } Xil_DCacheFlush(); // printf("%x\n\r", &tx_buffer[0]); // printf("%x\n\r", &rx_buffer[0]); Status = XAxiCdma_SimpleTransfer( &axi_cdma, (u32) tx_buffer, (u32) rx_buffer, BUFF_LEN, NULL, NULL); // printf("%d\n\r",Status); Xil_DCacheFlush(); printf("transaction from DDR to BRAM0 is done\n\r"); // Set up the AXI CDMA for (i=0;i<28;i++){ for (j=0;j<28;j++){ SrcPtr[i*28+j] = 999; } } // for(i=0;i<28;i++){ // printf("%d %d at %x\n\r",i,SrcPtr[i],&SrcPtr[i]); // } printf("--Set up the AXI CDMA from DDR to BRAM1\n\r"); axi_cdma_cfg = XAxiCdma_LookupConfig(XPAR_AXICDMA_0_DEVICE_ID); if (!axi_cdma_cfg) { printf("AXAxiCdma_LookupConfig failed\n\r"); } Status = XAxiCdma_CfgInitialize(&axi_cdma, axi_cdma_cfg, axi_cdma_cfg->BaseAddress); if (Status == XST_SUCCESS ){ printf("XAxiCdma_CfgInitialize succeed\n\r"); } printf("--Disable Interrupt of AXI CDMA\n\r"); XAxiCdma_IntrDisable(&axi_cdma, XAXICDMA_XR_IRQ_ALL_MASK); if (XAxiCdma_IsBusy(&axi_cdma)) { printf("AXI CDMA is busy...\n\r"); while (XAxiCdma_IsBusy(&axi_cdma)); } Xil_DCacheFlush(); // printf("%x\n\r", &tx_buffer[0]); // printf("%x\n\r", &rx_buffer1[0]); Status = XAxiCdma_SimpleTransfer( &axi_cdma, (u32) tx_buffer, (u32) rx_buffer1, BUFF_LEN, NULL, NULL); // printf("%d\n\r",Status); Xil_DCacheFlush(); printf("transaction from DDR to BRAM1 is done\n\r"); // Set up the AXI CDMA printf("--Set up the AXI CDMA from BRAM0 to DDR\n\r"); axi_cdma_cfg = XAxiCdma_LookupConfig(XPAR_AXICDMA_0_DEVICE_ID); if (!axi_cdma_cfg) { printf("AXAxiCdma_LookupConfig failed\n\r"); } Status = XAxiCdma_CfgInitialize(&axi_cdma, axi_cdma_cfg, axi_cdma_cfg->BaseAddress); if (Status == XST_SUCCESS ){ printf("XAxiCdma_CfgInitialize succeed\n\r"); } printf("--Disable Interrupt of AXI CDMA\n\r"); XAxiCdma_IntrDisable(&axi_cdma, XAXICDMA_XR_IRQ_ALL_MASK); if (XAxiCdma_IsBusy(&axi_cdma)) { printf("AXI CDMA is busy...\n\r"); while (XAxiCdma_IsBusy(&axi_cdma)); } Xil_DCacheFlush(); // printf("%x\n\r", &tx_buffer1[0]); // printf("%x\n\r", &rx_buffer2[0]); Status = XAxiCdma_SimpleTransfer( &axi_cdma, (u32) tx_buffer1, (u32) rx_buffer2, BUFF_LEN/28, NULL, NULL); // printf("%d\n\r",Status); Xil_DCacheFlush(); printf("transaction from BRAM0 to DDR is done\n\r"); // Set up the AXI CDMA printf("--Set up the AXI CDMA from BRAM1 to DDR\n\r"); axi_cdma_cfg = XAxiCdma_LookupConfig(XPAR_AXICDMA_0_DEVICE_ID); if (!axi_cdma_cfg) { printf("AXAxiCdma_LookupConfig failed\n\r"); } Status = XAxiCdma_CfgInitialize(&axi_cdma, axi_cdma_cfg, axi_cdma_cfg->BaseAddress); if (Status == XST_SUCCESS ){ printf("XAxiCdma_CfgInitialize succeed\n\r"); } printf("--Disable Interrupt of AXI CDMA\n\r"); XAxiCdma_IntrDisable(&axi_cdma, XAXICDMA_XR_IRQ_ALL_MASK); if (XAxiCdma_IsBusy(&axi_cdma)) { printf("AXI CDMA is busy...\n\r"); while (XAxiCdma_IsBusy(&axi_cdma)); } Xil_DCacheFlush(); // printf("%x\n\r", &tx_buffer2[0]); // printf("%x\n\r", &rx_buffer3[0]); Status = XAxiCdma_SimpleTransfer( &axi_cdma, (u32) tx_buffer2, (u32) rx_buffer3, BUFF_LEN/28, NULL, NULL); // printf("%d\n\r",Status); Xil_DCacheFlush(); printf("transaction from BRAM1 to DDR is done\n\r"); for(i=0;i<28*2;i++){ if (i == 0){ printf("Data transfer from BRAM0 to DEST_DDR[0]~[27]\n\r"); printf("Data should be 0~27 :\n\r"); } if (i == 28){ printf("Data transfer from BRAM1 to DEST_DDR[28]~[55]\n\r"); printf("Data should be 999 :\n\r"); } printf("%d %d at %x\n\r",i,rx_buffer2[i],&rx_buffer2[i]); } //cleanup_platform(); return 0; } ``` ::: ### 連結: 圖1-2 : https://www.cnblogs.com/xingce/p/16386108.html 圖1-3 : https://blog.csdn.net/qq_23379273/article/details/102672567 M_AXI_SG : https://blog.csdn.net/baidu_37503452/article/details/79023026 DMA vs CDMA : https://xilinx.eetrend.com/blog/2020/100052890.html PYNQ 實作 : https://docs.google.com/document/d/189Y34sIyZ-syknVFp6eB79JaQ1Rmj49x-aGoY_IsBrM/edit?usp=sharing SmartConnnect and Interconnect : https://blog.csdn.net/shinn476391300/article/details/102605801 CDMA與DMA詳細比較 : https://xilinx.eetrend.com/blog/2020/100052890.html https://xilinx.eetrend.com/blog/2021/100554297.html