Skip to content

Commit

Permalink
Fix dial backlash
Browse files Browse the repository at this point in the history
  • Loading branch information
goodhoko committed Dec 14, 2023
1 parent 8554094 commit eb434b7
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 8 deletions.
52 changes: 45 additions & 7 deletions src/counter.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,64 @@
use hal::{prelude::*, qei::Qei, stm32::TIM1};
use hal::{
prelude::*,
qei::Qei,
stm32::TIM1,
timer::{Instant, MonoTimer},
};
use stm32f4xx_hal as hal;

pub struct Counter<PINS> {
const DETENT_RESET_TIMOUT_MS: u32 = 200;

pub struct Counter<'a, PINS> {
qei: Qei<TIM1, PINS>,
// Cache for the count returned by qei for detecting changes
last_count: u16,
timer: &'a MonoTimer,
last_update: Instant,
diff_accumulator: i16,
}

impl<PINS> Counter<PINS> {
pub fn new(qei: Qei<TIM1, PINS>) -> Self {
impl<'a, PINS> Counter<'a, PINS> {
pub fn new(qei: Qei<TIM1, PINS>, timer: &'a MonoTimer) -> Self {
let last_count = qei.count();
Counter { qei, last_count }
Counter { qei, last_count, last_update: timer.now(), timer, diff_accumulator: 0 }
}

pub fn poll(&mut self) -> Option<i8> {
let count = self.qei.count();
let diff = count.wrapping_sub(self.last_count) as i16;

let diff = self.update_counts(count);

if diff.abs() >= 4 {
self.last_count = count;
self.diff_accumulator = 0;
Some((diff / 4) as i8)
} else {
None
}
}

// Sometimes the accumulator gets out of sync with the physical detents. We require count to
// increment by 4 to fire a single tick but when the zero of accumulator lands in between
// detents (because of noise) we get backlash or missed ticks.
// Assume that when the dial rests for more than DETENT_RESET_TIMOUT_MS it is aligned to a detent
// and reset the accumulator.
fn update_counts(&mut self, count: u16) -> i16 {
if count != self.last_count {
self.last_update = self.timer.now();
}

if self.accumulator_timed_out() {
self.diff_accumulator = 0;
}

self.diff_accumulator += self.last_count.wrapping_sub(count) as i16;
self.last_count = count;

self.diff_accumulator
}

fn accumulator_timed_out(&self) -> bool {
let timeout_ticks =
self.timer.frequency().0 as f32 * (DETENT_RESET_TIMOUT_MS as f32 / 1000.0);
self.last_update.elapsed() > timeout_ticks as u32
}
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ fn main() -> ! {
let rotary_encoder_pins = (gpioa.pa8.into_alternate_af1(), gpioa.pa9.into_alternate_af1());
let rotary_encoder = Qei::new(rotary_encoder_timer, rotary_encoder_pins);

let mut counter = Counter::new(rotary_encoder);
let mut counter = Counter::new(rotary_encoder, &timer);

let button_pin = gpioa.pa10.into_pull_up_input();
let debounced_encoder_pin = Debouncer::new(button_pin, Active::Low, 30, 3000);
Expand Down

0 comments on commit eb434b7

Please sign in to comment.