我通过串口将数据从linux应用程序发送到嵌入式设备。
在当前实现中,固件中使用字节循环缓冲区。 (只有带有读写指针的数组) 当字节进入时,它被写入循环缓冲区。
现在,PC应用程序似乎发送的数据太快,无法由固件处理。错过字节,导致固件返回WRONG_INPUT太多次。
我认为波特率(115200)不是问题。固件端更有效的数据结构可能会有所帮助。有关数据结构选择的任何建议吗?
答案 0 :(得分:13)
循环缓冲区是最佳答案。这是在纯软件中建模硬件FIFO的最简单方法。
真正的问题可能是你从UART收集字节放入缓冲区的方式,或者是缓冲区的溢出。
在115200波特率下,通常的1个起始位,1个停止位和8个数据位,您可以看到每秒多达11520个字节到达该端口。这使得每个字节平均可以使用大约86.8μs。在PC中,这似乎需要很多时间,但在一个小型微处理器中,它可能不是那么多的总指令,或者在某些情况下可能是非常多的I / O寄存器访问。如果你的缓冲区溢出,因为字节的平均到达时间比你消耗它们的速度快,那么你就会有错误。
一些一般性建议:
调整环形缓冲区大小以容纳完整的消息非常重要。如果你的协议已经知道了消息大小的限制,那么你可以使用更高级别的协议进行流量控制,并且能够在没有让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端将在每次写入数据包时检查设备上的队列是否已满。固件端将运行校验和以查看所有数据是否有效,并读取直到数据长度。