AXI DMA研究 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
ILA抓取的stream端的波形
mm2s
可以清楚看到,读memory期间,一次性读了256个bytes,共64个word。在整个读数据期间,tvalid一直有效,读完之后tlast信号变为1,产生了mm2s_introut中断信号。
s2mm
用xsct分析dma的寄存器配置情况
对比寄存器手册知道:
MM2S_DMA_CR的RS=1, IOC_IrqEn=1, Dly_IrqEn=1, Err_IrqEn=1。 IRQThreshold=0x1(默认值) MM2S_SA=0x12000000 S2MM_DMA_CR的RS=1, IOC_IrqEn=1, Dly_IrqEn=1, Err_IrqEn=1。 IRQThreshold=0x1(默认值) S2MM_SA=0x14000000
源寄存器和目的寄存器的内容:
从这里看,src的内容没有被正确写入dest,因此print failed了。后来发现,如果我们把ILA去掉就可以正确读写了。看样子ILA影响了数据传输。原因不清楚。
搞懂了dma的寄存器后,我们明白了更简单的驱动方法
1)中断不是必须的,直接用下面2句话就可以驱动dma传输。这种方式可以采用轮询的方法等待标志位。
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) TxBufferPtr,
256, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) RxBufferPtr,
256, XAXIDMA_DEVICE_TO_DMA);
usleep(1000);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 1024);
2)可以直接用寄存器搞,也非常简单
u32 base=0x40400000;
Xil_Out32(base, 0x00010003);
Xil_Out32(base+0x30, 0x00010003);
Xil_Out32(base+0x18, TX_BUFFER_BASE);
Xil_Out32(base+0x48, RX_BUFFER_BASE);
Xil_Out32(base+0x28, 1024);
Xil_Out32(base+0x58, 1024);
sleep(1);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 1024);
3) xsct加断点或者读取寄存器非常方便
connect
tar
tar 2
bpadd -file main.c -line 65
mrd 0x40400000 20
mrd 0x12000000 64
mrd 0x14000000 64
nxt 10000
4)关于小梅哥dma读取数量超过256的错误
经过xsct分析后,我们才知道,小梅哥的程序读写数量>256会报错。修改后,结果正确。
//如果发生错误,则打印失败提示
if (Error) {
printf("DMA Transfer Failed!\n");
} else {
//测试完成,检查数据
for(Index = 0; Index < 1024; Index++)
{
//原始程序是这一句:if(RxBufferPtr[Index] != Index) {
//导致当Index数据量>256时,比较结果会出错。实际内存是对的。原因不清楚。
if(RxBufferPtr[Index] != TxBufferPtr[Index]) {
Error_Cnt++;
}
}
if(Error_Cnt > 0)
printf("Test Failed! %d\n", Error_Cnt);
else
printf("Test Successfully!\n");
}
return 0;
}
5)后来原因搞清楚了
- 与TxBuffer, RxBuffer数组的定义类型有关系。DMA传输和CacheClean操作,都是以bytes为单位。长度上要留意,要匹配。
- 如果TxBuffer, RxBuffer数组是u8类型,那么DMA传输和CacheClean操作的长度与TxBuffer, RxBuffer数组保持一致即可。
- 如果TxBuffer, RxBuffer数组是u16类型,那么DMA传输和CacheClean操作的长度是TxBuffer, RxBuffer数组长度的2倍。
- 如果TxBuffer, RxBuffer数组是u32类型,那么DMA传输和CacheClean操作的长度是TxBuffer, RxBuffer数组长度的4倍。
u32类型
uint32_t *TxBufferPtr; //传输数据的指针
uint32_t *RxBufferPtr; //接收数据的指针
//将指针TxBufferPtr指向TX_BUFFER_BASE
TxBufferPtr = (uint32_t *)TX_BUFFER_BASE;
//将指针RxBufferPtr指向RX_BUFFER_BASE
RxBufferPtr = (uint32_t *)RX_BUFFER_BASE;
//初始化AXI DMA
AXI_DMA_Init(&AxiDma0, XPAR_AXIDMA_0_DEVICE_ID);
//给TxBufferPtr赋值为0~255
for(Index = 0; Index < 1024; Index ++) {
TxBufferPtr[Index] = Index;
}
//在DMA传输之前刷新Buffer
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, 1024*4);
//开启数据传输
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) TxBufferPtr,
1024*4, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) RxBufferPtr,
1024*4, XAXIDMA_DEVICE_TO_DMA);
sleep(1);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 1024*4);
u16类型
uint16_t *TxBufferPtr; //传输数据的指针
uint16_t *RxBufferPtr; //接收数据的指针
//将指针TxBufferPtr指向TX_BUFFER_BASE
TxBufferPtr = (uint16_t *)TX_BUFFER_BASE;
//将指针RxBufferPtr指向RX_BUFFER_BASE
RxBufferPtr = (uint16_t *)RX_BUFFER_BASE;
//初始化AXI DMA
AXI_DMA_Init(&AxiDma0, XPAR_AXIDMA_0_DEVICE_ID);
//给TxBufferPtr赋值为0~255
for(Index = 0; Index < 1024; Index ++) {
TxBufferPtr[Index] = Index;
}
//在DMA传输之前刷新Buffer
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, 1024*2);
//开启数据传输
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) TxBufferPtr,
1024*2, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) RxBufferPtr,
1024*2, XAXIDMA_DEVICE_TO_DMA);
sleep(1);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 1024*2);
u8类型
uint8_t *TxBufferPtr; //传输数据的指针
uint8_t *RxBufferPtr; //接收数据的指针
//将指针TxBufferPtr指向TX_BUFFER_BASE
TxBufferPtr = (uint8_t *)TX_BUFFER_BASE;
//将指针RxBufferPtr指向RX_BUFFER_BASE
RxBufferPtr = (uint8_t *)RX_BUFFER_BASE;
//初始化AXI DMA
AXI_DMA_Init(&AxiDma0, XPAR_AXIDMA_0_DEVICE_ID);
//给TxBufferPtr赋值为0~255
for(Index = 0; Index < 1024; Index ++) {
TxBufferPtr[Index] = Index;
}
//在DMA传输之前刷新Buffer
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, 1024);
//开启数据传输
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) TxBufferPtr,
1024, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&AxiDma0,(UINTPTR) RxBufferPtr,
1024, XAXIDMA_DEVICE_TO_DMA);
sleep(1);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, 1024);