# dtof驱动移植
最近在玩一款dToF传感器TMF8821,接口是I2C,现在将这款传感器的驱动移植到RV1106G3下面。
内核模块
rv1106使用的是5.10.160
内核版本。TMF8821提供linux官方驱动TMF882x_Driver_Linux_v3.56.zip 内核模块。
GitHub上面有其他公司修改后的版本:https://github.com/brainlab-vied/tmf8820_21_28_driver_linux
修改Makefile
,设置好ARCH
和交叉编译器路径
KDIR:=/home/bruce/Documents/luckfox-pico/sysdrv/source/kernel
PWD?=$(shell pwd)
MAKE := make
ARCH := arm
CROSS_COMPILE := /home/bruce/Documents/luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-
KBUILD_OUTPUT := $(abspath $(dir $(lastword $(KDIR))))/objs_kernel
ifneq ($(KERNELRELEASE),)
include Kbuild
else
all:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KDIR) M=$(PWD) modules
modules:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KDIR) M=$(PWD) $@
sign:
$(SIGN_SCRIPT) sha512 $(LINUX_SRC)/signing_key.priv $(LINUX_SRC)/signing_key.x509 $(DEVICE_NAME).ko
clean:
$(MAKE) -C $(LINUX_SRC) M=$$PWD clean
endif
直接编译有错误
make CONFIG_SENSORS_TMF882X=m
make ARCH=arm CROSS_COMPILE=/home/bruce/Documents/luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf- -C /home/bruce/Documents/luckfox-pico/sysdrv/source/kernel M=/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56 modules
make[1]: Entering directory '/home/bruce/Documents/luckfox-pico/sysdrv/source/kernel'
CC [M]/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.o
In file included from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_host_interface.h:36,
from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_mode_app.h:39,
from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_interface.h:38,
from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:57:
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_shim_linux_kernel.h: In function 'tof_get_timespec':
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_shim_linux_kernel.h:89:5: error: implicit declaration of function 'getnstimeofday'; did you mean 'getname_flags'? [-Werror=implicit-function-declaration]
getnstimeofday(ts);
^~~~~~~~~~~~~~
getname_flags
In file included from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_interface.h:38,
from /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:57:
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_mode_app.h: At top level:
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_mode_app.h:228:25: error: field 'timestamp' has incomplete type
struct timespec timestamp;
^~~~~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c: In function 'tof_ram_patch_callback':
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:12: error: variable 'start_ts' has initializer but incomplete type
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:33: error: excess elements in struct initializer [-Werror]
struct timespec start_ts = {0}, end_ts = {0};
^
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:33: note: (near initialization for 'start_ts')
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:21: error: storage size of 'start_ts' isn't known
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:12: error: variable 'end_ts' has initializer but incomplete type
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:47: error: excess elements in struct initializer [-Werror]
struct timespec start_ts = {0}, end_ts = {0};
^
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:47: note: (near initialization for 'end_ts')
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:37: error: storage size of 'end_ts' isn't known
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2276:17: error: implicit declaration of function 'timespec_sub'; did you mean 'timespec64_sub'? [-Werror=implicit-function-declaration]
fwdl_time = timespec_sub(end_ts, start_ts).tv_nsec / 1000000;
^~~~~~~~~~~~
timespec64_sub
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:37: error: unused variable 'end_ts' [-Werror=unused-variable]
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~
/home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.c:2250:21: error: unused variable 'start_ts' [-Werror=unused-variable]
struct timespec start_ts = {0}, end_ts = {0};
^~~~~~~~
cc1: all warnings being treated as errors
make[2]: *** [scripts/Makefile.build:273: /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56/tmf882x_driver.o] Error 1
make[1]: *** [Makefile:1935: /home/bruce/Documents/ams_tmf8820_linux_driver_src_v3.56] Error 2
make[1]: Leaving directory '/home/bruce/Documents/luckfox-pico/sysdrv/source/kernel'
make: *** [Makefile:16: all] Error 2
编译失败的主要原因是 Linux 内核 API 的兼容性问题。具体来说,驱动代码中使用了较旧的内核 API(如 getnstimeofday
和 timespec
),而这些 API 在新版本的内核中已经被弃用或修改。
需要修改源代码
struct timespec ts;
getnstimeofday(&ts);
替换成
struct timespec64 ts;
ktime_get_real_ts64(&ts);
代码中使用了 struct timespec
,需要将其替换为 struct timespec64
修改 tmf882x_shim_linux_kernel.h
:
#include <linux/time64.h>
static inline void tof_get_timespec(struct timespec64 *ts) {
ktime_get_real_ts64(ts);
}
相关变量都修改好,再次编译成功。可以看到在当前目录下成功生成了tmf882x.ko
内核模块。
修改设备树
根据开发板接线图,准备使用i2c3
。
修改sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-max.dts
,使能i2c3
,添加节点tmf8821
,添加gpio控制引脚。GPIO1_C6接ENABLE引脚,高电平有效。GPIO1_C7接irq引脚,下降沿有效。
&i2c3 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c3m1_xfer>;
clock-frequency = <100000>;
tmf8821: tmf8821@41 {
compatible = "ams,tmf882x";
status = "okay";
reg = <0x41>;
enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>;
irq-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio1>;
interrupts = <RK_PC7 IRQ_TYPE_EDGE_FALLING>;
};
};
编译重新烧录开发板。
加载firmware
tmf8821传感器上电后需要加载固件才能进入app运行模式,将官方提供的hex文件放到开发板/lib/firmware/tmf882x_firmware.bin
。注意:这里必须将官方提供的.hex
文件重命名为tmf882x_firmware.bin
,不要转换hex文件。我刚开始用工具将hex文件转换成bin
文件加载一直无法启动。
加载运行
将上面编译好的tmf882x.ko
,官方提供的设备固件tmf882x_firmware.bin
下载到设备中
运行
insmod tmf882x.ko
成功启动设备
总结
通过在RV1106上集成tmf8821,了解了linux下i2c和gpio中断驱动开发的一些基本知识,并且对RV1106软件构架有了一些认识。