11

我正在尝试通过 SPI 在一侧的微控制器和另一侧的多核 TI 芯片上的 ARM 处理器之间设计一种有效的通信协议。

所需协议的要求:

1 - 支持排队的多会话,因为我有多个发送/接收线程,所以将有多个应用程序使用此通信协议,我需要该协议来处理这些请求的排队(如果传输,我将继续保留缓冲区是队列,但我只需要协议来管理调度队列)。

2 - 通过 SPI 作为底层协议工作。

3 - 简单的错误检查。

在这个线程:“简单的串行点对点通信协议”中,PPP 是一个推荐的选项,但是我看到 PPP 只完成了部分工作。

我还发现了具有 PPP over serial 的轻量级 IP (LwIP) 项目(我假设我可以通过 SPI 使用它),所以我考虑了利用 TCP/UDP 等任何上层协议来完成其余工作的可能性所需的工作。幸运的是,我发现 TI 将 LwIP 作为其以太网软件的一部分包含在 starterware 包中,我认为这至少可以简化 TI 芯片方面的移植。

所以,我的问题是:

1 - 在这种通信方案中使用 LwIP 是否有效?由于点对点(芯片级)通信不需要的 IP 标头,这不会引入太多开销并杀死吞吐量吗?

2 - 驻留在 LwIP 中的 TCP 或任何类似协议是否会处理传输请求的排队,例如,如果我在通信通道忙于发送/接收另一个线程的另一个套接字(会话)的请求时通过套接字请求传输,这会由协议栈管理?如果是这样,哪个协议层管理它?

3 - 它们是比 LwIP 更有效的协议栈,满足上述要求吗?

更新 1:要考虑的更多要点

1 - SPI 是唯一可用的选项,我将它与可用的 GPIO 一起使用,以便在从机有数据要发送时向主机指示。

2 - 当前实现的(非标准)协议使用带有SPI的DMA,消息格式为《STX_MsgID_length_payload_ETX》,消息片段长度固定,但当前方案的主要缺点是主机等待消息的响应(不是片段)在发送另一个之前,这会杀死吞吐量并且不利用 SPI 的全双工特性。

3- 对这一点的改进是使用一种邮箱来接收碎片,因此长消息可以被更高优先级的消息打断,这样单个消息的碎片可以非顺序到达,但问题是这种设计导致使事情复杂化,特别是我没有太多可用资源供许多缓冲区使用控制器(主)端的邮箱方法。所以我认为这就像我通过为可能效率不高的简单点对点链接设计一个协议栈来重新发明轮子一样。

4- SPI之上一般可以使用什么样的更高级的协议来建立多个会话并解决消息的排队/调度?

更新 2:另一个有用的线程“嵌入式设备的良好串行通信协议/堆栈?

更新3:我看了一下Modbus协议,它似乎指定了应用层,然后直接指定了数据链路层进行串行线路通信,这听起来可以跳过面向网络的协议层的不必要开销。

对于预期目的,您认为这会比 LwIP 更好吗?此外,是否有像 LwIP 这样广泛使用的开源实现,但适用于 Modbus?

4

2 回答 2

4

我认为也许您对不起眼的 SPI 期望过高。

SPI 链路只是每个节点中的一对移位寄存器。主机选择单个节点连接到其 SPI 移位寄存器。当它移入数据时,从机同时移出数据。除非主机明确将数据输出时钟,否则不会交换数据。SPI 上的高效协议涉及从机在主机输入时输出有用的东西。这可能很难安排,因此您通常需要一种指示空数据的方法。

当在两个任意端点之间建立连接时,PPP 很有用,当端点是固定的并且先验已知时,PPP 除了使事情变得不必要地复杂化之外没有其他用途。

SPI 不是一个非常复杂也不灵活的接口,可能不适合 TCP/IP 等重量级通用协议。由于 SPI 上的“寻址”是通过物理芯片选择执行的,因此此类协议中固有的寻址是没有意义的。

流量控制也是 SPI 的一个问题。在推送更多数据之前,主设备无法确定从设备是否已将数据从 SPI 复制到移位寄存器。如果您的从属 SPI 支持 DMA,您最好使用它。

无论哪种方式,我建议您开发一些特定于您的目的的东西。由于 SPI 本身不是一个网络,因此您只需要一种方法来寻址所选节点上的线程。这可能很简单STX<thread ID><length><payload>ETX

2013 年 9 月 27 日添加以回应评论 通常 SPI 顾名思义用于连接外围设备,在这种情况下,协议由外围设备定义。例如,EEPROMS 通常使用跨供应商的通用或至少兼容的命令接口,而 SD/MMC 卡 SPI 接口使用标准化的命令测试和协议。

在两个微控制器之间,我想大多数实现都是专有的和特定于应用程序的。开放协议是为通用互操作性而设计的,实现这一点可能会给封闭系统带来大量不必要的开销,除非节点运行的系统可能已经内置了网络堆栈。

我建议如果您确实想使用通用网络堆栈,您应该在每一端使用设备驱动程序抽象 SPI,这些设备驱动程序为 SPI 提供标准 I/O 流接口(open()、close()、read()、 write() 等),那么您可以使用更高级别的 PPP 和 TCP/IP 协议(​​尽管可能可以避免使用 PPP,因为连接是永久的)。然而,只有当两个节点都支持这些协议(例如运行 Linux)时,这才会有吸引力,否则这将是巨大的努力和代码,但收益甚微,而且肯定不会“高效”。

于 2013-09-24T18:32:17.497 回答
1

我假设您真的不想要或没有空间在微控制器上放置完整的 ip (lwip) 堆栈?这听起来有点矫枉过正。为什么不直接滚动您自己的简单数据包结构来移动您需要移动的数据项。根据双方对 spi 的支持方式,您可能会或可能无法使用它来定义数据的帧,如果不是简单的开始模式、长度和尾随校验和,也许尾部模式就足以找到数据包边界流(与串行/uart 解决方案没有什么不同)。您甚至可以将 PPP 解决方案与开始模式一起使用,我认为每当开始模式恰好出现在数据中时,使用两字节模式的有效负载结束模式。我现在不记得所有的细节了。

无论你的帧是什么,然后添加一个数据包类型和你的握手,或者如果数据只是微控制器来武装,那么你甚至不需要这样做。

回到你的直接问题。是的,我认为 ip 堆栈(lwip 或其他)会引入很多开销。带宽和更重要的是支持该堆栈所需的代码量都会消耗双方的 rom/ram。如果您最终需要以 ip 方式(由嵌入式系统托管的网站)呈现此数据,那么在路径中的某个位置您需要一个 ip 堆栈等。

我无法想象 lwip 会为您管理您的队列。我想你需要自己做。各种队列可能希望与处理单个 spi 总线的单个驱动程序通信(假设有一个具有多个芯片选择的单个 spi 总线)。它还取决于您如何使用 spi 接口,如果您允许 arm 与多个微控制器通信,并且数据包从该控制器分解成一点点,从该控制器分解成一点点,这样就没有人需要等待早在他们获得更多字节的数据之前。或者一个完整的帧是否必须从一个微控制器移动,然后才能移动到下一个 gpio 中断以提取那些数据?总而言之,我假设您必须像在任何其他有多个共享资源用户(rtos、成熟的操作系统等)的情况下一样管理共享资源。我根本不记得lwip,但是使用完整的伯克利套接字应用程序接口,用户可以编写单独的应用程序,其中每个应用程序只关心一个TCP或UDP端口,并且库和驱动程序管理将这些数据包分离到每个应用程序以及IP 堆栈的所有规则。

如果您还没有在 spi 接口上移动数据进行实验,我将首先从简单的实验开始,只是为了了解它是否有效,每个 spi 可以可靠地进行传输的大小交易等。您的解决方案自然可能会从这些实验中脱颖而出。

于 2013-09-25T04:26:34.560 回答