【问题标题】:Data structure for storing serial port data in firmware固件中存储串口数据的数据结构
【发布时间】:2023-04-02 15:43:01
【问题描述】:

我正在通过串行端口将数据从 linux 应用程序发送到嵌入式设备。

在当前的实现中,固件中使用了一个字节循环缓冲区。 (只不过是一个带有读写指针的数组) 随着字节的进入,它被写入循环缓冲区。

现在,PC 应用程序发送数据的速度似乎太快,固件无法处理。字节丢失导致固件返回 WRONG_INPUT 时间过长。

我认为波特率 (115200) 不是问题。固件端更有效的数据结构可能会有所帮助。对数据结构的选择有什么建议吗?

【问题讨论】:

  • 请澄清:嵌入式系统的规格是什么?它以什么时钟频率运行?可以实际执行多少条指令?

标签: c linux serialization data-structures embedded


【解决方案1】:

循环缓冲区是最好的答案。这是在纯软件中对硬件 FIFO 建模的最简单方法。

真正的问题可能是您从 UART 收集字节以放入缓冲区的方式,或者是缓冲区溢出。

在 115200 波特率下,通常有 1 个起始位、1 个停止位和 8 个数据位,您可以看到每秒多达 11520 个字节到达该端口。这使您平均每字节只有大约 86.8 µs 可以使用。在 PC 中,这似乎需要很多时间,但在小型微处理器中,总指令可能不会那么多,或者在某些情况下 I/O 寄存器访问次数可能并不多。如果由于字节的平均到达速度比消耗它们的速度快而导致缓冲区溢出,那么您将遇到错误。

一些一般性建议:

  • 不要执行轮询 I/O。
  • 请使用 Rx Ready 中断。
  • 启用接收 FIFO(如果可用)。
  • 在中断处理程序中完全清空 FIFO。
  • 使环形缓冲区足够大。
  • 考虑流量控制。

设置足够大的环形缓冲区以容纳完整的消息很重要。如果您的协议对消息大小有已知限制,那么您可以使用更高级别的协议来进行流量控制并生存下来,而无需让 XON/XOFF 流量在所有边缘情况或 RTS/CTS 中正常工作的痛苦可以在几乎一样多毛的电线两端按预期工作。

如果你不能使环形缓冲区那么大,那么你将需要某种流量控制。

【讨论】:

  • 我不确定做 IRQ 驱动的接收是否总是:-可用-可取
  • 恕我直言,轮询 IO 很麻烦,因为它要求代码能够及时检查下一个字符。然而,在一个非常小的处理器上,它可能是您唯一的选择。在较大的处理器上,轮询的效率可能远低于使用中断或 DMA。
【解决方案2】:

没有什么比循环缓冲区更好的了。

您可以使用较慢的波特率或加快固件中的应用程序,以便它可以处理全速传输的数据。

如果 PC 的输出是突发的,则可能有助于使缓冲区大到足以处理一次突发。

最后一个选项是实现某种形式的流量控制。

【讨论】:

    【解决方案3】:

    嵌入式设备是什么意思?我认为当前的大多数 DSP 和处理器都可以轻松处理这种负载。问题不在于循环缓冲区,而在于如何从串口收集字节。

    你的 UART 有硬件 fifo 吗?如果是,那么您应该启用它。如果每个字节都有一个中断,那么很快就会遇到麻烦,尤其是在使用操作系统或虚拟内存时,IRQ 成本可能会很高。

    如果您的接收固件非常简单(没有多任务处理),并且您没有硬件 fifo,那么轮询模式可能是比中断驱动更好的解决方案,因为您的处理器只进行 UART 数据接收,而您有没有中断开销。

    另一个问题可能与传输协议有关。例如,如果您有一个长数据包需要校验和,并且您在数据包末尾进行整个校验和,那么数据包的所有处理时间都在它的末尾,这就是您可能会错过的原因下一个数据包的开始。

    所以循环缓冲区很好,你必须改进: - 您与硬件交互的方式 - 协议(数据包长度、确认等...)

    【讨论】:

    • 是的,在替换底层数据结构之前,首先确保这确实是你看到的瓶颈
    【解决方案4】:

    在尝试解决问题之前,首先需要确定问题的真正含义。否则,您可能会浪费时间尝试修复实际上没有损坏的东西。

    如果不了解您的设置,就很难给出更具体的建议。但是您应该进一步调查以确定当字节进入时硬件和软件当前正在做什么,然后它们丢失的弱点是什么。

    【讨论】:

    • 我同意。我在嵌入式应用程序上浪费了太多时间,试图解决实际问题出在其他地方的问题。
    【解决方案5】:

    具有中断驱动 IO 的循环缓冲区将适用于最小和最慢的嵌入式目标。

    首先以最低波特率尝试,然后才以高速尝试。

    【讨论】:

      【解决方案6】:

      将循环缓冲区与 IRQ 结合使用是一个很好的建议。如果您的处理器每次接收到一个字节时都会产生一个中断,则将该字节存储在缓冲区中。您决定如何清空该缓冲区取决于您是在处理数据流还是数据包。如果您正在处理一个流,只需让您的后台进程从缓冲区中删除字节并先进先出处理它们。如果您正在处理数据包,那么只需继续归档缓冲区,直到您有一个完整的数据包。过去我已经成功使用过多次分组方法。如果出现问题(例如缓冲区已满)或数据包处理时间过长,我会实施某种类型的流量控制,以向 PC 发出信号,以指示 PC 何时准备好接收下一个数据包。

      【讨论】:

        【解决方案7】:

        您可以实现 IP 数据报之类的内容,其中包含数据长度、ID 和校验和。

        编辑: 然后,您可以为数据包硬编码一些固定长度,例如 1024 字节或任何对设备有意义的长度。然后,PC 端将在每次写入数据包时检查设备上的队列是否已满。固件端会运行校验和以查看所有数据是否有效,并读取直到数据长度。

        【讨论】:

        • 什么?这如何回答这个问题?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-12
        • 1970-01-01
        • 1970-01-01
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多