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:
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