input: analog_axis: rework deadzone calibration code

Rework the data scaling algorithm for the "deadzone" mode so that the
deadzone is subtracted from the input rather than from the output. This
makes the whole output range usable rather than making the output jump
from the center value to the minimum deadzone range.

This changes the calibration data structure as well so now all values
refer to the input data, which is more coherent.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
Fabio Baltieri 2024-03-18 01:25:46 +00:00 committed by Anas Nashif
commit 55c14e6fa6
6 changed files with 64 additions and 21 deletions

View file

@ -101,6 +101,48 @@ int analog_axis_calibration_set(const struct device *dev,
return 0;
}
static int32_t analog_axis_out_deadzone(const struct device *dev,
int channel,
int32_t raw_val)
{
const struct analog_axis_config *cfg = dev->config;
const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[channel];
struct analog_axis_calibration *cal = &cfg->calibration[channel];
int16_t in_range = cal->in_max - cal->in_min;
int16_t out_range = axis_cfg->out_max - axis_cfg->out_min;
int16_t in_mid = DIV_ROUND_CLOSEST(cal->in_min + cal->in_max, 2);
int16_t in_min = cal->in_min;
if (abs(raw_val - in_mid) < cal->in_deadzone) {
return DIV_ROUND_CLOSEST(axis_cfg->out_max + axis_cfg->out_min, 2);
}
in_range -= cal->in_deadzone * 2;
in_min += cal->in_deadzone;
if (raw_val < in_mid) {
raw_val += cal->in_deadzone;
} else {
raw_val -= cal->in_deadzone;
}
return DIV_ROUND_CLOSEST((raw_val - in_min) * out_range, in_range) + axis_cfg->out_min;
}
static int32_t analog_axis_out_linear(const struct device *dev,
int channel,
int32_t raw_val)
{
const struct analog_axis_config *cfg = dev->config;
const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[channel];
struct analog_axis_calibration *cal = &cfg->calibration[channel];
int16_t in_range = cal->in_max - cal->in_min;
int16_t out_range = axis_cfg->out_max - axis_cfg->out_min;
return DIV_ROUND_CLOSEST((raw_val - cal->in_min) * out_range, in_range) + axis_cfg->out_min;
}
static void analog_axis_loop(const struct device *dev)
{
const struct analog_axis_config *cfg = dev->config;
@ -135,8 +177,6 @@ static void analog_axis_loop(const struct device *dev)
const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i];
struct analog_axis_channel_data *axis_data = &cfg->channel_data[i];
struct analog_axis_calibration *cal = &cfg->calibration[i];
int16_t in_range = cal->in_max - cal->in_min;
int16_t out_range = axis_cfg->out_max - axis_cfg->out_min;
int32_t raw_val = bufs[i];
if (axis_cfg->invert) {
@ -149,17 +189,14 @@ static void analog_axis_loop(const struct device *dev)
LOG_DBG("%s: ch %d: raw_val: %d", dev->name, i, raw_val);
out = CLAMP((raw_val - cal->in_min) * out_range / in_range + axis_cfg->out_min,
axis_cfg->out_min, axis_cfg->out_max);
if (cal->out_deadzone > 0) {
int16_t center = DIV_ROUND_CLOSEST(
axis_cfg->out_max + axis_cfg->out_min, 2);
if (abs(out - center) < cal->out_deadzone) {
out = center;
}
if (cal->in_deadzone > 0) {
out = analog_axis_out_deadzone(dev, i, raw_val);
} else {
out = analog_axis_out_linear(dev, i, raw_val);
}
out = CLAMP(out, axis_cfg->out_min, axis_cfg->out_max);
if (axis_data->last_out != out) {
input_report_abs(dev, axis_cfg->axis, out, true, K_FOREVER);
}
@ -237,7 +274,7 @@ static int analog_axis_init(const struct device *dev)
{ \
.in_min = (int16_t)DT_PROP(node_id, in_min), \
.in_max = (int16_t)DT_PROP(node_id, in_max), \
.out_deadzone = DT_PROP(node_id, out_deadzone), \
.in_deadzone = DT_PROP(node_id, in_deadzone), \
}
#define ANALOG_AXIS_INIT(inst) \

View file

@ -27,7 +27,7 @@ static void analog_axis_calibration_log(const struct device *dev)
analog_axis_calibration_get(dev, i, &cal);
LOG_INF("%s: ch: %d min: %d max: %d deadzone: %d",
dev->name, i, cal.in_min, cal.in_max, cal.out_deadzone);
dev->name, i, cal.in_min, cal.in_max, cal.in_deadzone);
}
}