![减少微秒抖动(使用实时内核)](https://linux22.com/image/207184/%E5%87%8F%E5%B0%91%E5%BE%AE%E7%A7%92%E6%8A%96%E5%8A%A8%EF%BC%88%E4%BD%BF%E7%94%A8%E5%AE%9E%E6%97%B6%E5%86%85%E6%A0%B8%EF%BC%89.png)
我有一个运行 Gentoo 的树莓派 4B,并应用了 5.15.44 raspi 内核和实时补丁。内核配置为CONFIG_PREEMPT_RT
(大惊喜)以及 , CONFIG_HZ_PERIODIC
, CPU_FREQ_DEFAULT_GOV_PERFORMANCE
(我一时想不起来的其他一些选项),并且 raspi 本身以 1,800 GHz 时钟速度运行。
我要解决的问题如下:
我已将外部设备连接到 raspi 的 GPIO 引脚。该器件使用 1 个引脚作为输入和输出。对于输入和输出,通信的方式是每 4 us(微秒)传输 1 位。低位 (0) 分为 3us 的低信号,随后 1us 的高信号。高位 (1) 分为 1us 的低信号和 3us 的高信号。
外部设备会定期向 raspi 发送 000000001 序列(大约需要 36us),之后预计会返回 64 位的响应。为了读取外部设备的数据,我用 C++ 编写了一个小程序来读取当前引脚状态,并打印出自程序启动以来的微秒时间。
下面是一个示例,其中程序读取正在传输的值 0 的位:
Pin State: 0 | Time Dif: 7365.79
Pin State: 0 | Time Dif: 7365.92
Pin State: 0 | Time Dif: 7366.05
Pin State: 0 | Time Dif: 7366.36
Pin State: 0 | Time Dif: 7366.49
Pin State: 0 | Time Dif: 7366.62
Pin State: 0 | Time Dif: 7366.75
Pin State: 0 | Time Dif: 7366.88
Pin State: 0 | Time Dif: 7367.01
Pin State: 0 | Time Dif: 7367.14
Pin State: 0 | Time Dif: 7367.27
Pin State: 0 | Time Dif: 7367.4
Pin State: 0 | Time Dif: 7367.55
Pin State: 0 | Time Dif: 7367.68
Pin State: 0 | Time Dif: 7367.81
Pin State: 0 | Time Dif: 7367.94
Pin State: 0 | Time Dif: 7368.07
Pin State: 0 | Time Dif: 7368.2
Pin State: 0 | Time Dif: 7368.33
Pin State: 0 | Time Dif: 7368.46
Pin State: 0 | Time Dif: 7368.61
Pin State: 0 | Time Dif: 7368.74
Pin State: 0 | Time Dif: 7368.86
Pin State: 0 | Time Dif: 7368.99
Pin State: 0 | Time Dif: 7369.12
Pin State: 0 | Time Dif: 7369.25
Pin State: 0 | Time Dif: 7369.38
Pin State: 0 | Time Dif: 7369.51
Pin State: 0 | Time Dif: 7369.66
Pin State: 0 | Time Dif: 7369.79
Pin State: 1 | Time Dif: 7369.92
Pin State: 1 | Time Dif: 7370.05
Pin State: 1 | Time Dif: 7370.18
Pin State: 1 | Time Dif: 7370.31
Pin State: 1 | Time Dif: 7370.44
(我应该注意到这一点正在打印后程序已完成执行,而不是在读取这些值期间)
到目前为止,一切都很好。然而,有一个小问题我一直没能弄清楚。程序时不时地会跳过几微秒。在这个用例中这是一个很大的问题,因为这意味着多位信息将丢失:
Pin State: 0 | Time Dif: 7384.2
Pin State: 0 | Time Dif: 7384.33
Pin State: 1 | Time Dif: 7390.4
Pin State: 1 | Time Dif: 7390.53
正如您在这里看到的,它跳跃了几乎 6 微秒,即丢失了 1.5 位信息。如果只是从设备获取轮询请求,这并不是什么大问题,但是当涉及到向其发送信息时,恐怕一切都会变得混乱(设备不执行任何类型的错误纠正)。
现在我的问题是,如何防止这种情况发生?是否有一些我可以设置的内核配置,或者在某个优先级下运行该进程?我尝试过chrt -rr 99 <program>
但没有成功。任何帮助将不胜感激。
答案1
您选择安排节目 SCHED_RR 的做法是正确的。
有了 RT 补丁,我希望 IRQ 能够线程化(以及 SCHED_RR),提高与 GPIO 关联的 IRQ 线程的优先级。
最终,您应该将“程序”固定到一个内核,将 GPIO IRQ 线程固定到另一个内核,并让其他内核执行内务处理。
由于等待需要时间,您可能会忘记打印这些值。将它们记录在一些 tmpfs 文件中以供以后使用。