feat(encoder): 添加编码器模块支持
- 在CMakeLists.txt中添加encoder_module.c和encoder_event.c源文件 - 配置设备树pinctrl设置编码器引脚(QDEC_A和QDEC_B) - 在设备树中启用qdec外设并配置相关参数 - 添加atguigu厂商前缀到vendor-prefixes.txt - 创建encoder_event.h事件头文件定义编码器事件结构 - 在prj.conf中启用NRFX_QDEC和PINCTRL_DYNAMIC配置 - 实现encoder_module.c包含完整的编码器驱动逻辑 - 实现encoder_event.c处理编码器事件的发布和记录
This commit is contained in:
@@ -13,8 +13,10 @@ add_subdirectory(drivers)
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
src/battery_module.c
|
||||
src/encoder_module.c
|
||||
src/keyboard_core_module.c
|
||||
src/usb_hid_module.c
|
||||
src/events/encoder_event.c
|
||||
src/events/hid_led_event.c
|
||||
src/mode_switch_module.c
|
||||
src/events/keyboard_hid_report_event.c
|
||||
|
||||
@@ -13,4 +13,21 @@
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
encoder_default: encoder_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(QDEC_A, 0, 10)>,
|
||||
<NRF_PSEL(QDEC_B, 1, 6)>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
encoder_sleep: encoder_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(QDEC_A, 0, 10)>,
|
||||
<NRF_PSEL(QDEC_B, 1, 6)>;
|
||||
low-power-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
aliases {
|
||||
led0 = &myled0;
|
||||
qdec0 = &qdec;
|
||||
};
|
||||
|
||||
hid_kbd: hid_kbd {
|
||||
@@ -147,6 +148,16 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&qdec {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&encoder_default>;
|
||||
pinctrl-1 = <&encoder_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
led-pre = <0>;
|
||||
steps = <80>;
|
||||
nordic,period = "SAMPLEPER_1024US";
|
||||
};
|
||||
|
||||
&usbd {
|
||||
status = "okay";
|
||||
num-bidir-endpoints = <0>;
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
atguigu Atguigu
|
||||
injoinic Injoinic
|
||||
|
||||
22
inc/events/encoder_event.h
Normal file
22
inc/events/encoder_event.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef BLINKY_ENCODER_EVENT_H_
|
||||
#define BLINKY_ENCODER_EVENT_H_
|
||||
|
||||
#include <app_event_manager.h>
|
||||
#include <app_event_manager_profiler_tracer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct encoder_event {
|
||||
struct app_event_header header;
|
||||
int8_t detents;
|
||||
};
|
||||
|
||||
APP_EVENT_TYPE_DECLARE(encoder_event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BLINKY_ENCODER_EVENT_H_ */
|
||||
2
prj.conf
2
prj.conf
@@ -5,6 +5,8 @@ CONFIG_GPIO=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_NRFX_RTC2=y
|
||||
CONFIG_NRFX_GPPI=y
|
||||
CONFIG_NRFX_QDEC=y
|
||||
CONFIG_PINCTRL_DYNAMIC=y
|
||||
CONFIG_REBOOT=y
|
||||
CONFIG_SENSOR=y
|
||||
CONFIG_ADC=y
|
||||
|
||||
226
src/encoder_module.c
Normal file
226
src/encoder_module.c
Normal file
@@ -0,0 +1,226 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <app_event_manager.h>
|
||||
|
||||
#define MODULE encoder_module
|
||||
#include <caf/events/module_state_event.h>
|
||||
#include <caf/events/power_event.h>
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
|
||||
#include "encoder_event.h"
|
||||
|
||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
|
||||
#define ENCODER_QDEC_NODE DT_ALIAS(qdec0)
|
||||
#define ENCODER_PULSES_PER_DETENT 4LL
|
||||
#define ENCODER_DETENT_UDEG (360000000LL / (80LL / ENCODER_PULSES_PER_DETENT))
|
||||
|
||||
BUILD_ASSERT(DT_NODE_EXISTS(ENCODER_QDEC_NODE), "Missing qdec0 alias");
|
||||
|
||||
static const struct device *const qdec_dev = DEVICE_DT_GET(ENCODER_QDEC_NODE);
|
||||
|
||||
static struct k_work encoder_report_work;
|
||||
static struct sensor_trigger encoder_trigger = {
|
||||
.type = SENSOR_TRIG_DATA_READY,
|
||||
.chan = SENSOR_CHAN_ROTATION,
|
||||
};
|
||||
|
||||
static bool initialized;
|
||||
static bool running;
|
||||
static int64_t angle_remainder_udeg;
|
||||
|
||||
static int64_t sensor_value_to_udeg(const struct sensor_value *value)
|
||||
{
|
||||
return ((int64_t)value->val1 * 1000000LL) + value->val2;
|
||||
}
|
||||
|
||||
static void submit_detents(int32_t detents)
|
||||
{
|
||||
while (detents != 0) {
|
||||
struct encoder_event *event = new_encoder_event();
|
||||
|
||||
if (detents > INT8_MAX) {
|
||||
event->detents = INT8_MAX;
|
||||
detents -= INT8_MAX;
|
||||
} else if (detents < INT8_MIN) {
|
||||
event->detents = INT8_MIN;
|
||||
detents -= INT8_MIN;
|
||||
} else {
|
||||
event->detents = (int8_t)detents;
|
||||
detents = 0;
|
||||
}
|
||||
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
}
|
||||
|
||||
static void encoder_report_work_handler(struct k_work *work)
|
||||
{
|
||||
struct sensor_value rotation;
|
||||
int64_t total_udeg;
|
||||
int32_t detents;
|
||||
int err;
|
||||
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = sensor_sample_fetch(qdec_dev);
|
||||
if (err) {
|
||||
LOG_WRN("QDEC sample fetch failed (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &rotation);
|
||||
if (err) {
|
||||
LOG_WRN("QDEC channel get failed (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
total_udeg = angle_remainder_udeg + sensor_value_to_udeg(&rotation);
|
||||
detents = (int32_t)(total_udeg / ENCODER_DETENT_UDEG);
|
||||
angle_remainder_udeg = total_udeg - ((int64_t)detents * ENCODER_DETENT_UDEG);
|
||||
|
||||
if (detents != 0) {
|
||||
submit_detents(detents);
|
||||
}
|
||||
}
|
||||
|
||||
static void encoder_trigger_handler(const struct device *dev,
|
||||
const struct sensor_trigger *trigger)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(trigger);
|
||||
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_work_submit(&encoder_report_work);
|
||||
}
|
||||
|
||||
static int module_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!device_is_ready(qdec_dev)) {
|
||||
LOG_ERR("QDEC device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
k_work_init(&encoder_report_work, encoder_report_work_handler);
|
||||
angle_remainder_udeg = 0;
|
||||
|
||||
err = sensor_trigger_set(qdec_dev, &encoder_trigger, encoder_trigger_handler);
|
||||
if (err) {
|
||||
LOG_ERR("Cannot set QDEC trigger (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int module_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_RESUME);
|
||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||
LOG_ERR("Cannot resume QDEC device (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
angle_remainder_udeg = 0;
|
||||
running = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void module_pause(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
err = pm_device_action_run(qdec_dev, PM_DEVICE_ACTION_SUSPEND);
|
||||
if (err && (err != -EALREADY) && (err != -ENOTSUP)) {
|
||||
LOG_WRN("Cannot suspend QDEC device (%d)", err);
|
||||
}
|
||||
|
||||
angle_remainder_udeg = 0;
|
||||
running = false;
|
||||
}
|
||||
|
||||
static bool app_event_handler(const struct app_event_header *aeh)
|
||||
{
|
||||
if (is_module_state_event(aeh)) {
|
||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||
int err;
|
||||
|
||||
if (!initialized) {
|
||||
err = module_init();
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
err = module_start();
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
} else {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_power_down_event(aeh)) {
|
||||
if (initialized) {
|
||||
module_pause();
|
||||
module_set_state(MODULE_STATE_STANDBY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_wake_up_event(aeh)) {
|
||||
if (initialized) {
|
||||
int err = module_start();
|
||||
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
} else {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
||||
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
|
||||
27
src/events/encoder_event.c
Normal file
27
src/events/encoder_event.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "encoder_event.h"
|
||||
|
||||
static void log_encoder_event(const struct app_event_header *aeh)
|
||||
{
|
||||
const struct encoder_event *event = cast_encoder_event(aeh);
|
||||
|
||||
APP_EVENT_MANAGER_LOG(aeh, "detents:%d", event->detents);
|
||||
}
|
||||
|
||||
static void profile_encoder_event(struct log_event_buf *buf,
|
||||
const struct app_event_header *aeh)
|
||||
{
|
||||
const struct encoder_event *event = cast_encoder_event(aeh);
|
||||
|
||||
nrf_profiler_log_encode_int8(buf, event->detents);
|
||||
}
|
||||
|
||||
APP_EVENT_INFO_DEFINE(encoder_event,
|
||||
ENCODE(NRF_PROFILER_ARG_S8),
|
||||
ENCODE("detents"),
|
||||
profile_encoder_event);
|
||||
|
||||
APP_EVENT_TYPE_DEFINE(encoder_event,
|
||||
log_encoder_event,
|
||||
&encoder_event_info,
|
||||
APP_EVENT_FLAGS_CREATE(
|
||||
APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE));
|
||||
Reference in New Issue
Block a user