mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
FS#11172 - Fuzev2: Read the scrollwheel scrollwheel via IRQ
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25736 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
ee291a5e9b
commit
249aae587a
9 changed files with 242 additions and 58 deletions
|
|
@ -24,37 +24,198 @@
|
|||
#include "button.h"
|
||||
#include "backlight.h"
|
||||
|
||||
extern void scrollwheel(unsigned wheel_value);
|
||||
|
||||
#ifdef HAS_BUTTON_HOLD
|
||||
static bool hold_button = false;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
#define SCROLLWHEEL_BITS (1<<7|1<<6)
|
||||
/* TIMER units */
|
||||
#define TIMER_TICK (TIMER_FREQ/HZ) /* how long a tick lasts */
|
||||
#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */
|
||||
|
||||
#define WHEEL_REPEAT_INTERVAL (300*TIMER_MS) /* 300ms */
|
||||
#define WHEEL_FAST_ON_INTERVAL ( 20*TIMER_MS) /* 20ms */
|
||||
#define WHEEL_FAST_OFF_INTERVAL ( 60*TIMER_MS) /* 60ms */
|
||||
/* phsyical clicks per rotation * wheel value changes per phys click */
|
||||
#define WHEEL_CHANGES_PER_CLICK 4
|
||||
#define WHEELCLICKS_PER_ROTATION (12*WHEEL_CHANGES_PER_CLICK)
|
||||
|
||||
/*
|
||||
* based on button-e200.c, adjusted to the AMS timers and fuzev2's
|
||||
* scrollwheel and cleaned up a little
|
||||
*/
|
||||
static void scrollwheel(unsigned int wheel_value)
|
||||
{
|
||||
/* wheel values and times from the previous irq */
|
||||
static unsigned int old_wheel_value = 0;
|
||||
static unsigned int wheel_repeat = BUTTON_NONE;
|
||||
static long last_wheel_post = 0;
|
||||
|
||||
/* We only post every 4th action, as this matches better with the physical
|
||||
* clicks of the wheel */
|
||||
static unsigned int wheel_click_count = 0;
|
||||
/* number of items to skip in lists, 1 in slow mode */
|
||||
static unsigned int wheel_delta = 0;
|
||||
/* accumulated wheel rotations per second */
|
||||
static unsigned long wheel_velocity = 0;
|
||||
/* fast or slow mode? */
|
||||
static int wheel_fast_mode = 0;
|
||||
|
||||
/* Read wheel
|
||||
* Bits 6 and 7 of GPIOA change as follows (Gray Code):
|
||||
* Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00
|
||||
* Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00
|
||||
*
|
||||
* For easy look-up, actual wheel values act as indicies also,
|
||||
* which is why the table seems to be not ordered correctly
|
||||
*/
|
||||
static const unsigned char wheel_tbl[2][4] =
|
||||
{
|
||||
{ 2, 0, 3, 1 }, /* Clockwise rotation */
|
||||
{ 1, 3, 0, 2 }, /* Counter-clockwise */
|
||||
};
|
||||
|
||||
unsigned int btn = BUTTON_NONE;
|
||||
|
||||
if (old_wheel_value == wheel_tbl[0][wheel_value])
|
||||
btn = BUTTON_SCROLL_FWD;
|
||||
else if (old_wheel_value == wheel_tbl[1][wheel_value])
|
||||
btn = BUTTON_SCROLL_BACK;
|
||||
|
||||
if (btn == BUTTON_NONE)
|
||||
{
|
||||
old_wheel_value = wheel_value;
|
||||
return;
|
||||
}
|
||||
|
||||
int repeat = 1; /* assume repeat */
|
||||
long time = TIMER1_VALUE + current_tick*TIMER_TICK; /* to timer unit */
|
||||
long v = (time - last_wheel_post);
|
||||
|
||||
/* interpolate velocity in timer_freq/timer_unit == 1/s */
|
||||
if (v) v = TIMER_FREQ / v;
|
||||
|
||||
/* accumulate velocities over time with each v */
|
||||
wheel_velocity = (7*wheel_velocity + v) / 8;
|
||||
|
||||
if (btn != wheel_repeat)
|
||||
{
|
||||
/* direction reversals nullify all fast mode states */
|
||||
wheel_repeat = btn;
|
||||
repeat =
|
||||
wheel_velocity =
|
||||
wheel_click_count = 0;
|
||||
}
|
||||
|
||||
if (wheel_fast_mode != 0)
|
||||
{
|
||||
/* fast OFF happens immediately when velocity drops below
|
||||
threshold */
|
||||
if (TIME_AFTER(time,
|
||||
last_wheel_post + WHEEL_FAST_OFF_INTERVAL))
|
||||
{
|
||||
/* moving out of fast mode */
|
||||
wheel_fast_mode = 0;
|
||||
/* reset velocity */
|
||||
wheel_velocity = 0;
|
||||
/* wheel_delta is always 1 in slow mode */
|
||||
wheel_delta = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fast ON gets filtered to avoid inadvertent jumps to fast mode */
|
||||
if (repeat && wheel_velocity > TIMER_FREQ/WHEEL_FAST_ON_INTERVAL)
|
||||
{
|
||||
/* moving into fast mode */
|
||||
wheel_fast_mode = 1 << 31;
|
||||
wheel_click_count = 0;
|
||||
wheel_velocity = TIMER_FREQ/WHEEL_FAST_OFF_INTERVAL;
|
||||
}
|
||||
else if (++wheel_click_count < WHEEL_CHANGES_PER_CLICK)
|
||||
{ /* skip some wheel changes, so that 1 post represents
|
||||
* 1 item in lists */
|
||||
btn = BUTTON_NONE;
|
||||
}
|
||||
|
||||
/* wheel_delta is always 1 in slow mode */
|
||||
wheel_delta = 1;
|
||||
}
|
||||
|
||||
if (btn != BUTTON_NONE)
|
||||
{
|
||||
wheel_click_count = 0;
|
||||
|
||||
/* generate repeats if quick enough */
|
||||
if (repeat && TIME_BEFORE(time,
|
||||
last_wheel_post + WHEEL_REPEAT_INTERVAL))
|
||||
btn |= BUTTON_REPEAT;
|
||||
|
||||
last_wheel_post = time;
|
||||
|
||||
if (queue_empty(&button_queue))
|
||||
{
|
||||
queue_post(&button_queue, btn, wheel_fast_mode |
|
||||
(wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
|
||||
/* message posted - reset delta and poke backlight on*/
|
||||
wheel_delta = 1;
|
||||
backlight_on();
|
||||
buttonlight_on();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skipped post - increment delta */
|
||||
if (++wheel_delta > 0x7f)
|
||||
wheel_delta = 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
old_wheel_value = wheel_value;
|
||||
}
|
||||
#endif
|
||||
|
||||
void button_init_device(void)
|
||||
{
|
||||
#if defined(HAVE_SCROLLWHEEL)
|
||||
GPIOA_DIR &= ~(1<<6|1<<7);
|
||||
GPIOC_DIR = 0;
|
||||
GPIOB_DIR |= (1<<4)|(1<<0);
|
||||
|
||||
GPIOB_PIN(4) = 1<<4; /* activate the wheel */
|
||||
}
|
||||
|
||||
void get_scrollwheel(void)
|
||||
{
|
||||
#if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER)
|
||||
/* scroll wheel handling */
|
||||
|
||||
#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2)))
|
||||
#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset))
|
||||
scrollwheel(GPIOA_PIN76 >> 6);
|
||||
|
||||
/* setup scrollwheel isr */
|
||||
/* clear previous irq if any */
|
||||
GPIOA_IC = SCROLLWHEEL_BITS;
|
||||
/* enable edge detecting */
|
||||
GPIOA_IS &= ~SCROLLWHEEL_BITS;
|
||||
/* detect both raising and falling edges */
|
||||
GPIOA_IBE |= SCROLLWHEEL_BITS;
|
||||
/* lastly, enable the interrupt */
|
||||
GPIOA_IE |= SCROLLWHEEL_BITS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* read the 2 bits at the same time */
|
||||
#define GPIOA_PIN76_offset ((1<<(6+2)) | (1<<(7+2)))
|
||||
#define GPIOA_PIN76 (*(volatile unsigned char*)(GPIOA_BASE+GPIOA_PIN76_offset))
|
||||
|
||||
void button_gpioa_isr(void)
|
||||
{
|
||||
#if defined(HAVE_SCROLLWHEEL)
|
||||
/* scroll wheel handling */
|
||||
if (GPIOA_MIS & SCROLLWHEEL_BITS)
|
||||
scrollwheel(GPIOA_PIN76 >> 6);
|
||||
|
||||
/* ack interrupt */
|
||||
GPIOA_IC = SCROLLWHEEL_BITS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get button pressed from hardware
|
||||
*/
|
||||
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
int btn = 0;
|
||||
|
|
@ -62,12 +223,12 @@ int button_read_device(void)
|
|||
static long power_counter = 0;
|
||||
unsigned gpiod6;
|
||||
|
||||
|
||||
/* if we don't wait for the fifo to empty, we'll see screen corruption
|
||||
* (the higher the CPU frequency the higher the corruption) */
|
||||
while ((DBOP_STAT & (1<<10)) == 0);
|
||||
|
||||
get_scrollwheel();
|
||||
int delay = 30;
|
||||
while(delay--) nop;
|
||||
|
||||
CCU_IO &= ~(1<<12);
|
||||
|
||||
|
|
@ -77,6 +238,7 @@ int button_read_device(void)
|
|||
gpiod6 = GPIOD_PIN(6);
|
||||
|
||||
GPIOB_PIN(0) = 0;
|
||||
|
||||
udelay(1);
|
||||
|
||||
if (GPIOC_PIN(1) & 1<<1)
|
||||
|
|
@ -114,6 +276,12 @@ int button_read_device(void)
|
|||
{
|
||||
hold_button_old = hold_button;
|
||||
backlight_hold_changed(hold_button);
|
||||
/* mask scrollwheel irq so we don't need to check for
|
||||
* the hold button in the isr */
|
||||
if (hold_button)
|
||||
GPIOA_IE &= ~SCROLLWHEEL_BITS;
|
||||
else
|
||||
GPIOA_IE |= SCROLLWHEEL_BITS;
|
||||
}
|
||||
#else
|
||||
(void)hold_button_old;
|
||||
|
|
|
|||
|
|
@ -30,12 +30,6 @@
|
|||
void button_init_device(void);
|
||||
bool button_hold(void);
|
||||
int button_read_device(void);
|
||||
void get_scrollwheel(void);
|
||||
|
||||
#define WHEEL_REPEAT_INTERVAL (HZ/5)
|
||||
#define WHEEL_COUNTER_DIV 4
|
||||
#define ACCEL_INCREMENT 2
|
||||
#define ACCEL_SHIFT 2
|
||||
/* Sandisk Sansa Fuze button codes */
|
||||
|
||||
/* Main unit's buttons */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue