Skip to content

Commit bdcac73

Browse files
author
root
committed
feat(sensors): debounce ec11 encoder.
1 parent 2ded791 commit bdcac73

File tree

5 files changed

+137
-219
lines changed

5 files changed

+137
-219
lines changed

app/module/drivers/sensor/ec11/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ zephyr_include_directories(.)
66
zephyr_library()
77

88
zephyr_library_sources(ec11.c)
9-
zephyr_library_sources_ifdef(CONFIG_EC11_TRIGGER ec11_trigger.c)

app/module/drivers/sensor/ec11/ec11.c

Lines changed: 117 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
#include <zephyr/drivers/gpio.h>
1111
#include <zephyr/sys/util.h>
1212
#include <zephyr/kernel.h>
13-
#include <zephyr/drivers/sensor.h>
14-
#include <zephyr/sys/__assert.h>
1513
#include <zephyr/logging/log.h>
1614

1715
#include "ec11.h"
@@ -20,57 +18,42 @@
2018

2119
LOG_MODULE_REGISTER(EC11, CONFIG_SENSOR_LOG_LEVEL);
2220

23-
static int ec11_get_ab_state(const struct device *dev) {
24-
const struct ec11_config *drv_cfg = dev->config;
25-
26-
return (gpio_pin_get_dt(&drv_cfg->a) << 1) | gpio_pin_get_dt(&drv_cfg->b);
27-
}
28-
29-
static int ec11_sample_fetch(const struct device *dev, enum sensor_channel chan) {
30-
struct ec11_data *drv_data = dev->data;
31-
const struct ec11_config *drv_cfg = dev->config;
32-
uint8_t val;
33-
int8_t delta;
34-
35-
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_ROTATION);
36-
37-
val = ec11_get_ab_state(dev);
38-
39-
LOG_DBG("prev: %d, new: %d", drv_data->ab_state, val);
40-
41-
switch (val | (drv_data->ab_state << 2)) {
42-
case 0b0010:
43-
case 0b0100:
44-
case 0b1101:
45-
case 0b1011:
46-
delta = -1;
47-
break;
48-
case 0b0001:
49-
case 0b0111:
50-
case 0b1110:
51-
case 0b1000:
52-
delta = 1;
53-
break;
54-
default:
55-
delta = 0;
56-
break;
21+
static void ec11_apply_reading(struct ec11_data *drv_data, uint8_t a, uint8_t b) {
22+
if (a == drv_data->prev_a && b == drv_data->prev_b) {
23+
LOG_DBG("no state change");
24+
return;
5725
}
5826

59-
LOG_DBG("Delta: %d", delta);
27+
bool bwd1 = (drv_data->prev_b != a);
28+
bool bwd2 = (drv_data->prev_a == b);
29+
int8_t delta = (bwd1 == bwd2) ? (bwd1 ? -1 : +1) : 0; // delta == 0 implies missing states
30+
LOG_DBG("state %u%u -> %u%u delta:%d", drv_data->prev_a, drv_data->prev_b, a, b, delta);
6031

6132
drv_data->pulses += delta;
62-
drv_data->ab_state = val;
33+
drv_data->prev_a = a;
34+
drv_data->prev_b = b;
6335

6436
// TODO: Temporary code for backwards compatibility to support
6537
// the sensor channel rotation reporting *ticks* instead of delta of degrees.
6638
// REMOVE ME
39+
const struct ec11_config *drv_cfg = drv_data->dev->config;
6740
if (drv_cfg->steps == 0) {
6841
drv_data->ticks = drv_data->pulses / drv_cfg->resolution;
6942
drv_data->delta = delta;
7043
drv_data->pulses %= drv_cfg->resolution;
7144
}
7245

73-
return 0;
46+
#ifdef CONFIG_EC11_TRIGGER
47+
// TODO: CONFIG_EC11_TRIGGER_OWN_THREAD, CONFIG_EC11_TRIGGER_GLOBAL_THREAD
48+
// XXX: zmk_sensors_trigger_handler() already uses a work queue?
49+
if (delta != 0 && drv_data->handler) {
50+
drv_data->handler(drv_data->dev, drv_data->trigger);
51+
}
52+
#endif
53+
}
54+
55+
static int ec11_sample_fetch(const struct device *dev, enum sensor_channel chan) {
56+
return 0; // nothing to do; driven by interrupts & timer
7457
}
7558

7659
static int ec11_channel_get(const struct device *dev, enum sensor_channel chan,
@@ -100,6 +83,16 @@ static int ec11_channel_get(const struct device *dev, enum sensor_channel chan,
10083
return 0;
10184
}
10285

86+
#ifdef CONFIG_EC11_TRIGGER
87+
static int ec11_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
88+
sensor_trigger_handler_t handler) {
89+
struct ec11_data *drv_data = dev->data;
90+
drv_data->trigger = trig;
91+
drv_data->handler = handler;
92+
return 0;
93+
}
94+
#endif
95+
10396
static const struct sensor_driver_api ec11_driver_api = {
10497
#ifdef CONFIG_EC11_TRIGGER
10598
.trigger_set = ec11_trigger_set,
@@ -108,42 +101,113 @@ static const struct sensor_driver_api ec11_driver_api = {
108101
.channel_get = ec11_channel_get,
109102
};
110103

104+
static void ec11_period(struct k_timer *timer_id) {
105+
struct ec11_data *drv_data = CONTAINER_OF(timer_id, struct ec11_data, debouncer);
106+
const struct ec11_config *drv_cfg = drv_data->dev->config;
107+
108+
uint32_t samples_needed = drv_cfg->debounce_ms / drv_cfg->debounce_scan_period_ms;
109+
samples_needed += !!(drv_cfg->debounce_ms % drv_cfg->debounce_scan_period_ms); // round up
110+
111+
// add a single reading to the moving window
112+
drv_data->hist_a = (drv_data->hist_a << 1) | gpio_pin_get_dt(&drv_cfg->a);
113+
drv_data->hist_b = (drv_data->hist_b << 1) | gpio_pin_get_dt(&drv_cfg->b);
114+
if (drv_data->samples < samples_needed) {
115+
drv_data->samples++;
116+
}
117+
118+
// histogram from the window
119+
uint32_t as = drv_data->hist_a;
120+
uint32_t bs = drv_data->hist_b;
121+
uint8_t cnts[4] = {0, 0, 0, 0};
122+
for (uint8_t i = 0; i < drv_data->samples; i++) {
123+
cnts[((as & 1) << 1) | (bs & 1)]++;
124+
as >>= 1;
125+
bs >>= 1;
126+
}
127+
LOG_DBG("histogram 00:%u 01:%u 10:%u 11:%u", cnts[0], cnts[1], cnts[2], cnts[3]);
128+
129+
// check if any state has reached the threshold
130+
for (uint8_t ab = 0; ab < 4; ab++) {
131+
if (cnts[ab] >= samples_needed / 2 + 1) { // more than half
132+
ec11_apply_reading(drv_data, ab >> 1, ab & 1);
133+
if (cnts[ab] == samples_needed) { // stable for a full window
134+
LOG_DBG("timer stop");
135+
drv_data->samples = 0;
136+
drv_data->running = false;
137+
k_timer_stop(&drv_data->debouncer);
138+
}
139+
break;
140+
}
141+
}
142+
}
143+
144+
static void ec11_interrupt_cb_comon(struct ec11_data *drv_data) {
145+
if (!drv_data->running) {
146+
LOG_DBG("timer start");
147+
drv_data->running = true;
148+
const struct ec11_config *drv_cfg = drv_data->dev->config;
149+
int32_t ms = drv_cfg->debounce_scan_period_ms;
150+
k_timer_start(&drv_data->debouncer, K_MSEC(ms), K_MSEC(ms));
151+
}
152+
}
153+
154+
static void ec11_cb_a(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
155+
ec11_interrupt_cb_comon(CONTAINER_OF(cb, struct ec11_data, a_gpio_cb));
156+
}
157+
158+
static void ec11_cb_b(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
159+
ec11_interrupt_cb_comon(CONTAINER_OF(cb, struct ec11_data, b_gpio_cb));
160+
}
161+
111162
int ec11_init(const struct device *dev) {
112-
struct ec11_data *drv_data = dev->data;
113163
const struct ec11_config *drv_cfg = dev->config;
114-
115164
LOG_DBG("A: %s %d B: %s %d resolution %d", drv_cfg->a.port->name, drv_cfg->a.pin,
116165
drv_cfg->b.port->name, drv_cfg->b.pin, drv_cfg->resolution);
117166

118167
if (!device_is_ready(drv_cfg->a.port)) {
119168
LOG_ERR("A GPIO device is not ready");
120169
return -EINVAL;
121170
}
122-
123171
if (!device_is_ready(drv_cfg->b.port)) {
124172
LOG_ERR("B GPIO device is not ready");
125173
return -EINVAL;
126174
}
127175

128176
if (gpio_pin_configure_dt(&drv_cfg->a, GPIO_INPUT)) {
129-
LOG_DBG("Failed to configure A pin");
177+
LOG_ERR("Failed to configure A pin");
130178
return -EIO;
131179
}
132-
133180
if (gpio_pin_configure_dt(&drv_cfg->b, GPIO_INPUT)) {
134-
LOG_DBG("Failed to configure B pin");
181+
LOG_ERR("Failed to configure B pin");
135182
return -EIO;
136183
}
137184

138-
#ifdef CONFIG_EC11_TRIGGER
139-
if (ec11_init_interrupt(dev) < 0) {
140-
LOG_DBG("Failed to initialize interrupt!");
185+
struct ec11_data *drv_data = dev->data; // already zero-initialized
186+
drv_data->dev = dev;
187+
drv_data->prev_a = gpio_pin_get_dt(&drv_cfg->a);
188+
drv_data->prev_b = gpio_pin_get_dt(&drv_cfg->b);
189+
190+
// enable interrupts
191+
gpio_init_callback(&drv_data->a_gpio_cb, ec11_cb_a, BIT(drv_cfg->a.pin));
192+
if (gpio_add_callback(drv_cfg->a.port, &drv_data->a_gpio_cb) < 0) {
193+
LOG_ERR("Failed to set A callback!");
194+
return -EIO;
195+
}
196+
gpio_init_callback(&drv_data->b_gpio_cb, ec11_cb_b, BIT(drv_cfg->b.pin));
197+
if (gpio_add_callback(drv_cfg->b.port, &drv_data->b_gpio_cb) < 0) {
198+
LOG_ERR("Failed to set B callback!");
199+
return -EIO;
200+
}
201+
if (gpio_pin_interrupt_configure_dt(&drv_cfg->a, GPIO_INT_EDGE_BOTH)) {
202+
LOG_ERR("Unable to set A pin GPIO interrupt");
203+
return -EIO;
204+
}
205+
if (gpio_pin_interrupt_configure_dt(&drv_cfg->b, GPIO_INT_EDGE_BOTH)) {
206+
LOG_ERR("Unable to set B pin GPIO interrupt");
141207
return -EIO;
142208
}
143-
#endif
144-
145-
drv_data->ab_state = ec11_get_ab_state(dev);
146209

210+
k_timer_init(&drv_data->debouncer, ec11_period, NULL);
147211
return 0;
148212
}
149213

@@ -154,6 +218,8 @@ int ec11_init(const struct device *dev) {
154218
.b = GPIO_DT_SPEC_INST_GET(n, b_gpios), \
155219
.resolution = DT_INST_PROP_OR(n, resolution, 1), \
156220
.steps = DT_INST_PROP_OR(n, steps, 0), \
221+
.debounce_ms = DT_INST_PROP_OR(n, debounce_ms, 5), \
222+
.debounce_scan_period_ms = DT_INST_PROP_OR(n, debounce_scan_period_ms, 1), \
157223
}; \
158224
DEVICE_DT_INST_DEFINE(n, ec11_init, NULL, &ec11_data_##n, &ec11_cfg_##n, POST_KERNEL, \
159225
CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api);

app/module/drivers/sensor/ec11/ec11.h

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,38 @@
66

77
#pragma once
88

9-
#include <zephyr/device.h>
109
#include <zephyr/drivers/gpio.h>
11-
#include <zephyr/sys/util.h>
10+
#include <zephyr/drivers/sensor.h>
1211

1312
struct ec11_config {
1413
const struct gpio_dt_spec a;
1514
const struct gpio_dt_spec b;
1615

1716
const uint16_t steps;
1817
const uint8_t resolution;
18+
int32_t debounce_ms;
19+
int32_t debounce_scan_period_ms;
1920
};
2021

2122
struct ec11_data {
22-
uint8_t ab_state;
2323
int8_t pulses;
2424
int8_t ticks;
2525
int8_t delta;
2626

27-
#ifdef CONFIG_EC11_TRIGGER
2827
struct gpio_callback a_gpio_cb;
2928
struct gpio_callback b_gpio_cb;
3029
const struct device *dev;
3130

31+
#ifdef CONFIG_EC11_TRIGGER
3232
sensor_trigger_handler_t handler;
3333
const struct sensor_trigger *trigger;
34-
35-
#if defined(CONFIG_EC11_TRIGGER_OWN_THREAD)
36-
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EC11_THREAD_STACK_SIZE);
37-
struct k_sem gpio_sem;
38-
struct k_thread thread;
39-
#elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD)
40-
struct k_work work;
41-
#endif
42-
4334
#endif /* CONFIG_EC11_TRIGGER */
44-
};
4535

46-
#ifdef CONFIG_EC11_TRIGGER
47-
48-
int ec11_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
49-
sensor_trigger_handler_t handler);
50-
51-
int ec11_init_interrupt(const struct device *dev);
52-
#endif
36+
bool running; // timer running?
37+
uint8_t prev_a; // previous state (debounced)
38+
uint8_t prev_b;
39+
uint8_t samples; // the window size
40+
uint32_t hist_a; // the moving window
41+
uint32_t hist_b;
42+
struct k_timer debouncer;
43+
};

0 commit comments

Comments
 (0)