New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers: input: Implement driver for ADC keys #68446
Conversation
21ee194
to
6db4b16
Compare
drivers/input/input_adc_keys.c
Outdated
adc_keys_process(dev); | ||
} | ||
|
||
static void adc_keys_timer_handler(struct k_timer *timer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could k_work_delayable
be used instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
6db4b16
to
2044fad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an instance of this in tests/drivers/build_all/input/app.overlay
so it gets built in CI?
drivers/input/input_adc_keys.c
Outdated
const struct device *self; | ||
struct k_work_delayable dwork; | ||
struct adc_sequence seq; | ||
struct adc_keys_key_data *key_data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pointer can go in the config structure since the pointer itself does not change, save few bytes of ram. Then at that point the only thing to initialize is self
, you can set that in adc_keys_init
and drop the static initialization, which saves few bytes of flash as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your suggestion. My understanding is that even if I assign data->self
in adc_keys_init
, the self
pointer would still occupy some memory within struct adc_keys_data
. The DEVICE_DT_INST_GET
merely populates this pointer with an address at compile time. Am I correct in this understanding? It's a bit unexpected for me. Looking forward to your clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's right, but if you initialize it statically then it's going to take the space in RAM and also space in flash for the static initialization, including for the members that you are not explicitly initializing (storing a bunch of 0 essentially), while if you let it uninitialized the system will zero-initialize it automatically and you just use the flash for the instructions to set the pointer, so it's usually a good idea to leave data structures uninitalized if possible.
1c36de9
to
32bd46c
Compare
io-channels = <&test_adc 0>; | ||
keyup-threshold-mv = <0>; | ||
button_0 { | ||
press-thresholds-mv = <1500>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add an extra value and an extra button to make sure that the iteration macros are tested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(still not addressed)
32bd46c
to
1c3e660
Compare
drivers/input/input_adc_keys.c
Outdated
* being overwritten by another threshold configuration. | ||
*/ | ||
if (closest_mv == code_cfg->press_mv) { | ||
key_data->curr_state = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key_data->curr_state = 1; | |
key_data->curr_state = true; |
drivers/input/input_adc_keys.c
Outdated
* Reset the state so that it can be updated in the next | ||
* iteration. | ||
*/ | ||
key_data->curr_state = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key_data->curr_state = 0; | |
key_data->curr_state = false; |
drivers/input/input_adc_keys.c
Outdated
#define ADC_KEYS_KEY_DATA(node_id) \ | ||
{ \ | ||
.zephyr_code = DT_PROP(node_id, zephyr_code), .last_state = 0, .curr_state = 0, \ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about moving zephyr_code in its own array? I think you could have a const uint16_t *codes
for the codes, that is going to be key_cnt
sized, then you only have to initialize that statically and you can leave key_data
being zero initialized automatically. That will save another bit of flash and another bit of ram. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! Now everything looks comfortable.
1c3e660
to
67bdd04
Compare
io-channels = <&test_adc 0>; | ||
keyup-threshold-mv = <0>; | ||
button_0 { | ||
press-thresholds-mv = <1500>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(still not addressed)
67bdd04
to
29fa6fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, just few nitpicks on the types but looks good otherwise
0de60a9
to
0602460
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff thanks for contributing this.
drivers/input/input_adc_keys.c
Outdated
data->self = dev; | ||
k_work_init_delayable(&data->dwork, adc_keys_work_handler); | ||
|
||
#if defined(CONFIG_INPUT_LOG_LEVEL_DBG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if defined(CONFIG_INPUT_LOG_LEVEL_DBG) | |
if (IS_ENABLED((CONFIG_INPUT_LOG_LEVEL_DBG)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? It should be completely removed in compile time if not enabled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linker should drop this part anyway. You can double-check that by comparing the binaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a bit too dependent on the compiler's optimization level. Wouldn't using the preprocessor be a more recommended approach, as discussed in #53200?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends. In that case, the compiler will catch the errors in that for loop even though CONFIG_INPUT_LOG_LEVEL_DBG
is disabled. As it's an init function it does not have much impact on the code even though the linker would not drop it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's enlightening. Thank you for your suggestion. Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for catching this @bbilas -- there's a bit in the coding style guide: https://docs.zephyrproject.org/latest/kernel/util/index.html#c.IS_ENABLED, yes it does depend on compiler optimization but that's a fairly common theme in the code base and at this point just something understood and utilized
0602460
to
9d4ee22
Compare
This commit introduces a driver for ADC keys, a common circuit design where keys are connected to an ADC input via a resistor ladder. Signed-off-by: Chen Xingyu <hi@xingrz.me>
* so that it'll be built by the CI Signed-off-by: Chen Xingyu <hi@xingrz.me>
9d4ee22
to
3648041
Compare
Thanks all! I've learned a lot from this PR. |
This commit introduces a driver for ADC keys, a common circuit design where keys are connected to an ADC input via a resistor ladder.
The driver itself does not calculate each possible combination of resistor values. Instead, users are required to specify the voltage for each single key press or for combinations of key presses.
Example 1
The schematic of a common design:
An example DTS:
Example 2
Another example that supports simultaneously press both of keys:
In the circuit above, for K4:
For K5:
For both K4 and K5 being pressed simultaneously: