**
Vitis 2019.2
Vivado 2019.2
MM2S、S2MM通道位宽64bit
**
**
SG模式Axi-Dma进行UDP传输图像数据时(一帧图像数据分成6000个数据包进行传输,帧图像数据长度是6000 * 8224字节),出现数据包开头8字节数据丢失,此时数据包已被解封装,丢失的是图像数据。这些错误数据包出现数量与出现位置(6000个数据包中位置)随机。尝试过减少Bd数量和缩小传输长度,依旧存在丢失开头8字节数据现象,只不过错误出现频率和错误包数量变少。尝试进行降低带宽,但是依旧会出现问题。
SG-cyclic AxiDma、SG-Normal AxiDma、Simple AxiDma三种模式都进行测试过,出现同样问题。
串口打印Tx通道传输信息按顺序分别是 “已被硬件处理的Bd数量、累加的中断完成计数、图像帧序号、Bd环设置Bd总数”,从打印信息来看,没有出现漏传。

硬件处理完成Bd环后,在中断回调函数中以轮询方式对每个Bd内设置的数据缓存区地址和传输长度进行判断,与Bd环设置部分中配置的缓存区地址和长度一致,没发现错误。
void TxCallBack(XAxiDma_BdRing * TxRingPtr)
{
int BdCount;
XAxiDma_Bd *BdPtr;
u32 BdSts;
XAxiDma_Bd *BdCurPtr;
int Status;
int Index;
//获取经过硬件处理的Bd
BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
BdCurPtr = BdPtr;
//用于测试硬件是否正确读取图像数据缓存区与输出数据长度是否正确,Bd内缓存区地址 - 基地址 = 传输长度
for (Index = 0; Index < BdCount; Index++) {
if(BdCount == 6000){
//在Bd特定字节段获取缓存区地址和实际传输长度
u32 addr = Xil_In32((UINTPTR)BdCurPtr + XAXIDMA_BD_BUFA_OFFSET) - TX_BUFFER_BASE;
u32 len = Xil_In32((UINTPTR)BdCurPtr + XAXIDMA_BD_CTRL_LEN_OFFSET) - XAXIDMA_BD_CTRL_ALL_MASK;
xil_printf("Pkt %d, buffer addr %x length %d\r\n",
Index, (addr + TX_BUFFER_BASE), len);
}
BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
}
//释放Bd环
Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr);
if (Status != XST_SUCCESS) {
Error = 1;
}
TxDone += BdCount;
}
**
**
下图为wireshark抓到的错误包、vitis memory窗口错误包对应缓存区的数据截图、串口打印错误包信息
1. 红框处为帧序号,也是数据包编号

2. memory窗口错误数据包数据截图

3. 串口打印错误包信息

4. 错误包具体信息

**
**
UDP是由FPGA同事移植的开源UDP,关闭了校验和功能。开启校验和功能后会出现UDP校验和错误,但是传输数据完全正确。下图为FPGA同事抓DMA核输出信号,发现每次出现错误包时Tvalid信号出现异常,不规律且出现14个时钟周期的拉低。

**
**
代码部分由Xilinx官方例程xaxidma_example_sg_cyclic_intr.c进行修改,Tx通道中断服务函数、中断回调函数和Tx通道设置与官方例程一致,可以参考
//////////////////////////////////////// Bd环参数设置 /////////////////////////////////////
//循环模式连续传图
int ContinuousTransmissionImg(XAxiDma * AxiDmaInstPtr)
{
XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr);
XAxiDma_Bd *BdPtr, *BdCurPtr;
int Status;
int Index, Pkts;
//使能cyclic模式
XAxiDma_BdRingEnableCyclicDMA(TxRingPtr);
XAxiDma_SelectCyclicMode(AxiDmaInstPtr, XAXIDMA_DMA_TO_DEVICE, 1);
//配置Bd空间
Status = XAxiDma_BdRingAlloc(TxRingPtr, TOTAL_BD_COUNT, &BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed to alloc error Bd\r\n");
}
UINTPTR BufferAddr = TX_BUFFER_BASE;
BdCurPtr = BdPtr;
Xil_DCacheFlushRange((UINTPTR)TX_BUFFER_BASE, TOTAL_BD_COUNT * MAX_PKT_LEN);
for(Index = 0; Index < TOTAL_BD_COUNT; Index++) {
for(Pkts = 0; Pkts < NUMBER_OF_BDS_PER_PKT; Pkts ++){
Status = XAxiDma_BdSetBufAddr(BdCurPtr, BufferAddr);
if (Status != XST_SUCCESS) {
xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n",
(unsigned int)BufferAddr, (UINTPTR)BdCurPtr, Status);
return XST_FAILURE;
}
Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN, TxRingPtr->MaxTransferLen);
if (Status != XST_SUCCESS) {
xil_printf("Tx set length %d on BD %x failed %d\r\n",
MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);
return XST_FAILURE;
}
u32 Bits = 0;
if(Pkts == 0){
Bits |= XAXIDMA_BD_CTRL_TXSOF_MASK;
}
if(Pkts == (NUMBER_OF_BDS_PER_PKT - 1)){
Bits |= XAXIDMA_BD_CTRL_TXEOF_MASK;
}
XAxiDma_BdSetCtrl(BdCurPtr, Bits);
XAxiDma_BdSetId(BdCurPtr, BufferAddr);
}
BufferAddr += MAX_PKT_LEN;
//转到下个待处理BD
BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
}
//配置好的Bd交给硬件处理
Status = XAxiDma_BdRingToHw(TxRingPtr, TOTAL_BD_COUNT, BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed to hw, length %d, error code %d\r\n",
(int)XAxiDma_BdGetLength(BdPtr, TxRingPtr->MaxTransferLen), Status);
return XST_FAILURE;
}
while(XAxiDma_Busy(AxiDmaInstPtr, XAXIDMA_DMA_TO_DEVICE));
TxDone = 0;
return XST_SUCCESS;
}
以单帧图像传输为例,如果连续两次传输间的间隔时间长,不会出现丢字节问题(比如传完一帧后间隔几秒传第二帧,那么第二帧基本不会出现丢字节问题),间隔时间短则会出现丢字节现象。
我想知道造成这个首部丢8字节问题的原因是什么?是否与软核开发axi-dma有关?还有什么方式可以进一步排查问题点?
**