14. 旋转编码器 - 用于 GPIO 连接设备的通用驱动程序

作者:

Daniel Mack <daniel@caiaq.de>,2009 年 2 月

14.1. 功能

旋转编码器是通过两根线连接到 CPU 或其他外围设备的设备。输出相位差为 90 度,通过触发下降沿和上升沿,可以确定转动方向。

一些编码器在稳定状态下两个输出都为低电平,另一些编码器也有两个输出都为高电平的稳定状态(半周期模式),还有一些编码器在所有步进都有稳定状态(四分之一周期模式)。

这两个输出的相位图如下所示

                _____       _____       _____
               |     |     |     |     |     |
Channel A  ____|     |_____|     |_____|     |____

               :  :  :  :  :  :  :  :  :  :  :  :
          __       _____       _____       _____
            |     |     |     |     |     |     |
Channel B   |_____|     |_____|     |_____|     |__

               :  :  :  :  :  :  :  :  :  :  :  :
Event          a  b  c  d  a  b  c  d  a  b  c  d

              |<-------->|
                one step

              |<-->|
                one step (half-period mode)

              |<>|
                one step (quarter-period mode)
更多信息,请参阅

https://en.wikipedia.org/wiki/Rotary_encoder

14.2. 事件 / 状态机

在半周期模式下,使用上面的状态 a) 和 c) 基于上一个稳定状态来确定旋转方向。如果在状态 b) 和 d) 中新的稳定状态与上一个状态不同(即旋转没有在半途中反向),则报告事件。

否则,适用以下情况

  1. 通道 A 上升沿,通道 B 处于低电平状态

    此状态用于识别顺时针转动

  2. 通道 B 上升沿,通道 A 处于高电平状态

    进入此状态时,编码器被置于“已准备”状态,这意味着它已经看到一步过渡的一半。

  3. 通道 A 下降沿,通道 B 处于高电平状态

    此状态用于识别逆时针转动

  4. 通道 B 下降沿,通道 A 处于低电平状态

    驻留位置。如果编码器进入此状态,则应该发生完全转换,除非它在半途中翻转回去。“已准备”状态告诉我们这一点。

14.3. 平台要求

由于此驱动程序中没有硬件相关的调用,因此使用它的平台必须支持 gpiolib。另一个要求是 IRQ 必须能够在两个边沿触发。

14.4. 板级集成

要在您的系统中使用此驱动程序,请注册一个名为“rotary-encoder”的 platform_device,并将 IRQ 和一些特定的平台数据与之关联。由于该驱动程序使用通用设备属性,因此可以通过设备树、ACPI 或使用静态板文件来完成,如下例所示

/* board support file example */

#include <linux/input.h>
#include <linux/gpio/machine.h>
#include <linux/property.h>

#define GPIO_ROTARY_A 1
#define GPIO_ROTARY_B 2

static struct gpiod_lookup_table rotary_encoder_gpios = {
        .dev_id = "rotary-encoder.0",
        .table = {
                GPIO_LOOKUP_IDX("gpio-0",
                                GPIO_ROTARY_A, NULL, 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("gpio-0",
                                GPIO_ROTARY_B, NULL, 1, GPIO_ACTIVE_HIGH),
                { },
        },
};

static const struct property_entry rotary_encoder_properties[] = {
        PROPERTY_ENTRY_U32("rotary-encoder,steps-per-period", 24),
        PROPERTY_ENTRY_U32("linux,axis",                      ABS_X),
        PROPERTY_ENTRY_U32("rotary-encoder,relative_axis",    0),
        { },
};

static const struct software_node rotary_encoder_node = {
        .properties = rotary_encoder_properties,
};

static struct platform_device rotary_encoder_device = {
        .name           = "rotary-encoder",
        .id             = 0,
};

...

gpiod_add_lookup_table(&rotary_encoder_gpios);
device_add_software_node(&rotary_encoder_device.dev, &rotary_encoder_node);
platform_device_register(&rotary_encoder_device);

...

请查阅设备树绑定文档以查看驱动程序支持的所有属性。