我想知道使用bitbanging通过Raspberry Pi上的GPIO引脚来驱动9600波特串行的可行性。驱动程序和其他中断的数量,可能会长时间阻塞CPU(1-10毫秒)。但是,这种情况最近变得越来越好,现在内核中已定期启用某些抢占。我还怀疑实时修补的内核可以很容易地在Raspberry Pi上使用,并且可以仔细选择连接的硬件和驱动程序。大多数情况下,串行容差。我目前不确定在实践中可以容忍多少错误,但是协议中存在重传和确认,因此至少可以容忍。 >
Userland软件能否可靠地提高9600波特率?
是否需要实时修补的内核? >此外,是否有任何示例代码通过GPIO位敲打进行串行处理?我知道Arduino SoftSerial,但仅此而已。

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

评论

+1好问题。我也将对此答案感兴趣。但是,可靠性问题可能取决于操作和期望。

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

GPIO引脚14和15上还有第二个UART。虽然功能不如主要功能完整

zh.wikipedia.org/wiki/Bit_banging

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

#1 楼

我终于解决了这个问题,但是以一种非常非常规的方式。由于过于可靠,我放弃了位冲击,并试图找到其他解决方案,这些解决方案使我能够在不增加硬件的情况下实现同一目标。我当时正在考虑编写一个内核驱动程序,该驱动程序将在GPIO上触发一个中断,然后将该引脚重新配置为SPI,并使用SPI读取整个数据字节-但是我有了一个更好的主意。使用SPI以20倍的波特率对线路进行采样。我完全忽略了SCLK和SS引脚,将RX线连接到MISO,将TX线连接到MOSI。这给了我一个类似于RX线的(1位)示波器视图,并清楚地看到了串行线中正在传输的位:

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

之所以比位敲打更好,是因为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频率通过/ dev / mem直接使用SPI芯片,可以完全从用户域可靠地在9600波特串行链路上进行发送和接收。

评论


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

–周杰伦
13年5月17日下午4:47

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

–猎豹
2013年6月6日23:34

是的,传输也可以。

–可以裸体
13年6月17日在8:26

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

–valentt
2014年4月19日在17:35

#2 楼

看起来,至少没有实时补丁(CONFIG_PREEMPT_RT),Raspberry Pi无法可靠地对9600波特序列进行位冲击。 (sched_fifo,优先级99,cpu_dma_latench 0us,mlockall)。我尝试休眠100微秒(大约9600波特),并在安静的系统上检查2分钟的延迟超限。结果为:

最小值:12 µsec
平均:24 µsec
最大值:282 µsec

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

我想最大延迟应在50微秒以下,以便9600波特不出错并且任何超过100微秒的等待时间都会导致传输或接收中完全丢失一点。由于即使只有2秒钟我也无法正常运行,因此可以肯定地说,如果没有实时补丁,Raspberry Pi不会在不产生任何严重错误的情况下使9600波特串行链接发生故障。 >
如果时间允许,我将稍后测试实时补丁。 git / clrkwllms / rt-tests.git; a =摘要)

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

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

#3 楼

您不需要位爆炸。
您可以在rx gpio中设置用户登陆中断,以检测起始位的下降。
然后设置时间中断以在中断中间进行采样位。
一个可行的内核模块。

评论


但这仍然有些令人震惊。确实,这就是您通常会撞的方式。

– Philippos
17-10-24在13:55