vcnl36825t: additional delay after wakeup on "force"-mode

There is an (undocumented) additional delay necessary if the device woke
up and a measurement is triggered via the "force"-mode. The additional
sleep time was determined empirically on different devices.

Signed-off-by: Juliane Schulze <juliane.schulze@deveritec.com>
This commit is contained in:
Juliane Schulze 2024-08-09 11:37:59 +02:00 committed by Carles Cufí
commit 38ee9aa17b
2 changed files with 70 additions and 16 deletions

View file

@ -65,6 +65,8 @@ static int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, u
static int vcnl36825t_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct vcnl36825t_config *config = dev->config;
struct vcnl36825t_data *data = dev->data;
int rc;
switch (action) {
@ -98,6 +100,9 @@ static int vcnl36825t_pm_action(const struct device *dev, enum pm_device_action
if (rc < 0) {
return rc;
}
data->meas_timeout_us = data->meas_timeout_wakeup_us;
break;
case PM_DEVICE_ACTION_SUSPEND:
rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK,
@ -166,6 +171,10 @@ static int vcnl36825t_sample_fetch(const struct device *dev, enum sensor_channel
}
k_usleep(data->meas_timeout_us);
#ifdef CONFIG_PM_DEVICE
data->meas_timeout_us = data->meas_timeout_running_us;
#endif
}
rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_PS_DATA, &data->proximity);
@ -201,6 +210,22 @@ static int vcnl36825t_channel_get(const struct device *dev, enum sensor_channel
return 0;
}
/**
* @brief calculate measurement timeout in us
*
* @param meas_duration base duration of a measurement in us*VCNL36825T_FORCED_FACTOR_SCALE
* @param meas_factor factor which needs to be multiplied to cope with additional delays (multiplied
* by VCNL36825T_FORCED_FACTOR_SCALE)
*
* @note
* Always add 1 to prevent corner case losses due to precision.
*/
static inline unsigned int vcn36825t_measurement_timeout_us(unsigned int meas_duration,
unsigned int forced_factor)
{
return ((meas_duration * forced_factor) / VCNL36825T_FORCED_FACTOR_SCALE) + 1;
}
/**
* @brief helper function to configure the registers
*
@ -214,6 +239,8 @@ static int vcnl36825t_init_registers(const struct device *dev)
int rc;
uint16_t reg_value;
unsigned int meas_duration = 1;
/* reset registers as defined by the datasheet */
const uint16_t resetValues[][2] = {
{VCNL36825T_REG_PS_CONF1, VCNL36825T_CONF1_DEFAULT},
@ -229,8 +256,6 @@ static int vcnl36825t_init_registers(const struct device *dev)
vcnl36825t_write(&config->i2c, resetValues[i][0], resetValues[i][1]);
}
data->meas_timeout_us = 1;
/* PS_CONF1 */
reg_value = 0x01; /* must be set according to datasheet */
reg_value |= VCNL36825T_PS_ON;
@ -277,21 +302,21 @@ static int vcnl36825t_init_registers(const struct device *dev)
switch (config->proximity_it) {
case VCNL36825T_PROXIMITY_INTEGRATION_1T:
reg_value |= VCNL36825T_PS_IT_1T;
data->meas_timeout_us *= 1;
meas_duration *= 1;
break;
case VCNL36825T_PROXIMITY_INTEGRATION_2T:
reg_value |= VCNL36825T_PS_IT_2T;
data->meas_timeout_us *= 2;
meas_duration *= 2;
break;
case VCNL36825T_PROXIMITY_INTEGRATION_4T:
reg_value |= VCNL36825T_PS_IT_4T;
data->meas_timeout_us *= 4;
meas_duration *= 4;
break;
case VCNL36825T_PROXIMITY_INTEGRATION_8T:
__fallthrough;
default:
reg_value |= VCNL36825T_PS_IT_8T;
data->meas_timeout_us *= 8;
meas_duration *= 8;
break;
}
@ -315,13 +340,13 @@ static int vcnl36825t_init_registers(const struct device *dev)
switch (config->proximity_itb) {
case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_25us:
reg_value |= VCNL36825T_PS_ITB_25us;
data->meas_timeout_us *= 25;
meas_duration *= 25;
break;
case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_50us:
__fallthrough;
default:
reg_value |= VCNL36825T_PS_ITB_50us;
data->meas_timeout_us *= 50;
meas_duration *= 50;
break;
}
@ -409,13 +434,22 @@ static int vcnl36825t_init_registers(const struct device *dev)
return -EIO;
}
/* calculate measurement timeout
* Note: always add 1 to prevent corner case losses due to precision.
*/
data->meas_timeout_us =
(data->meas_timeout_us * VCNL36825T_FORCED_FACTOR_SUM) /
(VCNL36825T_FORCED_FACTOR_SCALE) +
1;
vcn36825t_measurement_timeout_us(meas_duration, VCNL36825T_FORCED_FACTOR_SUM);
#ifdef CONFIG_PM_DEVICE
data->meas_timeout_running_us = data->meas_timeout_us;
data->meas_timeout_wakeup_us = vcn36825t_measurement_timeout_us(
meas_duration, VCNL36825T_FORCED_FACTOR_WAKEUP_SUM);
/* ensure that the time is roughly around VCNL36825T_FORCED_WAKEUP_DELAY_MAX_US if the
* wakeup time is bigger but "normal" measurement time is less
*/
if (data->meas_timeout_wakeup_us > VCNL36825T_FORCED_WAKEUP_DELAY_MAX_US) {
data->meas_timeout_wakeup_us =
MAX(data->meas_timeout_running_us, VCNL36825T_FORCED_WAKEUP_DELAY_MAX_US);
}
#endif
return 0;
}
@ -424,6 +458,7 @@ static int vcnl36825t_init(const struct device *dev)
{
const struct vcnl36825t_config *config = dev->config;
int rc;
uint16_t reg_value;
if (!i2c_is_ready_dt(&config->i2c)) {

View file

@ -219,12 +219,26 @@
#define VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT 3
#define VCNL36825T_FORCED_FACTOR_MEASUREMENT 1
#define VCNL36825T_FORCED_FACTOR_SHUTDOWN 1
#define VCNL36825T_FORCED_FACTOR_SCALE 10
#define VCNL36825T_FORCED_FACTOR_SCALE 10
/* necessary time to wait before data of a "forced" measurement is available */
#define VCNL36825T_FORCED_FACTOR_SUM \
((VCNL36825T_FORCED_FACTOR_TIME_TO_TRIGGER + VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT + \
VCNL36825T_FORCED_FACTOR_MEASUREMENT + VCNL36825T_FORCED_FACTOR_SHUTDOWN) * \
VCNL36825T_FORCED_FACTOR_SCALE)
#ifdef CONFIG_PM_DEVICE
#define VCNL36825T_FORCED_WAKEUP_DELAY_MAX_US 1000
#define VCNL36825T_FORCED_FACTOR_WAKEUP_DELAY 10
/* necessary wait time before data for a "forced" measurement is available AFTER the device slept */
#define VCNL36825T_FORCED_FACTOR_WAKEUP_SUM \
(VCNL36825T_FORCED_FACTOR_SUM + \
(VCNL36825T_FORCED_FACTOR_WAKEUP_DELAY * VCNL36825T_FORCED_FACTOR_SCALE))
#endif
enum vcnl36825t_operation_mode {
VCNL36825T_OPERATION_MODE_AUTO,
VCNL36825T_OPERATION_MODE_FORCE,
@ -288,7 +302,12 @@ struct vcnl36825t_config {
struct vcnl36825t_data {
uint16_t proximity;
int meas_timeout_us; /** wait time for finished measurement for "forced" operation mode */
unsigned int meas_timeout_us; /** wait time for finished measurement in "forced"-mode */
#ifdef CONFIG_PM_DEVICE
unsigned int meas_timeout_running_us;
unsigned int meas_timeout_wakeup_us;
#endif
};
#endif