[英]Data structure for storing serial port data in firmware
我将数据从Linux应用程序通过串口发送到嵌入式设备。
在当前实现中,在固件中使用字节循环缓冲器。 (只有带有读写指针的数组)当字节进入时,它被写入循环缓冲区。
现在,PC应用程序似乎发送数据的速度太快,无法让固件处理。 错过字节,导致固件返回WRONG_INPUT太多次。
我认为波特率(115200)不是问题。 固件端更有效的数据结构可能会有所帮助。 有关数据结构选择的任何建议吗?
循环缓冲区是最佳答案。 这是在纯软件中建模硬件FIFO的最简单方法。
真正的问题可能是您从UART收集字节以放入缓冲区的方式,或者是该缓冲区的溢出。
在115200波特率下,通常的1个起始位,1个停止位和8个数据位,您可以看到每秒多达11520个字节到达该端口。 这使得每个字节平均可以使用大约86.8μs。 在PC中,这似乎需要很多时间,但在一个小型微处理器中,它可能不是那么多的总指令,或者在某些情况下可能是非常多的I / O寄存器访问。 如果你的缓冲区溢出,因为字节的平均到达速度比你可以消耗的速度快,那么你就会有错误。
一些一般建议:
调整环形缓冲区的大小足以容纳完整的消息非常重要。 如果你的协议已经知道了消息大小的限制,那么你可以使用更高级别的协议进行流量控制,并且能够在没有让XON / XOFF流程在所有边缘情况下正常工作的情况下生存,或者RTS / CTS在电线的两端按预期工作,这几乎可以像毛茸茸一样。
如果你不能使环形缓冲区那么大,那么你将需要某种流量控制。
没有比循环缓冲区更好的了。
您可以使用较慢的波特率或加速固件中的应用程序,以便它可以处理全速数据。
如果PC的输出处于突发状态,则可能有助于使缓冲区足够大以处理一个突发。
最后一个选项是实现某种形式的流控制。
嵌入式设备是什么意思? 我认为目前大多数DSP和处理器都可以轻松处理这种负载。 问题不在于循环缓冲区,而是如何从串行端口收集字节。
你的UART有硬件fifo吗? 如果是,那么你应该启用它。 如果每个字节有一个中断,则很快就会遇到麻烦,特别是如果您正在使用操作系统或虚拟内存,其中IRQ成本可能会很高。
如果您的接收固件非常简单(没有多任务处理),并且您没有硬件fifo,则轮询模式可能是比中断驱动更好的解决方案,因为那时您的处理器只进行UART数据接收,并且您没有中断开销。
另一个问题可能是传输协议。 例如,如果您有长数据包需要校验和,并且您在数据包末尾执行整个校验和,那么数据包的所有处理时间都在它的末尾,这就是您可能错过的原因下一个数据包的开头。
所以循环缓冲区很好,你必须改进: - 你与硬件交互的方式 - 协议(数据包长度,确认等...)
在尝试解决问题之前,首先需要确定问题的真正原因。 否则你可能会浪费时间来修复一些实际上没有破坏的东西。
如果不了解您的设置,很难提供更具体的建议。 但是你应该进一步调查以确定当字节进入时硬件和软件当前正在做什么,然后它们将丢失的弱点是什么。
将循环缓冲区与IRQ结合使用是一个很好的建议。 如果处理器在每次接收到一个字节时产生一个中断,则取该字节并将其存储在缓冲区中。 如何决定清空缓冲区取决于您是否正在处理数据流或数据包。 如果您正在处理流,只需让后台进程从缓冲区中删除字节并先进先处理它们。 如果您正在处理数据包,那么只需继续填充缓冲区,直到您有一个完整的数据包。 我过去曾多次成功使用过数据包方法。 我会实现某种类型的流量控制,如果出现问题(例如完整缓冲区)或者数据包处理时间很长,以便在准备好下一个数据包时向PC指示,则向PC发出信号。
具有中断驱动IO的循环缓冲区将适用于最小和最慢的嵌入式目标。
首先以最低波特率尝试,然后再尝试高速。
您可以实现类似IP数据报的内容,其中包含数据长度,ID和校验和。
编辑 :然后你可以硬编码一些固定长度的数据包,例如1024字节或任何对设备有意义的。 然后,PC端将在每次写入数据包时检查设备上的队列是否已满。 固件端将运行校验和以查看是否所有数据都有效,并读取直到数据长度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.