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.

[参考译文] RTOS/TM4C129CNCZAD:usblib 中的 USBBuffer 根本不考虑溢出

Guru**** 1818760 points
Other Parts Discussed in Thread: EK-TM4C1294XL
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/787139/rtos-tm4c129cnczad-usbbuffer-in-usblib-doesn-t-account-for-overflow-at-all

器件型号:TM4C129CNCZAD
Thread 中讨论的其他器件:EK-TM4C1294XL

工具/软件:TI-RTOS

在开始查看 usblib 中的 usbbuffer.c 中的代码之前、我一直在想知道为什么缓冲 USB 写入会表现异常。  事实证明,虽然缓冲区实现考虑了索引的翻转,但它根本不考虑溢出...就像这样。  也许我刚刚错过了它、但我找不到任何文件中溢出的引用。  也许我缺少一些东西、但这似乎是对缓冲区实现的巨大监督。

我本来应该至少看到一次回调、事件指示缓冲区溢出、这样应用程序就可以记录它并清除缓冲区、因为这就是问题、一旦你在 usblib 中溢出缓冲区实现、 如果不显式调用刷写函数、它似乎无法恢复。  应用程序永远不会发生、因为发生这种情况时不会触发任何事件/回调。  

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

    USB 缓冲区是环形缓冲区、因此溢出不会发生、因此没有这样的实现。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    哈?

    如果您写入的数据多于它能够接收的数据、任何静态大小的缓冲器都可能溢出。 如果我创建一个1024字节的环形缓冲区、并且在多次调用写入函数的过程中写入超过1024字节、则它将无法接受该新数据。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    也许我不看您使用的函数。 函数 USBBufferWrite()返回实际写入的字节数。 如果传输缓冲区中没有足够的空间、则返回的值将小于参数 ui32Length 中传递的值。 下面是 usbbuffer.c 文件第793行至797行中的注释

    //! 尝试发送比传输缓冲区中有更多空间的数据
    //! 将导致写入的字节少于预期。 返回的值
    //! By 函数指示复制到缓冲区的实际字节数。
    //!
    //! 返回实际写入的字节数。
    

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

    环形缓冲器的实现方式是、当它达到1024字节时、它再次从字节0开始。 这就是它的整个概念。 使用环形缓冲器并不能很容易地定义溢出概念、因为它看起来很简单。 如果用于接收新数据的指针位于900字节、并且您已经从0-500读取了数据、并且您又接收了200个字节、那么您应该回路并完全正常。 但是、如果你遇到相同的情况并且没有从0-500读取数据、你会"溢出"-但是你如何知道案例 B 中的案例 A?

    最后、您必须将环形缓冲区设置为足够大以存储数据、直到您可以将其读出、这样您就不会遇到"溢出"情况、 但是、除非您有数据以您可以判断字节是否错误的方式进行排序、否则没有一种简单的方法来定义缓冲区由于端到端而溢出。

    如果您在进行可视化时遇到问题、可能此 Wiki 文章中的图形将会有所帮助: en.wikipedia.org/.../Circular_buffer
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Bob:

    感谢您的介绍、这一点很重要- TivaWare API 旨在提供有关可用缓冲区空间的反馈。 另一个非常有用的 API 是 USBBufferSpaceAvailable。 或接收时、USB 缓冲器数据可用。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    USBBufferWrite 是用于向缓冲区发送数据的 API。 深入探究、我似乎遇到的问题是、当它调用 ScheduleNextTransmission 时。 传输会发生、但随后似乎没有任何内容更新环形缓冲区的索引(在缓冲区已满时再次更新)、因此缓冲区永远不会恢复、并且同一组数据会反复传输、直到有一个显式调用刷新缓冲区。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用用户="Ralph Jacobi]Hello Kaveh、

    环形缓冲器的实现方式是、当它达到1024字节时、它再次从字节0开始。 这就是它的整个概念。 使用环形缓冲器并不能很容易地定义溢出概念、因为它看起来很简单。 如果用于接收新数据的指针位于900字节、并且您已经从0-500读取了数据、并且您又接收了200个字节、那么您应该回路并完全正常。 但是、如果你遇到相同的情况并且没有从0-500读取数据、你会"溢出"-但是你如何知道案例 B 中的案例 A?

    最后、您必须将环形缓冲区设置为足够大以存储数据、直到您可以将其读出、这样您就不会遇到"溢出"情况、 但是、除非您有数据以您可以判断字节是否错误的方式进行排序、否则没有一种简单的方法来定义缓冲区由于端到端而溢出。

    如果您在进行可视化时遇到问题、可能此 Wiki 文章中的图形将会有所帮助: en.wikipedia.org/.../Circular_buffer

    [/报价]

    您好、Ralph、

    谢谢、但我非常熟悉圆形/环形缓冲器的工作原理。  不过、您所说的内容似乎并不正确。  如果您知道 readIndex、writeIndex 和 buffersize、那么通过对 USBBufferWrite 的任何调用、您可以轻松地确定写入的字节数是否为:

    1)超过缓冲器的大小(虽然我不认为是这样、并且缓冲器的大小应该适当)

    2)导致 writeIndex 超过 readIndex (如果需要、考虑在整个缓冲区的长度周围滚动)

    从我到目前为止所读的内容来看、似乎我需要在调用对缓冲区的写入之前检查缓冲区、并在应用程序中考虑其完整性、而不是期望驱动程序执行该操作。   

    此外、我在上一篇文章中提到 的 USBBufferWrite 如何调用 ScheduleNextTransmission 仍然有效。  事实上、ScheduleNextTransmission 函数状态中的最后一条注释

    //
    //尚未更新环形缓冲区读取索引。 我们一旦开始就会执行该操作
    //确保数据包已正确传输。
    // 

    事情是、一旦返回到 USBBufferWrite、下一个操作将从 USBBufferWrite 返回。  当缓冲区已满且空间为零时、索引永远不会更新。  我一定会错过一些东西、因为这似乎永远不会奏效。

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

    正确、我更想解释为什么没有显式溢出标志不是一个缺陷、因为正确处理时、环形缓冲区应该如何工作。 您的初始帖子侧重于缓冲区溢出、这就是为什么我试图解释为什么从概念层面上我们没有这样的实现。

    不管怎样、前后不会帮助解决您的问题、但希望以下信息能让您朝着正确的方向前进。

    关于索引更新所涉及的主题、API 调用将实际处理传输的函数。 如果您是 CDC 器件、则此函数应为 USBDCDCPacketWrite。 API ScheduleNextTransmission 实际上不会发送数据、因此无法更新索引、因为它无法判断数据是否已正确发送。 您将看到 USBDCDCPacketWrite 可以处理此问题。

    现在回顾一下您的第一篇帖子、我想知道您是否设置不正确。 您曾提到将 USB 缓冲器放在 USBCDC 前面、您能详细说明一下您在尝试做什么吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    直接调用 USBDCDCPacketWrite 有效。 不过、根据 usblib 用户指南、应该可以将这个函数进行缓冲、并为为缓冲区创建的`tUSBBuffer`实例指定该写入函数为`pfnTransferFxn`。

    USBDCDCPacketWrite 不依赖于 usbbuffer.c 中的任何内容、因此我不知道它如何知道它未使用的环型缓冲器的 writeIndex/readIndex。 在 usbbuffer.c 周围搜索时、我更有可能会错过一个代码路径来调用`USBRingBufAdvanceRead`、在这里、readIndex 实际上会被更新。

    是否有一个文档大致描述了此库的工作原理? 我正在关注 spmu297d、虽然它通常非常有用、但它似乎与当前实施的情况略有不同、因此我想知道我是否只是错过了一些东西。

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

    您好 Kaveh、

    您可能缺少的链接随 USB 结构应用程序文件一起提供。

    正确配置的传输缓冲区如下所示:

    //
    //
    ///发送缓冲区(从 USB 角度)。
    ////
    *****************
    uint8_t g_pui8USBTxBuffer[UART_buffer_size];
    tUSBBuffer g_sTxBuffer =
    {
    对、 //这是一个发送缓冲区。
    TxHandler、 // pfnCallback
    (void *)&g_sCDCDevice、 //回调数据是我们的器件指针。
    USBDCDCPacketWrite、 // pfnTransfer
    USBDCDCTxPacketAvailable、 // pfnAvailable
    (void *)&g_sCDCDevice、 // pvHandle
    G_pui8USBTx 缓冲器、 // pui8Buffer
    UART_buffer_size、 // ui32BufferSize
    }; 

    然后、 USBBufferInit (&g_sTxBuffer);API 会将此信息传递到 USB 库的缓冲区部分、并允许使用 USB 缓冲区调用、然后在 usbbuffer 文件中的 psBuffer->pfnTransfer 调用中的任何位置进行类似 USBDCDCPacketWrite 的调用。

    这就是使用 USBBuffer API 时 TivaWare 示例的设置方式。

    如果您想查看 EK-TM4C1294XL 上单个 CDC 端口的 TivaWare 示例、这是一个我在一段时间前就放在一起的项目-注释并非全部是最新的、但功能是: e2e.ti.com/.../0640.usb_5F00_dev_5F00_cdcserial.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、这就是我的设置方式。 这似乎不是根本原因。

    具体地说、您的示例显示 USB 用户指南已过期、因为它将`tUSBBuffer`声明为`const`、然后继续在其中使用`USBBufferInit()`、这会导致崩溃、因为库中尝试在 Init 函数中修改该数据。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Kaveh、

    感谢您的介绍、我将了解我们是否可以在用户指南中更新该内容。

    我一直在思考你的情况、但我还没有给出解释。 为了进行调试、您是否可以尝试使用我之前提到的 API 检查缓冲区状态、如 USBBufferSpaceAvailable? 此外、当您观察到问题时、能否检查 USBBufferWrite 的返回值、并将其与从 USBBufferSpaceAvailable 获得的信息进行比较? 也许这些实验将帮助我们找到根本原因。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我认为我发现了这个问题。   tUSBDCDCDevice 类型具有回调(pfnRxCallback 和 pfnTxCallback) 、通常会设置为应用提供的 Rx 和 Tx 处理程序。  我需要从 usblib 提供一个指向 USBBufferEventCallback 的指针、以便这些回调能够正确连接所有内容。  不知怎么说、我早些时候错过了这个。

    静态 tUSBDCDCDevice logDevice ={
    ui16VID = USB_VID_TI_1CBE、
    ui16PID = USB_PID_COMP_serial、
    ui16MaxPowermA = 0、
    ui8PwrAttributes = USB_CONF_ATTR_self_PWR、
    
    .pfnControlCallback =&LogControlCallback、
    .pvControlCBData =&logDevice、
    .pfnRxCallback =&USBBufferEventCallback、
    .pvRxCBData =(void*)&logRxBuffer、
    .pfnTxCallback =&USBBufferEventCallback、
    .pvTxCBData =(void*)&logTxBuffer、
    
    .ppui8StringDescriptionors =字符串描述符、
    .ui32NumStringDescriptionors = STRINGDESCROIPTORSCOUNT
    、}; 

    感谢您的响应。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    啊,是的,可以这样做! 我没有意识到您使用的是不同的结构格式、所以没有考虑询问这件事。 TI-RTOS 结构基本上直接从 TivaWare IIRC 中获取。 无论如何、很高兴您发现了此问题、并感谢您更新解决方案!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    、还有一个问题。 似乎 usblib 中的 USBBuffer.c 函数在操作缓冲区时未禁用中断(仅更新索引除外)。 在实现这些缓冲器时、TI 在这里考虑的预期用例是什么? 如果您有多个线程尝试写入它、您可能无法保证缓冲区中的项目顺序、或者无法中断与缓冲区的某些事务。

    我想、如果我足够调整 USB 缓冲区的大小、我不需要使用邮箱机制、但是如果我对 usblib 代码的解释中没有遗漏任何内容、我不认为可以。  提供的缓冲区是否只是为了在 USB 上提供64字节有效载荷大小的简单方法?

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

    我不是 USB 库的开发人员、因此我对编码背后的思想过程没有第一手的了解、但鉴于该库是为 TM4C MCU 设计的、TM4C MCU 是单核器件、 在 RTOS 系统的普及之前设计、我相信没有任何设计意图让它支持您描述的多线程情况。

    就支持比简单 USB 器件更复杂的接口而言、USB 库更适合支持多个管道、从而使 TM4C 能够用作复合器件、而不是任何器件。