上文介绍了ZDMA的SG模式下的Linear模式操作,本文将着手于Linked-list和混合模式; Linked-List模式本质属于链表结构,与Linear模式对应的数组结构相对应,可以在不能产生足够多的线性空间下实现DMA操作信息的描述。
SG模式与Simple模式最大区别在于BD,下面介绍在Linked-list模式下的BD描述符:
和Linear模式相比,Linked-List多了对下一个BD的地址描述(NEXT DSCR ADDR),;编程Linked-List模式和Linear模式很类似,需要注意的是BD的CNTL的比特1需要设置为1,并且每一条BD的地址需要是256bit对齐,而Linear模式则需要128位对齐。步骤如下: 1. 写入1到ZDMA_CH_CTRL0的POINT_TYPE位; 2. 根据需要建立合适数量的BD结构体,源端和目的端的BD结构体数量应该相等,依次填入需要搬移的内存的地址、大小和操作行为(CNTL)、下一个BD结构的地址, CNTL的比特1必须设为1; 3. 将第一个源端BD结构体的地址写入ZDMA_CH_SRC_START_LSB、 ZDMA_CH_SRC_START_MSB,第一个目的端BD结构体的地址写入 ZDMA_CH_DST_START_LSB、ZDMA_CH_DST_START_MSB 4. 按需要设置其他寄存器,例如OverFetch,有些情况需要有些不需要; 5. 启动通道DMA传输,通过写入1进ZDMA_CH_CTRL2寄存器; 6. 轮询ZDMA_CH_STATUS,如果为0则可以退出,如果为3表示DMA过程出现错误,需要检查ZDMA_CH_ISR查看出现什么错误,如果出现1,则需要Resume,出现1一般是用户在BD里的CNTL设置了暂停操作,具体操作取决于用户自己,为2就表示DMA仍未完成。 通过Linked-List,同样可以将内存中两块区域的值进行交换,并且只需要执行一次DMA操作,下述代码即实现此功能,需要注意BD所在的地址需要256比特对齐,CNTL的比特1必须为1:
- u64 base_addr = 0xFFFC0000;
- init_platform();
- Xil_DCacheDisable();
-
- XZDma_LlDscr *Src_Des = 0x10000;
- XZDma_LlDscr *Dst_Des = 0x20000;
-
- for(int i=0; i<0x1000; i=i+4)
- {
- Xil_Out32(i+base_addr+0x0100, i);
- Xil_Out32(i+base_addr+0x2100, i+0x2100);
- }
-
- Src_Des[0].Size = 0x1000;
- Src_Des[0].Cntl = 2;
- Src_Des[0].Address = base_addr+0x0100;
- Src_Des[0].NextDscr = &Src_Des[1];
-
- Src_Des[1].Address = base_addr+0x2100;
- Src_Des[1].Size = 0x1000;
- Src_Des[1].Cntl = 2;
- Src_Des[1].NextDscr = &Src_Des[2];
-
- Src_Des[2].Address = base_addr+0x1100;
- Src_Des[2].Size = 0x1000;
- Src_Des[2].Cntl = 0x12;
-
- Dst_Des[0].Address = base_addr+0x1100;
- Dst_Des[0].Size = 0x1000;
- Dst_Des[0].Cntl = 2;
- Dst_Des[0].NextDscr = &Dst_Des[1];
-
- Dst_Des[1].Address = base_addr+0x0100;
- Dst_Des[1].Size = 0x1000;
- Dst_Des[1].Cntl = 2;
- Dst_Des[1].NextDscr = &Dst_Des[2];
-
- Dst_Des[2].Address = base_addr+0x2100;
- Dst_Des[2].Size = 0x1000;
- Dst_Des[2].Cntl = 0x12;
-
- if((Xil_In32(ZDMA_ADDR+ZDMA_CH_CTRL0)&0x40)!=0x40)
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL0, (Xil_In32(ZDMA_ADDR+ZDMA_CH_CTRL0)&0x7f)|0x40);
- //Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL1, 0);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_SRC_START_LSB, ((UINTPTR)(&Src_Des[0]))&0xFFFFFFFF);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_SRC_START_MSB, (((u64)Src_Des)>>32)&0xFFF);
-
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_DST_START_LSB, ((UINTPTR)(&Dst_Des[0]))&0xFFFFFFFF);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_DST_START_MSB, (((u64)Dst_Des)>>32)&0xFFF);
-
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL2, 1);
-
- while(Xil_In32(ZDMA_ADDR+ZDMA_CH_STATUS)==2);
-
- xil_printf("Done Status: %dnr", Xil_In32(ZDMA_ADDR+ZDMA_CH_STATUS));
- for(int i=0; i<0x1000; i=i+4)
- {
- if(Xil_In32(i+base_addr+0x0100)!=i+0x2100)
- {
- xil_printf("Error: %x in %xnr", i, Xil_In32(i+0x100));
- }
- if(Xil_In32(i+base_addr+0x2100)!=i)
- {
- xil_printf("Error: %x in %xnr", i, Xil_In32(i+0x2100));
- }
- }
复制代码
结果:
结果可以看出,两片内存空间值被交换。 Linear模式的一个BD只需要256bit描述一次DMA过程,而Linked-List模式需要512bit来描述,但Linear模式受限于内存最大连续空间的大小,而Linked-List没有这个限制,根据这些,可以结合Linear和Linked-List,使用混合模式(Hybrid)。下面使用Hybrid模式交换两篇内存空间的内容,第一个BD使用Linked-List描述,后面的使用Linear描述;代码如下:
- u64 base_addr = 0xFFFC0000;
- init_platform();
- Xil_DCacheDisable();
- print("Hello Worldnr");
-
- XZDma_LlDscr *Src_Des = 0x10000;
- XZDma_LiDscr *Src1_Des = 0x40000;
- XZDma_LlDscr *Dst_Des = 0x20000;
- XZDma_LiDscr *Dst1_Des = 0x80000;
-
- for(int i=0; i<0x1000; i=i+4)
- {
- Xil_Out32(i+base_addr+0x0100, i);
- Xil_Out32(i+base_addr+0x2100, i+0x2100);
- }
-
- Src_Des[0].Size = 0x1000;
- Src_Des[0].Cntl = 2;
- Src_Des[0].Address = base_addr+0x0100;
- Src_Des[0].NextDscr = &Src1_Des[0];
-
- Src1_Des[0].Address = base_addr+0x2100;
- Src1_Des[0].Size = 0x1000;
- Src1_Des[0].Cntl = 0;
- //Src_Des[1].NextDscr = &Src_Des[2];
-
- Src1_Des[1].Address = base_addr+0x1100;
- Src1_Des[1].Size = 0x1000;
- Src1_Des[1].Cntl = 0x10;
-
- Dst_Des[0].Address = base_addr+0x1100;
- Dst_Des[0].Size = 0x1000;
- Dst_Des[0].Cntl = 2;
- Dst_Des[0].NextDscr = &Dst1_Des[0];
-
- Dst1_Des[0].Address = base_addr+0x0100;
- Dst1_Des[0].Size = 0x1000;
- Dst1_Des[0].Cntl = 0;
- //Dst_Des[1].NextDscr = &Dst_Des[2];
-
- Dst1_Des[1].Address = base_addr+0x2100;
- Dst1_Des[1].Size = 0x1000;
- Dst1_Des[1].Cntl = 0x10;
-
- if((Xil_In32(ZDMA_ADDR+ZDMA_CH_CTRL0)&0x40)!=0x40)
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL0, (Xil_In32(ZDMA_ADDR+ZDMA_CH_CTRL0)&0x7f)|0x40);
- //Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL1, 0);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_SRC_START_LSB, ((UINTPTR)(&Src_Des[0]))&0xFFFFFFFF);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_SRC_START_MSB, (((u64)Src_Des)>>32)&0xFFF);
-
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_DST_START_LSB, ((UINTPTR)(&Dst_Des[0]))&0xFFFFFFFF);
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_DST_START_MSB, (((u64)Dst_Des)>>32)&0xFFF);
-
- Xil_Out32(ZDMA_ADDR+ZDMA_CH_CTRL2, 1);
-
- while(Xil_In32(ZDMA_ADDR+ZDMA_CH_STATUS)==2);
-
- xil_printf("Done Status: %dnr", Xil_In32(ZDMA_ADDR+ZDMA_CH_STATUS));
- for(int i=0; i<0x1000; i=i+4)
- {
- if(Xil_In32(i+base_addr+0x0100)!=i+0x2100)
- {
- xil_printf("Error: %x in %xnr", i, Xil_In32(i+0x100));
- }
- if(Xil_In32(i+base_addr+0x2100)!=i)
- {
- xil_printf("Error: %x in %xnr", i, Xil_In32(i+0x2100));
- }
- }
复制代码
结果: j截止到目前ZDMA试用贴源码: 使用平台均为Vivado2019.1/SDK 2019.1;Fpga使用Vivado,在Tcl Console运行tcl脚本文件;SDK部分使用SDK导入Archieve文件。
|