tof 测距

准备工作

  • tof 连接 soc 的 4个脚的原理图:
    • image
  • 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 )
    • image
    • 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

 

posted @ 2025-12-26 16:05  封兴旺  阅读(1)  评论(0)    收藏  举报

联系方式: 18274305123(微信同号)