iio: proximity: add nds03 tof sensor

Change-Id: I263bc2a7cc302ded8c940a10f73e050abdefa1de
Signed-off-by: Jianwei Fan <jianwei.fan@rock-chips.com>
This commit is contained in:
Jianwei Fan
2025-09-19 09:47:45 +08:00
committed by Tao Huang
parent 1e7a3292b6
commit 97faaa82e2
21 changed files with 3713 additions and 0 deletions

View File

@@ -32,6 +32,8 @@ config CROS_EC_MKBP_PROXIMITY
To compile this driver as a module, choose M here: the
module will be called cros_ec_mkbp_proximity.
source "drivers/iio/proximity/nds03/Kconfig"
config ISL29501
tristate "Intersil ISL29501 Time Of Flight sensor"
depends on I2C

View File

@@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
obj-$(CONFIG_DTOF_NDS03) += nds03/
obj-$(CONFIG_ISL29501) += isl29501.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_MB1232) += mb1232.o

View File

@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
config DTOF_NDS03
tristate "NDS03 I2C DEVICE"
depends on I2C && SYSFS
help
Using I2C

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Makefile for the nds03 drivers.
#
obj-$(CONFIG_DTOF_NDS03) += nds03.o
nds03-y += nds03_module.o nds03_platform.o nds03_module_i2c.o nds03_iio.o \
nds03_dev.o nds03_data.o \
nds03_comm.o nds03_calib.o

View File

@@ -0,0 +1,104 @@
/*!
@file nds03.h
@brief
@author lull
@date 2025-06
@copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd.
@license BSD 3-Clause License
This file is part of the Nephotonics sensor SDK.
It is licensed under the BSD 3-Clause License.
A copy of the license can be found in the project root directory, in the file named LICENSE.
*/
#ifndef __NDS03_H
#define __NDS03_H
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/atomic.h>
#include <linux/interrupt.h>
/* nds03 sdk */
#include "nds03_comm.h"
#include "nds03_dev.h"
#include "nds03_data.h"
#include "nds03_calib.h"
#include "nds03_def.h"
#define TOF_NDS03_DRV_NAME "tof_nds03"
#define DRIVER_VERSION "1.0.4"
#define TOF_NDS03_MAJOR 255
#define MAX_POS_BITS 32
/*! use debug */
extern int nds03_enable_debug;
#define nds03_dbgmsg(str, ...) \
do { \
if (nds03_enable_debug > 0) \
printk("%s: " str, __FUNCTION__, ##__VA_ARGS__); \
} while (0)
#define nds03_info(str, ...) \
pr_info("%s: " str , __FUNCTION__, ##__VA_ARGS__)
#define nds03_errmsg(str, ...) \
pr_err("%s: " str, __FUNCTION__, ##__VA_ARGS__)
#define nds03_warnmsg(str, ...) \
pr_warn("%s: " str,__FUNCTION__, ##__VA_ARGS__)
struct nds03_context {
/*!< multiple device id 0 based*/
int id;
/*!< misc device name */
char name[64];
struct i2c_client * client;
/*!< nds03 device info */
NDS03_Dev_t g_nds03_device;
/*!< main dev mutex/lock */
struct mutex work_mutex;
// /*!< work for pseudo irq polling check */
struct delayed_work dwork;
struct work_struct irq_work;
// /*!< input device used for sending event */
struct input_dev *idev;
/*!< intr gpio number */
int irq;
bool remove_flag;
/// /* user control configuration parameter */
/*!< measure mode irq or poll*/
atomic_t meas_mode;
/*!< rescheduled time use in poll mode */
atomic_t poll_delay_ms;
/*!< use ctrl measure state */
atomic_t is_meas;
/*!< calibtion result of the deivce */
int calib_result;
/*!< open input file descriptor count*/
int fd_open_count;
struct iio_dev *indio_dev;
struct nds03_iio_dev *iio;
};
int nds03_common_probe(struct nds03_context * ctx);
int nds03_common_remove(struct nds03_context * ctx);
int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open);
int nds03_sensor_init(struct nds03_context *ctx);
#endif

View File

@@ -0,0 +1,275 @@
/**
* @file nds03_calib.c
* @author tongsheng.tang
* @brief NDS03 Calibration functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*/
#include "nds03_comm.h"
#include "nds03_dev.h"
#include "nds03_data.h"
#include "nds03_calib.h"
/**
* @brief NDS03 Get Offset Calib Depth MM
* offset标定距离
* @param pNxDevice
* @param calib_depth_mm
* @return NDS03_Error
*/
NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm));
return ret;
}
/**
* @brief NDS03 Set Offset Calib Depth MM
* offset标定距离
* @param pNxDevice
* @param calib_depth_mm
* @return NDS03_Error
*/
NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if (calib_depth_mm == 0)
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, &calib_depth_mm));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
return ret;
}
/**
* @brief NDS03 Offset Calibration Check
* Offset
* @param pNxDevice
* @param calib_depth_mm
* @return NDS03_Error
*/
static NDS03_Error NDS03_OffsetCalibrationCheck(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint16_t ref_histo_max, depth[2];
uint8_t depth_flag;
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max));
if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) {
ret = NDS03_ERROR_VCSEL_ERROR;
NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max);
return ret;
}
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DEPTH_FLAG, &depth_flag));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 1));
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
depth[0] = pNxDevice->ranging_data[0].depth;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 2));
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
depth[1] = pNxDevice->ranging_data[0].depth;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, depth_flag));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
if (ret == NDS03_ERROR_NONE && ((depth[0] + NDS03_OFFSET_DEPTH_ERROR_TH < depth[1]) ||
(depth[0] > depth[1] + NDS03_OFFSET_DEPTH_ERROR_TH) ||
depth[0] == NDS03_DEPTH_INVALID_VALUE || depth[1] == NDS03_DEPTH_INVALID_VALUE)) {
ret = NDS03_ERROR_OFFSET_ERROR;
NX_PRINTF("depth[0]:%d depth[1]:%d\r\n", depth[0], depth[1]);
}
return ret;
}
/**
* @brief ToF Offset
* @details 使500mm
*
* @param pNxDevice
* @return int8_t
* @retval 0:
* @retval !0: Offset标定失败
*/
NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint16_t ambient_bg;
NX_PRINTF("%s Start!\r\n", __func__);
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg));
if (ambient_bg > NDS03_AMBIENT_TH) {
ret = NDS03_ERROR_AMBIENT_HIGH;
NX_PRINTF("ambient_bg:%d\r\n", ambient_bg);
return ret;
}
// 打开使能
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB));
CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE));
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret));
CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice));
NX_PRINTF("%s End!\r\n", __func__);
return ret;
}
/**
* @brief ToF Offset
* @details
*
* @param pNxDevice
* @param calib_depth_mm
* @return int8_t
* @retval 0:
* @retval !0: Offset标定失败
*/
NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint16_t ambient_bg;
NX_PRINTF("%s Start!\r\n", __func__);
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg));
if (ambient_bg > NDS03_AMBIENT_TH){
ret = NDS03_ERROR_AMBIENT_HIGH;
NX_PRINTF("ambient:%d \r\n", ambient_bg);
return ret;
}
CHECK_RET(NDS03_SetOffsetCalibDepthMM(pNxDevice, calib_depth_mm));
// 打开使能
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB));
CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE));
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret));
CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice));
NX_PRINTF("%s End!\r\n", __func__);
return ret;
}
/**
* @brief NDS03 Read Xtalk Data
* NDS03串扰数据
* @param pNxDevice
* @param rbuf
* @param size
* @return NDS03_Error
*/
static NDS03_Error NDS03_ReadXtalkData(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint32_t rsize, _size;
uint8_t one_size;
uint16_t addr;
uint16_t rbuf[240];
uint8_t *rbuf_ptr = (uint8_t *)rbuf;
uint32_t size = 240 * 2;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, 0xEC, &addr));
_size = (uint32_t)one_size;
rsize = 0;
while ((rsize < size) && (ret == NDS03_ERROR_NONE)) {
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0));
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200));
CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, rbuf_ptr,
((size-rsize)>_size) ? _size:(size-rsize)));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
rbuf_ptr += _size;
addr += _size;
rsize += _size;
}
for (int i = 80; i < 240; i++) {
if (rbuf[i] > 10000)
return -14;
}
return ret;
}
/**
* @brief NDS03 Xtalk Calibration
* NDS03串扰/
* @param pNxDevice
* @return int8_t
* @retval 0:
* @retval !0: xtalk标定失败
*/
NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE, calib_state = NDS03_ERROR_NONE;
uint16_t ambient_bg,ref_histo_max;
uint8_t cnt = 2;
int8_t check_xtalk_state = 0;
NX_PRINTF("%s Start!\r\n", __func__);
do {
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max));
if (ambient_bg > NDS03_AMBIENT_TH) {
ret = NDS03_ERROR_AMBIENT_HIGH;
NX_PRINTF("ambient:%d\r\n", ambient_bg);
return ret;
}
if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) {
ret = NDS03_ERROR_VCSEL_ERROR;
NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max);
return ret;
}
// 打开使能
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_XTALK_CALIB));
CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_XTALK_CALIB, 5000));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE));
CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice));
if (pNxDevice->chip_info.fw_version == 0x10203) {
CHECK_RET(NDS03_GetSingleRangingData(pNxDevice));
check_xtalk_state = NDS03_ReadXtalkData(pNxDevice);
}
} while (cnt-- && check_xtalk_state != 0);
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&calib_state));
ret = check_xtalk_state ? check_xtalk_state : (ret | calib_state) &
(NDS03_CALIB_ERROR_XTALK_OVERFLOW | NDS03_CALIB_ERROR_XTALK_EXCESSIVE);
NX_PRINTF("%s End!\r\n", __func__);
return ret;
}
/**
* @brief NDS03 Get Xtalk Value
*
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_XTALK, xtalk_value));
return ret;
}

View File

@@ -0,0 +1,42 @@
/**
* @file nds03_calib.h
* @author tongsheng.tang
* @brief NDS03 Calibration functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory, in the file named LICENSE.
*
*/
#ifndef __NDS03_CALIB_H__
#define __NDS03_CALIB_H__
#include "nds03_def.h"
/** @defgroup NDS03_Calibration_Group NDS03 Calibration Functions
* @brief NDS03 Calibration Functions
* @{
*/
/** 获取offset标定距离 */
NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm);
/** 设置offset标定距离 */
NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm);
/** Offset标定函数(无标定距离设置) */
NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice);
/** Offset标定函数(有标定距离设置) */
NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm);
/** XTalk标定 */
NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice);
/** 获取标定串扰值 */
NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value);
/** @} NDS03_Calibration_Group */
#endif

View File

@@ -0,0 +1,385 @@
/**
* @file nds03_comm.c
* @author tongsheng.tang
* @brief NDS03 communication functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*/
#include "nds03_stdint.h"
#if NDS03_PLATFORM != PLATFORM_LINUX_DRIVER
#include <stdint.h>
#include <stdlib.h>
#else
#include <linux/types.h>
#endif
#include "nds03_dev.h"
#include "nds03_comm.h"
#include "nds03_def.h"
#include "nds03_platform.h"
/**
* @brief NDS03 Delay 1ms
* @param ms
* @return void
*/
NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms)
{
return nds03_delay_1ms(&pNxDevice->platform, ms);
}
/**
* @brief NDS03 Delay 10us
* @param us
* @return void
*/
NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us)
{
return nds03_delay_10us(&pNxDevice->platform, us);
}
/**
* @brief NDS03 Get System Clk Ms
* @param pNxDevice
* @param time_ms ms
* @return void
*/
NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret = nds03_get_system_clk_ms(&pNxDevice->platform, time_ms);
return ret;
}
/**
* @brief NDS03 Set XShut Pin Level
* xshut引脚的电平
* @param pNxDevice
* @param level xshut引脚电平01
* @return void
*/
NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level)
{
return nds03_set_xshut_pin_level(&pNxDevice->platform, level);
}
/**
* @brief i2c时钟频率
*
* @param pNxDevice
* @param freq
* @return
*/
NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq)
{
return nds03_i2c_get_clock_frequency(&pNxDevice->platform, freq);
}
/**
* @brief i2c时钟频率
*
* @param pNxDevice
* @param freq
* @return
*/
NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq)
{
return nds03_i2c_set_clock_frequency(&pNxDevice->platform, freq);
}
/**
* @brief 2
*
* @param buf
* @param buf_num
*/
static void NDS03_HalfWordDataFmtChange(uint16_t *buf, uint16_t buf_num)
{
uint16_t tmp;
uint8_t *pu8buf = (uint8_t*)buf;
uint16_t i;
for (i = 0; i < buf_num; i++) {
tmp = buf[i];
*pu8buf++ = (tmp >> 0);
*pu8buf++ = (tmp >> 8);
}
}
/**
* @brief 14
*
* @param buf
* @param buf_num
*/
static void NDS03_WordDataFmtChange(uint32_t *buf, uint16_t buf_num)
{
uint32_t tmp;
uint8_t *pu8buf = (uint8_t*)buf;
uint16_t i;
for (i = 0; i < buf_num; i++) {
tmp = buf[i];
*pu8buf++ = (tmp >> 0);
*pu8buf++ = (tmp >> 8);
*pu8buf++ = (tmp >> 16);
*pu8buf++ = (tmp >> 24);
}
}
/**
* @brief Write n Words to NDS03
* NDS03的寄存器写N个字
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @param len:
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size);
return ret;
}
/**
* @brief Read n Words from NDS03
* NDS03的寄存器读N个字
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @param len:
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size);
return ret;
}
/**
* @brief Write 1 Byte to NDS03
* NDS03的寄存器写1个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, &wdata, 1);
return ret;
}
/**
* @brief Read 1 Byte from NDS03
* NDS03的寄存器读1个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, rdata, 1);
return ret;
}
/**
* @brief Write N bytes By Half-Word to NDS03
* NDS03的寄存器写N个字节,使
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @param size:
* size必须是2的倍数
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice,
uint8_t addr, uint16_t *wdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if ((size & 0x01) == 0) {
NDS03_HalfWordDataFmtChange(wdata, size / 2);
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size);
NDS03_HalfWordDataFmtChange(wdata, size / 2);
}
return ret;
}
/**
* @brief Read N Bytes By Half-World from NDS03
* NDS03的寄存器读N个字节,使
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @param size:
* size必须是2的倍数
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if ((size & 0x01) == 0 && rdata != NULL) {
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size);
NDS03_HalfWordDataFmtChange(rdata, size / 2);
}
return ret;
}
/**
* @brief Write 2 Byte to NDS03
* NDS03的寄存器写2个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t tmp[2];
tmp[0] = (wdata >> 0) & 0xFF;
tmp[1] = (wdata >> 8) & 0xFF;
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp));
return ret;
}
/**
* @brief Read 2 Byte from NDS03
* NDS03的寄存器读2个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t tmp[2];
if (rdata != NULL) {
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp));
*rdata = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8);
}
return ret;
}
/**
* @brief Write N Bytes By Word to NDS03
* NDS03的寄存器写N个字节,使
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @param size:
* size必须是4的倍数
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr,
uint32_t *wdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if ((size & 0x03) == 0) {
NDS03_WordDataFmtChange(wdata, size / 4);
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size);
NDS03_WordDataFmtChange(wdata, size / 4);
}
return ret;
}
/**
* @brief Read N Bytes By Word from NDS03
* NDS03的寄存器读N个字节,使
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @param size:
* size必须是4的倍数
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata, uint16_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if ((size & 0x03) == 0 && rdata != NULL) {
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size);
NDS03_WordDataFmtChange(rdata, size / 4);
}
return ret;
}
/**
* @brief Write 4 Byte to NDS03
* NDS03的寄存器写2个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param wdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t tmp[4];
tmp[0] = (wdata >> 0) & 0xFF;
tmp[1] = (wdata >> 8) & 0xFF;
tmp[2] = (wdata >> 16) & 0xFF;
tmp[3] = (wdata >> 24) & 0xFF;
ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp));
return ret;
}
/**
* @brief Read 4 Byte from NDS03
* NDS03的寄存器读2个字节
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param addr:
* @param rdata:
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t tmp[4];
if (rdata != NULL) {
ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp));
*rdata = (uint32_t)tmp[0] | ((uint32_t)tmp[1] << 8) |
((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[3] << 24);
}
return ret;
}

View File

@@ -0,0 +1,71 @@
/**
* @file nds03_comm.h
* @author tongsheng.tang
* @brief NDS03 communication functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*/
#ifndef __NDS03_COMM_H__
#define __NDS03_COMM_H__
#include "nds03_def.h"
/** @defgroup NDS03_Communication_Group NDS03 Communication Functions
* @brief NDS03 Communication Functions
* @{
*/
/** 延时时间ms */
NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms);
/** 延时时间10us */
NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us);
/** 设置xshut引脚的电平 */
NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level);
/** NDS03设置i2c频率 */
NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq);
/** NDS03获取i2c频率 */
NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq);
/** 对NDS03寄存器写N个字节 */
NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size);
/** 对NDS03寄存器读N个字节 */
NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size);
/** 对NDS03寄存器写1个字节 */
NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata);
/** 对NDS03寄存器写1个字节 */
NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata);
/** 对NDS03寄存器写N个字节使用半字方式 */
NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice,
uint8_t addr, uint16_t *wdata, uint16_t size);
/** 对NDS03寄存器读N个字节使用半字方式 */
NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice,
uint8_t addr, uint16_t *rdata, uint16_t size);
/** 对NDS03寄存器写1个字 */
NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata);
/** 对NDS03寄存器读1个字 */
NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata);
/** 对NDS03寄存器写N个字节,使用字方式 */
NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice,
uint8_t addr, uint32_t *wdata, uint16_t size);
/** 对NDS03寄存器读N个字节,使用字方式 */
NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice,
uint8_t addr, uint32_t *rdata, uint16_t size);
/** 对NDS03寄存器写1个字 */
NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata);
/** 对NDS03寄存器读1个字 */
NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata);
/** 获取系统时钟时间ms */
NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms);
/** @} NDS03_Communication_Group */
#endif

View File

@@ -0,0 +1,238 @@
/**
* @file nds03_data.c
* @author tongsheng.tang
* @brief NDS03 get depth data functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*/
#include "nds03_def.h"
#include "nds03_comm.h"
#include "nds03_dev.h"
#include "nds03_data.h"
/**
* @brief NDS03 Get Ranging Data Ready
* NDS03测距是否完成
* @param pNxDevice
* @return int8_t
* @retval
* - 0
* 1:
* - ::NDS03_ERROR_I2C:IIC通讯错误/
*/
NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t buf_valid_flag = 0x00;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &buf_valid_flag));
if (buf_valid_flag == NDS03_DEPTH_DATA_FLAG)
return 1;
return ret;
}
/**
* @brief NDS03 Start Single Measurement
*
* @param pNxDevice
* @return int8_t
*/
NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
/* 清除标志位 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
/* 发送触发信号 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG));
return ret;
}
/**
* @brief NDS03 Start Continuous Measurement
*
* @param pNxDevice
* @return int8_t
*/
NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if (pNxDevice->config.continuous_flag == 0) {
/* 清除标志位 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
/* 发送触发信号 */
CHECK_RET(NDS03_WriteByte(pNxDevice,
NDS03_REG_DAT_REQ, NDS03_DEPTH_CONTINUOUS_FLAG));
pNxDevice->config.continuous_flag = 1;
}
return ret;
}
/**
* @brief NDS03 Stop Continuous Measurement
*
* @param pNxDevice
* @return int8_t
*/
NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
if (pNxDevice->config.continuous_flag != 0) {
/* 清除标志位 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DATA_REQ_IDLE));
/* 等待测量完成 */
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_CONTINUOUS_FLAG, 200));
/* 清除标志位 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
pNxDevice->config.continuous_flag = 0;
}
return ret;
}
/**
* @brief NDS03 Clear Data Valid Flag
* NDS03测量数据的有效位
* NDS03数据已读取
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
return ret;
}
/**
* @brief NDS03 Read Ranging Data
* NDS03寄存器获取测量数据
* @param pNxDevice
* @return int32_t
*/
NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
#if NDS03_TARGET_MAX_NUM == 1
CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice,
NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0],
sizeof(pNxDevice->ranging_data[0])));
#endif
#if NDS03_TARGET_MAX_NUM == 2
CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice,
NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0],
2 * sizeof(pNxDevice->ranging_data[0])));
#endif
#if NDS03_TARGET_MAX_NUM == 3
CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice,
NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0],
3 * sizeof(pNxDevice->ranging_data[0])));
#endif
#if NDS03_TARGET_MAX_NUM >= 4
CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice,
NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0],
4 * sizeof(pNxDevice->ranging_data[0])));
#endif
return ret;
}
/**
* @brief NDS03 Get Continuous Ranging Data
* NDS03中获取一次深度数据
* NDS03_StartContinuousMeasurement函数搭配
* @param pNxDevice
* @param pData
* @return int32_t
*/
NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t data_cnt;
uint32_t retry_cnt = 20000;
/* 等待测量完成 */
do {
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &data_cnt));
CHECK_RET(NDS03_Delay10us(pNxDevice, 10));
} while (data_cnt == pNxDevice->data_cnt && --retry_cnt);
pNxDevice->data_cnt = data_cnt;
if (retry_cnt != 0) {
/* 读取测量数据 */
CHECK_RET(NDS03_ReadRangingData(pNxDevice));
/* 清除数据有效标志位 */
CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice));
} else {
ret = NDS03_ERROR_TIMEOUT;
}
return ret;
}
/**
* @brief NDS03 Get Single Ranging Data
* NDS03中获取一次深度数据
*
* @param pNxDevice
* @return int32_t
*/
NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
int32_t timeout_ms = pNxDevice->config.range_frame_time_us / 1000;
/* 清除标志位 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
/* 发送触发信号 */
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG));
/* 等待测量完成 */
timeout_ms = (timeout_ms < 200) ? 200 : timeout_ms;
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_DATA_FLAG, timeout_ms));
/* 读取测量数据 */
CHECK_RET(NDS03_ReadRangingData(pNxDevice));
/* 清除数据有效标志位 */
CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice));
return ret;
}
/**
* @brief NDS03 Get Interrupt Ranging Data
* NDS03中获取一次中断深度数据
*
* @param pNxDevice
* @return int32_t
*/
NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
/* 读取测量数据 */
CHECK_RET(NDS03_ReadRangingData(pNxDevice));
/* 清除数据有效标志位 */
CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice));
return ret;
}

View File

@@ -0,0 +1,46 @@
/**
* @file nds03_data.h
* @author tongsheng.tang
* @brief NDS03 communication and data handling functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*
*/
#ifndef __NDS03_DATA_H__
#define __NDS03_DATA_H__
#include "nds03_def.h"
/** @defgroup NDS03_Data_Group NDS03 Data Functions
* @brief NDS03 Data Functions
* @{
*/
/** 检测NDS03测距是否完成 */
NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice);
/** 发送开始单次测量信号 */
NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice);
/** 发送开始连续测量信号 */
NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice);
/** 发送结束连续测量信号 */
NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice);
/** 清除数据有效位 */
NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice);
/** 读取深度和幅度值 */
NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice);
/** 获取连续测量深度和幅度值 */
NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice);
/** 获取一次测量深度和幅度值 */
NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice);
/** 获取一次中断数据 */
NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice);
/** @} NDS03_Data_Group */
#endif // __NDS03_DATA_H__

View File

@@ -0,0 +1,308 @@
/**
* @file nds03_def.h
* @author tongsheng.tang
* @brief NDS03's Macro definition and data structure
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*
*/
#ifndef __NDS03_DEF_H__
#define __NDS03_DEF_H__
#include "nds03_stdint.h"
#if NDS03_PLATFORM == PLATFORM_LINUX_DRIVER
#include <linux/kernel.h>
#else
#include <stdio.h>
#endif
#include "nds03_platform.h"
#ifndef DEBUG_INFO
#define DEBUG_INFO 0 /** 调试信息打印开关 */
#endif
#if NDS03_PLATFORM == PLATFORM_NOT_C51
#include <stdio.h>
#define NX_PRINTF(fmt, ...) do { if (DEBUG_INFO) printf(fmt, ##__VA_ARGS__); } while(0)
#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER
#include <linux/kernel.h>
#define NX_PRINTF(fmt, args...) do { if (DEBUG_INFO) printk(fmt, ##args); } while(0)
#elif NDS03_PLATFORM == PLATFORM_C51
#define NX_PRINTF(fmt, ...)
#else
#define NX_PRINTF(fmt, ...)
#endif
/** @defgroup NDS03_Global_Define_Group NDS03 Defines
* @brief NDS03 Defines
* @{
*/
/** @defgroup NDS03_Reg_Group NDS03 Register Defines
* @brief NDS03 Register Defines
* @{
*/
#define NDS03_REG_DEV_ADDR (0x1E) /** 模组的设备地址 */
#define NDS03_REG_STATE (0x20) /** 模组运行状态寄存器 */
#define NDS03_REG_DATA_CNT (0x21) /** 模组测距次数计数值 */
#define NDS03_REG_FW_VER (0x24) /** 模组固件版本号寄存器 */
#define NDS03_REG_RANGE_STATE (0x28) /** 测距状态码 */
#define NDS03_REG_CALIB_STATE (0x29) /** 标定状态码 */
#define NDS03_REG_THERM (0x2A) /** 温度值 */
#define NDS03_REG_AMBIENT (0x2C) /** 环境光值 */
#define NDS03_REG_DEPTH (0x30) /** 深度值 */
#define NDS03_REG_CONFI (0x32) /** 置信度 */
#define NDS03_REG_COUNT (0x34) /** 计数值 */
#define NDS03_REG_CRATE (0x36) /** 计数率 */
#define NDS03_REG_DEPTH2 (0x38) /** 深度值 */
#define NDS03_REG_CONFI2 (0x3A) /** 置信度 */
#define NDS03_REG_COUNT2 (0x3C) /** 计数值 */
#define NDS03_REG_CRATE2 (0x3E) /** 计数率 */
#define NDS03_REG_DEPTH3 (0x40) /** 深度值 */
#define NDS03_REG_CONFI3 (0x42) /** 置信度 */
#define NDS03_REG_COUNT3 (0x44) /** 计数值 */
#define NDS03_REG_CRATE3 (0x46) /** 计数率 */
#define NDS03_REG_DEPTH4 (0x48) /** 深度值 */
#define NDS03_REG_CONFI4 (0x4A) /** 置信度 */
#define NDS03_REG_COUNT4 (0x4C) /** 计数值 */
#define NDS03_REG_CRATE4 (0x4E) /** 计数率 */
#define NDS03_REG_DAT_REQ (0x50) /** 获取深度请求寄存器 */
#define NDS03_REG_DAT_VAL (0x51) /** 获取数据命令有效寄存器 */
#define NDS03_REG_CMD_REQ (0x52) /** 命令请求寄存器 */
#define NDS03_REG_CMD_VAL (0x53) /** 命令完成寄存器 */
#define NDS03_REG_CMD_ENA (0x54) /** 命令使能寄存器 */
#define NDS03_REG_CFG_ENA (0x55) /** 配置使能该值为0xA5才能访问其他寄存器 */
#define NDS03_REG_REF_HISTO_MAX (0x56) /** 参考直方图最大值 */
#define NDS03_REG_DEPTH_FLAG (0x64) /** 测距结果标志位 */
#define NDS03_REG_SLEEP_TIME (0x66) /** 睡眠时间(ms) */
#define NDS03_REG_PULSE_NUM (0x6C) /** 发光次数 */
#define NDS03_REG_DEPTH_TH_L (0x70) /** 深度低阈值 */
#define NDS03_REG_DEPTH_TH_H (0x72) /** 深度高阈值 */
#define NDS03_REG_GPIO1_FUNC (0x74) /** 中断功能/方式 */
#define NDS03_REG_SLEEP_MODE (0x75) /** 睡眠方式 */
#define NDS03_REG_CONFI_TH (0x76) /** 置信度阈值 */
#define NDS03_REG_TARGET_NUM (0x77) /** 目标个数 */
#define NDS03_REG_INV_TIME (0x7C) /** 测量间隔时间 */
#define NDS03_REG_OFFSET_MM (0x90) /** offset 标定位置 */
#define NDS03_REG_XTALK_TH (0xB0) /** 串扰阈值 */
#define NDS03_REG_XTALK (0xB2) /** 串扰值 */
#define NDS03_REG_DATA_SIZE (0x5C) /** 数据大小 */
#define NDS03_REG_CACHE_SIZE (0x5D) /** 缓存大小 */
#define NDS03_REG_CACHE_ADDR (0x5E) /** 缓存地址 */
#define NDS03_REG_CACHE_DATA (0xC0) /** 缓存数据 */
/** @} NDS03_Reg_Group */
/** @defgroup NDS03_State_Group NDS03 Data Request Index
* @brief NDS03 State (NDS03_REG_STATE)
* @{
*/
#define NDS03_STATE_IDLE 0x00 /** 空闲状态 */
#define NDS03_STATE_SOFT_READY 0xA5 /** 软件就绪状态 */
#define NDS03_STATE_GOT_DEPTH 0xA6 /** 已获取深度状态 */
/** @} NDS03_State_Group */
/** @defgroup NDS03_Data_Val_Req_Idx_Group NDS03 Data Request Index
* @brief NDS03 Data Request Mask (NDS03_REG_DAT_VAL_REQ)
* @{
*/
/** DATA REQ */
#define NDS03_DATA_REQ_IDLE 0x00 /** 无效数据命令标志位 */
#define NDS03_DEPTH_DATA_FLAG 0x10 /** 获取深度数据标志 */
#define NDS03_DEPTH_CONTINUOUS_FLAG 0x13 /** 连续获取深度数据标志 */
#define NDS03_USER_DATA_FLAG 0x50 /** 读用户数据标志位 */
#define NDS03_GET_MODEL_FLAG 0x51 /** 获取模组型号标志位 */
#define NDS03_CMD_READ_HGM_DATA 0xC0 /** 读直方图数据标志位 */
#define NDS03_CMD_READ_HGM_DATA_ENA 0x05 /** 读直方图数据使能标志位 */
/** DATA VAL */
#define NDS03_DATA_VAL_IDLE 0x00 /** 无效数据标志位 */
/** CMD REQ */
#define NDS03_CMD_OFFSET_CALIB 0x20 /** offset标定命令 */
#define NDS03_CMD_XTALK_CALIB 0x24 /** xtalk标定 */
#define NDS03_CMD_WRITE_USER_DATA 0x50 /** 写用户数据区域标志位 */
/** CMD VAL */
#define NDS03_CMD_VAL_IDLE 0x00 /** 无效命令标志位 */
/** CMD ENA */
#define NDS03_CMD_WRITE_USER_DATA_ENA 0xAA /** 用户数据使能标志位 */
#define NDS03_CMD_ENA_ENABLE 0xA5 /** 配置开启标志位 */
#define NDS03_CMD_ENA_DISABLE 0x00 /** 配置关闭标志位 */
/** @} NDS03_Data_Val_Req_Idx_Group */
/** @defgroup NDS03_Sleep_Group NDS03 Sleep Group
* @brief NDS03 Sleep (NDS03_REG_SLEEP_MODE)
* @{
*/
#define NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP 0xA5 /* 手动进入软件睡眠标志位,超时唤醒 */
#define NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP 0xA4 /* 手动进入软件睡眠标志位,手动唤醒 */
// #define NDS03_AUTO_SLEEP_MANUAL_WEAK_UP 0xA3 /* 测量结束自动进入软件睡眠标志位,手动唤醒 */
// #define NDS03_AUTO_SLEEP_TIME_OUT_WEAK_UP 0xA2 /* 测量结束自动进入软件睡眠标志位,超时唤醒 */
/** @} NDS03_Sleep_Group */
/** @enum NDS03_Status_e
* @brief NDS03状态宏
*/
typedef int8_t NDS03_Error;
/** @defgroup NDS03_Error_Group NDS03 Error Group
* @brief NDS03 Error Group (NDS03_REG_ERROR_FLAG)
* @{
*/
#define NDS03_ERROR_NONE 0 /** 成功 */
#define NDS03_ERROR_API -1 /** api接口注册失败 */
#define NDS03_ERROR_TIMEOUT -2 /** 超时错误 */
#define NDS03_ERROR_I2C -3 /** IIC通讯错误 */
#define NDS03_ERROR_BOOT -4 /** 模组启动错误 */
#define NDS03_ERROR_CALIB -5 /** 标定失败错误 */
#define NDS03_ERROR_INIT -6 /** 初始化失败 */
#define NDS03_ERROR_RANGING -7 /** 测距出错 */
#define NDS03_ERROR_UPGRADE_VER -8 /** 升级版本不对 */
#define NDS03_ERROR_UPGRADE -9 /** 升级失败 */
#define NDS03_ERROR_AMBIENT_HIGH -10 /** 标定时环境光强过大 */
#define NDS03_ERROR_NO_NDS03 -11 /** 不是NDS03模组 */
#define NDS03_ERROR_VCSEL_ERROR -12 /** VCSEL不亮 */
#define NDS03_ERROR_OFFSET_ERROR -13 /** OFFSET 标定失败 */
/** @} NDS03_Error_Group */
/** @defgroup NDS03_Calib_State_Group NDS03 Calib State Group
* @brief NDS03 Calib State Group (NDS03_REG_CALIB_STATE)
* @{
*/
#define NDS03_CALIB_ERROR_NONE 0x00 /** 成功 */
#define NDS03_CALIB_ERROR_XTALK_OVERFLOW 0x02 /** 串扰溢出 */
#define NDS03_CALIB_ERROR_XTALK_EXCESSIVE 0x10 /** 串扰过大 */
#define NDS03_CALIB_ERROR_OFFSET 0x20 /** offset标定后测距误差过大 */
/** @} NDS03_Calib_State_Group */
/** @defgroup NDS03_GPIO1_Func_Group NDS03 GPIO1 Functions Define
* @brief NDS03 GPIO1 Functions Define Group (NDS03_REG_GPIO1_FUNC)
* @{
*/
/** REG_GPIO1_SETTING Mask */
#define NDS03_GPIO1_FUNCTIONALITY_MASK 0x07 /** GPIO1功能配置掩码 */
#define NDS03_GPIO1_POLARITY_MASK 0x08 /** 极性配置掩码 */
/** GPIO1 Functionality */
typedef uint8_t NDS03_Gpio1Func_t;
#define NDS03_GPIO1_FUNCTIONALITY_OFF ((NDS03_Gpio1Func_t)0x00) /** 无触发中断 */
#define NDS03_GPIO1_THRESHOLD_LOW ((NDS03_Gpio1Func_t)0x01) /** 低深度触发中断 (value < NDS03_REG_DEPTH_TH_L) */
#define NDS03_GPIO1_THRESHOLD_HIGH ((NDS03_Gpio1Func_t)0x02) /** 高深度触发中断 (value > NDS03_REG_DEPTH_TH_H) */
#define NDS03_GPIO1_THRESHOLD_DOMAIN_OUT ((NDS03_Gpio1Func_t)0x03) /** 低深度或高深度触发中断 (value < NDS03_REG_DEPTH_TH_L 或 value > NDS03_REG_DEPTH_TH_H) */
#define NDS03_GPIO1_NEW_MEASURE_READY ((NDS03_Gpio1Func_t)0x04) /** 新深度数据就绪中断 */
/** GPIO1 polarity */
typedef uint8_t NDS03_Gpio1Polar_t;
#define NDS03_GPIO1_POLARITY_LOW ((NDS03_Gpio1Polar_t)0x00) /** 负极性, 低电平有效 */
#define NDS03_GPIO1_POLARITY_HIGH ((NDS03_Gpio1Polar_t)0x01) /** 正极性, 高电平有效 */
/** @} NDS03_GPIO1_Func_Group */
#define NDS03_TARGET_MAX_NUM 4
#define NDS03_AMBIENT_TH 1000 /** 标定时环境光强阈值 */
#define NDS03_OFFSET_DEPTH_ERROR_TH 10 /** OFFSET 标定深度误差阈值 */
#define NDS03_OFFSET_REF_MAX_COUNT_TH 500 /** OFFSET 标定深度误差阈值 */
#define NDS03_DEPTH_INVALID_VALUE 65300 /** 深度无效值 */
/** @enum NDS03_Status_e
* @brief NDS03状态宏
*/
typedef enum{
NDS03_DISABLE = 0, ///< 关闭状态
NDS03_ENABLE = 1 ///< 使能状态
} NDS03_Status_e;
/**
* @struct NDS03_RangingData_t
*
* @brief NDS03测量结果结构体 \n
* NDS03的深度
*/
typedef struct{
uint16_t depth; ///< 测量距离
uint16_t confi; ///< 测量置信度
uint16_t count; ///< 计数值
uint16_t crate; ///< 计数率
} NDS03_RangingData_t;
/**
* @struct NDS03_ChipInfo_t
*
* @brief NDS03模组生产信息\n
*/
typedef struct {
uint32_t fw_version; ///< NDS03固件版本
} NDS03_ChipInfo_t;
/**
* @struct NDS03_DevConfig_t
*
* @brief NDS03模组配置数据\n
*/
typedef struct {
uint32_t range_frame_time_us; //< 模组取图帧间隔时间配置
uint8_t continuous_flag; ///< 连续模式标志位
uint8_t target_num; ///< 目标个数
} NDS03_DevConfig_t;
/**
* @struct NDS03_Dev_t
*
* @brief \n
*/
typedef struct {
uint8_t dev_pwr_state; ///< 设备的当前状态, 就绪模式或者休眠模式
NDS03_DevConfig_t config; ///< 模组配置信息
NDS03_ChipInfo_t chip_info; ///< 模组设备信息
uint8_t data_cnt; ///< 数据获取次数
NDS03_RangingData_t ranging_data[NDS03_TARGET_MAX_NUM]; ///< 测距数据结果
NDS03_Platform_t platform;
} NDS03_Dev_t;
#define NDS03_DEFAULT_SLAVE_ADDR 0x5C
#if NDS03_PLATFORM == PLATFORM_C51
#define CHECK_RET(func) \
ret = func; \
if(ret != NDS03_ERROR_NONE) \
return ret;
#else
#define CHECK_RET(func) do { \
ret = func; \
if(ret != NDS03_ERROR_NONE) { \
NX_PRINTF("%s I2c Error, ret: %d\r\n", #func, ret); \
return ret; \
} \
} while (0)
#endif
#endif

View File

@@ -0,0 +1,743 @@
/**
* @file nds03_dev.c
* @author tongsheng.tang
* @brief NDS03 device setting functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory,
* in the file named LICENSE.
*
*/
#include "nds03_dev.h"
#include "nds03_def.h"
#include "nds03_comm.h"
/** SDK主版本 */
static uint8_t sdk_version_major = 2;
/** SDK次版本 */
static uint8_t sdk_version_minor = 0;
/** SDK小版本 */
static uint8_t sdk_version_patch = 3;
/**
* @brief NDS03 Get SDK Version
* SDK的软件版本号
* @return uint32_t
* @retval
*/
uint32_t NDS03_GetSdkVersion(void)
{
return ((uint32_t)sdk_version_major << 16) +
((uint32_t)sdk_version_minor << 8) + (uint32_t)sdk_version_patch;
}
/**
* @brief NDS03 Get Firmware Version
* NDS03模组固件版本号
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_FW_VER, &pNxDevice->chip_info.fw_version));
return ret;
}
/**
* @brief NDS03 Get Therm
* NDS03的温度
* @param pNxDevice
* @param therm 0.1
* @return NDS03_Error
*/
NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_THERM, (uint16_t*)therm));
return ret;
}
/**
* @brief NDS03 Set Pulse Num
*
* @param pNxDevice
* @param pulse_num
* @return NDS03_Error
*/
NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
return ret;
}
/**
* @brief NDS03 Get Pulse Num
*
* @param pNxDevice
* @param pulse_num
* @return NDS03_Error
*/
NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num));
return ret;
}
/**
* @brief NDS03 Set Frame Time
* (us)
* @param pNxDevice
* @param inv_time
* @return NDS03_Error
*/
NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_INV_TIME, frame_time_us));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME,
&pNxDevice->config.range_frame_time_us));
return ret;
}
/**
* @brief NDS03 Get Frame Time
* (us)
* @param pNxDevice
* @param inv_time
* @return NDS03_Error
*/
NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME,
&pNxDevice->config.range_frame_time_us));
*frame_time_us = pNxDevice->config.range_frame_time_us;
return ret;
}
/**
* @brief NDS03 Set Confidence threshold
*
* @param pNxDevice
* @param confi_th
* @return NDS03_Error
*/
NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
return ret;
}
/**
* @brief NDS03 Get Confidence threshold
*
* @param pNxDevice
* @param confi_th
* @return NDS03_Error
*/
NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th));
return ret;
}
/**
* @brief NDS03 Set Target Num
*
* @param pNxDevice
* @param num
* @return NDS03_Error
*/
NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num)
{
NDS03_Error ret = NDS03_ERROR_NONE;
num = (num > NDS03_TARGET_MAX_NUM) ? NDS03_TARGET_MAX_NUM : num;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_TARGET_NUM, num));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
pNxDevice->config.target_num = num;
return ret;
}
/**
* @brief NDS03 Get Target Num
*
* @param pNxDevice
* @param num
* @return NDS03_Error
*/
NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_TARGET_NUM, num));
pNxDevice->config.target_num = *num;
return ret;
}
/**
* @brief NDS03 Set Gpio1 Configuration
*
* @param pNxDevice: NDS03模组设备信息结构体
* @param functionality:
* NDS03_GPIO1_FUNCTIONALITY_OFF:
* NDS03_GPIO1_THRESHOLD_LOWGPIO输出有效电平
* NDS03_GPIO1_THRESHOLD_HIGHGPIO输出有效电平
* NDS03_GPIO1_THRESHOLD_DOMAIN_OUTGPIO输出有效电平
* NDS03_GPIO1_NEW_MEASURE_READY:GPIO输出有效电平
* @param polarity: INT引脚有效电平
* NDS03_GPIO1_POLARITY_LOW
* NDS03_GPIO1_POLARITY_HIGH
* @return NDS03_Error
*/
NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice,
NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t rbuf;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf));
/** 设置中断功能 */
rbuf = rbuf & (~NDS03_GPIO1_FUNCTIONALITY_MASK);
rbuf = rbuf | (functionality & NDS03_GPIO1_FUNCTIONALITY_MASK);
/** 设置中断引脚极性 */
if (polarity == NDS03_GPIO1_POLARITY_HIGH)
rbuf = rbuf | NDS03_GPIO1_POLARITY_MASK;
else
rbuf = rbuf & (~NDS03_GPIO1_POLARITY_MASK);
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_GPIO1_FUNC, rbuf));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
return ret;
}
/**
* @brief NDS03 Get Gpio1 Config
*
* @param pNxDevice: NDS03模组设备信息结构体指针
* @param functionality:
* @param polarity:
* @return NDS03_Error
*/
NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice,
NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t rbuf;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf));
// Polarity
*polarity = ((rbuf & NDS03_GPIO1_POLARITY_MASK) == NDS03_GPIO1_POLARITY_MASK) ?
NDS03_GPIO1_POLARITY_HIGH : NDS03_GPIO1_POLARITY_LOW;
// Functionality
*functionality = rbuf & NDS03_GPIO1_FUNCTIONALITY_MASK;
return ret;
}
/**
* @brief NDS03 Set Depth Threshold
*
* GPIO功能为
* NDS03_GPIO1_THRESHOLD_LOW
* NDS03_GPIO1_THRESHOLD_HIGH
* NDS03_GPIO1_THRESHOLD_DOMAIN_OUT
* @param pNxDevice: NDS03模组设备信息结构体
* @param depth_low: / mm
* @param depth_high: / mm
* @return NDS03_Error
*/
NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice,
uint16_t depth_low, uint16_t depth_high)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low));
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE));
return ret;
}
/**
* @brief NDS03 Get Depth Threshold
*
* @param pNxDevice: NDS03模组设备信息结构体
* @param depth_low: / mm
* @param depth_high: / mm
* @return NDS03_Error
*/
NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice,
uint16_t *depth_low, uint16_t *depth_high)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low));
CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high));
return ret;
}
/**
* @brief NDS03 Waitfor Data Val
*
* @param pNxDevice
* @param flag
* @return NDS03_Error
*/
NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t dat_valid_flag = 0x00;
int32_t retry_cnt;
retry_cnt = timeout_ms * 2;
do {
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &dat_valid_flag));
if (dat_valid_flag == flag)
break;
NDS03_Delay10us(pNxDevice, 50);
} while (--retry_cnt);
if (retry_cnt == 0) {
NX_PRINTF("data_valid_flag: %d\r\n", dat_valid_flag);
ret = NDS03_ERROR_TIMEOUT;
}
return ret;
}
/**
* @brief NDS03 Waitfor Cmd Val
*
* @param pNxDevice
* @param cmd
* @param timeout_ms
* @return NDS03_Error
*/
NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms)
{
NDS03_Error ret = NDS03_ERROR_NONE;
int32_t retry_cnt;
uint8_t val;
retry_cnt = timeout_ms * 2;
do {
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CMD_VAL, &val));
if (val == cmd)
break;
NDS03_Delay10us(pNxDevice, 50);
} while (--retry_cnt);
if (retry_cnt == 0) {
NX_PRINTF("Timeout!!, val: 0x%02x\r\n", val);
ret = NDS03_ERROR_TIMEOUT;
}
return ret;
}
/**
* @brief NDS03 Read Hgm Data
* NDS03直方图数据
* @param pNxDevice
* @param rbuf
* @param size
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice, uint8_t *rbuf, uint32_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint32_t rsize, _size;
uint8_t one_size;
uint16_t addr = 0xe000;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size));
_size = (uint32_t)one_size;
rsize = 0;
while ((rsize < size) && (ret == NDS03_ERROR_NONE)) {
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0));
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200));
CHECK_RET(NDS03_ReadNBytes(pNxDevice,
NDS03_REG_CACHE_DATA, rbuf,
((size - rsize) > _size) ? _size : (size - rsize)));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
rbuf += _size;
addr += _size;
rsize += _size;
}
return ret;
}
/**
* @brief NDS03 Read User Data
* NDS03中用户数据区域0xFFF032
* 160xFFF0~0xFFFF160x0000~0x000F
* @param pNxDevice
* @param addr 0x0000~0xFFFF
* @param rbuf
* @param size
* @return NDS03_Error
*/
NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice,
uint16_t addr, uint8_t *rbuf, uint32_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint32_t rsize, _size;
uint8_t one_size;
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size));
_size = (uint32_t)one_size;
rsize = 0;
while ((rsize < size) && (ret == NDS03_ERROR_NONE)) {
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_USER_DATA_FLAG));
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_USER_DATA_FLAG, 200));
CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA,
rbuf, ((size - rsize) > _size) ? _size : (size - rsize)));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
rbuf += _size;
addr += _size;
rsize += _size;
}
return ret;
}
/**
* @brief NDS03 Read User Data
* NDS03中用户数据区域, 0xFFF032
* 160xFFF0~0xFFFF160x0000~0x000F
* @param pNxDevice
* @param addr 0x0000~0xFFFF
* @param wbuf
* @param size
* @return NDS03_Error
*/
NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice,
uint16_t addr, uint8_t *wbuf, uint32_t size)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint32_t rsize, _size;
uint8_t one_size;
// NX_PRINTF("%s Start\r\n", __func__);
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size));
_size = (uint32_t)one_size;
rsize = 0;
while ((rsize < size) && (ret == NDS03_ERROR_NONE)) {
CHECK_RET(NDS03_WriteNBytes(pNxDevice, NDS03_REG_CACHE_DATA,
wbuf, ((size - rsize) > _size) ? _size : (size - rsize)));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DATA_SIZE,
((size - rsize) > _size) ? _size : (size - rsize)));
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA,
NDS03_CMD_WRITE_USER_DATA_ENA));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ,
NDS03_CMD_WRITE_USER_DATA));
CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_WRITE_USER_DATA, 500));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_VAL_IDLE));
wbuf += _size;
addr += _size;
rsize += _size;
}
// NX_PRINTF("%s End\r\n", __func__);
return ret;
}
/**
* @brief NDS03软件休眠
*
* @param pNxDevice
* @param sleep_time_ms
* @return NDS03_Error
*/
NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE,
NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP));
return ret;
}
/**
* @brief NDS03软件休眠
*
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice,
NDS03_REG_SLEEP_MODE, NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP));
return ret;
}
/**
* @brief NDS03 Sleep
* NDS03进入休眠
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 0));
return ret;
}
/**
* @brief NDS03 Wakeup
* NDS03从软件睡眠中唤醒
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint32_t freq;
CHECK_RET(NDS03_GetI2cFreq(pNxDevice,&freq));
CHECK_RET(NDS03_SetI2cFreq(pNxDevice,1000));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, 0));
CHECK_RET(NDS03_SetI2cFreq(pNxDevice,freq));
return ret;
}
/**
* @brief NDS03 Software Sleep
*
* @param pNxDevice
* @param sleep_time_ms
* @return NDS03_Error
* @deprecated 使NDS03_SoftSleepWithAutoWakeup()
*/
static __maybe_unused NDS03_Error NDS03_SoftSleep(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms)
{
NDS03_Error ret = NDS03_ERROR_NONE;
ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE);
ret |= NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms);
ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE,
NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP);
return ret;
}
/**
* @brief NDS03 Wakeup
* NDS03从睡眠中唤醒
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 1));
return ret;
}
/**
* @brief NDS03
*
* @param pNxDevice
* @return NDS03_Error
* @arg 0: NDS03
* @arg NDS03_ERROR_NO_NDS03: NDS03
* @arg others: I2C通信异常
* I2C通信异常NDS03
*/
NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint8_t buf[4] = {0};
NDS03_SetXShutPinLevel(pNxDevice, 1);
CHECK_RET(NDS03_Delay1ms(pNxDevice, 10));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_GET_MODEL_FLAG));
CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_GET_MODEL_FLAG, 200));
CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, buf, sizeof(buf)));
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE));
if ((buf[0] != 0x31) || (buf[1] != 0x53) || (buf[2] != 0x30) || (buf[3] != 0x33))
ret = NDS03_ERROR_NO_NDS03;
return ret;
}
/**
* @brief NDS03 Set Device Address
*
* @param pNxDevice
* @param dev_addr
* @return NDS03_Error
*/
NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr)
{
NDS03_Error ret = NDS03_ERROR_NONE;
CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEV_ADDR, dev_addr));
pNxDevice->platform.i2c_dev_addr = dev_addr;
return ret;
}
/**
* @brief NDS03 InitDevice
*
* @param pNxDevice
* @return NDS03_Error
*/
NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
// NX_PRINTF("%s Start!\r\n", __func__);
CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice));
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &pNxDevice->data_cnt));
CHECK_RET(NDS03_GetFrameTime(pNxDevice, &pNxDevice->config.range_frame_time_us));
pNxDevice->config.continuous_flag = 0;
// NX_PRINTF("%s End!\r\n", __func__);
return ret;
}
/**
* @brief NDS03 Wait for Device Boot Up
* NDS03模组启动
* @param pNxDevice
* @return NDS03_ERROR_NONE:
* NDS03_ERROR_BOOT:--i2c地址与读写函数是否错误
* NDS03_ERROR_FW:--FAE联系SDK不兼容
*/
NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice)
{
NDS03_Error ret = NDS03_ERROR_NONE;
int32_t try_times = 200;
uint8_t slave_addr = pNxDevice->platform.i2c_dev_addr;
NDS03_SetXShutPinLevel(pNxDevice, 0);
CHECK_RET(NDS03_Delay10us(pNxDevice, 20));
NDS03_SetXShutPinLevel(pNxDevice, 1);
CHECK_RET(NDS03_Delay1ms(pNxDevice, 2));
ret = NDS03_SetXShutPinLevel(pNxDevice, 1);
pNxDevice->platform.i2c_dev_addr = (ret == NDS03_ERROR_NONE) ?
NDS03_DEFAULT_SLAVE_ADDR : pNxDevice->platform.i2c_dev_addr;
pNxDevice->data_cnt = 0;
pNxDevice->config.continuous_flag = 0;
do {
CHECK_RET(NDS03_Delay10us(pNxDevice, 10));
CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_STATE, &pNxDevice->dev_pwr_state));
} while ((pNxDevice->dev_pwr_state != NDS03_STATE_SOFT_READY) &&
(pNxDevice->dev_pwr_state != NDS03_STATE_GOT_DEPTH) && --try_times);
if (0 == try_times) {
NX_PRINTF("state: 0x%02x\r\n", pNxDevice->dev_pwr_state);
NX_PRINTF("NDS03 boot error\r\n");
return NDS03_ERROR_BOOT;
}
if (slave_addr != pNxDevice->platform.i2c_dev_addr)
CHECK_RET(NDS03_SetDevAddr(pNxDevice, slave_addr));
return ret;
}
/**
* @brief NDS03 Dirty Warning
*
* @param pNxDevice
* @param flag 10
* @param time_th ms
* @return NDS03_ERROR_NONE:
*/
NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th)
{
NDS03_Error ret = NDS03_ERROR_NONE;
uint16_t depth_low_th = 30;
static int32_t depth_low_count = 0, depth_low_time_sta = 0, depth_low_time_end = 0;
if (time_th == 0)
time_th = 10 * 1000;
if (pNxDevice->ranging_data[0].depth < depth_low_th) {
depth_low_count ++;
if (depth_low_count == 1)
NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_sta);
NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_end);
if (depth_low_time_end < depth_low_time_sta) {
depth_low_time_sta = 0;
depth_low_time_end = 0;
}
} else {
depth_low_count = 0;
depth_low_time_sta = 0;
depth_low_time_end = 0;
}
if (depth_low_count > 10 && pNxDevice->ranging_data[1].depth != NDS03_DEPTH_INVALID_VALUE)
*flag = 1;
if ((depth_low_time_end - depth_low_time_sta) > time_th)
*flag = 1;
return ret;
}

View File

@@ -0,0 +1,94 @@
/**
* @file nds03_dev.h
* @author tongsheng.tang
* @brief NDS03 device setting functions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory, in the file named LICENSE.
*
*/
#ifndef __NDS03_DEV_H__
#define __NDS03_DEV_H__
#include "nds03_def.h"
/** @defgroup NDS03_Dev_Group NDS03 Device Functions
* @brief NDS03 Device Functions
* @{
*/
/** 获取SDK版本号 */
uint32_t NDS03_GetSdkVersion(void);
/** 获取NDS03模组固件版本号 */
NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice);
/** 获取温度 */
NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm);
/** 设置发光次数 */
NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num);
/** 获取发光次数 */
NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num);
/** 设置测量间隔时间 */
NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us);
/** 获取测量间隔时间 */
NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us);
/** 设置置信度阈值 */
NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th);
/** 获取置信度阈值 */
NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th);
/** 设置目标个数 */
NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num);
/** 获取目标个数 */
NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num);
/** 设置中断引脚功能 */
NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice,
NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity);
/** 获取中断引脚功能 */
NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice,
NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity);
/** 设置深度阈值 */
NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice,
uint16_t depth_low, uint16_t depth_high);
/** 获取深度阈值 */
NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice,
uint16_t *depth_low, uint16_t *depth_high);
/** 等待获取数据结束 */
NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms);
/** 等待命令结束 */
NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms);
/** 从NDS03中读取直方图数据 */
NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice,uint8_t *rbuf, uint32_t size);
/** 从NDS03中读取用户数据 */
NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, uint16_t addr, uint8_t *rbuf, uint32_t size);
/** 从NDS03中写入用户数据 */
NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice,
uint16_t addr, uint8_t *wbuf, uint32_t size);
/** NDS03进入软件睡眠,手动唤醒 */
NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice);
/** NDS03进入软件睡眠,自动唤醒 */
NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms);
/** NDS03从软件睡眠中唤醒 */
NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice);
/** NDS03进入睡眠 */
NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice);
/** NDS03从睡眠中唤醒 */
NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice);
/** 判断是否为NDS03设备,返回值为0表示是NDS03设备 */
NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice);
/** 设置模组设备地址 */
NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr);
/** 初始化设备 */
NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice);
/** 等待设备启动 */
NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice);
/** 脏污预警 */
NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th);
/** @} NDS03_Dev_Group */
#endif

View File

@@ -0,0 +1,235 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/ktime.h>
#include "nds03_iio.h"
#include "nds03.h"
#define NDS03_DISTANCE_CHANNEL { \
.type = IIO_DISTANCE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_ENABLE), \
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),\
.scan_index = NDS03_IIO_CHAN_DISTANCE, \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
static const int nds03_scales[] = { 1 };
static const struct iio_chan_spec nds03_channels[] = {
NDS03_DISTANCE_CHANNEL,
IIO_CHAN_SOFT_TIMESTAMP(NDS03_IIO_CHAN_TIMESTAMP),
};
static int nds03_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT;
*vals = nds03_scales;
*length = ARRAY_SIZE(nds03_scales);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
/* === read_raw === */
static int nds03_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->scan_index == NDS03_IIO_CHAN_DISTANCE) {
*val = iio->ctx->g_nds03_device.ranging_data[0].depth;
return IIO_VAL_INT;
}
break;
case IIO_CHAN_INFO_SCALE:
*val = nds03_scales[0];
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
*val = iio->enabled;
return IIO_VAL_INT;
default:
return -EINVAL;
}
return -EINVAL;
}
static int nds03_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_RAW:
return -EINVAL;
case IIO_CHAN_INFO_SCALE:
/* NOTE: Default to 1 */
return 0;
case IIO_CHAN_INFO_ENABLE:
return -EINVAL;
default:
return -EINVAL;
}
}
static const struct iio_info nds03_iio_info = {
.read_raw = nds03_read_raw,
.write_raw = nds03_write_raw,
.read_avail= nds03_read_avail,
};
/* === buffer setup === */
static void nds03_enable_work(struct work_struct *work)
{
struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, enable_work);
struct nds03_context *ctx = iio->ctx;
NDS03_Dev_t *dev = &ctx->g_nds03_device;
int ret;
mutex_lock(&ctx->work_mutex);
if (iio->enabled)
goto out;
schedule_delayed_work(&ctx->dwork,
msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms)));
atomic_set(&ctx->is_meas, 1);
ret = nds03_sensor_init(ctx);
if(ret != 0) {
dev_err(&ctx->client->dev, "nds03 sensor init failed %d\n", ret);
goto out;
}
ret = NDS03_StartContinuousMeasurement(dev);
if (ret) {
dev_err(&ctx->client->dev, "StartContinuous fail %d\n", ret);
goto out;
}
iio->enabled = true;
dev_info(&ctx->client->dev, "NDS03 sensor started\n");
goto out;
out:
mutex_unlock(&ctx->work_mutex);
}
static void nds03_disable_work(struct work_struct *work)
{
struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, disable_work);
struct nds03_context *ctx = iio->ctx;
NDS03_Dev_t *dev = &ctx->g_nds03_device;
mutex_lock(&ctx->work_mutex);
if (!iio->enabled)
goto out;
atomic_set(&ctx->is_meas, 0);
NDS03_StopContinuousMeasurement(dev);
iio->enabled = false;
dev_info(&ctx->client->dev, "NDS03 sensor stopped\n");
out:
mutex_unlock(&ctx->work_mutex);
}
static int nds03_buffer_preenable(struct iio_dev *indio_dev)
{
struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev);
schedule_work(&iio->enable_work);
return 0;
}
static int nds03_buffer_predisable(struct iio_dev *indio_dev)
{
struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev);
schedule_work(&iio->disable_work);
return 0;
}
static const struct iio_buffer_setup_ops nds03_buffer_setup_ops = {
.preenable = nds03_buffer_preenable,
.predisable = nds03_buffer_predisable,
};
int nds03_iio_init(struct nds03_context *ctx)
{
struct device *dev = &ctx->client->dev;
struct nds03_iio_dev *iio;
int ret;
iio = devm_kzalloc(dev, sizeof(*iio), GFP_KERNEL);
if (!iio) {
nds03_errmsg("devm_kzalloc error\n");
return -ENOMEM;
}
iio->indio_dev = devm_iio_device_alloc(dev, 0);
if (!iio->indio_dev) {
nds03_errmsg("devm_iio_device_alloc error\n");
return -ENOMEM;
}
iio->ctx = ctx;
iio->enabled = false;
INIT_WORK(&iio->enable_work, nds03_enable_work);
INIT_WORK(&iio->disable_work, nds03_disable_work);
iio->indio_dev->name = "nds03";
iio->indio_dev->channels = nds03_channels;
iio->indio_dev->num_channels = ARRAY_SIZE(nds03_channels);
iio->indio_dev->info = &nds03_iio_info;
iio->indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
iio_device_set_drvdata(iio->indio_dev, iio);
/* kfifo buffer + setup_ops */
ret = devm_iio_kfifo_buffer_setup(dev, iio->indio_dev, &nds03_buffer_setup_ops);
if (ret)
return ret;
ret = devm_iio_device_register(dev, iio->indio_dev);
if (ret)
return ret;
ctx->iio = iio;
return 0;
}
EXPORT_SYMBOL_GPL(nds03_iio_init);
void nds03_iio_remove(struct nds03_context *ctx)
{
return;
}
EXPORT_SYMBOL_GPL(nds03_iio_remove);
void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm)
{
struct nds03_iio_dev *iio = ctx->iio;
struct nds03_scan scan;
if (!iio || !iio->enabled)
return;
scan.distance = distance_mm;
if (iio_buffer_enabled(iio->indio_dev))
iio_push_to_buffers_with_timestamp(iio->indio_dev, &scan,
ktime_get_boottime_ns());
}
EXPORT_SYMBOL_GPL(nds03_iio_push_data);

View File

@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NDS03_IIO_H
#define __NDS03_IIO_H
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
struct nds03_iio_dev {
struct iio_dev *indio_dev;
struct nds03_context *ctx;
bool enabled;
struct work_struct enable_work;
struct work_struct disable_work;
};
enum nds03_iio_chan {
NDS03_IIO_CHAN_DISTANCE,
NDS03_IIO_CHAN_TIMESTAMP,
};
struct nds03_scan {
__le16 distance;
s64 ts;
};
int nds03_iio_init(struct nds03_context *ctx);
void nds03_iio_remove(struct nds03_context *ctx);
void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm);
#endif

View File

@@ -0,0 +1,674 @@
/*!
@file nds03_module.c
@brief
@author lull
@date 2025-06
@copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd.
@license BSD 3-Clause License
This file is part of the Nephotonics sensor SDK.
It is licensed under the BSD 3-Clause License.
A copy of the license can be found in the project root directory, in the file named LICENSE.
*/
#include "nds03.h"
#include "nds03_iio.h"
/* Set default value to 1 to allow to see module insertion debug messages */
int nds03_enable_debug = 0;
static inline NDS03_Platform_t *to_nds03_platform(struct nds03_context *ctx)
{
return &ctx->g_nds03_device.platform;
}
static inline NDS03_Dev_t * to_nds03_dev(struct nds03_context *ctx)
{
return &ctx->g_nds03_device;
}
int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open)
{
int8_t retval = 0;
if (is_open) {
retval |= NDS03_SetGpio1Config(pNxDevice,
NDS03_GPIO1_NEW_MEASURE_READY, NDS03_GPIO1_POLARITY_LOW);
/* 连续模式开启测量 */
retval |= NDS03_StartContinuousMeasurement(pNxDevice);
} else {
/* 连续模式关闭测量 */
retval |= NDS03_StopContinuousMeasurement(pNxDevice);
/* 关闭测距中断 */
retval |= NDS03_SetGpio1Config(pNxDevice,
NDS03_GPIO1_FUNCTIONALITY_OFF, NDS03_GPIO1_POLARITY_LOW);
}
return retval;
}
EXPORT_SYMBOL_GPL(nds03_interrupt_config);
int nds03_sensor_init(struct nds03_context *ctx)
{
NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx);
NDS03_Platform_t *pdev = to_nds03_platform(ctx);
/* 函数指针结构体 */
if (NDS03_ERROR_NONE != nds03_platform_init(pdev, ctx->client)) {
nds03_errmsg("nds03_platform init error\n");
return -1;
}
/* 循环等待设备启动, 若模组或者IIC读写函数有问题则会报错 */
if (NDS03_ERROR_NONE != NDS03_WaitDeviceBootUp(pNxDevice)) {
nds03_errmsg("NDS03_WaitDeviceBootUp error\r\n");
return -1;
}
/** 判断是否为NDS03设备 */
if (NDS03_ERROR_NONE != NDS03_IsNDS03(pNxDevice)) {
nds03_errmsg("The device is not NDS03, please change the device!\n");
return -2;
}
/* 初始化模组设备 */
if (NDS03_ERROR_NONE != NDS03_InitDevice(pNxDevice)) {
nds03_errmsg("NDS03_InitDevice error!!\r\n");
return -3;
}
if (atomic_read(&ctx->meas_mode) == 0)
nds03_interrupt_config(pNxDevice, 1);
else
nds03_interrupt_config(pNxDevice, 0);
return 0;
}
EXPORT_SYMBOL_GPL(nds03_sensor_init);
static void printf_ranging_data(NDS03_Dev_t *pNxDevice)
{
nds03_info("ranging data start:\r\n");
nds03_info("dist start:\r\n");
nds03_info(
"%d %d %d %d\r\n",
pNxDevice->ranging_data[0].depth, pNxDevice->ranging_data[1].depth,
pNxDevice->ranging_data[2].depth, pNxDevice->ranging_data[3].depth);
nds03_info("dist end\r\n");
nds03_info("confi start:\r\n");
nds03_info(
"%d %d %d %d\r\n",
pNxDevice->ranging_data[0].confi, pNxDevice->ranging_data[1].confi,
pNxDevice->ranging_data[2].confi, pNxDevice->ranging_data[3].confi);
nds03_info("confi end\r\n");
nds03_info("count start:\r\n");
nds03_info(
"%d %d %d %d\r\n",
pNxDevice->ranging_data[0].count, pNxDevice->ranging_data[1].count,
pNxDevice->ranging_data[2].count, pNxDevice->ranging_data[3].count);
nds03_info("count end\r\n");
nds03_info("crate start:\r\n");
nds03_info(
"%d %d %d %d\r\n",
pNxDevice->ranging_data[0].crate, pNxDevice->ranging_data[1].crate,
pNxDevice->ranging_data[2].crate, pNxDevice->ranging_data[3].crate);
nds03_info("crate end\r\n");
nds03_info("ranging data end\r\n");
}
static int32_t nds03_make_measure(struct nds03_context *ctx)
{
int32_t ret = 0;
NDS03_Dev_t *pNxDevice = &ctx->g_nds03_device;
mutex_lock(&ctx->work_mutex);
/* 获取测量数据 */
if (atomic_read(&ctx->meas_mode))
ret = NDS03_GetSingleRangingData(pNxDevice);
else
ret = NDS03_GetInterruptRangingData(pNxDevice);
if (ret >= 0 && nds03_enable_debug)
printf_ranging_data(pNxDevice);
mutex_unlock(&ctx->work_mutex);
return ret;
}
static int __ctrl_tof_start(struct nds03_context * ctx)
{
schedule_delayed_work(&ctx->dwork,
msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms)));
atomic_set(&ctx->is_meas, 1);
return 0;
}
static int __ctrl_tof_stop(struct nds03_context * ctx)
{
atomic_set(&ctx->is_meas, 0);
return 0;
}
static int __ctrl_tof_reset(struct nds03_context * ctx)
{
int ret = 0;
__ctrl_tof_stop(ctx);
mutex_lock(&ctx->work_mutex);
ret = nds03_sensor_init(ctx);
if (ret != 0)
nds03_errmsg("nds03 sensor init failed\n");
mutex_unlock(&ctx->work_mutex);
return ret;
}
static int32_t tof_offset_calib(struct nds03_context *ctx, uint16_t calib_dist)
{
int32_t i, cnt = 20;
int32_t depth_sum, depth_aver;
NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx);
/* 将设备处于500mm处 */
NDS03_StopContinuousMeasurement(pNxDevice);
msleep(100);
/* 串扰标定 */
ctx->calib_result = NDS03_XtalkCalibration(pNxDevice);
if (NDS03_ERROR_NONE != ctx->calib_result) {
nds03_info("Xtalk calib error: %d\n", ctx->calib_result);
return -1;
}
/* Offset标定 */
ctx->calib_result = NDS03_OffsetCalibrationAtDepth(pNxDevice, calib_dist);
if(NDS03_ERROR_NONE != ctx->calib_result) {
nds03_info("Offset calib error: %d\n", ctx->calib_result);
return -1;
}
/* 获取平均值 */
NDS03_GetSingleRangingData(pNxDevice);
NDS03_GetSingleRangingData(pNxDevice);
depth_sum = 0;
for (i = 0; i < cnt; i++) {
if (NDS03_ERROR_NONE != NDS03_GetSingleRangingData(pNxDevice)) {
nds03_info("NDS03_GetSingleRangingData error!!\r\n");
return -1;
}
depth_sum = depth_sum + (int32_t)(uint32_t)pNxDevice->ranging_data[0].depth;
}
depth_aver = depth_sum / cnt;
if (depth_aver < (calib_dist - 20) || depth_aver > (calib_dist + 20)) {
ctx->calib_result = NDS03_ERROR_RANGING;
nds03_info("NDS03 calibration fail!!\r\n");
return -1;
}
nds03_info("NDS03 calibration success\r\n");
return 0;
}
static void report_meas_event(struct nds03_context * ctx)
{
int retval = 0;
retval = nds03_make_measure(ctx);
if (retval < 0)
return;
uint16_t distance = ctx->g_nds03_device.ranging_data[0].depth;
nds03_iio_push_data(ctx, distance);
}
static irqreturn_t tof_irq_handler_i2c(int vec, void *info)
{
struct nds03_context *ctx = (struct nds03_context *)info;
bool is_meas = atomic_read(&ctx->is_meas);
if (ctx->irq == vec && is_meas)
schedule_work(&ctx->irq_work);
return IRQ_HANDLED;
}
static void nds03_work_handler(struct work_struct *work)
{
struct nds03_context *ctx = container_of(work, struct nds03_context, dwork.work);
if (atomic_read(&ctx->meas_mode) && atomic_read(&ctx->is_meas)) {
nds03_make_measure(ctx);
schedule_delayed_work(&ctx->dwork,
msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms)));
report_meas_event(ctx);
}
}
static void nds03_measure_irq_work(struct work_struct *work)
{
struct nds03_context *ctx = container_of(work, struct nds03_context, irq_work);
report_meas_event(ctx);
}
static ssize_t nds03_show_is_meas(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
return snprintf(buf, 10, "%d\n", atomic_read(&ctx->is_meas));
}
static ssize_t nds03_store_is_meas(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
int ret = count;
switch (buf[0]) {
case '0':
__ctrl_tof_stop(ctx);
break;
case '1':
__ctrl_tof_start(ctx);
break;
default:
nds03_warnmsg("Invalid value\n");
ret = -EINVAL;
break;
}
return ret ;
}
static DEVICE_ATTR(is_meas, 0660, nds03_show_is_meas, nds03_store_is_meas);
static ssize_t nds03_show_poll_delay_ms(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint32_t poll_ms;
struct nds03_context *ctx = dev_get_drvdata(dev);
poll_ms = atomic_read(&ctx->poll_delay_ms);
return snprintf(buf, 10, "%d\n", poll_ms);
}
static ssize_t nds03_store_poll_delay_ms(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
int ret;
unsigned long delay_ms;
ret = kstrtoul(buf, 10, &delay_ms);
if(ret < 0) {
nds03_warnmsg("Invalid input ctx\n");
goto store_err;
}
atomic_set(&ctx->poll_delay_ms, delay_ms);
nds03_dbgmsg("Poll delay %lu ms\n", delay_ms);
store_err:
return ret < 0 ? -EINVAL : count;
}
static DEVICE_ATTR(meas_delay_ms, 0660, nds03_show_poll_delay_ms, nds03_store_poll_delay_ms);
static ssize_t nds03_show_meas_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
return snprintf(buf, 10, "%d\n",atomic_read(&ctx->meas_mode));
}
static ssize_t nds03_store_meas_mode(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx);
int ret = count;
mutex_lock(&ctx->work_mutex);
switch (buf[0]) {
case '0':
if(ctx->irq < 0){
nds03_warnmsg("No support Interrupt\n");
ret = -EINVAL;
} else {
atomic_set(&ctx->meas_mode, 0);
nds03_interrupt_config(pNxDevice, 1);
nds03_dbgmsg("Enter Interrupt Mode\n");
}
break;
case '1':
atomic_set(&ctx->meas_mode, 1);
nds03_interrupt_config(pNxDevice, 0);
nds03_dbgmsg("Enter Poll Mode\n");
break;
default:
nds03_warnmsg("Invalid value\n");
ret = -EINVAL;
break;
}
mutex_unlock(&ctx->work_mutex);
return ret ;
}
static DEVICE_ATTR(meas_mode, 0660, nds03_show_meas_mode, nds03_store_meas_mode);
static ssize_t nds03_store_tof_reset(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
int ret = 0;
if(buf[0] == '1')
ret = __ctrl_tof_reset(ctx);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR(tof_reset, 0660, NULL, nds03_store_tof_reset);
static ssize_t nds03_show_tof_calib(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
return snprintf(buf, 10, "%d\n",ctx->calib_result);
}
static ssize_t nds03_store_tof_calib(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
int ret;
unsigned long calib_dis;
mutex_lock(&ctx->work_mutex);
ret = kstrtoul(buf, 10, &calib_dis);
if(ret < 0) {
nds03_warnmsg("Invalid input ctx\n");
ret = -EPERM;
goto store_err;
}
nds03_info("offset calib distance: %ld mm\n", calib_dis);
ret = tof_offset_calib(ctx, calib_dis);
if (nds03_sensor_init(ctx) != 0)
nds03_errmsg("nds03 sensor init failed\n");
store_err:
mutex_unlock(&ctx->work_mutex);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR(tof_calib, 0660, nds03_show_tof_calib, nds03_store_tof_calib);
static ssize_t nds03_show_enable_debug(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, 10, "%d\n", nds03_enable_debug);
}
static ssize_t nds03_store_enable_debug(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
struct nds03_context *ctx = dev_get_drvdata(dev);
int32_t ret = 0;
mutex_lock(&ctx->work_mutex);
switch (buf[0]) {
case '0':
nds03_enable_debug = 0;
nds03_info("close nds03 debug\n");
break;
case '1':
nds03_enable_debug = 1;
nds03_info("open nds03 debug\n");
break;
default:
nds03_warnmsg("Invalid value\n");
ret = -EINVAL;
break;
}
mutex_unlock(&ctx->work_mutex);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR(enable_debug, 0660, nds03_show_enable_debug, nds03_store_enable_debug);
static ssize_t nds03_store_tof_pulsenum(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
int ret;
unsigned long pulsenum;
struct nds03_context *ctx = dev_get_drvdata(dev);
NDS03_Dev_t *pdev = to_nds03_dev(ctx);
ret = kstrtoul(buf, 10, &pulsenum);
if (ret < 0) {
nds03_errmsg("Invalid input ctx\n");
return -EPERM;
}
mutex_lock(&ctx->work_mutex);
ret = NDS03_SetPulseNum(pdev, pulsenum);
mutex_unlock(&ctx->work_mutex);
nds03_info("set tof pulsenum: %ld, ret: %d\n", pulsenum, ret);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR(tof_pulsenum, 0660, NULL, nds03_store_tof_pulsenum);
static ssize_t nds03_show_tof_xtalk(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret, count;
uint16_t xtalk_value;
struct nds03_context *ctx = dev_get_drvdata(dev);
NDS03_Dev_t *pdev = to_nds03_dev(ctx);
mutex_lock(&ctx->work_mutex);
ret = NDS03_GetXTalkValue(pdev, &xtalk_value);
if (ret < 0)
nds03_errmsg("get tof xtalk_value error\n");
mutex_unlock(&ctx->work_mutex);
count = snprintf(buf, 10, "%d\n",xtalk_value);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR(tof_xtalk, 0660, nds03_show_tof_xtalk, NULL);
static ssize_t nds03_store_xtalk_calibration(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
int32_t ret = 0;
struct nds03_context *ctx = dev_get_drvdata(dev);
NDS03_Dev_t *pdev = to_nds03_dev(ctx);
if (sysfs_streq(buf, "1") || sysfs_streq(buf, "on") ||
sysfs_streq(buf, "start")) {
mutex_lock(&ctx->work_mutex);
NDS03_StopContinuousMeasurement(pdev);
ret = NDS03_XtalkCalibration(pdev);
if (nds03_sensor_init(ctx) != 0)
nds03_errmsg("nds03 sensor init failed\n");
mutex_unlock(&ctx->work_mutex);
if(ret < 0) {
nds03_errmsg("NDS03_XtalkCalibration error, ret = %d\n", ret);
return -EIO;
}
return count;
} else {
return -EINVAL;
}
}
static DEVICE_ATTR(xtalk_calibration, 0660, NULL, nds03_store_xtalk_calibration);
static ssize_t nds03_store_offset_calibration(struct device *dev,
struct device_attribute *attr, const char *buf,size_t count)
{
int ret;
struct nds03_context *ctx = dev_get_drvdata(dev);
NDS03_Dev_t *pdev = to_nds03_dev(ctx);
int32_t calib_depth_mm_tmp = 0;
ret = kstrtoint(buf, 10, &calib_depth_mm_tmp);
if (ret)
return -EINVAL;
mutex_lock(&ctx->work_mutex);
NDS03_StopContinuousMeasurement(pdev);
ret = NDS03_OffsetCalibrationAtDepth(pdev, calib_depth_mm_tmp);
if (nds03_sensor_init(ctx) != 0)
nds03_errmsg("nds03 sensor init failed\n");
mutex_unlock(&ctx->work_mutex);
if (ret < 0) {
nds03_errmsg("NDS03_OffsetCalibrationAtDepth error, ret = %d\n", ret);
return -EIO;
}
return count;
}
static DEVICE_ATTR(offset_calibration, 0660, NULL, nds03_store_offset_calibration);
static struct attribute *nds03_attributes[] = {
&dev_attr_is_meas.attr,
&dev_attr_meas_delay_ms.attr,
&dev_attr_meas_mode.attr,
&dev_attr_enable_debug.attr,
&dev_attr_tof_reset.attr,
&dev_attr_tof_calib.attr,
&dev_attr_tof_pulsenum.attr,
&dev_attr_tof_xtalk.attr,
&dev_attr_xtalk_calibration.attr,
&dev_attr_offset_calibration.attr,
NULL
};
static const struct attribute_group nds03_sysfs_groups = {
.attrs = nds03_attributes,
};
static void nds03_parse_device_tree(struct nds03_context *ctx)
{
int32_t ret;
NDS03_Platform_t *pdev = to_nds03_platform(ctx);
/* Initialize xshut gpio */
pdev->xshut_gpio = devm_gpiod_get_optional(&ctx->client->dev, "xshut", GPIOD_OUT_HIGH);
if (IS_ERR(pdev->xshut_gpio)) {
ret = PTR_ERR(pdev->xshut_gpio);
nds03_warnmsg( "no xshut pin available, error = %d\n", ret);
return;
} else {
nds03_dbgmsg("get xshut pin success\n");
}
/* Initialize irq gpio*/
atomic_set(&ctx->meas_mode, 1); //Default to polling mode
ctx->irq = -1;
pdev->intr_gpio = devm_gpiod_get_optional(&ctx->client->dev, "intr", GPIOD_IN);
if (IS_ERR(pdev->intr_gpio)) {
ret = PTR_ERR(pdev->intr_gpio);
nds03_warnmsg( "no intr pin available, error = %d\n", ret);
return;
}
nds03_dbgmsg("get intr pin success\n");
ctx->irq = ctx->client->irq;
if (ctx->irq) {
unsigned long default_trigger = irqd_get_trigger_type(irq_get_irq_data(ctx->irq));
ret = devm_request_threaded_irq(&ctx->client->dev,
ctx->irq, NULL,
tof_irq_handler_i2c,
default_trigger|IRQF_ONESHOT,
"nds03_interrupt",
(void *)ctx);
if (ret) {
nds03_errmsg("fail to req threaded irq rc=%d\n", ret);
} else {
nds03_info(
"request irq success, irq mode use, irq num: %d, type: %lu",
ctx->irq, default_trigger);
atomic_set(&ctx->meas_mode, 0); //Configure in interrupt mode
}
} else {
void *poll_interval_dt = NULL;
uint32_t delay_ms;
nds03_info("no irq number specified, polling mode is used\n");
poll_interval_dt = (void *)of_get_property(ctx->client->dev.of_node,
"nds03_poll_interval",
NULL);
delay_ms = poll_interval_dt ? be32_to_cpup(poll_interval_dt) : 0;
nds03_dbgmsg("poll delay ms:%d\n", delay_ms);
atomic_set(&ctx->poll_delay_ms, delay_ms);
}
}
int nds03_common_probe(struct nds03_context * ctx)
{
int ret = 0;
u32 i2c_freq = 0;
// struct input_dev *input;
/* Initialize mutex */
mutex_init(&ctx->work_mutex);
/* init work handler */
INIT_DELAYED_WORK(&ctx->dwork, nds03_work_handler);
INIT_WORK(&ctx->irq_work, nds03_measure_irq_work);
atomic_set(&ctx->is_meas, 0);
/* Parse the device tree for NDS03 sensor configuration. */
nds03_parse_device_tree(ctx);
of_property_read_u32(ctx->client->adapter->dev.of_node, "clock-frequency", &i2c_freq);
pr_info("I2C bus number is %d, bus speed: %u Hz\n", ctx->client->adapter->nr, i2c_freq);
ret = nds03_iio_init(ctx);
if (ret) {
nds03_errmsg("IIO init failed: %d\n", ret);
goto err_iio;
}
ctx->fd_open_count = 0;
nds03_dbgmsg("create sysfs group successfully\n");
/* Initialize nds03 sensor */
ret = nds03_sensor_init(ctx);
if (ret != 0 ) {
nds03_errmsg("Failed to init nds03 sensor error:%d\n", ret);
goto err_iio;
}
nds03_dbgmsg("init nds03 sensor successfully\n");
ret = sysfs_create_group(&ctx->client->dev.kobj, &nds03_sysfs_groups);
if (ret) {
nds03_errmsg("Failed to create sysfs group error:%d\n", ret);
goto exit_err;
}
ctx->remove_flag = false;
nds03_dbgmsg("register chardev successfully\n");
nds03_info("nds03 module registered successfully\n");
nds03_info( "NDS03 Driver version: %s \n", DRIVER_VERSION);
return 0;
err_iio:
nds03_iio_remove(ctx);
exit_err:
return ret;
}
EXPORT_SYMBOL_GPL(nds03_common_probe);
int nds03_common_remove(struct nds03_context * ctx)
{
nds03_dbgmsg("Enter %s \n", __FUNCTION__);
cancel_delayed_work(&ctx->dwork);
ctx->remove_flag = true;
sysfs_remove_group(&ctx->client->dev.kobj, &nds03_sysfs_groups);
nds03_iio_remove(ctx);
return 0;
}
EXPORT_SYMBOL_GPL(nds03_common_remove);

View File

@@ -0,0 +1,99 @@
/*!
@file nds03_module_i2c.c
@brief
@author lull
@date 2025-06
@copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd.
@license BSD 3-Clause License
This file is part of the Nephotonics sensor SDK.
It is licensed under the BSD 3-Clause License.
A copy of the license can be found in the project root directory, in the file named LICENSE.
*/
#include "nds03.h"
#include "nds03_platform.h"
struct nds03_context *nds03_context_obj = NULL;
// int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret = 0;
struct device *dev = &client->dev;
struct nds03_context * ctx = NULL;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if(IS_ERR(ctx)) {
nds03_errmsg("nds03_data memory allocation failed\n");
ret = -ENOMEM;
goto module_reg_err;
}
nds03_context_obj = ctx;
ctx->client = client;
ret = nds03_common_probe(ctx);
if(ret != 0) {
nds03_errmsg("Failed to register nds03 module: %d\n", ret);
goto module_reg_err;
}
i2c_set_clientdata(client, ctx);
return 0;
module_reg_err:
return ret;
}
static void nds03_i2c_remove(struct i2c_client *client)
{
struct nds03_context * ctx = i2c_get_clientdata(client);
nds03_common_remove(ctx);
// return 0;
}
static const struct i2c_device_id tof_nds03_id[] = {
{TOF_NDS03_DRV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tof_nds03_id);
static const struct of_device_id tof_nds03_dt_match[] = {
{ .compatible = "nx,"TOF_NDS03_DRV_NAME, },
{ }
};
MODULE_DEVICE_TABLE(of, tof_nds03_dt_match);
static struct i2c_driver tof_nds03_driver = {
.driver = {
.name = TOF_NDS03_DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = tof_nds03_dt_match,
},
.probe = nds03_i2c_probe,
.remove = nds03_i2c_remove,
.id_table = tof_nds03_id,
};
static int __init tof_nds03_init_i2c(void)
{
int ret = 0;
nds03_dbgmsg("Enter\n");
ret = i2c_add_driver(&tof_nds03_driver);
if (ret)
nds03_errmsg("%d erro ret:%d\n", __LINE__, ret);
return ret;
}
static void __exit tof_nds03_exit_i2c(void )
{
nds03_dbgmsg("Exit\n");
i2c_del_driver(&tof_nds03_driver);
}
module_init(tof_nds03_init_i2c);
module_exit(tof_nds03_exit_i2c);
MODULE_DESCRIPTION("Time-of-Flight sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);

View File

@@ -0,0 +1,117 @@
/*!
@file nds03_platform.c
@brief
@author lull
@date 2025-06
@copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd.
@license BSD 3-Clause License
This file is part of the Nephotonics sensor SDK.
It is licensed under the BSD 3-Clause License.
A copy of the license can be found in the project root directory, in the file named LICENSE.
*/
#include "nds03_platform.h"
int8_t nds03_platform_init(NDS03_Platform_t *pdev, void * client)
{
pdev->client = (struct i2c_client *)client;
pdev->i2c_dev_addr = 0X5C;
return 0;
}
int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void * param)
{
return 0;
}
int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len)
{
int8_t ret;
struct i2c_msg i2c_message[2];
uint8_t i2c_buf[256];
i2c_buf[0] = i2c_raddr;
i2c_message[0].addr = pDev->i2c_dev_addr;
i2c_message[0].buf = i2c_buf;
i2c_message[0].len = 1;
i2c_message[0].flags = 0 ; //| I2C_M_STOP;//I2C_M_STOP;
i2c_message[1].addr = pDev->i2c_dev_addr;
i2c_message[1].buf = i2c_rdata;
i2c_message[1].len = len;
i2c_message[1].flags = I2C_M_RD;
ret = i2c_transfer(pDev->client->adapter, i2c_message, 2);
if (ret != 2) {
pr_err("NDS03: i2c read error, i2c_raddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_raddr, ret);
return -EIO;
}
return 0;
}
int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len)
{
int32_t ret;
struct i2c_msg i2c_message;
//For user implement
uint8_t i2c_buf[256];
memcpy(&i2c_buf[1], i2c_wdata, len);
i2c_buf[0] = i2c_waddr;
i2c_message.addr = pDev->i2c_dev_addr;
i2c_message.buf = i2c_buf;
i2c_message.len = len + 1;
i2c_message.flags = 0;
ret = i2c_transfer(pDev->client->adapter, &i2c_message, 1);
if (ret != 1) {
pr_err("NDS03: i2c write error, i2c_waddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_waddr, ret);
return -EIO;
}
return 0;
}
int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us)
{
wait_10us *= 10;
if (wait_10us < 10)
udelay(wait_10us);
else if (wait_10us < 20000)
usleep_range(wait_10us, wait_10us + 1);
else
msleep(wait_10us / 1000);
return 0;
}
int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms)
{
nds03_delay_10us(pDev, wait_ms * 100);
return 0;
}
int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level)
{
if (pDev->xshut_gpio == NULL) {
pr_err("xshut_gpiod is not init , not setting xshut\n");
return -1;
}
gpiod_set_value(pDev->xshut_gpio, level);
// pr_info("xshut set to %d\n", level);
return 0;
}
int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency)
{
return 0;
}
int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency)
{
return 0;
}
int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms)
{
return 0;
}

View File

@@ -0,0 +1,137 @@
/*!
@file nds03_platform.h
@brief
@author lull
@date 2025-06
@copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd.
@license BSD 3-Clause License
This file is part of the Nephotonics sensor SDK.
It is licensed under the BSD 3-Clause License.
A copy of the license can be found in the project root directory, in the file named LICENSE.
*/
#ifndef __NDS03_PLATFORM__H__
#define __NDS03_PLATFORM__H__
#include "nds03_stdint.h"
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/gpio.h>
/**
* @struct NDS03_Platform_t
*
* @brief NDS03平台相关定义 \n
* i2c地址等i2c地址
*/
typedef struct{
//文件描述符
int fd;
/** 用户不可更改以下变量 @{ */
uint8_t i2c_dev_addr; // i2c设备地址
/** @} */
/** 用户可根据需要添加变量 */
struct i2c_client *client;
////// /* nds03 device io */
struct gpio_desc *intr_gpio;
/*!< xsdn reset (low active) gpio number to device */
struct gpio_desc *xshut_gpio;
} NDS03_Platform_t;
/**
* @brief NDS03平台初始化
*
* @param pDev
* @param void*
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_platform_init(NDS03_Platform_t *pdev, void *);
/**
* @brief NDS03平台释放
*
* @param pDev
* @param void*
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void *);
/**
* @brief I2C读一个字节
*
* @param pDev
* @param i2c_raddr
* @param i2c_rdata
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len);
/**
* @brief I2C写一个字节
*
* @param pDev
* @param i2c_waddr
* @param i2c_wdata
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len);
/**
* @brief wait_ms毫秒
*
* @param pDev
* @param wait_ms
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms);
/**
* @brief 10*wait_10us微秒
*
* @param pDev
* @param wait_10us
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us);
/**
* @brief nds03 xshut引脚电平
*
* @param pDev
* @param level 01
* @return int8_t
* @retval 0:, :
*/
int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level);
/*!
@brief NDS03获取当前i2c时钟频率
@param pDev
@param clock_frequency
@return int8_t
*/
int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency);
/*!
@brief NDS03设置当前i2c时钟频率
@param pDev
@param clock_frequency
@return int8_t
*/
int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency);
/*!
@brief ms
@param pDev
@param time_ms
@return int8_t
*/
int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms);
#endif

View File

@@ -0,0 +1,95 @@
/**
* @file nds03_stdint.h
* @author tongsheng.tang
* @brief NDS03 platform-specific integer type definitions
* @version 2.x.x
* @date 2025-06
*
* @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd.
*
* @license BSD 3-Clause License
* This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License.
* You may obtain a copy of the license in the project root directory, in the file named LICENSE.
*
*/
#ifndef __NDS03_STDINT_H__
#define __NDS03_STDINT_H__
#define PLATFORM_C51 0
#define PLATFORM_NOT_C51 1
#define PLATFORM_LINUX_DRIVER 2
#ifndef NDS03_PLATFORM
#define NDS03_PLATFORM PLATFORM_LINUX_DRIVER
#endif
#if NDS03_PLATFORM == PLATFORM_NOT_C51
#include <stdint.h>
#elif NDS03_PLATFORM == PLATFORM_C51
/* exact-width signed integer types */
typedef signed char int8_t;
typedef signed int int16_t;
typedef signed long int32_t;
/* exact-width unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;
#define __func__ __FILE__
/* minimum values of exact-width signed integer types */
#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */
/* maximum values of exact-width signed integer types */
#define INT32_MAX 2147483647
/* maximum values of exact-width unsigned integer types */
#define UINT32_MAX 4294967295u
/* 7.18.2.2 */
/* minimum values of minimum-width signed integer types */
#define INT_LEAST32_MIN (~0x7fffffff)
/* maximum values of minimum-width signed integer types */
#define INT_LEAST32_MAX 2147483647
/* maximum values of minimum-width unsigned integer types */
#define UINT_LEAST32_MAX 4294967295u
/* 7.18.2.3 */
/* minimum values of fastest minimum-width signed integer types */
#define INT_FAST32_MIN (~0x7fffffff)
/* maximum values of fastest minimum-width signed integer types */
#define INT_FAST32_MAX 2147483647
/* maximum values of fastest minimum-width unsigned integer types */
#define UINT_FAST32_MAX 4294967295u
#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER
/* exact-width signed integer types */
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
/* exact-width unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define __func__ __FILE__
/* minimum values of exact-width signed integer types */
#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */
/* maximum values of exact-width signed integer types */
#define INT32_MAX 2147483647
/* maximum values of exact-width unsigned integer types */
#define UINT32_MAX 4294967295u
#endif
#endif /** __NDS03_STDINT_H__ */