This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] PROCESSOR-SDK-AM64X:AM64x LWIP ENET CPSW TCP 服务器示例 App_shutdownNetworkStack () 问题???

Guru**** 2442090 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1545997/processor-sdk-am64x-am64x-lwip-enet-cpsw-tcp-server-example--app_shutdownnetworkstack-problem

器件型号:PROCESSOR-SDK-AM64X


工具/软件:

您好、专家、

我使用的是 MCU_PLUS_SDK_am64x_09_01_00_41 版本的 SDK 和 Code Composer Studio 12.8.0。 我目前正在自定义 AM64x 电路板上的{MCU_SDK_PATH}/examples/networking/lwip/enet_cpsw_tcpserver 上运行示例工程。

我的目标是在运行时完全取消初始化并重新初始化 Enet、UDMA 和 LwIP 等所有组件。 我有一个定期执行此重新初始化的函数。

SDK 提供了一个名为 App_shutdownNetworkStack() 的函数来关闭 netif 连接。 基于此、我将尝试按以下顺序执行重新初始化:

空 myFunction (void)

App_shutdownNetworkStack();
EnetApp_closeDmaChannels();

EnetApp_driverClose (gEnetAppParams[0].enetType、gEnetAppParams[0].instId);

for (instId = 0;instId < CONFIG_UDMA_NUM_instances;instId++)

RetVal += UDMA_deinit (&gUdmaDrvObj[instId]);
DebugP_ASSERT (UDMA_Sok == RetVal);
}

switch_mac_port();


for (instId = 0;instId < CONFIG_UDMA_NUM_instances;instId++)

RetVal += UDMA_init (&gUdmaDrvObj[instId]、&gUdmaInitPrms[instId]);
DebugP_ASSERT (UDMA_Sok == RetVal);
}

EnetApp_driverInit();

对于 (uint32_t enetInstIdx = 0;enetInstIdx < ENET_SYSCFG_MAX_ENET_Instances;enetInstIdx++)

状态= EnetApp_driverOpen (gEnetAppParams[enetnstIdx].enetType、gEnetAppParams[enetInstIdx].instId);
IF (status!= ENET_Sok)

EnetAppUtils_print(“打开 ENE[%d]失败:%d\r\n“、enetInstIdx、status);
EnetAppUtils_assert (status == ENET_Sok);
}
EnetApp_addMCastEntry (gEnet App_Params Idx].enetType、
Enet App_Params [enetInstIdx].instId、
EnetSoc_getCoreId ()、
BROADCAST_MAC_ADDRESS、
CPSW_ALE_ALL_PORT_MASK);
}

App_setupNetwork();

}

到目前为止、一切都正常工作、并打印有效的日志输出、只有一项除外。 在 App_shutdownNetworkStack -> LwipIfEnetApp_netifClose ()-> nettif_remove ()-> remove_callback ()-> Lwip2enet_close () 期间、将显示以下警告:

Lwip2enet_close() 无法检索所有 PktInfo

此时、hLwip2enet->allocPktInfo 为 48。

尽管如此、EnetApp_driverClose() 和 EnetMem_deInit() 不会失败、表示所有数据包计数器都已正确平衡。

但是、当代码到达 App_setupNetwork ()-> ApptcpipInitCompleteCb ()-> LwipifEnetApp_netifOpen ()-> LWIP_START ()-> Lwip2enet_open ()-> Lwip2enet_initRxObj () 时、它会在以下位置崩溃:

对于 (i = 0U;i < numCustombuf;i++)

cpbuf = NULL;
cpbuf =(Rx_Custom cpbuf *) LWIP_MEMPOOL_ALLOC (RX_POOL);
EnetAppUtils_assert (cPbuf != NULL );//<--此断言失败
}

错误为:

cpbuf !=空:失败!!!

因此、即使在 EnetMem_deInit(检查数据包泄漏)期间没有出现错误、此重新分配也会失败。

我的问题:

  1. 我是否缺少需要手动释放数据包缓冲区或其他资源的步骤?

  2. 在重新初始化之前、LWIP 自定义 pbuf 池是否需要 deinit 回调或额外清理?

  3. 在运行时完全关断和重新启动 enet-UDMA-LwIP 协议栈的正确顺序是什么?

void EnetApp_closeDmaChannels (void)

LwipifEnetApp If_Release RxHandleInfo Rx_handle;
LwipifEnetApp If_Release TxHandleInfo TX_handle;
Enet Dma_Pkt fqPktInfoQ、cqPktInfoQ;

rx_handle.enetType = gEnetAppParams[0].enetType;
rx_handle.instId = gEnetAppParams[0].instId;
rx_handle.rxChNum = 0;

Enet App_Handle.Info handleInfo;
Enet Per_Attach CoreOutArgs attachInfo;
uint32_t CoreID = EnetSoc_getCoreId ();

EnetApp_acquireHandleInfo (rx_handle.enetType、rx_handle.instId、&handleInfo);
EnetApp_coreAttach (rx_handle.enetType、rx_handle.instId、CoreID、&attachInfo);


EnetQueue_initQ (&fqPktInfoQ);
EnetQueue_initQ (&cqPktInfoQ);

EnetApp_closeRxDma (0、
handleInfo.henet、
attachInfo.coreKey、
CoreID、
&fqPktInfoQ、
&cqPktInfoQ);

EnetAppUtils_freePktInfoQ (&fqPktInfoQ);
EnetAppUtils_freePktInfoQ (&cqPktInfoQ);

// TX 通道

tx_handle.enetType = gEnetAppParams[0].enetType;
tx_handle.instId = gEnetAppParams[0].instId;
tx_handle.rxChNum = 0;

EnetQueue_initQ (&fqPktInfoQ);
EnetQueue_initQ (&cqPktInfoQ);

EnetApp_acquireHandleInfo (tx_handle.enetType、tx_handle.instId、&handleInfo);

EnetApp_closeTxDma (0、
handleInfo.henet、
attachInfo.coreKey、
CoreID、
&fqPktInfoQ、
&cqPktInfoQ);

EnetAppUtils_freePktInfoQ (&fqPktInfoQ);
EnetAppUtils_freePktInfoQ (&cqPktInfoQ);

返回;
}

我非常感谢为帮助解决此问题提供的任何建议、见解或工作流程示例。 提前感谢您的支持。

此外、我将使用如下所示的方法关闭 DMA 通道、我也通过引用相同的 SDK 示例创建了该方法。 如果您也能考虑到这一点、我将不胜感激。  

此致、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Berlam:

    我发现 在 调用 EnetApp_driverClose() 函数后、EnetApp_driverDeInit() 调用丢失。 这可能是由于以前的缓冲区未正确释放、内存不可用于为任何新数据包分配的原因。

    [报价 userid=“541328" url="“ url="~“~/support/processors-group/processors/f/processors-forum/1545997/processor-sdk-am64x-am64x-lwip-enet-cpsw-tcp-server-example--app_shutdownnetworkstack-problem

    到目前为止、一切都正常工作、并打印有效的日志输出、只有一项除外。 在 App_shutdownNetworkStack -> LwipIfEnetApp_netifClose ()-> nettif_remove ()-> remove_callback ()-> Lwip2enet_close () 期间、将显示以下警告:

    Lwip2enet_close() 无法检索所有 PktInfo

    [/报价]

    这是一个错误警告、可以忽略不计。 我将通知开发团队解决此问题。  

    谢谢。此致、
    Teja。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Teja:

    非常感谢您的答复。

    首先,关于你提到的 EnetApp_driverDeInit() 点—我目前使用的是 MCU_PLUS_SDK_am64x_09_01_00_41 ,在这个 SDK 版本中, EnetApp_driverDeInit() 的功能已经包含在 EnetApp_driverClose() 函数中。

    当我检查较新的 SDK 版本(如 11.0.x.x)时、EnetApp_driverDeInit() 函数定义如下:

    void EnetApp_driverDeInit()


    EnetMem_deInit();
    Enet_deInit();
    }

    但是,在版本 09.01.00.41 中,这个逻辑已经被移动到 EnetApp_driverClose() 中,因此 driverDeInit() 执行的任务已经被处理。

    为了更详细地解释这种情况、初始设置可以正常进行。 但是、在运行时、我通过切换 MDIO 引脚来更改 CPSW 的 MAC 端口。 为了安全起见、我希望在每次发生这种情况时完全关闭并重新初始化整个以太网系统。

    下面是我用于该目的的函数:

    空 myFunction (void)

    App_shutdownNetworkStack();
    EnetApp_closeDmaChannels();

    EnetApp_driverClose (gEnetAppParams[0].enetType、gEnetAppParams[0].instId);

    对于 (instId = 0;instId < CONFIG_UDMA_NUM_Instances;instId++)

    RetVal += UDMA_deinit (&gUdmaDrvObj[instId]);
    DebugP_ASSERT (UDMA_Sok == RetVal);
    }

    switch_mac_port();

    对于 (instId = 0;instId < CONFIG_UDMA_NUM_Instances;instId++)

    RetVal += UDMA_init (&gUdmaDrvObj[instId]、&gUdmaInitPrms[instId]);
    DebugP_ASSERT (UDMA_Sok == RetVal);
    }

    EnetApp_driverInit();

    对于 (uint32_t enetInstIdx = 0;enetInstIdx < ENET_SYSCFG_MAX_ENET_Instances;enetInstIdx++)

    Status = EnetApp_driverOpen (gEnetAppParams[enetInstIdx].enetType、
    gEnetAppParams[enetInstIdx].instId);
    IF (STATUS != ENET_Sok)

    EnetAppUtils_print(“打开 ENE[%d]失败:%d\r\n“、enetInstIdx、status);
    EnetAppUtils_assert (status == ENET_Sok);
    }

    EnetApp_addMCastEntry (gEnetAppParams[enetInstIdx].enetType、
    gEnetAppParams[enetInstIdx].instId、
    EnetSoc_getCoreId ()、
    BROADCAST_MAC_ADDRESS、
    CPSW_ALE_ALL_PORT_MASK);
    }

    App_setupNetwork();

    }

    一切都按预期运行、日志看起来正确、直到调用 App_setupNetwork。 在这个函数中,我避免再次调用 TCPIP_init(),因为它是在第一次设置过程中调用的。 以下是 App_setupNetworkStack 函数的工作原理:

    Void App_setupNetworkStack ()

    SYS_SEM_t pInitSem;
    IF(!isTcpipInitDone)

    DebugP_LOG(“TCP IP 正在首次初始化...“);
    err_t err = sys_esm_new (&pInitSem、0);
    EnetAppUtils_assert (err == ERR_OK);

    TCPIP_init (App_tcpipInitCompleteCb、&pInitSem);
    SYS_SEM_WAIT (&pInitSem);
    SYS_SEM_FREE (&pInitSem);

    isTcpipInitDone = true;
    }
    暴露

    DebugP_log(“TCP/IP 堆栈已初始化。 正在重置网络和 DHCP。\r\n“);
    app_tcpipInitCompleteCb (NULL);
    }
    返回;

    }

    然后、流程如下所示:
    LwipifEnetApp_netifOpen -> LWIPIF_LWIP_START -> Lwip2enet_open -> Lwip2enet_initRxObj -> LwipfEnetAppCb_getRxHandleInfo

    在这个函数中、我在这里得到了以下误差:

    对于 (i = 0U;i < numCustombuf;i++)

    cpbuf = NULL;
    cpbuf =(Rx_Custom cpbuf *) LWIP_MEMPOOL_ALLOC (RX_POOL);
    EnetAppUtils_assert (cpbuf != NULL );
    }

    断言失败、我得到:
    “cpbuf != NULL:失败!!!"</s>! !“

    在分析该问题时、我得出结论:LwIP 在 RX 自定义池中的内存不足、无法分配新的 pbuf。 如果我解释不正确、请随时纠正我。

    2)  

    LwipifEnetAppCb_releaseRxHandleLwipifEnetAppCb_releaseTxHandle似乎是 SDK 提供的函数、旨在关闭 DMA 通道。 但是、由于内部序列LwipifEnetAppCb_releaseRxHandleLwipifEnetAppCb_releaseTxHandle->->EnetApp_releaseHandleInfoEnetApp_driverClose、这些函数会尝试关闭 RX 或 TX、然后立即关闭驱动器。 因此、它在EnetMem_DeInit函数内部始终出现故障。

    这是因为为了让EnetApp_closeDriver->EnetMem_DeInit正常工作、RX 和 TX DMA 通道都必须完全关闭。

    因此、我的要求是:如何正确、安全地关闭 DMA 通道并释放所有数据包资源? 如果您能解释如何正确执行某些LwipifEnetAppCb_releaseRxHandleLwipifEnetAppCb_releaseTxHandle某些功能正在尝试实现、我将不胜感激。 这将是非常有帮助的。

    但是、我找不到解决方案。 因此、我很感激能了解正确的关断和重新初始化序列来安全重新启动以太网系统、包括 Enet、UDMA 和 LwIP。

    我期待着你的建议,再次感谢你的支持。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Berlam:

    我已经完成了代码、并确定了 导致问题的领域。 请为我提供一天的时间、以便找到关闭、验证和测试修复程序的正确方法。 从最初的扣款开始,它主要与成交顺序有关,这也是您看到这些问题的一个原因。

    谢谢。此致、
    Teja。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Teja:

    非常感谢您的答复。 我激动地期待着您的解决方案。

    此致、

    Berlam

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Berlam:

    以下修复内容将为 LwIP 示例启用正确的关闭序列。 仍有一些与时序相关的打开项目。 但这些应该会对您取消阻止。 如果您对此有任何疑问、敬请告知。

    e2e.ti.com/.../0001_2D00_all_2D00_socs_2D00_LwIP_2D00_Enet_2D00_Fix_2D00_LwIP_2D00_close_2D00_sequence.patch

    此致、
    Teja。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Teja:

    非常感谢您的回复和分享这个补丁。

    遗憾的是、您对 App_shutdownNetworkStack 所做的修改未能解决问题、实际上导致了一个新问题。

    具体流程如下:
    App_shutdownNetworkStack -> LwipifEnetApp_stopSchedule -> SemaphoreP_Pend (&pPollTaskInfo->shutDownSemObj、SystemP_WAIT_FOREVER)、然后从此处直接跳转到 LwipifEnetApp_txPacketTask 内的以下行:

    void LwipifEnetApp_txPacketTask(void *arg)
    {
        LwipifEnetApp_TxTaskInfo* pTaskInfo = (LwipifEnetApp_TxTaskInfo*)arg;
        
        while(!pTaskInfo->shutDownFlag)
        {
            /*
            * Wait for the Tx ISR to notify us that empty packets are avaliable
            * that were used to send data
            */
            SemaphoreP_pend(&pTaskInfo->sem, SystemP_WAIT_FOREVER);
            LWPIF_LWIP_txPktHandler(pTaskInfo->netif); // it jumps directly to this line
        }
        
        /* We are shutting down, notify that we are done */
        SemaphoreP_post(&pTaskInfo->shutDownSemObj);
    }

    之后、它从不退出此 while 循环、代码流会卡在其中。

    然后执行遵循以下路径:
    LWIPIF_LWIP_txPktHandler -> Lwip2enet_txPktHandler -> Lwip2enet_retrieveTxPkts
    然后它再次循环回到 while(!pTaskInfo->shutDownFlag)中、无限期地重复此循环。

    1) 如果您能分享如何解决此问题、我将非常感激。

    2) 如果您已经测试了您共享的修补程序、那么如果您还可以共享您使用的测试代码、将会非常有帮助。 我想知道您测试了多远、以及您是否能够完全关闭并重新初始化以太网栈。 如果是、请您分享您所遵循的步骤、我将不胜感激。

    再次感谢您。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Berlam:

    我能够在测试中重新初始化 netif。 您描述的问题看起来与设置了关闭标志的情况类似、但由于某些竞态条件(我想, 然而,解决这个问题)。 这就是我在设置标志后增加 1-2 秒等待的原因之一、我在 sys_core_lock 之外完成了此操作。  

    我建议您尝试此操作、或者尝试在运行时手动将标志设置为 true 并检查功能。 请告知我们结果。

    此致、
    Teja。