我酱爆,要爆呃! 2025-03-03 10:24 采纳率: 75%
浏览 26
已结题

SG-Cyclic AxiDma重启流程以及内存一致性问题

软核开发SG-Cyclic模式AxiDma Tx通道循环传输。将Tx通道与Rx通道修改成并发进行,在Tx通道循环传输过程中如果Rx通道接收到特定数据,则(使用复位函数XAxiDma_Reset()、将Tx控制寄存器RS位写为0、将Tx控制寄存器cyclic使能位写为0,三种方式中的一种)停止循环传输。但是在停止循环传输后无法再次进行循环传输,控制寄存器与状态寄存器截图如下:

_
红框:Tx Ctrl Reg 0x41e00000; Tx Stat Reg 0x41e00004;
蓝框:Rx Ctrl Reg 0x41e00030; Rx Stat Reg 0x41e00034.
_

1)复位函数停止循环传输(禁用Cyclic停止循环传输,双通道寄存器值相同)

img

2)RS位停止循环传输

img

cyclic传输会跳过CPU,由硬件自动进行传输,在循环传输过程中只有Tx、Rx通道的中断系统部分的代码会运行,所以我在Tx中断服务函数中加入重启DMA引擎,没有作用,无法再次进行循环传输。我不知道重启流程是否正确,这方面的参考资料太少。

1)DMA中断系统

//Tx中断回调函数
static void TxCallBack(XAxiDma_BdRing * TxRingPtr)
{
    int BdCount;
    XAxiDma_Bd *BdPtr;
 
    //获取经过硬件处理的Bd
    BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
 
    if (!start_transfer_img) {  //单帧和返回数据时,需要释放Bd环
 
        u32 BdSts;
        XAxiDma_Bd *BdCurPtr;
        int Status;
        int Index;
 
        BdCurPtr = BdPtr;
        //检查Bd环中每个Bd是否都传输完成
        for (Index = 0; Index < BdCount; Index++) {
            BdSts = XAxiDma_BdGetSts(BdCurPtr);
            if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
                (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
 
                Error = 1;
                xil_printf("tx Bd error\r\n");
                break;
            }
 
            BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
        }
 
        //释放Bd环
        Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr);
        if (Status != XST_SUCCESS) {
            Error = 1;
        }
 
    } else {  //连续传输需要rx通道中断信号停止
 
        if(stop_img == 0x0400){
//            XAxiDma_Reset(&AxiDma);
//            set_register_value(TX_CTRL_REG, 0, 0, 0);  //停止Tx通道运行位
            set_register_value(TX_CTRL_REG, 4, 4, 0);  //禁用cyclic
 
        }
        else {
 
            //刷新内存
            Xil_DCacheFlush();
 
            //写入帧序号,实时更新图像数据
            write_img_num(TX_BUFFER_BASE);
            set_img_para();
            img_num += 1;
        }
    }
 
    if(!Error){
        TxDone += BdCount;   //传输完成,中断计数变化
        Tx_Intr_Flag = 1;    //传输完成,中断信号变化
    }
}
 
//mm2s通道中断服务函数
static void TxIntrHandler(void *Callback)
{
    XAxiDma_BdRing *TxRingPtr = (XAxiDma_BdRing *) Callback;
    u32 IrqStatus;
 
    //获取中断状态
    IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr);
    //挂起中断
    XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus);
    if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
        xil_printf("error tx intr\r\n");
 
        return;
    }
 
    if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
 
        XAxiDma_BdRingDumpRegs(TxRingPtr);
 
        Error = 1;
        xil_printf("irq intr error\r\n");
 
        XAxiDma_Reset(&AxiDma);
        while (!XAxiDma_ResetIsDone(&AxiDma));
 
        return;
    }
 
    if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
        TxCallBack(TxRingPtr);
 
        if (start_transfer_img && (!(Xil_In32(TX_CTRL_REG) & XAXIDMA_CR_RUNSTOP_MASK))) {
 
            //重新设置dma
            restart_dma();
            usleep(1000);
        }
    }
    Tx_Intr_Flag = 0;
}
 
//Rx中断回调函数
static void RxCallBack(XAxiDma_BdRing * RxRingPtr)
{
    int BdCount;
    XAxiDma_Bd *BdPtr;
    Rx_Intr_Flag = 0;
 
    BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
 
    RxDone += BdCount;
    Rx_Intr_Flag = 1;
}
 
//s2mm通道中断服务函数
static void RxIntrHandler(void *Callback)
{
    XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
    u32 IrqStatus = 0;
 
    stop_img = 0;
 
    IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
 
    XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);
    if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
        xil_printf("rx assert error, error stat %x\r\n", IrqStatus);
        return ;
    }
 
    if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
 
        XAxiDma_BdRingDumpRegs(RxRingPtr);
 
        Error = 1;
        xil_printf("rx intr error, code %x\r\n", (IrqStatus & XAXIDMA_IRQ_ERROR_MASK));
 
        XAxiDma_Reset(&AxiDma);
        while (!XAxiDma_ResetIsDone(&AxiDma));
 
        return ;
    }
 
    if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
        RxCallBack(RxRingPtr);
        stop_img = Xil_In32(RX_BUFFER_BASE + 4);  //获取停止传输命令码
    }
}
 
//设置dma中断系统
int SetupAxiDmaIntrSystem(INTC * IntcInstancePtr, XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
    XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr);
    XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr);
    int Status;
 
    //连接Tx中断源
    Status = XIntc_Connect(IntcInstancePtr, TxIntrId, (XInterruptHandler) TxIntrHandler, TxRingPtr);
    if (Status != XST_SUCCESS) {
        xil_printf("Failed tx connect intc\r\n");
        return XST_FAILURE;
    }
 
    //连接Rx中断源
    Status = XIntc_Connect(IntcInstancePtr, RxIntrId, (XInterruptHandler) RxIntrHandler, RxRingPtr);
    if (Status != XST_SUCCESS) {
        xil_printf("Failed rx connect intc\r\n");
        return XST_FAILURE;
    }
 
    //开启中断控制器
    Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
    if (Status != XST_SUCCESS) {
        xil_printf("Failed to start intc\r\n");
        return XST_FAILURE;
    }
 
    XIntc_Disable(IntcInstancePtr, TxIntrId);
    XIntc_Disable(IntcInstancePtr, RxIntrId);
 
    XIntc_Enable(IntcInstancePtr, TxIntrId);
    XIntc_Enable(IntcInstancePtr, RxIntrId);
 
    //中断异常处理
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
            (Xil_ExceptionHandler)INTC_HANDLER, (void *)IntcInstancePtr);
    Xil_ExceptionEnable();
 
    return XST_SUCCESS;
}

2)重启dma

void restart_dma()
{
    XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma);
    XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
 
    //等待通道关闭
    while((!(Xil_In32(TX_STAT_REG) & XAXIDMA_HALTED_MASK)) ||
            (!(Xil_In32(RX_STAT_REG) & XAXIDMA_HALTED_MASK)));
 
    XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
    XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
 
    //清除双向通道DMA、INTC核中断位
    Xil_Out32(TX_CTRL_REG, Xil_In32(TX_CTRL_REG) & (~XAXIDMA_IRQ_ALL_MASK));
    Xil_Out32(TX_STAT_REG, Xil_In32(TX_STAT_REG) | XAXIDMA_IRQ_ALL_MASK);
    ClearIntrStatus(TX_MASK);
 
    Xil_Out32(RX_CTRL_REG, Xil_In32(RX_CTRL_REG) & (~XAXIDMA_IRQ_ALL_MASK));
    Xil_Out32(RX_STAT_REG, Xil_In32(RX_STAT_REG) | XAXIDMA_IRQ_ALL_MASK);
    ClearIntrStatus(RX_MASK);
 
    //使能dma工作模式
    set_register_value(TX_CTRL_REG, 4, 4, 0);
    set_register_value(RX_CTRL_REG, 4, 4, 1);
 
    XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
    XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
 
    //设置双通道首尾描述符
    Xil_Out32((UINTPTR)TX_CTRL_REG + XAXIDMA_CDESC_OFFSET, TX_RETURN_DATA_BUF);
    Xil_Out32((UINTPTR)TX_CTRL_REG + XAXIDMA_TDESC_OFFSET, TX_RETURN_DATA_BUF);
 
    Xil_Out32((UINTPTR)RX_CTRL_REG + XAXIDMA_CDESC_OFFSET, RX_BUFFER_BASE);
    Xil_Out32((UINTPTR)RX_CTRL_REG + XAXIDMA_TDESC_OFFSET, RX_BUFFER_BASE);
 
    //打开传输通道
    set_register_value(TX_CTRL_REG, 0, 0, 1);
    set_register_value(RX_CTRL_REG, 0, 0, 1);
}


我的问题是如何主动停止Tx循环传输后,再次进行循环传输?

另外我发现在Tx中断回调函数中加入内存刷新Xil_DCacheFlushRange()、内存无效化Xil_DCacheInvalidateRange()函数后带宽8.7GBps,但是会出现每帧图像会出现一个错误包(一帧图像6000个包),错误统一表现为丢失开头8字节数据,错误包(在一帧图像中)出现位置随机。回调函数中去掉内存无效化函数,并使用Xil_DCacheFlush()刷新内存则不会出现丢失字节的错误包,但是带宽会降低到4.8GBps。这个丢字节原因是因为内存不一致吗?

  • 写回答

3条回答 默认 最新

  • 我酱爆,要爆呃! 2025-03-13 14:58
    关注

    在写控制寄存器“RS”位,停止cyclic循环传输后,重新配置通道与描述符链,再打开通道。

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

报告相同问题?

问题事件

  • 系统已结题 3月21日
  • 已采纳回答 3月13日
  • 创建了问题 3月3日