VL53L0X調試總結

最近調VL53L0X花了不少時間,特總結下

https://www.st.com/content/st_com/en/search.html#q=vl53l-t=products-page=1

VL53L0X測距2m 

VL53L1X測距4m 支持將校準數據保存到芯片內部

我們使用是是VL53L0X作爲接近傳感器  項目中存在兩個VL53L0X對射的情況

接st官方的塑料帽或者不接,VL53L0X的測距都是挺準的 官方的塑料帽的發射和接收進行了物理隔離,所以不會有干擾問題。

但接上我們的玻璃蓋板後,60cm的距離測出的是40cm,而且每塊玻璃蓋板都有差異。官方有該現象的解釋(VL53L0X calibration free dirty environment cover glass solution)https://www.st.com/content/st_com/en/search.html#q=vl53l-t=videos-page=1,可以通過校準來修正。

校準分爲長距(xtalk 60cm)和短距(offect 10cm)校準
假設沒校準前,測量60cm的距離,讀出來的距離是40cm,校準後,讀數也是60cm,相等於對數據進行了修正。

應用層的校準demo如下

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "vl53l0x_def.h"

#define MODE_RANGE		0
#define MODE_XTAKCALIB	1
#define MODE_OFFCALIB	2
#define MODE_HELP		3
#define MODE_PARAMETER  6
#define MODE_OFFCALIB_SET 7
#define MODE_XTAKCALIB_SET 8


//******************************** IOCTL definitions
#define VL53L0X_IOCTL_INIT			_IO('p', 0x01)
#define VL53L0X_IOCTL_XTALKCALB		_IOW('p', 0x02, unsigned int)
#define VL53L0X_IOCTL_OFFCALB		_IOW('p', 0x03, unsigned int)
#define VL53L0X_IOCTL_STOP			_IO('p', 0x05)
#define VL53L0X_IOCTL_SETXTALK		_IOW('p', 0x06, unsigned int)
#define VL53L0X_IOCTL_SETOFFSET		_IOW('p', 0x07, int8_t)
#define VL53L0X_IOCTL_GETDATAS		_IOR('p', 0x0b, VL53L0X_RangingMeasurementData_t)
#define VL53L0X_IOCTL_PARAMETER		_IOWR('p', 0x0d, struct stmvl53l0x_parameter)

//modify the following macro accoring to testing set up
#define OFFSET_TARGET		100
#define XTALK_TARGET		600
#define NUM_SAMPLES			20//20

typedef enum {
	OFFSET_PAR = 0,
	XTALKRATE_PAR = 1,
	XTALKENABLE_PAR = 2,
	GPIOFUNC_PAR = 3,
	LOWTHRESH_PAR = 4,
	HIGHTHRESH_PAR = 5,
	DEVICEMODE_PAR = 6,
	INTERMEASUREMENT_PAR = 7,
	REFERENCESPADS_PAR = 8,
	REFCALIBRATION_PAR = 9,
} parameter_name_e;
/*
 *  IOCTL parameter structs
 */
struct stmvl53l0x_parameter {
	uint32_t is_read; //1: Get 0: Set
	parameter_name_e name;
	int32_t value;
	int32_t value2;
	int32_t status;
};

static void help(void)
{
	fprintf(stderr,
		"Usage: vl53l0x_test [-c] [-h]\n"
		" -h for usage\n"
		" -c for crosstalk calibration\n"
		" -x set crosstalk calibration\n"
		" -o for offset calibration\n"
		" -s set offset calibration\n"
		" default for ranging\n"
		);
	exit(1);
}
//xtalk Calibrate place black target at 600mm from glass===
//XtalkInt:280

//xtalk Calibrate place black target at 100mm from glass===
//get offset 9000 micrometer===
//get VhvSettings is 27 ===
//get PhaseCas is 1 ===
//get SpadCount is 9 ===
//get IsApertureSpads is 1 =
int main(int argc, char *argv[])
{
	int fd;
	unsigned long data;
	VL53L0X_RangingMeasurementData_t range_datas;
	struct stmvl53l0x_parameter parameter;
	int flags = 0;
	int mode = MODE_RANGE;
	unsigned int targetDistance=0;
	int i = 0;

	/* handle (optional) flags first */
	while (1+flags < argc && argv[1+flags][0] == '-') {
		switch (argv[1+flags][1]) {
		case 'c': mode= MODE_XTAKCALIB; break;
		case 'x': mode= MODE_XTAKCALIB_SET; break;
		case 'o': mode = MODE_OFFCALIB; break;
		case 's': mode = MODE_OFFCALIB_SET; break;
		case 'h': mode= MODE_HELP; break;
		default:
			fprintf(stderr, "Error: Unsupported option "
				"\"%s\"!\n", argv[1+flags]);
			help();
			exit(1);
		}
		flags++;
	}
	if (mode == MODE_HELP)
	{
		help();
		exit(0);
	}

	fd = open("/dev/stmvl53l0y_ranging",O_RDWR | O_SYNC);
	if (fd <= 0)
	{
		fprintf(stderr,"Error open stmvl53l0x_ranging device: %s\n", strerror(errno));
		return -1;
	}

	if (ioctl(fd, VL53L0X_IOCTL_STOP , NULL) < 0) {	//make sure it's not started
		fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_STOP : %s\n", strerror(errno));
		close(fd);
		return -1;
	}
	if (mode == MODE_XTAKCALIB)//校準並獲取校準因子
	{
		unsigned int XtalkInt = 0;
		uint8_t XtalkEnable = 0;
		fprintf(stderr, "xtalk Calibrate place black target at %dmm from glass===\n",XTALK_TARGET);

		targetDistance = XTALK_TARGET;
		if (ioctl(fd, VL53L0X_IOCTL_XTALKCALB , &targetDistance) < 0) {//開始校準
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_XTALKCALB : %s\n", strerror(errno));
			close(fd);
			return -1;
		}

		parameter.is_read = 1;
		parameter.name = XTALKRATE_PAR;
		if (ioctl(fd, VL53L0X_IOCTL_PARAMETER , &parameter) < 0) {
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}
		XtalkInt = (unsigned int)parameter.value;//xtalk(得到的校準因子 需要保存)
		fprintf(stderr,"XtalkInt:%d\n",XtalkInt);
		close(fd);
		return 0;
	}else if(mode == MODE_XTAKCALIB_SET){//每次開機設置XTAK校準因子到機器
		fprintf(stderr, "start MODE_XTAKCALIB_SET\n");
		parameter.is_read = 0;
		parameter.name = XTALKENABLE_PAR;
		parameter.value=1;
		if (ioctl(fd, VL53L0X_IOCTL_PARAMETER , &parameter) < 0) { //使能校準
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}

		parameter.name = XTALKRATE_PAR;
		parameter.value=432; //上面的XtalkInt 就是校準因子 假設是432
		if (ioctl(fd, VL53L0X_IOCTL_PARAMETER , &parameter) < 0) {//寫校準因子到機器
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}
		fprintf(stderr, "stop MODE_XTAKCALIB_SET\n");
		close(fd);
		return 0;
	}else if (mode == MODE_OFFCALIB){
		int offset=0;
		uint32_t SpadCount=0;
		uint8_t IsApertureSpads=0;
		uint8_t VhvSettings=0,PhaseCal=0;
		fprintf(stderr, "offset Calibrate place black target at %dmm from glass===\n",OFFSET_TARGET);

		targetDistance = OFFSET_TARGET;
		if (ioctl(fd, VL53L0X_IOCTL_OFFCALB , &targetDistance) < 0) {
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_OFFCALB : %s\n", strerror(errno));
			close(fd);
			return -1;
		}

		parameter.is_read = 1;
		parameter.name = OFFSET_PAR;
		if (ioctl(fd, VL53L0X_IOCTL_PARAMETER, &parameter) < 0) {
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}
		offset = (int)parameter.value;  //獲取offset校準因子
		fprintf(stderr, "get offset %d micrometer===\n",offset);

		close(fd);
		return -1;
	}else if (mode == MODE_OFFCALIB_SET){
		int offset=0;
		uint32_t SpadCount=0;
		uint8_t IsApertureSpads=0;
		uint8_t VhvSettings=0,PhaseCal=0;
		fprintf(stderr, "start MODE_OFFCALIB_SET\n");
		parameter.is_read = 0;
		parameter.name = OFFSET_PAR;

		parameter.value=400;                   //設置offset校準因子,假設是400
		if (ioctl(fd, VL53L0X_IOCTL_PARAMETER, &parameter) < 0) {
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}

		if (ioctl(fd, VL53L0X_IOCTL_SETOFFSET , &parameter) < 0) {//寫校準因子到機器
			fprintf(stderr, "Error: Could not perform VL53L0X_IOCTL_PARAMETER : %s\n", strerror(errno));
			close(fd);
			return -1;
		}

		fprintf(stderr, "stop MODE_OFFCALIB_SET\n");
		close(fd);
		return -1;
	}
	else{
	}
	return 0;
}

驅動層的校準可參考

static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev,
				struct device_attribute *attr, const char *buf,
				size_t count)
{
	struct stmvl53l0x_data *data = dev_get_drvdata(dev);
	int ret;
	FixPoint1616_t TempFix1616;
	VL53L0Y_DEV vl53l0x_dev = data;
	unsigned long val = simple_strtoul(buf, NULL, 10);

	if ((val != 0) && (val != 1) && (val != 2) && (val != 3)) {
		vl53l0x_errmsg("store unvalid value=%ld\n", val);
		return count;
	}
	mutex_lock(&data->work_mutex);
	vl53l0x_dbgmsg("Enter, enable_ps_sensor flag:%d\n",
		data->enable_ps_sensor);
	vl53l0x_dbgmsg("enable ps senosr ( %ld)\n", val);

	if (val == 1) {
		/* turn on tof sensor */
		if (data->enable_ps_sensor == 0) {
			/* to start */
			stmvl53l0x_start(data, 3, NORMAL_MODE);
		} else {
			vl53l0x_errmsg("Already enabled. Skip !");
		}
	}else if(val == 2){
		vl53l0x_dbgmsg("Enter XTALKCALIB_MODE!\n");
		if (data->enable_ps_sensor == 1) {
			data->enable_ps_sensor = 0;
			stmvl53l0x_stop(data);
		}
		data->xtalkCalDistance=600;
		stmvl53l0x_start(data, 3, XTALKCALIB_MODE);
		papi_func_tbl->GetXTalkCompensationRateMegaCps(vl53l0x_dev, &TempFix1616);
		vl53l0x_dbgmsg("Enter XTALKCALIB_MODE TempFix1616=%d\n",TempFix1616);
		xtalk_calib = TempFix1616;
		ret=stmvl53l0x_write_xtalk_calibration_file();
		if(ret<0){
			vl53l0x_errmsg("stmvl53l0x_write_xtalk_calibration_file error !");
			count=-1;
		}
	}
	else if(val == 3){
		vl53l0x_dbgmsg("Enter OFFSETCALIB_MODE!\n");
		if (data->enable_ps_sensor == 1) {
			data->enable_ps_sensor = 0;
			stmvl53l0x_stop(data);
		}
		data->offsetCalDistance=100;
		stmvl53l0x_start(data, 3, OFFSETCALIB_MODE);
		papi_func_tbl->GetOffsetCalibrationDataMicroMeter(vl53l0x_dev, &TempFix1616);
		vl53l0x_dbgmsg("Enter XTALKCALIB_MODE TempFix1616=%d\n",TempFix1616);
		offset_calib=TempFix1616;
		ret=stmvl53l0x_write_offset_calibration_file();
		if(ret<0){
			vl53l0x_errmsg("stmvl53l0x_write_offset_calibration_file error !");
			count=-1;
		}
	}
	else {
		/* turn off tof sensor */
		if (data->enable_ps_sensor == 1) {
			data->enable_ps_sensor = 0;
			/* to stop */
			stmvl53l0x_stop(data);
		}
	}
	vl53l0x_dbgmsg("End\n");
	mutex_unlock(&data->work_mutex);

	return count;
}

保存和讀取校準文件,注意文件的權限,否則會出現文件創建,讀寫失敗

stmvl53l0x_read_calibration_file
stmvl53l0x_write_offset_calibration_file
stmvl53l0x_write_xtalk_calibration_file

f->f_op->read會變成NULL,直接調用有空指針,需修正爲

f->f_op->read ---> vfs_read
f->f_op->write---> vfs_write

默認有個工作隊列(非中斷模式)循環獲取數據data->delay_ms(修改成int型),因爲我們的產品存在兩個vl53l0x對射的情況,需要加大該值來降低vl53l0x工作頻率(減少單位時間內的發光量)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章