Raspberry Pi是否可以可靠地使9600波特序列发生爆炸,并且有示例代码?


29

我想知道使用bitbanging通过Raspberry Pi上的GPIO引脚驱动9600波特串行的可行性。

显然,Linux不是一个非常好的位敲打平台,因为有大量的驱动程序和其他中断可能会长时间阻塞CPU(1-10毫秒)。但是,这种情况最近变得越来越好,现在内核中已定期启用某些抢占。我还怀疑实时修补的内核可以轻松地在Raspberry Pi上使用,并且可以仔细选择连接的硬件和驱动程序。

我的可靠性标准是,大多数情况下,它应保持在正常的9600波特串行容差范围内。我目前不确定在实践中可以容忍多少错误,但是协议中存在重传和确认,因此至少可以容忍。

因此,我的问题是:

  • Userland软件能否可靠地提高9600波特率?
  • 这是否需要实时修补的内核?
  • 我一般应该期望多少个错误?

此外,是否有任何示例代码通过GPIO位敲打进行串行处理?我知道Arduino SoftSerial,但仅此而已。

以防万一,为了限制这个问题:这不是标准的串行接口,并且Raspberry Pi的UART已经用于另一个串行链接。我既不希望提出建议使用外部硬件(例如Gertboard或Arduino)的答案,也不希望依赖于UART的答案。


1
+1好问题。我也将对此答案感兴趣。但是,问题reliability可能取决于行动和期望。
Jivings 2012年

2
RS-232需要负电压,但是此串行链路不使用RS-232电压。我不知道,但我相信RPi需要标准的TTL到RS-232转换器,例如MAX232或数十种选择中的任何一种。但是,需要明确的是,这与我的问题无关,我只是想回答。
赤裸裸的2012年

4
GPIO引脚14和15上还有第二个UART。尽管功能不如主要功能
强大


1
@Nakedible您能分享您的作品吗?我有一个类似的问题,想看看您如何通过spi做第二个串行。感谢MSP

Answers:


15

我终于解决了这个问题,但是以一种非常非常规的方式。由于过于可靠,我放弃了位冲击,并试图找到其他解决方案,这些解决方案使我能够在不增加硬件的情况下实现同一目标。我当时正在考虑编写一个内核驱动程序,该驱动程序将在GPIO上触发一个中断,然后将该引脚重新配置为SPI,并使用SPI读取整个数据字节-但是我有了一个更好的主意。

我使用SPI以20倍的波特率对线路进行采样。我完全忽略了SCLK和SS引脚,将RX线连接到MISO,将TX线连接到MOSI。这给了我一个类似于RX线的(1位)示波器视图,并清楚地看到了串行线中正在传输的位:

00 00 00 00 00 00 
00 00 00 00 01 FF 
FF FF FF FF 00 00 
01 FF FF FF FF FF 
FF FF E0 00 00 00 
00 00 07 FF FF FF 
FF FF 

由此,只需进行编码即可找出从中采样实际数据位的正确位置。发送端也同样琐碎,我只需要将每个字节转换为包含起始位和停止位的长位流即可。

它比位敲打更好的原因是SPI有自己的时钟,不会与内核冻结,并且SPI发送和接收线具有16字节的FIFO用于传输,这也与内核冻结无关。对于9600波特,我使用的是250kHz的SPI时钟,这意味着我可以在填充和耗尽FIFO之间睡眠甚至一毫秒,而不会发生任何传输错误。但是,为了安全起见,我正在使用300 µs的睡眠时间。我简短地测试了我可以将其推进多远,并且至少仍可以使用2MHz的SPI时钟,因此该解决方案也可以扩展到更高的波特率。

该解决方案的一个丑陋部分是内核SPI驱动程序不支持这种流式传输位。这意味着我无法通过使用内核SPI驱动程序编写自己的内核模块来执行此操作,并且也无法通过在用户域中使用/dev/sdidev0.0来执行此操作。但是,在Raspberry Pi上,可以通过mmap():n / dev / mem直接从用户域访问SPI和其他外围设备,而完全绕开了内核控制。我对此并不满意,但是它可以完美地工作,它还带来了一个额外的好处,即用户域中的分段错误不会使内核崩溃(除非偶然与其他外设弄乱了)。至于CPU的使用,300 µs的睡眠似乎可以持续为我提供约7%的CPU使用率,但是我的代码不是很理想。延长睡眠时间显然会直接降低CPU使用率。

编辑:忘了提一下,我使用了不错的bcm2835库来从用户区控制SPI,并在需要时进行扩展。

因此,总而言之:通过在Raspberry Pi上以250kHz的频率/ kHz / dev / mem直接使用SPI芯片我可以完全从用户域可靠地在9600波特串行链路上进行发送和接收。


@Nakedible-您能否在mmap()部分进行详细说明或提供链接。我正在做同样的事情。
杰伊·K

您是否也在使用SPI硬件进行发送?
猎豹

是的,传输也可以。
赤裸裸的

3
如果您使用自己修补的内容,可以请逐步说明如何发送和接收代码,以及共享任何修改的软件包... TIA!
2014年

10

看起来,至少没有实时补丁(CONFIG_PREEMPT_RT),Raspberry Pi无法可靠地对9600波特序列进行位冲击。

我使用了一个简单的等待时间测试器,该测试器以最佳方式配置了所有Linux方面的东西(sched_fifo,优先级99,cpu_dma_latench 0us,mlockall)。我尝试休眠100微秒(大约9600波特),并在安静的系统上检查2分钟的延迟超限。结果是:

最小:12微秒平均:24微秒最大:282微秒

这似乎是常见的结果。在较慢的测量中,最大值在100微秒和300微秒之间变化。我还检查了分布,似乎绝大多数都在24微秒范围内。只有少数超过50微秒,但几乎总是有些。有时还会有巨大的延迟,例如4000微秒,但这些延迟现在至少很少被忽略。

我想9600波特的最大延迟应低于50微秒,以免出错,而任何超过100微秒的延迟都将导致传输或接收完全丢失。

这一切都还没有触及GPIO引脚。由于即使只有2秒钟我也无法正常运行,因此可以肯定地说,如果没有实时修补程序,Raspberry Pi不会在9600波特串行链接上产生任何严重的错误。

如果有时间,我将稍后测试实时补丁。

(使用的工具:http : //git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary

更新:如果使用CONFIG_PREEMPT_RT补丁集进行编译,则RPi内核会在启动时挂起,而不会检测到SD卡。修复起来可能很简单,但是看到RPi源代码中凌乱的差异,我想我要等到更多的代码进入主线内核。

因此,测试这太困难了,我放弃了。


0

您无需大呼小叫。您可以在rx gpio中设置一个用户登陆中断,以检测起始位的下降。然后设置一个时间中断以在这些位的中间进行采样。这样做的内核模块是可行的。


但这仍然有些打击。确实,这就是您通常会撞的方式。
Philippos
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.