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.

[参考译文] TM4C123GH6PM:usblib CDC 驱动器传输栈数据(可能损坏?)

Guru**** 2461030 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/653182/tm4c123gh6pm-usblib-cdc-driver-transmits-stack-data-with-possible-corruption

器件型号:TM4C123GH6PM

您好!

我正在开发基于 TivaWare 中 usblib USBDCDC 驱动程序的 USB 驱动程序(用于 USBTMC)。 我发现 usbdcdc.c 中似乎有一个错误、如果可以将其确认为错误、我将不胜感激。

我使用的是 TivaWare 2.1.4.178。

在 HandleRequests(...)中  函 数、对于 USB_CDC_GET_LINE_Coding、使用栈上定义的数据调用 USBDCDSendDataEP0 ()(第1849行)。  USBDCDSendDataEP0的文档说明数据在 收到 pfnDataSent 之前必须保持不变。 但是、由于它是在堆栈上发送数据、因此在发送数据之前它似乎可能会损坏。

谢谢、

Nathan

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

    pui8Data 是指向要通过 EP0发送的数据缓冲区的指针。 通常、这将是 SRAM 中已包含要发送到主机的数据的缓冲区。 应用程序应该已经准备好了* pui8Data 指向的有效数据。 虽然我不是 USB 驱动程序的专家、但我有点怀疑这里有一个错误。 此 USBDCDSendDataEP0用于不同 USB 库文件中的不同位置。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Nathan、

    为了补充 Charles 的回答、我认为您的担忧可能来自 case 陈述中的 sLineCoding 变量声明?

    如果是、我不认为这应该是任何问题、因为从下面的代码中、它只用作一个指针来将 USBDCDSendDataEP0指向行编码的实际位置。 这意味着它不会是通过 API 传递到堆栈的数据、而只是一个在传递到 API 之后将保留在堆栈上的地址、直到 API 像函数调用中的任何标准指针那样访问该地址处的数据。 因此、数据在整个过程中将保持不变、因为它不会存储在堆栈上。 只能根据地址指向的存储器位置来访问它以进行传输。

    //
    //要求客户提供当前的行编码。
    //
    psCDCDevice->pfnControlCallback (psCDCDevice->pvControlCBData、
    USBD_CDC_EVENT_GET_LINE_Coding、0、
    sLineCoding (&S); 

    我还会注意 到、大多数针对 USBDCDSendDataEP0的其他调用也使用指针来实现类似目的、因此从我可以看到的结果来看、实现不存在错误或设计缺陷。

    此外、 针对 USBDCDSendDataEP0的 API 进一步强制要求数据只根据 API 描述中的以下语句通过指针提供给 API:

    //! \param pui8Data 是指向要通过端点0发送的缓冲区的指针。 

    此信息是否能缓解您的疑虑?

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

    是的、我的问题是在 case 语句中声明了 sLineCoding。

    对 pfnControlCallback 的调用是完美的,因为它仍在 HandleRequests()函数中。

    USBDCDSendDataEP0()函数的文档显示"\n pui8Data 缓冲区的内容必须保持不变、直到收到 pfnDataSent 回调。"。

    &sLineCoding 被用作 pui8Data、所以我认为它必须保持有效直到调用 pfnDataSent?

    由于在 HandleRequests()函数中声明了 sLineCoding,它驻留在栈上。 函数返回后、栈框将被拆分、因此如果调用其他函数并覆盖栈、则&sLineCoding 处的数据可能会损坏?

    除非函数的文档错误、并且我们不需要等待 pfnDataSent 回调?

    -弥敦

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

    您好 Nathan、

    sLineCoding  指针只是传递地址的一种临时方法。 调用 USBDCDSendDataEP0 API 后、执行以下代码:

    G_psDCDInst[0].pui8EP0Data = pui8Data; 

    一旦该调用发生、指向数据的地址(是  sLineCoding 提供的唯一地址) 存储在全局变量 g_psDCDInst 的 usbdenum.c 文件中、因此它现在位于栈外部。 此时 、不再需要 sLineCoding 保存在堆栈上的地址、因此在等待 pfnDataSent 回调时、堆栈帧是否被拆分无关紧要。

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

    拉尔夫

    我仍然无法理解这一点。 也许代码是正确的、所以我会睡在上面、早上再看一下。

    我不担心指针 pui8Data 丢失、因为它保存在 g_psDCDInst 中 (正如您所说的)。

    我担心被指向的数据。 就我可以读取的内容而言,*pui8Data 存储在堆栈中。

    问题是 sLineCoding 不是指针。 它是在栈上分配的结构(在 case 语句中):

    案例 USB_CDC_GET_LINE_Coding:
    {
    // sLineCoding 存储在堆栈中。
    tLineCoding sLineCoding;
    MAP_USBDevEndpointDataAck (psInst->ui32USBBase、USB_EP_0、false);
    //将线性化数据复制到本地结构中
    psCDCDevice->pfnControlCallback (psCDCDevice->pvControlCBData、
    USBD_CDC_EVENT_GET_LINE_Coding、0、
    sLineCoding (&S);
    //发送 sLineCoding 的地址,该地址是栈上数据的指针
    USBDCDSendDataEP0 (0、(uint8_t *)和 sLineCoding、sizeof (tLineCoding));
    中断;
    } 

    pfnControlCallback 将应用程序的线性存储结构中的数据复制到提供的指向预分配内存的指针中,即在 HandleRequests(...)中声明的 sLineCoding。 它不会将其设置为指向应用程序的行的指针。

    -弥敦

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

    您好 Nathan、

    好的、我理解您现在提出的问题。 我将进一步研究、敬请期待。

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

    我承认、这在实践中不可能导致问题。 我认为最可能的情况是、如果在 USB 处理程序之后立即调用第二个中断处理程序。 也许可以通过触发具有较大堆栈帧大小的软件中断(许多局部变量、关闭优化?)来测试它。 HandleRequests 函数结束时。

    我确实注意到,文献目录中的其他几个驱动因素也有同样的问题,也许会产生更大的后果。 线路编码数据损坏似乎不是我可以想到的任何应用的主要问题。

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

    您好 Nathan、

    我认为我们忽视的细节也许有一个魔鬼,因为我现在肯定同意,一旦堆栈框架被破坏,你的解释就会消失(抱歉,不能在前面得出这一结论)。 我想通过尝试跟踪 pfnDataSent 回调的起作用位置来了解这不会导致问题的原因。 在 CDC 应用程序中、我没有跟踪正在检查的任何位置。 这让我重新阅读有关的评论,我认为我们大家都得出了错误的结论。

    再次回顾一下注释:

    //! 当自定义命令为
    //时、此函数处理向主机发送数据的操作! 端点0上已发出或已请求非标准描述符。 如果
    //! 完成此操作后、应用程序需要通知、
    //! psCallbacks->tDeviceInfo 结构中的 pfnDataSent 必须
    //! 包含有效的函数指针。 此回调可用于释放
    //! 缓冲区在参数\e pui8Data 中传递到该函数。
    //! 在
    //! 接收到 pfnDataSent 回调。 

    以“如果应用程序在完成时需要通知,...”开头的语句 我认为这是关键所在。 这就是引入 pfnDataSent 回调的内容。 我认为,该评论是缓冲区内容在 收到 pfnDataSent 回调之前必须保持不变的评论的前体。 该条件仅在应用程序需要通知时适用。 但根据我看到的情况、应用程序不会。

    此外、深入探究 USBDCDSendDataEP0本身、 它返回之前在其末尾进行的 USBDEP0StateTx 调用会 检查 pfnDataSent 回调、因此它只是在应用级别进行检查。 这将解释为什么在 USBDEP0StateTx 内部无法找到正在检查的 pfnDataSent 的任何跟踪。

    因此、我认为基于所有这些、没有错误... 只是一些英语不太好(这不是第一次出现在库软件评论中)。

    请告诉我您对此有何看法。