项目上需要用到树莓派CM4,驱动XR21V1414芯片,树莓派版本是2021-05-07-raspios-buster-armhf-full,XR21V1414是USB转4路串口芯片。
当将XR21V1414连接树莓派的USB口后,会自动识别成ttyACM0、ttyACM1、ttyACM2、ttyACM3,此时打开任意串口,并进行读写操作,可以成功,但当发送到几十次后就会卡主,再也无法读写。而且经过测量发现实际数据并没有发出来,TX,RX上均没有电平变化。出现这个问题的原因是树莓派内置的驱动是cdc-acm,实际无法驱动XR21V1414芯片,需要更新驱动。
从官方网站上找到驱动,根据自己板子的内核版本来选择驱动版本,可以用uname -a来查看内核版本号,比如我自己的板子
可以看到我的是5.10版本,需要驱动支持3.6以上版本即可
也就是这一条,下载之后放到板子上,直接解压,并进入板子,用make指令编译,即可得到驱动包xr_usb_serial_common.ko。此时还不能直接加载驱动,因为系统本身还有cdc-acm驱动,需要卸载掉之后才行,因此需要先执行卸载,再加载命令
sudo rmmod cdc-acm
sudo insmod ./xr_usb_serial_common.ko
此时,查看dev下设备,即可看到 ttyXRUSB0、 ttyXRUSB1、 ttyXRUSB2、 ttyXRUSB3这4个设备,这时就可以进行正常收发操作。
事情到后面又发生了变化,因为树莓派更新了系统,在21年11月之后,发布的2021-10-30-raspios-bullseye-armhf-full版本,内核变成了5.15, 此时再重复以上操作,就会出错,首先是进入驱动文件进行make操作时,会提示找不到build文件
pi@raspberrypi:/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak $ make
make -C /lib/modules/5.15.32-v8+/build M=/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak
make[1]: *** /lib/modules/5.15.32-v8+/build: No such file or directory. Stop.
make: *** [Makefile:9: all] Error 2
此时需要加载kernel的build文件,使用以下命令
sudo apt install raspberrypi-kernel-headers
pi@raspberrypi:/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak $ sudo apt install raspberrypi-kernel-headers
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
raspberrypi-kernel-headers
0 upgraded, 1 newly installed, 0 to remove and 14 not upgraded.
Need to get 9675 kB of archives.
After this operation, 60.6 MB of additional disk space will be used.
Get:1 http://archive.raspberrypi.org/debian bullseye/main arm64 raspberrypi-kernel-headers arm64 1:1.20220331-1 [9675 kB]
Fetched 9675 kB in 6s (1602 kB/s)
apt-listchanges: Can't set locale; make sure $LC_* and $LANG are correct!
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = "en_US.UTF-8",
LC_ALL = "en_US.UTF-8",
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Selecting previously unselected package raspberrypi-kernel-headers.
(Reading database ... 99103 files and directories currently installed.)
Preparing to unpack .../raspberrypi-kernel-headers_1%3a1.20220331-1_arm64.deb ...
Unpacking raspberrypi-kernel-headers (1:1.20220331-1) ...
Setting up raspberrypi-kernel-headers (1:1.20220331-1) ...
pi@raspberrypi:/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak $
执行完成后,/lib/modules/5.15.32-v8+/路径下即可看到build文件夹,此时重新make编译驱动,会发现编译报错
pi@raspberrypi:/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak $ sudo make
make -C /lib/modules/5.15.32-v8+/build M=/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak
make[1]: Entering directory '/usr/src/linux-headers-5.15.32-v8+'
CC [M] /mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.o
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2019:17: error: initialization of 'unsigned int (*)(struct tty_struct *)' from incompatible pointer type 'int (*)(struct tty_struct *)' [-Werror=incompatible-pointer-types]
2019 | .write_room = xr_usb_serial_tty_write_room,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2019:17: note: (near initialization for 'xr_usb_serial_ops.write_room')
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2026:21: error: initialization of 'unsigned int (*)(struct tty_struct *)' from incompatible pointer type 'int (*)(struct tty_struct *)' [-Werror=incompatible-pointer-types]
2026 | .chars_in_buffer = xr_usb_serial_tty_chars_in_buffer,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2026:21: note: (near initialization for 'xr_usb_serial_ops.chars_in_buffer')
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c: In function 'xr_usb_serial_init':
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2040:29: error: implicit declaration of function 'alloc_tty_driver' [-Werror=implicit-function-declaration]
2040 | xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS);
| ^~~~~~~~~~~~~~~~
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2040:27: warning: assignment to 'struct tty_driver *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
2040 | xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS);
| ^
/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.c:2057:3: error: implicit declaration of function 'put_tty_driver' [-Werror=implicit-function-declaration]
2057 | put_tty_driver(xr_usb_serial_tty_driver);
| ^~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:277: /mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak/xr_usb_serial_common.o] Error 1
make[1]: *** [Makefile:1868: /mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.15.32-v8+'
make: *** [Makefile:9: all] Error 2
pi@raspberrypi:/mnt/Work/driver_64/xr_usb_serial_common_lnx-3.6-and-newer-pak $
这个报错是因为系统内核变化了,5.15版本以后不支持put_tty_driver和alloc_tty_driver,已经更换成tty_driver_kref_put和tty_alloc_driver,所以要进入代码文件进行修改,另外xr_usb_serial_tty_write_room函数和xr_usb_serial_tty_chars_in_buffer函数也需要修改,把定义函数时的int改为unsigned int,修改完成后(xr21v1414驱动,支持3.6-5.15版本)即可正常编译,得到ko文件,后面的操作就跟前面一样了。