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

时间:2009-06-13 08:00:29

标签: c linux serialization data-structures embedded

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

在当前实现中,固件中使用字节循环缓冲区。 (只有带有读写指针的数组) 当字节进入时,它被写入循环缓冲区。

现在,PC应用程序似乎发送的数据太快,无法由固件处理。错过字节,导致固件返回WRONG_INPUT太多次。

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

7 个答案:

答案 0 :(得分:13)

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

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

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

一些一般性建议:

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

调整环形缓冲区大小以容纳完整的消息非常重要。如果你的协议已经知道了消息大小的限制,那么你可以使用更高级别的协议进行流量控制,并且能够在没有让XON / XOFF流程在所有边缘情况下正常工作的情况下生存,或者RTS / CTS在电线的两端按预期工作,这几乎可以像毛茸茸一样。

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

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:1)

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

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

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

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

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

答案 3 :(得分:1)

在尝试解决问题之前,首先需要确定问题的真正原因。否则你可能会浪费时间来修复一些实际上没有破坏的东西。

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:-2)

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

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