Browse Source

drivers/rotary_encoder : WIP

pr/rotary
Marc Poulhiès 6 years ago
parent
commit
9ea379bf92
  1. 44
      drivers/include/rotary.h
  2. 3
      drivers/rotary_encoder/Makefile
  3. 136
      drivers/rotary_encoder/rotary.c

44
drivers/include/rotary.h

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016 Marc Poulhiès
* Copyright (C) 2011 Ben Buxton <bb@cactii.net>
*
* Licensed under the GNU GPL Version 3
*/
/**
* @defgroup drivers_rotary_encoder
* @{
*
* @file
* @brief Low-level rotary encoder implementation
*
* @author Marc Poulhiès <dkm@kataplop.net>
*
* @}
*/
#ifndef ROTARY_ENC_H
#define ROTARY_ENC_H
#include "kernel_types.h"
#include <periph/gpio.h>
typedef struct {
gpio_t pin1, pin2;
kernel_pid_t listener;
unsigned int state;
} rotary_t;
int rotary_init(rotary_t *dev, gpio_t pin1, gpio_t pin2);
void rotary_register(rotary_t *dev, kernel_pid_t pid);
#define ROTARY_MSG_EVENT 1
#define ROTARY_MSG_CLICK 2
enum rotary_dir_t {
DIR_NONE = 0x0, /* No complete step yet. */
DIR_CW = 0x10, /* Clockwise step. */
DIR_CCW = 0x20, /* Anti-clockwise step. */
};
#endif

3
drivers/rotary_encoder/Makefile

@ -0,0 +1,3 @@
MODULE = rotary_encoder
include $(RIOTBASE)/Makefile.base

136
drivers/rotary_encoder/rotary.c

@ -0,0 +1,136 @@
/*
* Copyright (C) 2016 Marc Poulhiès
* Copyright (C) 2011 Ben Buxton <bb@cactii.net>
*
* Licensed under the GNU GPL Version 3
*/
/**
* @ingroup drivers_rotary_encoder
* @{
*
* @file
* @brief Low-level rotary encoder implementation
*
* @author Marc Poulhiès <dkm@kataplop.net>
*
* @}
*/
#include "rotary.h"
/*
* Code mainly based on http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#define R_START 0x0
#ifndef HALF_STEP
#define HALF_STEP 0
#endif
#if HALF_STEP
/* Use the half-step state table (emits a code at 00 and 11) */
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
static const unsigned char ttable[6][4] = {
/* R_START (00) */
{ R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START },
/* R_CCW_BEGIN */
{ R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START },
/* R_CW_BEGIN */
{ R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START },
/* R_START_M (11) */
{ R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START },
/* R_CW_BEGIN_M */
{ R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW },
/* R_CCW_BEGIN_M */
{ R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW },
};
#else
/* Use the full-step state table (emits a code at 00 only) */
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6
static const unsigned char ttable[7][4] = {
/* R_START */
{ R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START },
/* R_CW_FINAL */
{ R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW },
/* R_CW_BEGIN */
{ R_CW_NEXT, R_CW_BEGIN, R_START, R_START },
/* R_CW_NEXT */
{ R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START },
/* R_CCW_BEGIN */
{ R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START },
/* R_CCW_FINAL */
{ R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW },
/* R_CCW_NEXT */
{ R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START },
};
#endif
static void rotary_cb(void *rot_dev)
{
rotary_t *dev = (rotary_t *) rot_dev;
const unsigned int b1_v = gpio_read(dev->pin1);
const unsigned int b2_v = gpio_read(dev->pin2);
const unsigned int pinstate = (b1_v ? 2 : 0) | (b2_v ? 1 : 0);
unsigned dir = 0;
dev->state = ttable[dev->state & 0xf][pinstate];
switch (dev->state & 0x30) {
case DIR_CCW:
case DIR_CW:
dir = dev->state & 0x30;
break;
case DIR_NONE:
default:
break;
}
if (dev->listener != KERNEL_PID_UNDEF && dir != 0) {
msg_t m;
m.type = ROTARY_MSG_EVENT;
m.content.value = dir;
DEBUG("Dispatching event : %d to pid %d\n", dir, dev->listener);
if (msg_send_int(&m, dev->listener) != 1) {
DEBUG("Not sent, queue full ?\n");
}
;
}
}
int rotary_init(rotary_t *dev, gpio_t pin1, gpio_t pin2)
{
gpio_init_int(pin1, GPIO_IN_PU, GPIO_BOTH, rotary_cb, dev);
gpio_init_int(pin2, GPIO_IN_PU, GPIO_BOTH, rotary_cb, dev);
dev->pin1 = pin1;
dev->pin2 = pin2;
dev->state = R_START;
dev->listener = KERNEL_PID_UNDEF;
return 0;
}
void rotary_register(rotary_t *dev, kernel_pid_t pid)
{
dev->listener = pid;
}
Loading…
Cancel
Save