TMF8821 dToF 项目总结报告
项目背景
本项目基于2024年艾迈斯欧司朗竞赛,旨在将TMF8821直接飞行时间(dToF)传感器集成到瑞芯微RV1106G3平台上,并开发一款简易的角度测算工具。通过将板卡固定并与平面保持一定夹角,程序能够测算出板卡与平面之间的夹角和垂直最小距离。
项目目标
- 硬件集成:将TMF8821 dToF传感器成功集成到RV1106G3平台。
- 软件开发:开发一个简易的角度测算工具,能够实时计算板卡与屏幕之间的夹角和垂直距离。
- 性能优化:确保系统稳定运行,并优化算法以提高测量精度。
硬件介绍
TMF8821 dToF传感器
TMF8821是一款直接飞行时间(dToF)传感器,采用单一模组封装,配备VCSEL(垂直腔面发射激光器)。该传感器利用SPAD(单光子雪崩二极管)、TDC(时间数字转换器)和直方图技术,实现了最大5000 mm的检测范围。TMF8821支持3×3、4×4和3×6多区输出数据,并具有动态可调的视场角(FoV)。所有数据处理均在片上进行,通过I2C接口提供距离信息和置信度值。
RV1106G3处理器
RV1106G3是一款专为人工智能应用设计的高度集成IPC视觉处理器SoC。基于单核ARM Cortex-A7 32位内核,集成了NEON和FPU,内置NPU支持INT4/INT8/INT16混合运算,计算能力高达1TOPS。RV1106G3还配备了全新的硬件ISP(图像信号处理器),支持多种算法加速器,如HDR、3A、LSC、3DNR等。开发板支持多种接口,包括GPIO、UART、SPI、I2C、USB等,便于快速开发和调试。
项目设计思路
方案框图
- 硬件连接:TMF8821通过I2C接口与RV1106G3连接,GPIO引脚用于控制传感器的使能和中断信号。
- 软件流程:
- 初始化TMF8821传感器并加载固件。
- 通过I2C读取传感器的距离数据。
- 根据距离数据计算板卡与屏幕之间的夹角和垂直距离。
- 输出计算结果并进行实时显示。
实际接线图
软件流程图
- 初始化:加载内核模块,配置设备树,初始化TMF8821传感器。
- 数据采集:通过I2C接口读取传感器的距离数据。
- 数据处理:根据采集到的距离数据,计算夹角和垂直距离。
- 结果输出:将计算结果输出到终端或显示设备。
关键代码介绍
内核模块
内核模块的编译和加载是项目的基础。通过修改Makefile和设备树,成功将TMF8821驱动集成到RV1106G3平台。
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),)
#kbuild part of Makefile
include Kbuild
else
#normal Makefile
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
设备树配置
设备树配置中,启用了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>; // GPIO1_C6 enable
irq-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; // GPIO1_C7 irq
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
成功启动设备
测试
设备成功初始化后默认会关闭测量,进入低功耗状态。进入以下文件夹,打开设备,进入正常的测量状态。
cd /sys/bus/i2c/devices/i2c-3/3-0041
# 手动打开设备
echo 1 > chip_enable
一旦TMF882X注册成功,TMF882X会注册标准的Linux input设备
查看/proc/bus/input/devices
文件可以获取到系统中注册的所有输入设备相关的信息,如下所示:
[root@luckfox app]# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="adc-keys"
P: Phys=adc-keys/input0
S: Sysfs=/devices/platform/adc-keys/input/input0
U: Uniq=
H: Handlers=kbd event0
B: PROP=0
B: EV=3
B: KEY=c0000 0 0 0
I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="tmf882x"
P: Phys=
S: Sysfs=/devices/platform/ff460000.i2c/i2c-3/3-0041/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=9
B: ABS=3ff
编写C语言测试程序
#include "ams/tmf882x.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
struct input_event in_ev = {0};
int fd;
// cat /proc/bus/input/devices
// /devices/platform/ff460000.i2c/i2c-3/3-0041/input/input1
fd = open("/dev/input/event1", O_RDONLY);
if (fd < 0) {
perror("open error");
exit(-1);
}
while (1)
{
if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) {
perror("read error");
exit(-1);
}
printf("type:%d code:%d value:%d\n", in_ev.type, in_ev.code, in_ev.value);
}
close(fd);
return 0;
}
已知三角形的两条边和夹角,可计算出第三条边。使用最近比较火的deepseek搜索计算方法
数据分析
type:3 code:6 value:12715503
type:3 code:7 value:5637566
type:3 code:8 value:7079289
type:0 code:0 value:0
type:3 code:1 value:3540985
type:3 code:2 value:5834647
type:3 code:3 value:1377967
type:3 code:4 value:2426319
type:3 code:5 value:4588905
type:3 code:6 value:2819379
type:3 code:7 value:3999051
type:3 code:8 value:5768423
type:3 code:9 value:5834050
type:3 code:1 value:1247611
type:3 code:2 value:1640725
type:3 code:3 value:4327255
type:3 code:4 value:7079565
type:3 code:5 value:14550566
测试程序
根据以上三角形的计算公式,编写C语言测试程序,读取TMF8821传感器的数据,并计算夹角和垂直距离。
#include "ams/tmf882x.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <linux/input.h>
#include <math.h>
#define DEFAULT_ANGLE 60.0
static float calculateDistance(uint16_t a, uint16_t b, uint8_t gamma) {
float gamma_rad = gamma * M_PI / 180.0;
float c = sqrt(a * a + b * b - 2 * a * b * cos(gamma_rad));
float S = 0.5 * a * b * sin(gamma_rad);
float h = (2 * S) / c;
return h;
}
static void calculateAngles(float a, float b, float gamma, float *alpha, float *beta) {
float gamma_rad = gamma * M_PI / 180.0;
float c = sqrt(a * a + b * b - 2 * a * b * cos(gamma_rad));
*alpha = asin((a * sin(gamma_rad)) / c);
*beta = M_PI - *alpha - gamma_rad;
}
int main(int argc, char *argv[])
{
uint16_t dis_array[9] = {0};
struct input_event in_ev = {0};
char buf[128];
int fd;
// cat /proc/bus/input/devices
fd = open("/dev/input/event1", O_RDONLY);
if (fd < 0) {
perror("open event1 error");
exit(-1);
}
while (1)
{
if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) {
perror("read error");
exit(-1);
}
if (in_ev.type == EV_ABS) {
int pos = 0;
uint16_t channel = in_ev.code;
uint32_t value = in_ev.value;
uint8_t confidence = (value >> 16) & 0xFF;
uint16_t distance = value & 0xFFFF;
if (channel < 9 && confidence > 150) {
dis_array[channel] = distance;
float angle[2];
float max;
float real_angle;
float a = dis_array[1];
float b = dis_array[2];
if (a > 0 && b > 0) {
calculateAngles(a, b, DEFAULT_ANGLE, &angle[0], &angle[1]);
angle[0] = angle[0]*180.0/M_PI;
angle[1] = angle[1]*180.0/M_PI;
if (angle[0] > angle[1]) {
max = angle[0];
} else {
max = angle[1];
}
real_angle = max - (180 - DEFAULT_ANGLE) / 2;
float min_dis = calculateDistance(a, b, DEFAULT_ANGLE);
printf("%.1f,%.1f -> %.1f, %.1f\n", angle[0], angle[1], real_angle, min_dis);
}
}
}
}
close(fd);
return 0;
}
测试与数据分析
通过测试程序,成功读取了TMF8821传感器的距离数据,并计算出了板卡与屏幕之间的夹角和垂直距离。测试结果表明,系统能够稳定运行,并且测量结果具有较高的精度。
总结
本项目成功将TMF8821 dToF传感器集成到RV1106G3平台,并开发了一款简易的角度测算工具。通过硬件和软件的协同工作,实现了与板卡夹角和垂直距离的实时测量。未来可以进一步优化算法,提高测量精度,并扩展更多功能。