# [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)。

圖1-1.DMA和CDMA的用處

圖1-2.AXI CDMA接口與參數設置。
**S_AXI_LITE連接到ZYNQ,M_AXI連接到BRAM controller,SG不太會使用到所以通常不接,類似下圖。**

圖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 : 
CDMA : 從BRAM到DDR的資料傳輸
### 3. Address editor


### 4. Block Diagram

Pink is BRAM8~15 to AXI_interconnect
Light blue to CPU's S_AXI_HP3
Red to CDMA

Light blue is BRAM0~7 to AXI_interconnect
Deep Green is to CPU
### 5. SDK


#### 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