Linux · 2024-09-19

树莓派编译 CH348 驱动的一点问题

CH348 芯片的主要功能和特点

  1. 高速传输:内置单片机高速 480Mbps USB 收发器和控制器。
  2. 单口高集:各串口内部置独立收发 FIFO,支持高达 6Mbps 波特率。
  3. 双电源设计:串口 IO 电压支持 3.3V/2.5V/1.8V(默认 3.3V)。
  4. 多功能:集成了 UART、Modem 信号、GPIO 和 RS485 发射使能等功能。
  5. USB 配置功能:支持 USB 设备描述符、供应商 ID、产品 ID、串号等配置。
  6. 驱动提供:支持 Windows、Linux、Android、macOS 等操作系统。
  7. 封装:提供 LQFP100 和 LQFP48 封装。
  8. TTM(Time To Market):快速上市时间。
  9. 技术支持:提供产品手册、驱动与应用软件、参考设计、芯片与评估板等技术支持资源。
  10. 兼容操作系统:支持 Windows、Linux、Android 和 macOS 操作系统。

在树莓派上编译驱动时遇到了一点问题,记录一下。

Linux 驱动库开源在 https://github.com/WCHSoftGroup/ch9344ser_linux。

编译驱动

按照 README 中的方法进行编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ch9344 linux serial driver

## Description

This driver supports USB to quad serial ports chip ch9344 and USB to octal serial ports chip ch348.

1. Open “Terminal”
2. Switch to “driver” directory
3. Compile the driver using “make”, you will see the module “ch9344.ko” if successful
4. Type “sudo make load” or “sudo insmod ch9344.ko” to load the driver dynamically
5. Type “sudo make unload” or “sudo rmmod ch9344.ko” to unload the driver
6. Type “sudo make install” to make the driver work permanently
7. Type “sudo make uninstall” to remove the driver
8. You can refer to the link below to acquire uart application, you can use gcc or Cross-compile with cross-gcc
https://github.com/WCHSoftGroup/tty_uart

Before the driver works, you should make sure that the usb device has been plugged in and is working properly, you can use shell command “lsusb” or “dmesg” to confirm that, USB VID of these devices are [1A86], you can view all IDs from the id table which defined in “ch9344.c”.

If the device works well, the driver will created tty devices named “ttyCH9344USBx” in /dev directory.

## Note

Any question, you can send feedback to mail: tech@wch.cn

大概率会遇到找不到指定路径的问题。

打开 driver 目录下的 Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CONFIG_MODULE_SIG=n

ifeq ($(KERNELRELEASE), )
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
clean:
rm -rf *.mk .tmp_versions Module.symvers *.mod.c *.o *.ko .*.cmd Module.markers modules.order *.a *.mod
load:
insmod ch9344.ko
unload:
rmmod ch9344
install: default
insmod ch9344.ko || true
mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true
cp -f ./ch9344.ko /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true
depmod -a
uninstall:
rmmod ch9344 || true
rm -rf /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ch9344.ko || true
depmod -a
else
obj-m := ch9344.o
endif

问题应该是出在 KERNELDIR 这里了,不同的 Linux 发行版,源码头文件安装位置不太一样,并且很多发行版默认是不安装源码的,所以需要手动安装下。

在树莓派上,可以使用以下命令安装:

1sudo apt-get install raspberrypi-kernel-headers

在树莓派上编译内核模块,需要知道你的树莓派的内核版本,并且需要有对应版本的内核源代码。可以通过以下命令获取内核版本:

1uname -r

树莓派的源码是安装在 /usr/src 目录下的,所以需要修改 Makefile 中的 KERNELDIR 为 /usr/src/linux-headers-$(shell uname -r)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CONFIG_MODULE_SIG=n

ifeq ($(KERNELRELEASE), )
# 需要根据你的实际情况修改路径
KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)
PWD := $(shell pwd)

default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

这个 Makefile 首先尝试使用环境变量 KERNELDIR,如果没有设置,就使用 /usr/src/linux-headers-$(shell uname -r)$(shell uname -r) 会被替换为你的内核版本。

default 目标会编译你的内核模块,clean 目标会清理编译生成的文件。

注意,你可能需要使用 sudo 来运行 make 命令,因为编译内核模块通常需要管理员权限。

不是所有的 Linux 发行版都会默认设置 KERNELDIR 这个环境变量。实际上,KERNELDIR 通常不会被默认设置,它通常在编译内核或内核模块时,由用户或脚本显式设置。

在 Linux 系统中,你可以使用 echo 命令来查看环境变量的值。如果你想查看 KERNELDIR 环境变量,你可以在终端中输入以下命令:

1echo $KERNELDIR

这将会打印出 KERNELDIR 环境变量的值。如果这个环境变量没有被设置,那么这个命令将不会输出任何内容。

在 Makefile 中,KERNELDIR 被用作一个变量,代表内核源代码的位置。如果没有在环境中设置这个变量,需要在 Makefile 中提供一个默认值,或者在调用 make 命令时,通过命令行参数提供这个值。

例如,你可以在 Makefile 中提供一个默认值:

1KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)

或者在调用 make 命令时,通过命令行参数提供这个值:

1make KERNELDIR=/usr/src/linux-headers-$(uname -r)

然后再次按照 README 中的方法执行剩下的步骤应该就可以正常加载驱动了。