driver: sensor: Add vl53l0x

Add driver for ST vl53l0x time of flight sensor.
This driver can be used in 2 modes :
  * proximity sensor :
      configure VL53L0X_PROXIMITY_THRESHOLD
      will return 1 if target is between sensor and threshold,
      else, 0
  * distance sensor :
      will return the distance in millimeters from sensor to target

This driver use the official STMicroelectronics library for vl53l0x.
(in ext/hal/st/lib/sensor/vl53l0x)

Signed-off-by: Vincent Veron <vincent.veron@st.com>
This commit is contained in:
Vincent Veron 2017-07-19 16:59:43 +02:00 committed by Kumar Gala
commit 347560459b
5 changed files with 359 additions and 0 deletions

View file

@ -35,5 +35,6 @@ add_subdirectory_ifdef(CONFIG_SX9500 sx9500)
add_subdirectory_ifdef(CONFIG_TH02 th02)
add_subdirectory_ifdef(CONFIG_TMP007 tmp007)
add_subdirectory_ifdef(CONFIG_TMP112 tmp112)
add_subdirectory_ifdef(CONFIG_VL53L0X vl53l0x)
zephyr_sources_ifdef(CONFIG_USERSPACE sensor_handlers.c)

View file

@ -114,4 +114,6 @@ source "drivers/sensor/tmp007/Kconfig"
source "drivers/sensor/tmp112/Kconfig"
source "drivers/sensor/vl53l0x/Kconfig"
endif # SENSOR

View file

@ -0,0 +1,4 @@
zephyr_sources(
vl53l0x.c
vl53l0x_platform.c
)

View file

@ -0,0 +1,67 @@
# Kconfig - VL53L0X time of flight sensor configuration options
#
# Copyright (c) 2017 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig VL53L0X
bool
prompt "VL53L0X time of flight sensor"
depends on SENSOR && I2C
default n
select HAS_STLIB
help
Enable driver for VL53L0X I2C-based time of flight sensor.
config VL53L0X_NAME
string
prompt "Driver name"
default "VL53L0X"
depends on VL53L0X && !HAS_DTS_I2C_DEVICE
help
Device name with which the VL53L0X sensor is identified.
config VL53L0X_I2C_ADDR
int
prompt "Vl53l0x I2C address"
default 0x29
depends on VL53L0X && !HAS_DTS_I2C_DEVICE
help
address of the i2c used for the vl53l0x sensor
config VL53L0X_I2C_MASTER_DEV_NAME
string
prompt "I2C master where VL53L0X is connected"
depends on VL53L0X && !HAS_DTS_I2C_DEVICE
default "I2C_0"
help
Specify the device name of the I2C master device to which VL53L0X is
connected.
config VL53L0X_XSHUT_GPIO_DEV_NAME
string
prompt "GPIO device"
default "GPIO_6"
depends on VL53L0X
help
The device name of the GPIO device to which the VL53L0X xshut pin
is connected.
config VL53L0X_XSHUT_GPIO_PIN_NUM
int
prompt "Interrupt GPIO pin number"
default 6
depends on VL53L0X
help
The number of the GPIO on which the xshut signal from the VL53L0X
is connected.
config VL53L0X_PROXIMITY_THRESHOLD
int
prompt "Proximity threshold in millimeters"
default 100
depends on VL53L0X
help
Threshold used for proximity detection when sensor is used with SENSOR_CHAN_PROX.

View file

@ -0,0 +1,285 @@
/* vl53l0x.c - Driver for ST VL53L0X time of flight sensor */
/*
* Copyright (c) 2017 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <kernel.h>
#include <i2c.h>
#include <sensor.h>
#include <init.h>
#include <gpio.h>
#include <misc/__assert.h>
#include <zephyr/types.h>
#include <device.h>
#include "vl53l0x_api.h"
#include "vl53l0x_platform.h"
#define SYS_LOG_DOMAIN "VL53L0X"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
#include <logging/sys_log.h>
/* All the values used in this driver are coming from ST datasheet and examples.
* It can be found here :
* https://my.st.com/content/my_st_com/en/products/embedded-software/
* proximity-sensors-software/stsw-img005.license%3d1505825745199.
* product%3dSTSW-IMG005.html
* (search for STSW-IMG005 on www.st.com)
* There are also examples of use in the L4 cube FW
* (http://www.st.com/en/embedded-software/stm32cubel4.html)
*/
#define VL53L0X_REG_WHO_AM_I 0xC0
#define VL53L0X_CHIP_ID 0xEEAA
#define VL53L0X_SETUP_SIGNAL_LIMIT (0.1*65536)
#define VL53L0X_SETUP_SIGMA_LIMIT (60*65536)
#define VL53L0X_SETUP_MAX_TIME_FOR_RANGING 33000
#define VL53L0X_SETUP_PRE_RANGE_VCSEL_PERIOD 18
#define VL53L0X_SETUP_FINAL_RANGE_VCSEL_PERIOD 14
struct vl53l0x_data {
struct device *i2c;
VL53L0X_Dev_t vl53l0x;
VL53L0X_RangingMeasurementData_t RangingMeasurementData;
};
static int vl53l0x_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct vl53l0x_data *drv_data = dev->driver_data;
u8_t ret;
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL
|| chan == SENSOR_CHAN_DISTANCE
|| chan == SENSOR_CHAN_PROX);
ret = VL53L0X_PerformSingleRangingMeasurement(&drv_data->vl53l0x,
&drv_data->RangingMeasurementData);
if (ret < 0) {
SYS_LOG_ERR("Could not perform measurment (error=%d)", ret);
return -EINVAL;
}
return 0;
}
static int vl53l0x_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct vl53l0x_data *drv_data = (struct vl53l0x_data *)dev->driver_data;
__ASSERT_NO_MSG(chan == SENSOR_CHAN_DISTANCE
|| chan == SENSOR_CHAN_PROX);
if (chan == SENSOR_CHAN_PROX) {
if (drv_data->RangingMeasurementData.RangeMilliMeter <=
CONFIG_VL53L0X_PROXIMITY_THRESHOLD) {
val->val1 = 1;
} else {
val->val1 = 0;
}
} else {
val->val1 = drv_data->RangingMeasurementData.RangeMilliMeter;
}
val->val2 = 0;
return 0;
}
static const struct sensor_driver_api vl53l0x_api_funcs = {
.sample_fetch = vl53l0x_sample_fetch,
.channel_get = vl53l0x_channel_get,
};
static int vl53l0x_setup_single_shot(struct device *dev)
{
struct vl53l0x_data *drv_data = dev->driver_data;
int ret;
u8_t VhvSettings;
u8_t PhaseCal;
u32_t refSpadCount;
u8_t isApertureSpads;
ret = VL53L0X_StaticInit(&drv_data->vl53l0x);
if (ret) {
SYS_LOG_ERR("VL53L0X_StaticInit failed");
goto exit;
}
ret = VL53L0X_PerformRefCalibration(&drv_data->vl53l0x,
&VhvSettings,
&PhaseCal);
if (ret) {
SYS_LOG_ERR("VL53L0X_PerformRefCalibration failed");
goto exit;
}
ret = VL53L0X_PerformRefSpadManagement(&drv_data->vl53l0x,
(uint32_t *)&refSpadCount,
&isApertureSpads);
if (ret) {
SYS_LOG_ERR("VL53L0X_PerformRefSpadManagement failed");
goto exit;
}
ret = VL53L0X_SetDeviceMode(&drv_data->vl53l0x,
VL53L0X_DEVICEMODE_SINGLE_RANGING);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetDeviceMode failed");
goto exit;
}
ret = VL53L0X_SetLimitCheckEnable(&drv_data->vl53l0x,
VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
1);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetLimitCheckEnable sigma failed");
goto exit;
}
ret = VL53L0X_SetLimitCheckEnable(&drv_data->vl53l0x,
VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
1);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetLimitCheckEnable signal rate failed");
goto exit;
}
ret = VL53L0X_SetLimitCheckValue(&drv_data->vl53l0x,
VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
VL53L0X_SETUP_SIGNAL_LIMIT);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetLimitCheckValue signal rate failed");
goto exit;
}
ret = VL53L0X_SetLimitCheckValue(&drv_data->vl53l0x,
VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
VL53L0X_SETUP_SIGMA_LIMIT);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetLimitCheckValue sigma failed");
goto exit;
}
ret = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(&drv_data->vl53l0x,
VL53L0X_SETUP_MAX_TIME_FOR_RANGING);
if (ret) {
SYS_LOG_ERR(
"VL53L0X_SetMeasurementTimingBudgetMicroSeconds failed");
goto exit;
}
ret = VL53L0X_SetVcselPulsePeriod(&drv_data->vl53l0x,
VL53L0X_VCSEL_PERIOD_PRE_RANGE,
VL53L0X_SETUP_PRE_RANGE_VCSEL_PERIOD);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetVcselPulsePeriod pre range failed");
goto exit;
}
ret = VL53L0X_SetVcselPulsePeriod(&drv_data->vl53l0x,
VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
VL53L0X_SETUP_FINAL_RANGE_VCSEL_PERIOD);
if (ret) {
SYS_LOG_ERR("VL53L0X_SetVcselPulsePeriod final range failed");
goto exit;
}
exit:
return ret;
}
static int vl53l0x_init(struct device *dev)
{
struct vl53l0x_data *drv_data = dev->driver_data;
u8_t ret;
u16_t vl53l0x_id = 0;
VL53L0X_DeviceInfo_t vl53l0x_dev_info;
struct device *gpio;
SYS_LOG_DBG("enter in %s", __func__);
/* configure and set VL53L0X_XSHUT_Pin */
gpio = device_get_binding(CONFIG_VL53L0X_XSHUT_GPIO_DEV_NAME);
if (gpio == NULL) {
SYS_LOG_ERR("Could not get pointer to %s device.",
CONFIG_VL53L0X_XSHUT_GPIO_DEV_NAME);
return -EINVAL;
}
if (gpio_pin_configure(gpio,
CONFIG_VL53L0X_XSHUT_GPIO_PIN_NUM,
GPIO_DIR_OUT | GPIO_PUD_PULL_UP) < 0) {
SYS_LOG_ERR("Could not configure GPIO %s %d).",
CONFIG_VL53L0X_XSHUT_GPIO_DEV_NAME,
CONFIG_VL53L0X_XSHUT_GPIO_PIN_NUM);
return -EINVAL;
}
gpio_pin_write(gpio, CONFIG_VL53L0X_XSHUT_GPIO_PIN_NUM, 1);
k_sleep(100);
drv_data->i2c = device_get_binding(CONFIG_VL53L0X_I2C_MASTER_DEV_NAME);
if (drv_data->i2c == NULL) {
SYS_LOG_ERR("Could not get pointer to %s device.",
CONFIG_VL53L0X_I2C_MASTER_DEV_NAME);
return -EINVAL;
}
drv_data->vl53l0x.i2c = drv_data->i2c;
drv_data->vl53l0x.I2cDevAddr = CONFIG_VL53L0X_I2C_ADDR;
/* Get info from sensor */
memset(&vl53l0x_dev_info, 0, sizeof(VL53L0X_DeviceInfo_t));
ret = VL53L0X_GetDeviceInfo(&drv_data->vl53l0x, &vl53l0x_dev_info);
if (ret < 0) {
SYS_LOG_ERR("Could not get info from device.");
return -ENODEV;
}
SYS_LOG_DBG("VL53L0X_GetDeviceInfo = %d", ret);
SYS_LOG_DBG(" Device Name : %s", vl53l0x_dev_info.Name);
SYS_LOG_DBG(" Device Type : %s", vl53l0x_dev_info.Type);
SYS_LOG_DBG(" Device ID : %s", vl53l0x_dev_info.ProductId);
SYS_LOG_DBG(" ProductRevisionMajor : %d",
vl53l0x_dev_info.ProductRevisionMajor);
SYS_LOG_DBG(" ProductRevisionMinor : %d",
vl53l0x_dev_info.ProductRevisionMinor);
ret = VL53L0X_RdWord(&drv_data->vl53l0x,
VL53L0X_REG_WHO_AM_I,
(uint16_t *) &vl53l0x_id);
if ((ret < 0) || (vl53l0x_id != VL53L0X_CHIP_ID)) {
SYS_LOG_ERR("Issue on device identification");
return -ENOTSUP;
}
/* sensor init */
ret = VL53L0X_DataInit(&drv_data->vl53l0x);
if (ret < 0) {
SYS_LOG_ERR("VL53L0X_DataInit return error (%d)", ret);
return -ENOTSUP;
}
ret = vl53l0x_setup_single_shot(dev);
if (ret < 0) {
return -ENOTSUP;
}
dev->driver_api = &vl53l0x_api_funcs;
return 0;
}
static struct vl53l0x_data vl53l0x_driver;
DEVICE_INIT(vl53l0x, CONFIG_VL53L0X_NAME, vl53l0x_init, &vl53l0x_driver,
NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY);