tof 测距
准备工作
- tof 连接 soc 的 4个脚的原理图:
- i2c地址: VL53L1 默认地址是 0x52(8-bit) VL53L1 文档里有写,但 Linux 的 /dev/i2c-* 使用 7-bit 地址,所以你应该用 0x29 // 7-bit 地址 = 0x52 >> 1 = 0x29
-
# i2c ============= 测试 # 软件复位 i2ctransfer -y 0 w2@0x29 0x00 0x00 w1@0x29 0x01 sleep 0.1 # 检查 ID i2ctransfer -y 0 w2@0x29 0x01 0x0f r1@0x29 # 启动测距 i2ctransfer -y 0 w2@0x29 0x00 0x80 w1@0x29 0x01 sleep 0.1 # 读结果 i2ctransfer -y 0 w2@0x29 0x00 0x89 r17@0x29 # i2c ============= 或者读取整个: i2cdetect -y 0
-
开发
- 找到4个对应的寄存器地址, 然后设置为相应的功能(2个设置为 gpio , 2个设置为 i2c )

c 语言配置 引脚模式代码
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> // 读取设备ID寄存器: i2cget -y 0 0x52 0x00 ; i2cget -y 0 0x29 0x00 // 扫描i2c总线0: i2cdetect -y 0 // i2cget -y 0 0x29 0x00 w → 0x2901 /* // 复位: echo 46 > /sys/class/gpio/export # 导出 GPIO46(对应 GPIO5_6) echo out > /sys/class/gpio/gpio46/direction # 设置为输出 echo 0 > /sys/class/gpio/gpio46/value # 先拉低(确保进入复位) sleep 0.1 echo 1 > /sys/class/gpio/gpio46/value # 再拉高(释放复位) sleep 0.1 i2cdetect -y 0 # 1. 软件复位 i2ctransfer -y 0 w2@0x29 0x00 0x00 w1@0x29 0x01 sleep 0.1 # 2. 检查 ID i2ctransfer -y 0 w2@0x29 0x01 0x0f r1@0x29 # 应返回 ea # 3. 启动测距(写 0x01 到 0x80) i2ctransfer -y 0 w2@0x29 0x00 0x80 w1@0x29 0x01 sleep 0.1 # 4. 检查 data ready (0x93) 这一步一直是 0 说明芯片没启动 → 需要完整初始化。 i2ctransfer -y 0 w2@0x29 0x00 0x93 r1@0x29 */ #define PAGE_SIZE (4096) #define REG_SCL_ADDR 0x0102F0140UL #define REG_SDA_ADDR 0x0102F013CUL #define REG_RST_ADDR 0x0102F0068UL #define REG_INT_ADDR 0x0102F006CUL #define REG_BASE(addr) ((addr) & ~(PAGE_SIZE - 1)) // 计算页对齐的基地址 #define REG_OFFSET(addr) ((addr) & (PAGE_SIZE - 1)) // 计算寄存器在页内的偏移 int set_addr_v(){ int fd; volatile unsigned int *mapped_base; unsigned int reg_val; fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd == -1) {perror("Error: Cannot open /dev/mem. Run as root!");return 1;} printf("=== Configuring TOF SCL/SDA to I2C mode ===\n"); // ------------------ SCL (0x0102F0140) ------------------ printf("\n[1] Processing SCL register at 0x%08lX\n", REG_SCL_ADDR); mapped_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, REG_BASE(REG_SCL_ADDR)); // mmap() 映射到用户空间的虚拟地址 if(mapped_base == MAP_FAILED) {perror("mmap failed for SCL");close(fd);return 1;} reg_val = *(mapped_base + REG_OFFSET(REG_SCL_ADDR) / sizeof(unsigned int)); printf(" Current value: 0x%08X\n", reg_val); reg_val = (reg_val & 0xFFFFFFF0) | 0x1; // 设置 bit[3:0] = 0x1, 其他位保持不变 *(mapped_base + REG_OFFSET(REG_SCL_ADDR) / sizeof(unsigned int)) = reg_val; // 写入到硬件 printf(" Writing new value: 0x%08X\n", reg_val); munmap((void*)mapped_base, PAGE_SIZE); // 解除内存映射 // ------------------ SDA (0x0102F013C) ------------------ printf("\n[2] Processing SDA register at 0x%08lX\n", REG_SDA_ADDR); mapped_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, REG_BASE(REG_SDA_ADDR)); if(mapped_base == MAP_FAILED) {perror("mmap failed for SDA");close(fd);return 1;} reg_val = *(mapped_base + REG_OFFSET(REG_SDA_ADDR) / sizeof(unsigned int)); printf(" Current value: 0x%08X\n", reg_val); reg_val = (reg_val & 0xFFFFFFF0) | 0x1; // 设置 bit[3:0] = 0x1,其他位保持不变 *(mapped_base + REG_OFFSET(REG_SDA_ADDR) / sizeof(unsigned int)) = reg_val; printf(" Writing new value: 0x%08X\n", reg_val); munmap((void*)mapped_base, PAGE_SIZE); // ------------------ RST (0x0102F0068) ------------------ printf("\n[3] Configuring RST (GPIO5_6) to GPIO mode\n"); mapped_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, REG_BASE(REG_RST_ADDR)); if(mapped_base == MAP_FAILED) {perror("mmap failed for RST");close(fd);return 1;} reg_val = *(mapped_base + REG_OFFSET(REG_RST_ADDR)/sizeof(unsigned int)); printf(" Current: 0x%08X\n", reg_val); reg_val = (reg_val & 0xFFFFFFF0) | 0x0; // 0 = GPIO *(mapped_base + REG_OFFSET(REG_RST_ADDR) / sizeof(unsigned int)) = reg_val; printf(" Set to: 0x%08X\n", reg_val); munmap(mapped_base, PAGE_SIZE); // ------------------ INT (0x0102F006CUL) ------------------ printf("\n[4] Configuring INT (GPIO5_7) to GPIO mode\n"); mapped_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, REG_BASE(REG_INT_ADDR)); if(mapped_base == MAP_FAILED) {perror("mmap failed for RST");close(fd);return 1;} reg_val = *(mapped_base + REG_OFFSET(REG_INT_ADDR)/sizeof(unsigned int)); printf(" Current: 0x%08X\n", reg_val); reg_val = (reg_val & 0xFFFFFFF0) | 0x0; // 0 = GPIO *(mapped_base + REG_OFFSET(REG_INT_ADDR) / sizeof(unsigned int)) = reg_val; printf(" Set to: 0x%08X\n", reg_val); munmap(mapped_base, PAGE_SIZE); close(fd); return 0; } int main() { set_addr_v(); return 0; }
- 复位引脚复位
-
复位引脚 GPIO5_6 也就是 全局的 GPIO46 (5*8 + 6) 复位一下(拉高): # 导出 GPIO46(对应 GPIO5_6) echo 46 > /sys/class/gpio/export # 设置为输出 echo out > /sys/class/gpio/gpio46/direction # 先拉低(确保进入复位) echo 0 > /sys/class/gpio/gpio46/value sleep 0.01 # 至少 1ms # 再拉高(释放复位) echo 1 > /sys/class/gpio/gpio46/value sleep 0.01 # 等待芯片启动
-
- 代码开发, 直接下载 官方驱动和代码比较好, VL53L1 的官方代码 是 STSW-IMG022
- STSW-IMG022 的驱动是 driver/vl53L1 目录,修改一下 makefile // 以模块的方式 挂在 ss927 的内核 编译
-
insmod stmvl53l1.ko force_device=1 adapter_nb=0 xsdn_gpio_nb=46 #intr_gpio_nb=47
-
chmod 777 /dev/stmvl53l1_ranging
-
- STSW-IMG022 的可执行程序是:android/hardware/vl53l1_test/phio // 注意修改一下 makefile
- STSW-IMG022 的驱动是 driver/vl53L1 目录,修改一下 makefile // 以模块的方式 挂在 ss927 的内核 编译
本文来自博客园,作者:封兴旺,转载请注明原文链接:https://www.cnblogs.com/fxw1/p/19405384


浙公网安备 33010602011771号