找回密码
 立即注册
首页 业界区 业界 龙芯2k0300 - 走马观碑组vl53l0x驱动移植

龙芯2k0300 - 走马观碑组vl53l0x驱动移植

赏勿 7 天前
在《龙芯2k0300 - 久久派开发环境搭建及内核升级》中我们介绍了如何将久久派默认带有的PMON固件以及内核linux 4.19升级为uboot及linux 6.12版本。当我们的板子执行了升级操作后,我们的系统环境已经搭建完成了,接下来的任务就是移植驱动程序和编写应用程序。其中涉及的模块有:

  • VL53测距模块;
  • 1.8寸SPI TFT屏幕;
  • MPU6050陀螺仪。
这里我们参考的资料主要来源以下两个仓库:

  • 《龙芯2K300_301软件开源库》;
  • 《WwuSama 21届智能车走马观碑开源仓库》。
一、开源驱动

1.1 创建项目目录

在/opt/2k0300目录下创建子目录loongson_2k300_lib;
  1. zhengyang@ubuntu:/opt/2k0300$ mkdir loongson_2k300_lib
  2. zhengyang@ubuntu:/opt/2k0300$ cd loongson_2k300_lib
复制代码
创建驱动子目录:
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib$ mkdir driver
复制代码
创建测试用例子目录:
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib$ mkdir example
复制代码
创建走马观碑项目子目录:
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib$ mkdir car_project
复制代码
1.2 拷贝驱动

这里我们将《WwuSama/21届智能车走马观碑开源仓库》开源的linux 6.9源码下载下来,需要注意的是仓库中已经将linux内核源码移除了,但是其QQ交流群依然提供了内核源码,这里我下载了linux-6.9-WuwuSama-99pi.tar.gz,其驱动位于drivers/wuwu_drivers/:
  1. zhengyang@ubuntu:/opt/2k0300/build-2k0300/workspace/linux-6.9-WuwuSama-99pi$ ll drivers/wuwu_drivers/
  2. -rw-rw-r--   1 zhengyang zhengyang  7109 12月 17 16:42 imc20602.h
  3. -rw-rw-r--   1 zhengyang zhengyang  4144 12月 17 16:42 wuwu_brushless.c
  4. -rw-rw-r--   1 zhengyang zhengyang  3601 12月 17 16:42 wuwu_buzzer.c
  5. -rw-rw-r--   1 zhengyang zhengyang  4134 12月 17 16:42 wuwu_fans.c
  6. -rw-rw-r--   1 zhengyang zhengyang  9198 12月 17 16:42 wuwu_icm42688.c
  7. -rw-rw-r--   1 zhengyang zhengyang  5306 12月 17 16:42 wuwu_icm42688.h
  8. -rw-rw-r--   1 zhengyang zhengyang 11666 12月 17 16:42 wuwu_imc20602.c
  9. -rw-rw-r--   1 zhengyang zhengyang 13770 12月 17 16:42 wuwu_motor.c
  10. -rw-rw-r--   1 zhengyang zhengyang  1488 12月 17 16:42 wuwu_motor.h
  11. -rw-rw-r--   1 zhengyang zhengyang  4416 12月 17 16:42 wuwu_servo.c
  12. -rw-rw-r--   1 zhengyang zhengyang 30204 12月 17 16:42 wuwu_vl53l0x.c
  13. -rw-rw-r--   1 zhengyang zhengyang   877 12月 17 16:42 wuwu_vl53l0x.h
复制代码
我们将这些驱动拷贝到loongson_2k300_lib/driver目录,供我们参考使用;
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib/driver$ cp /opt/2k0300/build-2k0300/workspace/linux-6.9-WuwuSama-99pi/drivers/wuwu_drivers/* ./
复制代码
1.3 准备工作

在下文,我们将会进行各个模块的驱动编译,在编译之前,先在内核源码目录执行如下命令,生成 Module.symvers:
  1. zhengyang@ubuntu:/opt/2k0300/build-2k0300/workspace/linux-6.12$ source ../set_env.sh && make loongson_2k300_defconfig V=1
  2. # 生成Module.symvers的命令
  3. zhengyang@ubuntu:/opt/2k0300/build-2k0300/workspace/linux-6.12$ source ../set_env.sh && make  modules_prepare -j$(nproc)
  4. # 如果没有Module.symvers才需要执行下面这条指令
  5. zhengyang@ubuntu:/opt/2k0300/build-2k0300/workspace/linux-6.12$ cp vmlinux.symvers Module.symvers
复制代码
这一步会生成完整的 Module.symvers,其中记录了内核导出的所有符号信息。
二、vl53l0x设备驱动

如果对I2C驱动源码移植感兴趣,可参考:

  • 《通信协议-I2C》;
  • 《linux驱动移植-I2C总线设备驱动》;
  • 《linux驱动移植-I2C适配器驱动移植》;
  • 《linux驱动移植-I2C驱动移植(OLED SSD1306)》。
2.1 项目目录

接下来我们创建子目录i2c_vl53l0x_driver :
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib/driver$ mkdir i2c_vl53l0x_driver
复制代码
拷贝源码:
  1. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib/driver/i2c_vl53l0x_driver$ cp ../wuwu_vl53l0x.* ./
  2. zhengyang@ubuntu:/opt/2k0300/loongson_2k300_lib/driver/i2c_vl53l0x_driver$ ll
  3. -rw-rw-r-- 1 zhengyang zhengyang 30204  3月 23 21:25 wuwu_vl53l0x.c
  4. -rw-rw-r-- 1 zhengyang zhengyang   877  3月 23 21:25 wuwu_vl53l0x.h
复制代码
wuwu_vl53l0x.c代码内容较多,这里我们对其进行拆分,并进行适当调整,最终目录结构如下:
  1. i2c_vl53l0x_driver/
  2. ├── inc/
  3. │   └── vl53l0x.h         # 公共头文件(宏、结构体定义、ioctl 命令等)
  4. ├── src/
  5. │   ├── vl53l0x_core.c    # 核心层:传感器初始化、测距算法
  6. │   ├── vl53l0x_dev.c     # 设备层:字符设备接口
  7. │   └── vl53l0x_hw.c      # 硬件层:I2C 读写操作
  8. ├── vl53l0x_driver.c      # 驱动层:I2C 驱动注册、probe/remove
  9. └── Makefile
复制代码
2.2 vl53l0x.h

inc为头文件目录,在inc创建vl53l0x.h文件;
  1. /*
  2. * VL53L0X Linux I2C Driver
  3. * Copyright (C) 2026 zhengyang
  4. *
  5. * Based on Seekfree TC264 Library: https://gitee.com/seekfree/TC264_Library
  6. * SPDX-License-Identifier: GPL-2.0-only
  7. */
  8. #ifndef _VL53L0X_H_
  9. #define _VL53L0X_H_
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/init.h>
  13. #include <linux/fs.h>
  14. #include <linux/uaccess.h>
  15. #include <linux/io.h>
  16. #include <linux/cdev.h>
  17. #include <linux/device.h>
  18. #include <linux/i2c.h>
  19. #include <linux/delay.h>
  20. #include <linux/ioctl.h>
  21. /* ========================= 设备信息 ========================= */
  22. #define VL53L0X_COUNT           1
  23. #define VL53L0X_NAME            "vl53l0x_tof"
  24. /* ========================= ioctl 命令 ========================= */
  25. #define VL53L0X_IOCTL_MAGIC     't'
  26. #define VL53L0X_GET_DATA        _IOR(VL53L0X_IOCTL_MAGIC, 1, uint16_t)
  27. /* ========================= 硬件常量 ========================= */
  28. #define VL53L0X_TIMEOUT_COUNT   10
  29. /* ========================= 辅助宏 ========================= */
  30. #define decode_vcsel_period(reg_val)            (((reg_val) + 1) << 1)
  31. #define calc_macro_period(vcsel_period_pclks)   ((((uint32_t)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)
  32. /* ========================= 枚举定义 ========================= */
  33. typedef enum {
  34.     VL53L0X_VCSEL_PERIOD_PER_RANGE,
  35.     VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
  36. } vl53l0x_vcsel_period_type_enum;
  37. /* ========================= 结构体定义 ========================= */
  38. typedef struct {
  39.     uint8_t tcc;
  40.     uint8_t msrc;
  41.     uint8_t dss;
  42.     uint8_t pre_range;
  43.     uint8_t final_range;
  44. } vl53l0x_sequence_enables_step_struct;
  45. typedef struct {
  46.     uint16_t pre_range_vcsel_period_pclks;
  47.     uint16_t final_range_vcsel_period_pclks;
  48.     uint16_t msrc_dss_tcc_mclks;
  49.     uint16_t pre_range_mclks;
  50.     uint16_t final_range_mclks;
  51.     uint32_t msrc_dss_tcc_us;
  52.     uint32_t pre_range_us;
  53.     uint32_t final_range_us;
  54. } vl53l0x_sequence_timeout_step_struct;
  55. /* 内部设备结构(所有模块共用) */
  56. struct vl53l0x_dev {
  57.     dev_t devid;
  58.     struct cdev cdev;
  59.     struct class *class;
  60.     struct device *device;
  61.     void *private_data;          /* 指向 i2c_client */
  62.     struct mutex lock;
  63.     uint16_t vl53l0x_distance_mm;
  64. };
  65. /* ========================= 全局变量声明 ========================= */
  66. extern struct vl53l0x_dev vl53l0x;
  67. /* ========================= 硬件层函数声明 ========================= */
  68. int vl53l0x_read_regs(struct vl53l0x_dev *dev, u8 reg, void *val, int len);
  69. int vl53l0x_write_regs(struct vl53l0x_dev *dev, u8 reg, u8 *buf, u8 len);
  70. void vl53l0x_writeByte(u8 reg, u8 Byte);
  71. void vl53l0x_writeBuf(u8 reg, u8 *buf, u8 len);
  72. void vl53l0x_readByte(u8 reg, u8 *byte);
  73. void vl53l0x_readBuf(u8 reg, u8 *buf, u8 len);
  74. /* ========================= 核心层函数声明 ========================= */
  75. void vl53l0x_set_signal_rate_limit(uint16_t limit_mcps);
  76. uint8_t vl53l0x_get_spad_info(uint8_t *index, uint8_t *type_is_aperture);
  77. void vl53l0x_get_sequence_step_enables(vl53l0x_sequence_enables_step_struct *enables);
  78. uint8_t vl53l0x_get_vcsel_pulse_period(vl53l0x_vcsel_period_type_enum type);
  79. uint32_t vl53l0x_timeout_mclks_to_microseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks);
  80. uint16_t vl53l0x_decode_timeout(uint16_t reg_val);
  81. void vl53l0x_get_sequence_step_timeouts(const vl53l0x_sequence_enables_step_struct *enables,
  82.                                         vl53l0x_sequence_timeout_step_struct *timeouts);
  83. uint32_t vl53l0x_get_measurement_timing_budget(void);
  84. uint16_t vl53l0x_encode_timeout(uint16_t timeout_mclks);
  85. uint32_t vl53l0x_timeout_microseconds_to_mclks(uint32_t timeout_period_us, uint8_t vcsel_period_pclks);
  86. uint8_t vl53l0x_set_measurement_timing_budget(uint32_t budget_us);
  87. uint8_t vl53l0x_perform_single_ref_calibration(uint8_t vhv_init_byte);
  88. int vl53l0x_init(void);
  89. void vl53l0x_get_distance(void);
  90. /* ========================= 设备层函数声明 ========================= */
  91. int vl53l0x_cdev_init(struct i2c_client *client);
  92. void vl53l0x_cdev_destroy(void);
  93. #endif /* _VL53L0X_H_ */
复制代码
2.3.2 vl53l0x_core.c

vl53l0x_core.c: 核心层,实现传感器初始化、距离读取等算法,调用硬件层;
点击查看详情
  1. #include "vl53l0x.h"
  2. /* I2C 读写函数(硬件层) */
  3. int vl53l0x_read_regs(struct vl53l0x_dev *dev, u8 reg, void *val, int len)
  4. {
  5.     struct i2c_client *client = (struct i2c_client *)dev->private_data;
  6.     struct i2c_msg msg[] = {
  7.         {
  8.             .addr = client->addr,
  9.             .flags = 0,
  10.             .len = 1,
  11.             .buf = &reg,
  12.         },
  13.         {
  14.             .addr = client->addr,
  15.             .flags = I2C_M_RD,
  16.             .len = len,
  17.             .buf = val,
  18.         },
  19.     };
  20.     return i2c_transfer(client->adapter, msg, 2);
  21. }
  22. int vl53l0x_write_regs(struct vl53l0x_dev *dev, u8 reg, u8 *buf, u8 len)
  23. {
  24.     u8 b[256];
  25.     struct i2c_msg msg;
  26.     struct i2c_client *client = (struct i2c_client *)dev->private_data;
  27.     b[0] = reg;
  28.     memcpy(&b[1], buf, len);
  29.     msg.addr = client->addr;
  30.     msg.flags = 0;
  31.     msg.len = len + 1;
  32.     msg.buf = b;
  33.     return i2c_transfer(client->adapter, &msg, 1);
  34. }
  35. /* 单字节/多字节封装 */
  36. void vl53l0x_writeByte(u8 reg, u8 Byte)
  37. {
  38.     vl53l0x_write_regs(&vl53l0x, reg, &Byte, 1);
  39. }
  40. void vl53l0x_writeBuf(u8 reg, u8 *buf, u8 len)
  41. {
  42.     vl53l0x_write_regs(&vl53l0x, reg, buf, len);
  43. }
  44. void vl53l0x_readByte(u8 reg, u8 *byte)
  45. {
  46.     vl53l0x_read_regs(&vl53l0x, reg, byte, 1);
  47. }
  48. void vl53l0x_readBuf(u8 reg, u8 *buf, u8 len)
  49. {
  50.     vl53l0x_read_regs(&vl53l0x, reg, buf, len);
  51. }
复制代码
2.4 vl53l0x_driver.c

vl53l0x_driver.c: I2C驱动层,实现probe/remove,创建设备节点;
  1. #include "vl53l0x.h"
  2. /* 全局设备结构实例(所有模块共享) */
  3. struct vl53l0x_dev vl53l0x;
  4. //-------------------------------------------------------------------------------------------------------------------
  5. // 函数简介     设置返回信号速率限制 该值单位为 MCPS (百万次每秒)
  6. // 参数说明     limit_mcps      设置的最小速率
  7. // 返回参数     void
  8. // 使用示例     vl53l0x_set_signal_rate_limit(32);
  9. // 备注信息     这个速率表示从目标反射并被设备检测到的信号的振幅
  10. //              设置此限制可以确定传感器报告有效读数所需的最小测量值
  11. //              设置一个较低的限制可以增加传感器的测量范围
  12. //              但似乎也增加了 <由于来自目标以外的物体的不需要的反射导致> 得到不准确读数的可能性
  13. //              默认为 32 MCPS 可预设范围为 0 - 65534
  14. //-------------------------------------------------------------------------------------------------------------------
  15. void vl53l0x_set_signal_rate_limit(uint16_t limit_mcps_fixed)
  16. {
  17.     uint8_t data_buffer[2];
  18.     data_buffer[0] = (limit_mcps_fixed >> 8) & 0xFF;
  19.     data_buffer[1] = limit_mcps_fixed & 0xFF;
  20.     vl53l0x_write_regs(&vl53l0x, 0x44, data_buffer, 2);
  21. }
  22. //-------------------------------------------------------------------------------------------------------------------
  23. // 函数简介     获取设备 SPAD 信息
  24. // 参数说明     index           索引
  25. // 参数说明     type            类型值
  26. // 返回参数     uint8_t           是否成功 0-成功 1-失败
  27. // 使用示例     vl53l0x_get_spad_info(index, type_is_aperture);
  28. // 备注信息
  29. //-------------------------------------------------------------------------------------------------------------------
  30. uint8_t vl53l0x_get_spad_info(uint8_t *index, uint8_t *type_is_aperture)
  31. {
  32.     uint8_t tmp = 0;
  33.     uint8_t return_state = 0;
  34.     volatile uint16_t loop_count = 0;
  35.     do {
  36.         vl53l0x_writeByte(0x80, 0x01);
  37.         vl53l0x_writeByte(0xFF, 0x01);
  38.         vl53l0x_writeByte(0x00, 0x00);
  39.         vl53l0x_writeByte(0xFF, 0x06);
  40.         vl53l0x_readByte(0x83, &tmp);
  41.         vl53l0x_writeByte(0x83, tmp | 0x04);
  42.         vl53l0x_writeByte(0xFF, 0x07);
  43.         vl53l0x_writeByte(0x81, 0x01);
  44.         vl53l0x_writeByte(0x80, 0x01);
  45.         vl53l0x_writeByte(0x94, 0x6b);
  46.         vl53l0x_writeByte(0x83, 0x00);
  47.         tmp = 0x00;
  48.         while (0x00 == tmp || 0xFF == tmp) {
  49.             msleep(1);
  50.             vl53l0x_readByte(0x83, &tmp);
  51.             if (VL53L0X_TIMEOUT_COUNT < loop_count++) {
  52.                 return_state = 1;
  53.                 break;
  54.             }
  55.         }
  56.         if (return_state)
  57.             break;
  58.         vl53l0x_writeByte(0x83, 0x01);
  59.         vl53l0x_readByte(0x92, &tmp);
  60.         *index = tmp & 0x7f;
  61.         *type_is_aperture = (tmp >> 7) & 0x01;
  62.         vl53l0x_writeByte(0x81, 0x00);
  63.         vl53l0x_writeByte(0xFF, 0x06);
  64.         vl53l0x_readByte(0x83, &tmp);
  65.         vl53l0x_writeByte(0x83, tmp);
  66.         vl53l0x_writeByte(0xFF, 0x01);
  67.         vl53l0x_writeByte(0x00, 0x01);
  68.         vl53l0x_writeByte(0xFF, 0x00);
  69.         vl53l0x_writeByte(0x80, 0x00);
  70.     } while (0);
  71.     return return_state;
  72. }
  73. //-------------------------------------------------------------------------------------------------------------------
  74. // 函数简介     获取序列步骤使能设置
  75. // 参数说明     enables         序列使能步骤结构体
  76. // 返回参数     void
  77. // 使用示例     vl53l0x_get_sequence_step_enables(enables);
  78. // 备注信息
  79. //-------------------------------------------------------------------------------------------------------------------
  80. void vl53l0x_get_sequence_step_enables(vl53l0x_sequence_enables_step_struct *enables)
  81. {
  82.     uint8_t sequence_config = 0;
  83.     vl53l0x_readByte(0x01, &sequence_config);
  84.     enables->tcc          = (sequence_config >> 4) & 0x1;
  85.     enables->dss          = (sequence_config >> 3) & 0x1;
  86.     enables->msrc         = (sequence_config >> 2) & 0x1;
  87.     enables->pre_range    = (sequence_config >> 6) & 0x1;
  88.     enables->final_range  = (sequence_config >> 7) & 0x1;
  89. }
  90. //-------------------------------------------------------------------------------------------------------------------
  91. // 函数简介     获取脉冲周期
  92. // 参数说明     type            预量程类型
  93. // 返回参数     uint8_t           返回的周期值
  94. // 使用示例     vl53l0x_get_vcsel_pulse_period(VL53L0X_VCSEL_PERIOD_PER_RANGE);
  95. // 备注信息     在 PCLKs 中获取给定周期类型的 VCSEL 脉冲周期
  96. //-------------------------------------------------------------------------------------------------------------------
  97. uint8_t vl53l0x_get_vcsel_pulse_period(vl53l0x_vcsel_period_type_enum type)
  98. {
  99.     uint8_t data_buffer = 0;
  100.     if (VL53L0X_VCSEL_PERIOD_PER_RANGE == type) {
  101.         vl53l0x_readByte(0x50, &data_buffer);
  102.         data_buffer = decode_vcsel_period(data_buffer);
  103.     } else if (VL53L0X_VCSEL_PERIOD_FINAL_RANGE == type) {
  104.         vl53l0x_readByte(0x70, &data_buffer);
  105.         data_buffer = decode_vcsel_period(data_buffer);
  106.     } else {
  107.         data_buffer = 255;
  108.     }
  109.     return data_buffer;
  110. }
  111. //-------------------------------------------------------------------------------------------------------------------
  112. // 函数简介     将超时数值从 MCLKs 转换到对应的 ms
  113. // 参数说明     timeout_period_mclks    超时周期 MCLKs
  114. // 参数说明     vcsel_period_pclks      PCLK 值
  115. // 返回参数     uint32_t                  返回超时数值
  116. // 使用示例     vl53l0x_timeout_mclks_to_microseconds(timeout_period_mclks, vcsel_period_pclks);
  117. // 备注信息     将序列步骤超时从具有给定 VCSEL 周期的 MCLK (以 PCLK 为单位)转换为微秒
  118. //-------------------------------------------------------------------------------------------------------------------
  119. uint32_t vl53l0x_timeout_mclks_to_microseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks)
  120. {
  121.     uint32_t macro_period_ns = calc_macro_period(vcsel_period_pclks);
  122.     return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000;
  123. }
  124. //-------------------------------------------------------------------------------------------------------------------
  125. // 函数简介     对超时数值进行解码
  126. // 参数说明     reg_val         超时时长 寄存器值
  127. // 返回参数     uint16_t          返回超时数值
  128. // 使用示例     vl53l0x_decode_timeout(reg_val);
  129. // 备注信息     从寄存器值解码 MCLK 中的序列步骤超时
  130. //-------------------------------------------------------------------------------------------------------------------
  131. uint16_t vl53l0x_decode_timeout(uint16_t reg_val)
  132. {
  133.     return (uint16_t)((reg_val & 0x00FF) << ((reg_val & 0xFF00) >> 8)) + 1;
  134. }
  135. //-------------------------------------------------------------------------------------------------------------------
  136. // 函数简介     获取序列步骤超时设置
  137. // 参数说明     enables         序列使能步骤结构体
  138. // 参数说明     timeouts        序列超时步骤结构体
  139. // 返回参数     void
  140. // 使用示例     vl53l0x_get_sequence_step_timeouts(enables, timeouts);
  141. // 备注信息     获取所有超时而不仅仅是请求的超时 并且还存储中间值
  142. //-------------------------------------------------------------------------------------------------------------------
  143. void vl53l0x_get_sequence_step_timeouts(const vl53l0x_sequence_enables_step_struct *enables,
  144.                                         vl53l0x_sequence_timeout_step_struct *timeouts)
  145. {
  146.     uint8_t reg_buffer[2];
  147.     uint16_t reg16_buffer = 0;
  148.     timeouts->pre_range_vcsel_period_pclks = vl53l0x_get_vcsel_pulse_period(VL53L0X_VCSEL_PERIOD_PER_RANGE);
  149.     vl53l0x_readByte(0x46, reg_buffer);
  150.     timeouts->msrc_dss_tcc_mclks = reg_buffer[0] + 1;
  151.     timeouts->msrc_dss_tcc_us = vl53l0x_timeout_mclks_to_microseconds(timeouts->msrc_dss_tcc_mclks,
  152.                                                                        (uint8_t)timeouts->pre_range_vcsel_period_pclks);
  153.     vl53l0x_readBuf(0x51, reg_buffer, 2);
  154.     reg16_buffer = ((uint16_t)reg_buffer[0] << 8) | reg_buffer[1];
  155.     timeouts->pre_range_mclks = vl53l0x_decode_timeout(reg16_buffer);
  156.     timeouts->pre_range_us = vl53l0x_timeout_mclks_to_microseconds(timeouts->pre_range_mclks,
  157.                                                                    (uint8_t)timeouts->pre_range_vcsel_period_pclks);
  158.     timeouts->final_range_vcsel_period_pclks = vl53l0x_get_vcsel_pulse_period(VL53L0X_VCSEL_PERIOD_FINAL_RANGE);
  159.     vl53l0x_readBuf(0x71, reg_buffer, 2);
  160.     reg16_buffer = ((uint16_t)reg_buffer[0] << 8) | reg_buffer[1];
  161.     timeouts->final_range_mclks = vl53l0x_decode_timeout(reg16_buffer);
  162.     if (enables->pre_range) {
  163.         timeouts->final_range_mclks -= timeouts->pre_range_mclks;
  164.     }
  165.     timeouts->final_range_us = vl53l0x_timeout_mclks_to_microseconds(timeouts->final_range_mclks,
  166.                                                                      (uint8_t)timeouts->final_range_vcsel_period_pclks);
  167. }
  168. //-------------------------------------------------------------------------------------------------------------------
  169. // 函数简介     获取测量定时预算 (以微秒为单位)
  170. // 参数说明     void
  171. // 返回参数     uint32_t          已设定的测量允许的时间
  172. // 使用示例     vl53l0x_get_measurement_timing_budget();
  173. // 备注信息
  174. //-------------------------------------------------------------------------------------------------------------------
  175. uint32_t vl53l0x_get_measurement_timing_budget(void)
  176. {
  177.     vl53l0x_sequence_enables_step_struct enables;
  178.     vl53l0x_sequence_timeout_step_struct timeouts;
  179.     uint32_t budget_us = 1910 + 960;
  180.     vl53l0x_get_sequence_step_enables(&enables);
  181.     vl53l0x_get_sequence_step_timeouts(&enables, &timeouts);
  182.     if (enables.tcc)
  183.         budget_us += (timeouts.msrc_dss_tcc_us + 590);
  184.     if (enables.dss)
  185.         budget_us += 2 * (timeouts.msrc_dss_tcc_us + 690);
  186.     else if (enables.msrc)
  187.         budget_us += (timeouts.msrc_dss_tcc_us + 660);
  188.     if (enables.pre_range)
  189.         budget_us += (timeouts.pre_range_us + 660);
  190.     if (enables.final_range)
  191.         budget_us += (timeouts.final_range_us + 550);
  192.     return budget_us;
  193. }
  194. //-------------------------------------------------------------------------------------------------------------------
  195. // 函数简介     对超时数值进行编码
  196. // 参数说明     timeout_mclks   超时时长 -MCLKs 值
  197. // 返回参数     uint16_t          返回编码值
  198. // 使用示例     vl53l0x_encode_timeout(timeout_mclks);
  199. // 备注信息     在 MCLK 中对超时的序列步骤超时寄存器值进行编码
  200. //-------------------------------------------------------------------------------------------------------------------
  201. uint16_t vl53l0x_encode_timeout (uint16_t timeout_mclks)
  202. {
  203.     uint32_t ls_byte = 0;
  204.     uint16_t ms_byte = 0;
  205.     uint16_t return_data = 0;
  206.     if(0 < timeout_mclks)
  207.     {
  208.         // 格式: (LSByte * 2 ^ MSByte) + 1
  209.         ls_byte = timeout_mclks - 1;
  210.         while(0 < (ls_byte & 0xFFFFFF00))
  211.         {
  212.             ls_byte >>= 1;
  213.             ms_byte++;
  214.         }
  215.         return_data = (ms_byte << 8) | ((uint16_t)ls_byte & 0xFF);
  216.     }
  217.     return return_data;
  218. }
  219. //-------------------------------------------------------------------------------------------------------------------
  220. // 函数简介     将超时数值从 ms 转换到对应的 MCLKs
  221. // 参数说明     timeout_period_us   超时周期 微秒单位
  222. // 参数说明     vcsel_period_pclks  PCLK 值
  223. // 返回参数     uint32_t              返回超时数值
  224. // 使用示例     vl53l0x_timeout_microseconds_to_mclks(timeout_period_us, vcsel_period_pclks);
  225. // 备注信息     将序列步骤超时从微秒转换为具有给定 VCSEL 周期的 MCLK (以 PCLK 为单位)
  226. //-------------------------------------------------------------------------------------------------------------------
  227. uint32_t vl53l0x_timeout_microseconds_to_mclks (uint32_t timeout_period_us, uint8_t vcsel_period_pclks)
  228. {
  229.     uint32_t macro_period_ns = calc_macro_period(vcsel_period_pclks);
  230.     return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
  231. }
  232. //-------------------------------------------------------------------------------------------------------------------
  233. // 函数简介     设置测量定时预算 (以微秒为单位)
  234. // 参数说明     budget_us       设定的测量允许的时间
  235. // 返回参数     uint8_t           操作结果 0-成功 1-失败
  236. // 使用示例     vl53l0x_set_measurement_timing_budget(measurement_timing_budget_us);
  237. // 备注信息     这是一次测量允许的时间
  238. //              即在测距序列的子步骤之间分配时间预算
  239. //              更长的时间预算允许更精确的测量
  240. //              增加一个N倍的预算可以减少一个sqrt(N)倍的范围测量标准偏差
  241. //              默认为33毫秒 最小值为20 ms
  242. //-------------------------------------------------------------------------------------------------------------------
  243. uint8_t vl53l0x_set_measurement_timing_budget (uint32_t budget_us)
  244. {
  245.     uint8_t return_state = 0;
  246.     uint8_t data_buffer[3];
  247.     uint16_t data = 0;
  248.     vl53l0x_sequence_enables_step_struct enables;
  249.     vl53l0x_sequence_timeout_step_struct timeouts;
  250.     do
  251.     {
  252.         if(20000 > budget_us)
  253.         {
  254.             return_state = 1;
  255.             break;
  256.         }
  257.         uint32_t used_budget_us = 1320 + 960;
  258.         vl53l0x_get_sequence_step_enables(&enables);
  259.         vl53l0x_get_sequence_step_timeouts(&enables, &timeouts);
  260.         if (enables.tcc)
  261.         {
  262.             used_budget_us += (timeouts.msrc_dss_tcc_us + 590);
  263.         }
  264.         if (enables.dss)
  265.         {
  266.             used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + 690);
  267.         }
  268.         else if (enables.msrc)
  269.         {
  270.             used_budget_us += (timeouts.msrc_dss_tcc_us + 660);
  271.         }
  272.         if (enables.pre_range)
  273.         {
  274.             used_budget_us += (timeouts.pre_range_us + 660);
  275.         }
  276.         if (enables.final_range)
  277.         {
  278.             // 请注意 最终范围超时由计时预算和序列中所有其他超时的总和决定
  279.             // 如果没有空间用于最终范围超时 则将设置错误
  280.             // 否则 剩余时间将应用于最终范围
  281.             used_budget_us += 550;
  282.             if (used_budget_us > budget_us)
  283.             {
  284.                 // 请求的超时太大
  285.                 return_state = 1;
  286.                 break;
  287.             }
  288.             // 对于最终超时范围 必须添加预量程范围超时
  289.             // 为此 最终超时和预量程超时必须以宏周期 MClks 表示
  290.             // 因为它们具有不同的 VCSEL 周期
  291.             uint32_t final_range_timeout_us = budget_us - used_budget_us;
  292.             uint16_t final_range_timeout_mclks =
  293.             (uint16_t)vl53l0x_timeout_microseconds_to_mclks(final_range_timeout_us,
  294.                      (uint8_t)timeouts.final_range_vcsel_period_pclks);
  295.             if (enables.pre_range)
  296.             {
  297.                 final_range_timeout_mclks += timeouts.pre_range_mclks;
  298.             }
  299.             data = vl53l0x_encode_timeout(final_range_timeout_mclks);
  300.             data_buffer[0] = 0x71;
  301.             data_buffer[1] = ((data >> 8) & 0xFF);
  302.             data_buffer[2] = (data & 0xFF);
  303.             vl53l0x_writeBuf(data_buffer[0], &data_buffer[1], 2);
  304.         }
  305.     }while(0);
  306.     return return_state;
  307. }
  308. //-------------------------------------------------------------------------------------------------------------------
  309. // 函数简介     执行单次参考校准
  310. // 参数说明     vhv_init_byte   预设校准值
  311. // 返回参数     uint8_t           操作是否成功 0-成功 1-失败
  312. // 使用示例     vl53l0x_get_vcsel_pulse_period(VL53L0X_VCSEL_PERIOD_PER_RANGE);
  313. // 备注信息     在 PCLKs 中获取给定周期类型的 VCSEL 脉冲周期
  314. //-------------------------------------------------------------------------------------------------------------------
  315. uint8_t vl53l0x_perform_single_ref_calibration (uint8_t vhv_init_byte)
  316. {
  317.     uint8_t return_state = 0;
  318.     uint8_t data_buffer = 0;
  319.     volatile uint16_t loop_count = 0;
  320.     do
  321.     {
  322.         vl53l0x_writeByte(0x00, 0x01 | vhv_init_byte);
  323.         vl53l0x_readByte(0x46, &data_buffer);
  324.         while(0 == (data_buffer & 0x07))
  325.         {
  326.             msleep(1);
  327.             vl53l0x_readByte(0x46, &data_buffer);
  328.             if(VL53L0X_TIMEOUT_COUNT < loop_count ++)
  329.             {
  330.                 return_state = 1;
  331.                 break;
  332.             }
  333.         }
  334.         if(return_state)
  335.         {
  336.             break;
  337.         }
  338.         vl53l0x_writeByte(0x0B, 0x01);
  339.         vl53l0x_writeByte(0x00, 0x00);
  340.     }while(0);
  341.     return return_state;
  342. }
  343. int vl53l0x_init(void)
  344. {
  345.     uint8_t stop_variable = 0;
  346.     uint8_t reg_data_buffer = 0;
  347.     uint8_t return_state = 0;
  348.     uint32_t measurement_timing_budget_us;
  349.     uint8_t data_buffer[7] = {0};
  350.     uint8_t ref_spad_map[6];
  351.     int i = 0;
  352.     do
  353.     {
  354.         vl53l0x_readByte(0x89, &reg_data_buffer);
  355.         vl53l0x_writeByte(0x89, reg_data_buffer | 0x01);
  356.         vl53l0x_writeByte(0x88, 0x00);
  357.         vl53l0x_writeByte(0x80, 0x01);
  358.         vl53l0x_writeByte(0xFF, 0x01);
  359.         vl53l0x_writeByte(0x00, 0x00);
  360.         vl53l0x_readByte(0x91, &stop_variable);
  361.         vl53l0x_writeByte(0x00, 0x01);
  362.         vl53l0x_writeByte(0xFF, 0x00);
  363.         vl53l0x_writeByte(0x80, 0x00);
  364.         vl53l0x_readByte(0x60, &reg_data_buffer);
  365.         vl53l0x_writeByte(0x60, reg_data_buffer | 0x12);
  366.         vl53l0x_set_signal_rate_limit(32);
  367.         vl53l0x_writeByte(0x01, 0xFF);
  368.         if(vl53l0x_get_spad_info(&data_buffer[0], &data_buffer[1]))
  369.         {
  370.             return_state = 1;
  371.             printk("init error\r\n");
  372.             break;
  373.         }
  374.         vl53l0x_read_regs(&vl53l0x, 0xB0, ref_spad_map, 6);
  375.         vl53l0x_writeByte(0xFF, 0x01);
  376.         vl53l0x_writeByte(0x4F, 0x00);
  377.         vl53l0x_writeByte(0x4E, 0x2C);
  378.         vl53l0x_writeByte(0xFF, 0x00);
  379.         vl53l0x_writeByte(0x86, 0xB4);
  380.         data_buffer[2] = data_buffer[1] ? 12 : 0;
  381.         for(i = 0; 48 > i; i ++)
  382.         {
  383.             if(i < data_buffer[2] || data_buffer[3] == data_buffer[0])
  384.             {
  385.                 // 此位低于应启用的第一个位
  386.                 // 或者 (eference_spad_count) 位已启用
  387.                 // 因此此位为零
  388.                 ref_spad_map[i / 8] &= ~(1 << (i % 8));
  389.             }
  390.             else if((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
  391.             {
  392.                 data_buffer[3] ++;
  393.             }
  394.         }
  395.         data_buffer[0] = 0xB0;
  396.         for(i = 1; 7 > i; i ++)
  397.         {
  398.             data_buffer[1] = ref_spad_map[i - 1];
  399.         }
  400.         vl53l0x_write_regs(&vl53l0x, 0xB0, &data_buffer[1], 6);
  401.         vl53l0x_writeByte(0xFF, 0x01);
  402.         vl53l0x_writeByte(0x00, 0x00);
  403.         vl53l0x_writeByte(0xFF, 0x00);
  404.         vl53l0x_writeByte(0x09, 0x00);
  405.         vl53l0x_writeByte(0x10, 0x00);
  406.         vl53l0x_writeByte(0x11, 0x00);
  407.         vl53l0x_writeByte(0x24, 0x01);
  408.         vl53l0x_writeByte(0x25, 0xFF);
  409.         vl53l0x_writeByte(0x75, 0x00);
  410.         vl53l0x_writeByte(0xFF, 0x01);
  411.         vl53l0x_writeByte(0x4E, 0x2C);
  412.         vl53l0x_writeByte(0x48, 0x00);
  413.         vl53l0x_writeByte(0x30, 0x20);
  414.         vl53l0x_writeByte(0xFF, 0x00);
  415.         vl53l0x_writeByte(0x30, 0x09);
  416.         vl53l0x_writeByte(0x54, 0x00);
  417.         vl53l0x_writeByte(0x31, 0x04);
  418.         vl53l0x_writeByte(0x32, 0x03);
  419.         vl53l0x_writeByte(0x40, 0x83);
  420.         vl53l0x_writeByte(0x46, 0x25);
  421.         vl53l0x_writeByte(0x60, 0x00);
  422.         vl53l0x_writeByte(0x27, 0x00);
  423.         vl53l0x_writeByte(0x50, 0x06);
  424.         vl53l0x_writeByte(0x51, 0x00);
  425.         vl53l0x_writeByte(0x52, 0x96);
  426.         vl53l0x_writeByte(0x56, 0x08);
  427.         vl53l0x_writeByte(0x57, 0x30);
  428.         vl53l0x_writeByte(0x61, 0x00);
  429.         vl53l0x_writeByte(0x62, 0x00);
  430.         vl53l0x_writeByte(0x64, 0x00);
  431.         vl53l0x_writeByte(0x65, 0x00);
  432.         vl53l0x_writeByte(0x66, 0xA0);
  433.         vl53l0x_writeByte(0xFF, 0x01);
  434.         vl53l0x_writeByte(0x22, 0x32);
  435.         vl53l0x_writeByte(0x47, 0x14);
  436.         vl53l0x_writeByte(0x49, 0xFF);
  437.         vl53l0x_writeByte(0x4A, 0x00);
  438.         vl53l0x_writeByte(0xFF, 0x00);
  439.         vl53l0x_writeByte(0x7A, 0x0A);
  440.         vl53l0x_writeByte(0x7B, 0x00);
  441.         vl53l0x_writeByte(0x78, 0x21);
  442.         vl53l0x_writeByte(0xFF, 0x01);
  443.         vl53l0x_writeByte(0x23, 0x34);
  444.         vl53l0x_writeByte(0x42, 0x00);
  445.         vl53l0x_writeByte(0x44, 0xFF);
  446.         vl53l0x_writeByte(0x45, 0x26);
  447.         vl53l0x_writeByte(0x46, 0x05);
  448.         vl53l0x_writeByte(0x40, 0x40);
  449.         vl53l0x_writeByte(0x0E, 0x06);
  450.         vl53l0x_writeByte(0x20, 0x1A);
  451.         vl53l0x_writeByte(0x43, 0x40);
  452.         vl53l0x_writeByte(0xFF, 0x00);
  453.         vl53l0x_writeByte(0x34, 0x03);
  454.         vl53l0x_writeByte(0x35, 0x44);
  455.         vl53l0x_writeByte(0xFF, 0x01);
  456.         vl53l0x_writeByte(0x31, 0x04);
  457.         vl53l0x_writeByte(0x4B, 0x09);
  458.         vl53l0x_writeByte(0x4C, 0x05);
  459.         vl53l0x_writeByte(0x4D, 0x04);
  460.         vl53l0x_writeByte(0xFF, 0x00);
  461.         vl53l0x_writeByte(0x44, 0x00);
  462.         vl53l0x_writeByte(0x45, 0x20);
  463.         vl53l0x_writeByte(0x47, 0x08);
  464.         vl53l0x_writeByte(0x48, 0x28);
  465.         vl53l0x_writeByte(0x67, 0x00);
  466.         vl53l0x_writeByte(0x70, 0x04);
  467.         vl53l0x_writeByte(0x71, 0x01);
  468.         vl53l0x_writeByte(0x72, 0xFE);
  469.         vl53l0x_writeByte(0x76, 0x00);
  470.         vl53l0x_writeByte(0x77, 0x00);
  471.         vl53l0x_writeByte(0xFF, 0x01);
  472.         vl53l0x_writeByte(0x0D, 0x01);
  473.         vl53l0x_writeByte(0xFF, 0x00);
  474.         vl53l0x_writeByte(0x80, 0x01);
  475.         vl53l0x_writeByte(0x01, 0xF8);
  476.         vl53l0x_writeByte(0xFF, 0x01);
  477.         vl53l0x_writeByte(0x8E, 0x01);
  478.         vl53l0x_writeByte(0x00, 0x01);
  479.         vl53l0x_writeByte(0xFF, 0x00);
  480.         vl53l0x_writeByte(0x80, 0x00);
  481.         vl53l0x_writeByte(0x0A, 0x04);
  482.         vl53l0x_readByte(0x84, &reg_data_buffer);
  483.         vl53l0x_writeByte(0x84, reg_data_buffer & ~0x10);
  484.         vl53l0x_writeByte(0x0B, 0x01);
  485.         measurement_timing_budget_us  = vl53l0x_get_measurement_timing_budget();
  486.         vl53l0x_writeByte(0x01, 0xE8);
  487.         vl53l0x_set_measurement_timing_budget(measurement_timing_budget_us);    // 重新计算时序预算
  488.         vl53l0x_writeByte(0x01, 0x01);
  489.         if(vl53l0x_perform_single_ref_calibration(0x40))
  490.         {
  491.             return_state = 1;
  492.             break;
  493.         }
  494.         vl53l0x_writeByte(0x01, 0x02);
  495.         if(vl53l0x_perform_single_ref_calibration(0x00))
  496.         {
  497.             return_state = 1;
  498.             break;
  499.         }
  500.         vl53l0x_writeByte(0x01, 0xE8);
  501.         msleep(100);
  502.         vl53l0x_writeByte(0x80, 0x01);
  503.         vl53l0x_writeByte(0xFF, 0x01);
  504.         vl53l0x_writeByte(0x00, 0x00);
  505.         vl53l0x_writeByte(0x91, stop_variable);
  506.         vl53l0x_writeByte(0x00, 0x01);
  507.         vl53l0x_writeByte(0xFF, 0x00);
  508.         vl53l0x_writeByte(0x80, 0x00);
  509.         vl53l0x_writeByte(0x00, 0x02);
  510.     }while(0);
  511.     return return_state;
  512. }
  513. //-------------------------------------------------------------------------------------------------------------------
  514. // 函数简介     返回以毫米为单位的范围读数
  515. // 参数说明     void
  516. // 返回参数     void
  517. // 使用示例     vl53l0x_get_distance();
  518. // 备注信息     在开始单次射程测量后也调用此函数
  519. //-------------------------------------------------------------------------------------------------------------------
  520. void vl53l0x_get_distance (void)
  521. {
  522.     uint8_t reg_databuffer[3];
  523.     vl53l0x_readByte(0x13, reg_databuffer);
  524.     if((reg_databuffer[0] & 0x07) != 0)
  525.     {
  526.         // 假设线性度校正增益为默认值 1000 且未启用分数范围
  527.         vl53l0x_readBuf(0x14 + 10, reg_databuffer, 2);
  528.         vl53l0x.vl53l0x_distance_mm = ((uint16_t)reg_databuffer[0] << 8);
  529.         vl53l0x.vl53l0x_distance_mm |= reg_databuffer[1];
  530.         vl53l0x_writeByte(0x0B, 0x01);
  531.     }
  532.     if(reg_databuffer[0] & 0x10)
  533.     {
  534.         vl53l0x_readBuf(0x14 + 10, reg_databuffer, 2);
  535.         vl53l0x_writeByte(0x0B, 0x01);
  536.     }
  537. }
复制代码
通过 of_match_table 与设备树中 compatible = "icar,vl53l0x" 的节点匹配,实现驱动与硬件自动绑定。
2.5 Makefile

创建Makefile文件:
[code]# 内核源码路径KERNELDIR ?= /opt/2k0300/build-2k0300/workspace/linux-6.12# 当前驱动目录PWD := $(shell pwd)# 交叉编译工具链CROSS_COMPILE := loongarch64-linux-gnu-# 架构ARCH := loongarch# 所需文件夹BUILD_DIR := buildINCLUDE:=incKO_DIR:=koSRC_DIR:=srcEXTRA_CFLAGS +=  -I$(src)/$(INCLUDE)# 编译目标obj-m := vl53l0x.ovl53l0x-y := vl53l0x_driver.o \             src/vl53l0x_hw.o \             src/vl53l0x_core.o \             src/vl53l0x_dev.o# 编译规则ll: prepare compile move_files# 提前创建目录prepare:        @mkdir -p $(BUILD_DIR) $(KO_DIR)        @echo "
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册