qdecode

quadrature encoder decoder
Author: Ricard Wanderlof
License: BSD
Github: ricard/logic/qdecode.axo

Inlets

bool32 a

bool32 b

Outlets

bool32.pulse up

bool32.pulse down

bool32.pulse step

Attributes

objref controller object

Declaration
int safe_a, prev_a, new_a;
int safe_b, prev_b, new_b;
int a_changed_count, a_same_count;
int b_changed_count, b_same_count;
int firstcount;
int count;
int prev_up, prev_down;
int accelerator;
Init
safe_a = prev_a = 0;
safe_b = prev_b = 0;
firstcount = 2;
a_changed_count = a_same_count = 0;
b_changed_count = b_same_count = 0;
count = 0;
prev_up = 0;
prev_down = 0;
accelerator = 0;
Control Rate
outlet_up = outlet_down = 0;
#if 0
new_a = inlet_a>0;
new_b = inlet_b>0;
if (new_a ^ prev_a) {
	a_changed_count++;
	if (a_changed_count > attr_ctrl.debounce) safe_a = new_a;
} else {
	a_changed_count = 0;
}
if (new_b ^ prev_b) {
	b_changed_count++;
	if (b_changed_count > attr_ctrl.debounce) safe_b = new_b;
} else {
	b_changed_count = 0;
}
#else
// Majority filter, pick the majority of the latest debounce*2+1 samples
// Works better than the simple debouncer above
new_a = (new_a << 1) | inlet_a > 0; // shift inlet bits left
new_b = (new_b << 1) | inlet_b > 0;
safe_a = __builtin_popcount(new_a & attr_ctrl.filt_mask) >= attr_ctrl.debounce;
safe_b = __builtin_popcount(new_b & attr_ctrl.filt_mask) >= attr_ctrl.debounce;
#endif
if (safe_a ^ prev_a) {
  // LogTextMessage("Diff a count %d", count);
  if (!firstcount || !firstcount--) // skip first changes
    if (!accelerator &&
        count >= attr_ctrl.debounce) // only accept if not toggling too fast
      if (attr_ctrl.rate || safe_a)  // always if full or half
        if (safe_a ^ safe_b)
          outlet_down = 1;
        else
          outlet_up = 1;
  prev_a = safe_a;
} else if (safe_b ^ prev_b) {
  // LogTextMessage("Diff b count %d", count);
  if (!accelerator && attr_ctrl.rate == 2 &&
      count > 2 * attr_ctrl.debounce) // full only
    if (!firstcount || !firstcount--) // skip first changes
      if (safe_a ^ !safe_b)
        outlet_down = 1;
      else
        outlet_up = 1;
  prev_b = safe_b;
}
if (accelerator) {
  outlet_up = prev_up;
  outlet_down = prev_down;
  accelerator--;
  // LogTextMessage("Acc %d Up %d Down %d", accelerator, outlet_up,
  // outlet_down);
} else if (outlet_up || outlet_down) {
  // LogTextMessage("Up %d Down %d Count %d", outlet_up, outlet_down, count);
  // If encoder turned fast enough, increase output by factor
  if (count < attr_ctrl.thresh)
    accelerator = attr_ctrl.factor;
  // accelerator = attr_factor / (count ? count : 1); // accelerator = 10 if
  // count = 15, etc
  prev_up = outlet_up;
  prev_down = outlet_down;
  count = 0;
}
if (count < 3000) // avoid potential long-term wrap
  count++;
outlet_step = outlet_down | outlet_up;

Privacy

© 2024 Zrna Research