Initial en11 exploration.

This commit is contained in:
Pete Johanson 2020-07-17 22:43:19 -04:00
parent f6110a632d
commit 893b99d907
10 changed files with 542 additions and 0 deletions

View file

@ -6,6 +6,18 @@
#include "kyria.dtsi" #include "kyria.dtsi"
/ {
sensors {
encoder: encoder0 {
compatible = "alps,en11";
label = "Rotary Encoder";
a-gpios = <&pro_micro_d 5 GPIO_ACTIVE_HIGH>;
b-gpios = <&pro_micro_d 9 GPIO_ACTIVE_HIGH>;
};
};
};
&kscan0 { &kscan0 {
col-gpios col-gpios
= <&pro_micro_a 3 GPIO_ACTIVE_HIGH> = <&pro_micro_a 3 GPIO_ACTIVE_HIGH>

View file

@ -6,4 +6,7 @@ if(CONFIG_ZMK_KSCAN_GPIO_DRIVER)
kscan_gpio_matrix.c kscan_gpio_matrix.c
kscan_gpio_direct.c kscan_gpio_direct.c
) )
zephyr_library_sources_ifdef(CONFIG_EN11 en11.c)
zephyr_library_sources_ifdef(CONFIG_EN11_TRIGGER en11_trigger.c)
endif() endif()

View file

@ -17,3 +17,50 @@ config ZMK_KSCAN_INIT_PRIORITY
help help
Keyboard scan device driver initialization priority. Keyboard scan device driver initialization priority.
menuconfig EN11
bool "EN11 Incremental Encoder Sensor"
depends on GPIO
help
Enable driver for EN11 incremental encoder sensors.
if EN11
choice
prompt "Trigger mode"
default EN11_TRIGGER_NONE
help
Specify the type of triggering to be used by the driver.
config EN11_TRIGGER_NONE
bool "No trigger"
config EN11_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select EN11_TRIGGER
config EN11_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select EN11_TRIGGER
endchoice
config EN11_TRIGGER
bool
config EN11_THREAD_PRIORITY
int "Thread priority"
depends on EN11_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config EN11_THREAD_STACK_SIZE
int "Thread stack size"
depends on EN11_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
endif # EN11

View file

@ -0,0 +1,17 @@
description: |
Sensor driver for the Alps en11 rotary encoder
compatible: "alps,en11"
properties:
label:
type: string
required: true
a-gpios:
type: phandle-array
required: true
description: A pin for the encoder
b-gpios:
type: phandle-array
required: true
description: A pin for the encoder

110
app/drivers/zephyr/en11.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2020 Peter Johanson
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT alps_en11
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <kernel.h>
#include <drivers/sensor.h>
#include <sys/__assert.h>
#include <logging/log.h>
#include "en11.h"
LOG_MODULE_REGISTER(EN11, CONFIG_SENSOR_LOG_LEVEL);
static int en11_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct en11_data *drv_data = dev->driver_data;
u16_t val;
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP);
// if (en11_reg_read(drv_data, EN11_REG_TOBJ, &val) < 0) {
// return -EIO;
// }
// if (val & EN11_DATA_INVALID_BIT) {
// return -EIO;
// }
// drv_data->sample = arithmetic_shift_right((s16_t)val, 2);
return 0;
}
static int en11_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct en11_data *drv_data = dev->driver_data;
// s32_t uval;
// if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
// return -ENOTSUP;
// }
// uval = (s32_t)drv_data->sample * EN11_TEMP_SCALE;
// val->val1 = uval / 1000000;
// val->val2 = uval % 1000000;
return 0;
}
static const struct sensor_driver_api en11_driver_api = {
#ifdef CONFIG_EN11_TRIGGER
.trigger_set = en11_trigger_set,
#endif
.sample_fetch = en11_sample_fetch,
.channel_get = en11_channel_get,
};
int en11_init(struct device *dev)
{
struct en11_data *drv_data = dev->driver_data;
const struct en11_config *drv_cfg = dev->config_info;
LOG_DBG("");
drv_data->a = device_get_binding(drv_cfg->a_label);
if (drv_data->a == NULL) {
LOG_ERR("Failed to get pointer to A GPIO device");
return -EINVAL;
}
drv_data->b = device_get_binding(drv_cfg->b_label);
if (drv_data->b == NULL) {
LOG_ERR("Failed to get pointer to B GPIO device");
return -EINVAL;
}
#ifdef CONFIG_EN11_TRIGGER
if (en11_init_interrupt(dev) < 0) {
LOG_DBG("Failed to initialize interrupt!");
return -EIO;
}
#endif
return 0;
}
struct en11_data en11_data;
const struct en11_config en11_cfg = {
.a_label = DT_INST_GPIO_LABEL(0, a_gpios),
.a_pin = DT_INST_GPIO_PIN(0, a_gpios),
.a_flags = DT_INST_GPIO_FLAGS(0, a_gpios),
.b_label = DT_INST_GPIO_LABEL(0, b_gpios),
.b_pin = DT_INST_GPIO_PIN(0, b_gpios),
.b_flags = DT_INST_GPIO_FLAGS(0, b_gpios),
};
DEVICE_AND_API_INIT(en11, DT_INST_LABEL(0), en11_init,
&en11_data,
&en11_cfg, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
&en11_driver_api);

61
app/drivers/zephyr/en11.h Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2020 Peter Johanson
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
struct en11_config {
const char *a_label;
const u8_t a_pin;
const u8_t a_flags;
const char *b_label;
const u8_t b_pin;
const u8_t b_flags;
};
enum en11_pin_state {
EN11_A_PIN_STATE,
EN11_B_PIN_STATE
};
struct en11_data {
struct device *a;
struct device *b;
u8_t ab_state;
s16_t sample;
#ifdef CONFIG_EN11_TRIGGER
struct device *gpio;
struct gpio_callback a_gpio_cb;
struct gpio_callback b_gpio_cb;
struct device *dev;
sensor_trigger_handler_t handler;
struct sensor_trigger trigger;
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EN11_THREAD_STACK_SIZE);
struct k_sem gpio_sem;
struct k_thread thread;
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_EN11_TRIGGER */
};
#ifdef CONFIG_EN11_TRIGGER
int en11_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int en11_init_interrupt(struct device *dev);
#endif

View file

@ -0,0 +1,210 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT alps_en11
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <kernel.h>
#include <drivers/sensor.h>
#include "en11.h"
extern struct en11_data en11_driver;
#include <logging/log.h>
LOG_MODULE_DECLARE(EN11, CONFIG_SENSOR_LOG_LEVEL);
static inline void setup_int(struct device *dev,
bool enable)
{
struct en11_data *data = dev->driver_data;
const struct en11_config *cfg = dev->config_info;
LOG_DBG("enabled %s", (enable ? "true" : "false"));
if (gpio_pin_interrupt_configure(data->a,
cfg->a_pin,
enable
? GPIO_INT_EDGE_BOTH
: GPIO_INT_DISABLE)) {
LOG_WRN("Unable to set A pin GPIO interrupt");
}
if (gpio_pin_interrupt_configure(data->b,
cfg->b_pin,
enable
? GPIO_INT_EDGE_BOTH
: GPIO_INT_DISABLE)) {
LOG_WRN("Unable to set A pin GPIO interrupt");
}
}
static void en11_a_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct en11_data *drv_data =
CONTAINER_OF(cb, struct en11_data, a_gpio_cb);
LOG_DBG("");
setup_int(drv_data->dev, false);
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
#endif
}
static void en11_b_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct en11_data *drv_data =
CONTAINER_OF(cb, struct en11_data, b_gpio_cb);
LOG_DBG("");
setup_int(drv_data->dev, false);
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
#endif
}
static void en11_thread_cb(void *arg)
{
struct device *dev = arg;
struct en11_data *drv_data = dev->driver_data;
const struct en11_config *cfg = dev->config_info;
u16_t status;
// gpio_pin_get(drv_data->a, cfg->a_pin)
// if (en11_reg_read(drv_data, EN11_REG_STATUS, &status) < 0) {
// return;
// }
// if (status & EN11_DATA_READY_INT_BIT &&
// drv_data->drdy_handler != NULL) {
// drv_data->drdy_handler(dev, &drv_data->drdy_trigger);
// }
// if (status & EN11_TOBJ_TH_INT_BITS &&
// drv_data->th_handler != NULL) {
// drv_data->th_handler(dev, &drv_data->th_trigger);
// }
setup_int(dev, true);
}
#ifdef CONFIG_EN11_TRIGGER_OWN_THREAD
static void en11_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct en11_data *drv_data = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
en11_thread_cb(dev);
}
}
#endif
#ifdef CONFIG_EN11_TRIGGER_GLOBAL_THREAD
static void en11_work_cb(struct k_work *work)
{
struct en11_data *drv_data =
CONTAINER_OF(work, struct en11_data, work);
LOG_DBG("");
en11_thread_cb(drv_data->dev);
}
#endif
int en11_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct en11_data *drv_data = dev->driver_data;
setup_int(dev, false);
drv_data->trigger = *trig;
drv_data->handler = handler;
setup_int(dev, true);
return 0;
}
int en11_init_interrupt(struct device *dev)
{
struct en11_data *drv_data = dev->driver_data;
const struct en11_config *drv_cfg = dev->config_info;
/* setup gpio interrupt */
LOG_DBG("A: %s %d B: %s %d", drv_cfg->a_label, drv_cfg->a_pin, drv_cfg->b_label, drv_cfg->b_pin);
gpio_pin_configure(drv_data->a, drv_cfg->a_pin,
drv_cfg->a_flags
| GPIO_INPUT);
if (gpio_pin_set(drv_data->a, drv_cfg->a_pin, 1)) {
LOG_DBG("Failed to set A active!");
return -EIO;
}
gpio_init_callback(&drv_data->a_gpio_cb,
en11_a_gpio_callback,
BIT(drv_cfg->a_pin));
if (gpio_add_callback(drv_data->a, &drv_data->a_gpio_cb) < 0) {
LOG_DBG("Failed to set A callback!");
return -EIO;
}
gpio_pin_configure(drv_data->b, drv_cfg->b_pin,
drv_cfg->b_flags
| GPIO_INPUT);
if (gpio_pin_set(drv_data->b, drv_cfg->b_pin, 1)) {
LOG_DBG("Failed to set B active!");
return -EIO;
}
gpio_init_callback(&drv_data->b_gpio_cb,
en11_b_gpio_callback,
BIT(drv_cfg->b_pin));
if (gpio_add_callback(drv_data->b, &drv_data->b_gpio_cb) < 0) {
LOG_DBG("Failed to set B callback!");
return -EIO;
}
LOG_DBG("A Pin? %d, B Pin? %d", gpio_pin_get(drv_data->a, drv_cfg->a_pin), gpio_pin_get(drv_data->b, drv_cfg->b_pin));
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
CONFIG_EN11_THREAD_STACK_SIZE,
(k_thread_entry_t)en11_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_EN11_THREAD_PRIORITY),
0, K_NO_WAIT);
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD)
drv_data->work.handler = en11_work_cb;
#endif
return 0;
}

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_EN11 en11.c)
zephyr_library_sources_ifdef(CONFIG_EN11_TRIGGER en11_trigger.c)

View file

@ -0,0 +1,52 @@
# EN11 incremental encoder sensor configuration options
# Copyright (c) 2020 Peter Johanson
# SPDX-License-Identifier: MIT
menuconfig EN11
bool "EN11 Incremental Encoder Sensor"
depends on GPIO
help
Enable driver for EN11 incremental encoder sensors.
if EN11
choice
prompt "Trigger mode"
default EN11_TRIGGER_NONE
help
Specify the type of triggering to be used by the driver.
config EN11_TRIGGER_NONE
bool "No trigger"
config EN11_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select EN11_TRIGGER
config EN11_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select EN11_TRIGGER
endchoice
config EN11_TRIGGER
bool
config EN11_THREAD_PRIORITY
int "Thread priority"
depends on EN11_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config EN11_THREAD_STACK_SIZE
int "Thread stack size"
depends on EN11_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
endif # EN11

View file

@ -8,6 +8,7 @@
#include <device.h> #include <device.h>
#include <devicetree.h> #include <devicetree.h>
#include <settings/settings.h> #include <settings/settings.h>
#include <drivers/sensor.h>
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -18,6 +19,27 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);
#define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID)
static struct sensor_trigger trigger;
void encoder_change(struct device *dev, struct sensor_trigger *trigger)
{
LOG_DBG("");
}
void init_sensor()
{
struct device *dev = device_get_binding("Rotary Encoder");
if (!dev) {
LOG_DBG("NO ENCODER!");
return;
}
trigger.type = SENSOR_TRIG_DATA_READY;
trigger.chan = SENSOR_CHAN_ROTATION;
sensor_trigger_set(dev, &trigger, encoder_change);
}
void main(void) void main(void)
{ {
printk("Welcome to ZMK!\n"); printk("Welcome to ZMK!\n");
@ -31,4 +53,6 @@ void main(void)
#ifdef CONFIG_SETTINGS #ifdef CONFIG_SETTINGS
settings_load(); settings_load();
#endif #endif
init_sensor();
} }