固件中用于存储串口数据的数据结构

5
我正在将数据从Linux应用程序通过串口发送到嵌入式设备。
目前的实现在固件中使用了一个字节循环缓冲区(只是带有读写指针的数组)。当字节进入时,它被写入循环缓冲区。
现在PC应用程序似乎以太快的速度发送数据,导致固件错过了一些字节,从而导致固件返回WRONG_INPUT太多次。
我认为波特率(115200)不是问题。在固件端使用更有效的数据结构可能会有所帮助。对于数据结构的选择有什么建议吗?

1
请说明嵌入式系统的规格是什么?它运行在多大的时钟频率下?实际上可以执行多少条指令? - none
7个回答

13

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

实际问题可能是从UART收集字节并放入缓冲区的方式,或者缓冲区溢出。

以115200波特率、通常的1起始位、1停止位和8数据位为例,可以看到每秒钟会有多达11520个字节到达该端口。这给你平均约86.8微秒的每个字节的处理时间。在PC中,这将看起来像是很多时间,但在小型微处理器中,它可能不是总指令数很多,或者在某些情况下非常多的I/O寄存器访问。如果因为字节平均到达速度比你消耗的速度更快而导致缓冲区过满,那么就会产生错误。

一些通用建议:

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

设置足够大的环形缓冲区来容纳完整的消息非常重要。如果您的协议对消息大小有已知的限制,那么您可以使用更高级别的协议来进行流控制,并且可以在不必处理所有边缘情况下生存,例如让XON/XOFF流量正常工作,或者使RTS/CTS在两端的预期方式中工作,这几乎同样棘手。

如果不能使环形缓冲区那么大,则需要某种形式的流控制。


我不确定使用IRQ驱动的接收始终是可行的或理想的。 - shodanex
1
在我看来,轮询IO很麻烦,因为它要求代码能够及时检查下一个字符。但在真正小的处理器上,这可能是您唯一的选择。在较大的处理器上,轮询可能比使用中断或DMA效率低得多。 - RBerteig

1

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

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

如果PC的输出是突发性的,则将缓冲区大小调整为足以处理一个突发可能会有所帮助。

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


1

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

你的UART是否有硬件FIFO?如果有,那么你应该启用它。如果每个字节都有一个中断,你可能会很快陷入麻烦,特别是如果你正在使用操作系统或虚拟内存,在这些情况下IRQ成本可能会很高。

如果你的接收固件非常简单(没有多任务),并且你没有硬件FIFO,则轮询模式可能比中断驱动模式更好,因为此时你的处理器只进行UART数据接收,而没有中断开销。

另一个问题可能与传输协议有关。例如,如果你有一长段数据包需要校验和,而你在数据包末尾进行整个校验和计算,那么整个数据包的处理时间都在末尾,这就是为什么你可能会错过下一个数据包的开头。

因此,循环缓冲区很好,你需要改进的是: - 与硬件交互的方式 - 协议(数据包长度、确认等)


是的,在替换底层数据结构之前,请确保这确实是您所看到的瓶颈。 - none

1
在尝试解决问题之前,首先需要确定问题的真正原因。否则,您可能会浪费时间尝试修复实际上并没有损坏的东西。
如果不了解有关您的设置的更多信息,则很难提供更具体的建议。但是,您应该进一步调查以确定当字节进入时硬件和软件当前正在执行什么操作,然后是它们丢失的弱点。

我同意。我在嵌入式应用程序上浪费了太多时间,试图修复实际问题在别处的情况。 - guzelo

0

在IRQ中使用循环缓冲区是一个很好的建议。如果您的处理器每次接收到一个字节时生成一个中断,请将该字节存储在缓冲区中。如何决定清空该缓冲区取决于您是否正在处理数据流或数据包。如果您正在处理数据流,只需让后台进程从缓冲区中删除字节并按先进先出的顺序处理它们即可。如果您正在处理数据包,则只需继续填充缓冲区,直到您拥有完整的数据包。我过去已经成功地使用了数据包方法。我还会实现某种类型的流量控制,以便在发生诸如缓冲区已满或数据包处理时间长等问题时向PC发出信号,并在准备好下一个数据包时向PC指示。


0
一个带有中断驱动IO的循环缓冲区可以在最小和最慢的嵌入式目标上运行。
首先以最低波特率尝试,然后再尝试高速传输。

-2
你可以实现类似于IP数据报的东西,其中包含数据长度、ID和校验和。 编辑: 然后,您可以为数据包硬编码一些固定长度,例如1024字节或任何对设备有意义的长度。PC端每次写入数据包时都会检查设备上的队列是否已满。固件端将运行校验和以查看所有数据是否有效,并读取到数据长度为止。

什么?这怎么回答问题了? - Matthew Flaschen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接