内核模块读取 uart 数据

2023-02-16 21:08:04 +08:00
 anytk

目前在研究一个高精度 IMU ,接口是 GPIO 和 422 串口,数据率每秒 500 帧。现在要读取数据以及数据的精确时刻用来同步,正在用一个 ARM 板读取数据,GPIO 已经写了一个内核模块来抓取同步信号时刻了,运行 Ok ,现在 Uart 这边不知道怎么搞,看了半天内核文档还是有点懵。

初步感觉最简单的是要写一个新的 tty line discipline 模块来接数据帧和时刻,但是考虑 tty 到 ldisc 存在延迟。又不想去重新写 uart driver ,这里都是 dma 和寄存器,而且和芯片强相关。又看到 low level serial api, 但是没什么例子可以参考。所以想问问这样内核模块怎么写?

PS:不要吐槽为啥不用单片机,是真不会单片机。

1835 次点击
所在节点    Linux
10 条回复
XiaoJSoft
2023-02-16 21:50:22 +08:00
这种需求感觉对接 TTY 的接口不太合适诶,而且也不知道具体是谁家的 SoC ,这种给出具体建议其实有点费劲...
不过既然是 Arm 的话,要不这样,在 UART RX 的 ISR 里面记一下 SysTick 定时器的值,中断优先级看看能不能调高点,DMA 也可以先不管,直接在 RX 中断里面把 FIFO 全读了,和时间戳一起存到自己维护的 Ring Buffer 里面,想办法通知用户空间来取数据( Watch queue?)
要是不想自己搞 ringbuf ,那就参考 TUN/TAP 或者 SocketCAN ,模拟一个网络设备,只不过这样的话就得把数据包分帧的这部分逻辑怼到 ko 里了...
anytk
2023-02-16 22:24:45 +08:00
@XiaoJSoft 感谢回复。
这样就复杂了,就是不大想涉及 uart 驱动部分,只是想着在内核态把能做的数据分帧打时间戳都做了,然后甩给用户态程序处理。就想知道 tty/uart 这个驱动层面能不能像 gpio 那样,直接写给模块注册 irq 中断,可以在最接近硬件数据到达的时刻,用系统时钟打上时间戳。明天先试试注册 ldisc 的方式试试看。
Licsber
2023-02-16 22:48:20 +08:00
真实时数据感觉我更喜欢 FPGA 可以看看 GNU Radio 的一些代码 应该有这部分的处理吧 具体没深究过
duke807
2023-02-17 00:21:46 +08:00
不会单片机建议学单片机,推荐 stm32g 系列

单片机打好时间戳再发给 linux

不用 mcu 的话,也可以找大小核的 cpu ,小核当 mcu 跑高实时任务,譬如君正 x1600 cpu

另外提一下,我实时 linux 会用 cdbus 这样的数据包(硬件控制器的数据包在内存占用不超过 256 字节),代替 char 型的 tty ,为了实时性整个数据不走 tty 层,驱动直接和用户空间互传数据块。
更高实时性要求,pc 我会接自己的 cdbus 的 pcie 卡,嵌入式会接 spi 接口的 cdbus 控制器,linux 驱动和用户空间直接内存共享,避免数据包重复拷贝。

不改硬件的话,楼主可以自己改串口控制器的驱动,不走 tty 层,驱动直接按块传数据给用户空间,我曾经这么干过,当时内核打过 preemt-rt 补丁。
XiaoJSoft
2023-02-17 01:50:05 +08:00
@duke807
其实仔细说来 OP 的要求确实有点很难全方位达到
比如加个 MCU 当下位机这事,确实是理论上最好的解决方案了,但 MCU 也得算钱啊,而且还得改 Layout 、BOM ,除非一开始做硬件的时候就想到了。
我是觉得 UART 这类 Peripheral 的控制器接口基本上没啥太复杂的,自己重新按照芯片手册写个驱动大概不会特别耗费时间,不过 OP 看起来确实不想碰这些鬼东西。当然做得再好一点可以直接 Map 一块空间让 Peripheral 直接 DMA 数据过去,做 zero copy ,不过这个就更复杂了,大概可以不用考虑了。
----
不过话说回来... OP 只是想要个 422 物理层上的通信协议啊,这玩意儿撑死 10M ,搞个便宜点的 MCU 来弄这事看起来还是更合适的...
(... 回想起了做 Modbus RTU 时那 1.5/3.5 char time 的噩梦 ...)
xsen
2023-02-17 08:17:19 +08:00
每秒 500 帧,那就是 20ms ,那也只能都在内核态做,可以定制一个 422 的驱动,把 gpio 的抓取同步信号加进去
类似是 422 接口+额外的 gpio 口,属于一种非标准的 422 接口,要实现就是这么一个驱动

通过别的方式,如楼上提的 gpio 、422 单独设备(驱动)这种复杂,而且 20ms 还不一定能够保证

其实,最简单的方式就是用个 mcu 来做
anytk
2023-02-17 08:34:59 +08:00
最简单的确是 MCU 来做,但是不大想去碰了,本来我也一直以来都做 Linux 应用开发,偶尔需要才小改改 BSP 而已。

不想去重写 uart driver,一部分是硬件 /寄存器 /DMA 这些的确一点经验没有,另外一方面是这部分跟 SOC 强绑定,后面再移植到其他 SOC 又需要改动。我的设想是在 uart driver 和 tty driver/ tty core 这两层,有没有办法获取到数据中断,在这里面处理数据。

今天先试试看,感谢楼上各位回复。
@xsen @duke807 @Licsber @XiaoJSoft
villivateur
2023-02-17 08:46:19 +08:00
@anytk
这个用单片机裸写就能解决的事,反正你也得学内核模块编写,不如直接去学一下单片机。会软件开发的人一两天就能上手,很简单的,实在不行先用 Arduino 做。
当然如果要改硬件方案的话,还是死磕内核模块编程吧。
elmagnificogg
2023-02-17 23:41:22 +08:00
可能我孤陋寡闻,IMU 的接口是 GPIO 和串口?? 不保密的话,能说一下名字吗,很奇怪啊
正常至少也得是一个 SPI 或者 I2C 吧?
如果是串口的话,因为这个比较简单,ARM 上这个驱动应该是开源的,很容易就能看到底层实现了。
串口驱动应该是很简单的,应该就是开了个缓冲器,然后用 DMA 去读串口数据,然后搬运到你的缓冲里,最后被外部驱动或者应用读走数据
如果想要非常准的同步的话,建议直接用中断串口,不用 DMA ,DMA 由于要搬运,其实也要花时间
anytk
2023-02-18 09:42:12 +08:00
@elmagnificogg 不是小的 mems ,型号霍尼韦尔 4930 ,一大坨那种。我是考虑要跟 soc uart 实现隔离一下,换 soc 方案源码可以基本不改。最终要求精度在百微秒级就差不多了,再高就得上单片机了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/916769

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX