我酱爆,要爆呃! 2025-01-16 09:49 采纳率: 75%
浏览 58
已结题

AxiDma进行UDP传输时出现丢开头8字节错误

**
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总数”,从打印信息来看,没有出现漏传。

img

硬件处理完成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. 红框处为帧序号,也是数据包编号

img

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

img

3. 串口打印错误包信息

img

4. 错误包具体信息

img

**

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

img


**

**
代码部分由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有关?还有什么方式可以进一步排查问题点?
**

  • 写回答

2条回答 默认 最新

  • 软件技术NINI 2025-01-16 10:04
    关注

    检查DMA配置:

    确保DMA的配置正确,特别是传输模式、数据宽度、传输长度等参数。
    确认DMA的传输模式是否正确设置,例如SG模式是否正确配置。
    检查数据包结构:

    确认数据包的结构是否正确,特别是数据包开头的8字节数据是否正确填充。
    检查数据包的封装和解封装过程,确保没有在这些过程中丢失数据。
    检查中断处理:

    确认中断处理是否正确,特别是中断处理函数是否正确处理了中断。
    检查中断处理函数中是否有任何可能导致数据丢失的操作。
    检查硬件资源:

    确认硬件资源是否足够,例如FPGA的资源是否足够支持当前的传输速率和数据量。
    检查是否有其他硬件资源冲突导致数据丢失。
    增加调试信息:

    在关键位置增加调试信息,例如在数据包发送和接收的关键位置打印数据包的状态和内容。
    使用逻辑分析仪或示波器等工具进行硬件调试,检查数据传输过程中的信号状态。
    尝试不同的传输策略:

    尝试使用不同的传输策略,例如使用流式传输而不是分包传输。
    考虑使用其他传输协议,例如TCP/IP,看看是否仍然存在数据丢失的问题。
    检查软件驱动:

    确认软件驱动是否正确安装和配置,特别是与DMA相关的驱动。
    检查是否有任何已知的软件驱动问题或bug。
    检查网络环境:

    确认网络环境是否稳定,是否有网络抖动或丢包的情况。
    检查网络设备的配置和状态,确保没有网络问题导致数据丢失。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 2月1日
  • 已采纳回答 1月24日
  • 修改了问题 1月16日
  • 修改了问题 1月16日
  • 展开全部