目前在研究一个高精度 IMU ,接口是 GPIO 和 422 串口,数据率每秒 500 帧。现在要读取数据以及数据的精确时刻用来同步,正在用一个 ARM 板读取数据,GPIO 已经写了一个内核模块来抓取同步信号时刻了,运行 Ok ,现在 Uart 这边不知道怎么搞,看了半天内核文档还是有点懵。
初步感觉最简单的是要写一个新的 tty line discipline 模块来接数据帧和时刻,但是考虑 tty 到 ldisc 存在延迟。又不想去重新写 uart driver ,这里都是 dma 和寄存器,而且和芯片强相关。又看到 low level serial api, 但是没什么例子可以参考。所以想问问这样内核模块怎么写?
PS:不要吐槽为啥不用单片机,是真不会单片机。
1
XiaoJSoft 2023-02-16 21:50:22 +08:00 1
这种需求感觉对接 TTY 的接口不太合适诶,而且也不知道具体是谁家的 SoC ,这种给出具体建议其实有点费劲...
不过既然是 Arm 的话,要不这样,在 UART RX 的 ISR 里面记一下 SysTick 定时器的值,中断优先级看看能不能调高点,DMA 也可以先不管,直接在 RX 中断里面把 FIFO 全读了,和时间戳一起存到自己维护的 Ring Buffer 里面,想办法通知用户空间来取数据( Watch queue?) 要是不想自己搞 ringbuf ,那就参考 TUN/TAP 或者 SocketCAN ,模拟一个网络设备,只不过这样的话就得把数据包分帧的这部分逻辑怼到 ko 里了... |
2
anytk OP @XiaoJSoft 感谢回复。
这样就复杂了,就是不大想涉及 uart 驱动部分,只是想着在内核态把能做的数据分帧打时间戳都做了,然后甩给用户态程序处理。就想知道 tty/uart 这个驱动层面能不能像 gpio 那样,直接写给模块注册 irq 中断,可以在最接近硬件数据到达的时刻,用系统时钟打上时间戳。明天先试试注册 ldisc 的方式试试看。 |
3
Licsber 2023-02-16 22:48:20 +08:00 1
真实时数据感觉我更喜欢 FPGA 可以看看 GNU Radio 的一些代码 应该有这部分的处理吧 具体没深究过
|
4
duke807 2023-02-17 00:21:46 +08:00 via Android 1
不会单片机建议学单片机,推荐 stm32g 系列
单片机打好时间戳再发给 linux 不用 mcu 的话,也可以找大小核的 cpu ,小核当 mcu 跑高实时任务,譬如君正 x1600 cpu 另外提一下,我实时 linux 会用 cdbus 这样的数据包(硬件控制器的数据包在内存占用不超过 256 字节),代替 char 型的 tty ,为了实时性整个数据不走 tty 层,驱动直接和用户空间互传数据块。 更高实时性要求,pc 我会接自己的 cdbus 的 pcie 卡,嵌入式会接 spi 接口的 cdbus 控制器,linux 驱动和用户空间直接内存共享,避免数据包重复拷贝。 不改硬件的话,楼主可以自己改串口控制器的驱动,不走 tty 层,驱动直接按块传数据给用户空间,我曾经这么干过,当时内核打过 preemt-rt 补丁。 |
5
XiaoJSoft 2023-02-17 01:50:05 +08:00 1
@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 的噩梦 ...) |
6
xsen 2023-02-17 08:17:19 +08:00 1
每秒 500 帧,那就是 20ms ,那也只能都在内核态做,可以定制一个 422 的驱动,把 gpio 的抓取同步信号加进去
类似是 422 接口+额外的 gpio 口,属于一种非标准的 422 接口,要实现就是这么一个驱动 通过别的方式,如楼上提的 gpio 、422 单独设备(驱动)这种复杂,而且 20ms 还不一定能够保证 其实,最简单的方式就是用个 mcu 来做 |
7
anytk OP |
8
villivateur 2023-02-17 08:46:19 +08:00
@anytk
这个用单片机裸写就能解决的事,反正你也得学内核模块编写,不如直接去学一下单片机。会软件开发的人一两天就能上手,很简单的,实在不行先用 Arduino 做。 当然如果要改硬件方案的话,还是死磕内核模块编程吧。 |
9
elmagnificogg 2023-02-17 23:41:22 +08:00
可能我孤陋寡闻,IMU 的接口是 GPIO 和串口?? 不保密的话,能说一下名字吗,很奇怪啊
正常至少也得是一个 SPI 或者 I2C 吧? 如果是串口的话,因为这个比较简单,ARM 上这个驱动应该是开源的,很容易就能看到底层实现了。 串口驱动应该是很简单的,应该就是开了个缓冲器,然后用 DMA 去读串口数据,然后搬运到你的缓冲里,最后被外部驱动或者应用读走数据 如果想要非常准的同步的话,建议直接用中断串口,不用 DMA ,DMA 由于要搬运,其实也要花时间 |
10
anytk OP @elmagnificogg 不是小的 mems ,型号霍尼韦尔 4930 ,一大坨那种。我是考虑要跟 soc uart 实现隔离一下,换 soc 方案源码可以基本不改。最终要求精度在百微秒级就差不多了,再高就得上单片机了。
|