按照官方案例,启动接收传输:
u32 Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)RxDMAPtr,
(u32)(1024), XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
printf("dma from device error:%d\n", Status);
pthread_exit(0);
}
发现接收到的中断总会进入IRQ_ERROR,打印IrqStatus的值
IrqStatus = XAxiDma_IntrGetIrq(&AxiDma, XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrAckIrq(&AxiDma, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
printf("all mask = %x\n", IrqStatus);
continue;
}
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
XAxiDma_Reset(&AxiDma);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if(XAxiDma_ResetIsDone(&AxiDma)) {
break;
}
TimeOut -= 1;
}
printf("Error:0x%x dma from device %d \n", IrqStatus,TimeOut);
continue;
}
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
RxDone++;
Packet_Rx_Length = XAxiDma_ReadReg(AxiDma.RxBdRing[0].ChanBase, XAXIDMA_BUFFLEN_OFFSET);
printf("actural rx length = %ld\n", Packet_Rx_Length);
sem_post(&c2h_sem);//trig to read
}
输出Error:0x5000 dma from device 10000
XAXIDMA_IRQ_ERROR_MASK宏定义为0x004000
XAXIDMA_IRQ_IOC_MASK宏定义为0x001000
说明同时接收完毕,也产生了错误,官方例程对错误的处理是直接对dma进行复位,没有对错误进行分类;
查看手册pg021_axi_dma,找到
S2MM_DMASR (S2MM DMA Status Register – Offset 34h)
This register provides the status for the Stream to Memory Map DMA Channel.
对于Error的分类在低11位,然而读到IrqStatus低11位全是0,想必在读函数中做了MASK;果然找到读出后与0x007000相与,重写读IrqStatus;
IrqStatus = XAxiDma_ReadReg(AxiDma.RegBase + (XAXIDMA_RX_OFFSET * XAXIDMA_DEVICE_TO_DMA), XAXIDMA_SR_OFFSET);
打印输出IrqStatus值为0x5011,表示DMAIntErr和Halted为1;
Halted位描述如下
DMA Channel Halted. Indicates the run/stop state of the DMAchannel.
• 0 = DMA channel running.
• 1 = DMA channel halted. For Scatter/Gather Mode this bit gets set when DMACR.RS = 0 and DMA and SG operations have halted. For Direct Register Mode this bit gets set when DMACR.RS = 0 and DMA operations have halted. There can be a lag of time between when DMACR.RS = 0 and when DMASR.Halted = 1.
Note: When halted (RS= 0 and Halted = 1), writing to TAILDESC_PTR pointer registers has no effect on DMA operations when in Scatter Gather Mode. For Direct Register Mode, writing to the LENGTH register has no effect on DMA operations.
DMAIntErr位描述如下:
DMA Internal Error. This error occurs if the buffer length specified in the fetched descriptor is set to 0. Also, when in Scatter Gather Mode and using the status app length field, this error occurs when the Status AXI4-Stream packet RxLength field does not match the S2MM packet being received by the S_AXIS_S2MM interface. When Scatter Gather is disabled, this error is flagged if any error occurs during Memory write or if the incoming packet is bigger than what is specified in the DMA length register.
This error condition causes the AXI DMA to halt gracefully. The DMACR.RS bit is set to 0, and when the engine has completely shut down, the DMASR.Halted bit is set to 1.
• 0 = No DMA Internal Errors.
• 1 = DMA Internal Error detected.
于是找到设置DMA length register:
S2MM_LENGTH (S2MM DMA Buffer Length Register – Offset 58h)
This register provides the length in bytes of the buffer to write data from the Stream to Memory map DMA transfer.
S2MM Length描述为:
Indicates the length in bytes of the S2MM buffer available to write receive data from the S2MM channel. Writing a non-zero value to this register enables S2MM channel to receive packet data.
At the completion of the S2MM transfer, the number of actual bytes written on the S2MM AXI4 interface is updated to the S2MM_LENGTH register.
Note: This value must be greater than or equal to the largest expected packet to be received on S2MM AXI4-Stream. Values smaller than the received packet result in undefined behavior.
Notes:
1. Width of Length field determined by Buffer Length Register Width parameter. Minimum width is 8 bits (7 to 0) and maximum width is 26 bits (25 to 0).
问题是设置传输的S2MM buffer length太小,在传输结束后读取S2MM length可以读到实际传输的包大小;
S2MM Length的位宽可在DMA IP核例化的时候设置。