drivers: input: input_adc_keys: add debouncing to avoid false events

The previous implementation already reported a key-press event after
reading an ADC value close to the threshold for the first time.

This may lead to false events if the ADC takes a reading just during
the transition from one button state to another (especially if a
somewhat large capacitor is used to avoid noise).

A key-press state must be same for at least two samples in order to
avoid such issues, which is what this commit implements.

Signed-off-by: Martin Jäger <martin@libre.solar>
This commit is contained in:
Martin Jäger
2025-05-06 11:59:18 +02:00
committed by Benjamin Cabé
parent 07e1de381a
commit 81cd7cacc4

View File

@@ -23,6 +23,7 @@ struct adc_keys_code_config {
};
struct adc_keys_key_state {
bool orig_state;
bool last_state;
bool curr_state;
};
@@ -99,7 +100,18 @@ static inline void adc_keys_process(const struct device *dev)
LOG_DBG("sample=%d mV, closest=%d mV, diff=%d mV", sample_mv, closest_mv, closest_diff);
/*
* Update cached key states according to the closest key press threshold.
* Update cached key states and init current states with false
*/
for (uint8_t i = 0; i < cfg->key_cnt; i++) {
key_state = &cfg->key_state[i];
key_state->last_state = key_state->curr_state;
key_state->curr_state = false;
}
/*
* Update current key states according to the closest key press threshold.
*
* Note that multiple keys may have the same press threshold, which is
* the mixed voltage that these keys are simultaneously pressed.
@@ -119,25 +131,20 @@ static inline void adc_keys_process(const struct device *dev)
}
/*
* Report the key event if the key state has changed.
* Report the key event if the key state changed for at least two continuous cycles.
*/
for (uint8_t i = 0; i < cfg->key_cnt; i++) {
key_state = &cfg->key_state[i];
key_code = cfg->key_code[i];
if (key_state->last_state != key_state->curr_state) {
if (key_state->orig_state != key_state->curr_state &&
key_state->last_state == key_state->curr_state) {
LOG_DBG("Report event %s %d, code=%d", dev->name, key_state->curr_state,
key_code);
input_report_key(dev, key_code, key_state->curr_state, true, K_FOREVER);
key_state->last_state = key_state->curr_state;
key_state->orig_state = key_state->curr_state;
}
/*
* Reset the state so that it can be updated in the next
* iteration.
*/
key_state->curr_state = false;
}
}