-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
352 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,300 @@ | ||
|
||
#include "Encoder.h" | ||
|
||
// Yes, all the code is in the header file, to provide the user | ||
// Most the code is in the header file, to provide the user | ||
// configure options with #define (before they include it), and | ||
// to facilitate some crafty optimizations! | ||
|
||
Encoder_internal_state_t * Encoder::interruptArgs[]; | ||
|
||
void ENCODER_ISR_ATTR Encoder::update(Encoder_internal_state_t *arg) ENCODER_ISR_ATTR { | ||
#if defined(__AVR__) | ||
// The compiler believes this is just 1 line of code, so | ||
// it will inline this function into each interrupt | ||
// handler. That's a tiny bit faster, but grows the code. | ||
// Especially when used with ENCODER_OPTIMIZE_INTERRUPTS, | ||
// the inline nature allows the ISR prologue and epilogue | ||
// to only save/restore necessary registers, for very nice | ||
// speed increase. | ||
asm volatile ( | ||
"ld r30, X+" "\n\t" | ||
"ld r31, X+" "\n\t" | ||
"ld r24, Z" "\n\t" // r24 = pin1 input | ||
"ld r30, X+" "\n\t" | ||
"ld r31, X+" "\n\t" | ||
"ld r25, Z" "\n\t" // r25 = pin2 input | ||
"ld r30, X+" "\n\t" // r30 = pin1 mask | ||
"ld r31, X+" "\n\t" // r31 = pin2 mask | ||
"ld r22, X" "\n\t" // r22 = state | ||
"andi r22, 3" "\n\t" | ||
"and r24, r30" "\n\t" | ||
"breq L%=1" "\n\t" // if (pin1) | ||
"ori r22, 4" "\n\t" // state |= 4 | ||
"L%=1:" "and r25, r31" "\n\t" | ||
"breq L%=2" "\n\t" // if (pin2) | ||
"ori r22, 8" "\n\t" // state |= 8 | ||
"L%=2:" "ldi r30, lo8(pm(L%=table))" "\n\t" | ||
"ldi r31, hi8(pm(L%=table))" "\n\t" | ||
"add r30, r22" "\n\t" | ||
"adc r31, __zero_reg__" "\n\t" | ||
"asr r22" "\n\t" | ||
"asr r22" "\n\t" | ||
"st X+, r22" "\n\t" // store new state | ||
"ld r22, X+" "\n\t" | ||
"ld r23, X+" "\n\t" | ||
"ld r24, X+" "\n\t" | ||
"ld r25, X+" "\n\t" | ||
"ijmp" "\n\t" // jumps to update_finishup() | ||
// TODO move this table to another static function, | ||
// so it doesn't get needlessly duplicated. Easier | ||
// said than done, due to linker issues and inlining | ||
"L%=table:" "\n\t" | ||
"rjmp L%=end" "\n\t" // 0 | ||
"rjmp L%=plus1" "\n\t" // 1 | ||
"rjmp L%=minus1" "\n\t" // 2 | ||
"rjmp L%=plus2" "\n\t" // 3 | ||
"rjmp L%=minus1" "\n\t" // 4 | ||
"rjmp L%=end" "\n\t" // 5 | ||
"rjmp L%=minus2" "\n\t" // 6 | ||
"rjmp L%=plus1" "\n\t" // 7 | ||
"rjmp L%=plus1" "\n\t" // 8 | ||
"rjmp L%=minus2" "\n\t" // 9 | ||
"rjmp L%=end" "\n\t" // 10 | ||
"rjmp L%=minus1" "\n\t" // 11 | ||
"rjmp L%=plus2" "\n\t" // 12 | ||
"rjmp L%=minus1" "\n\t" // 13 | ||
"rjmp L%=plus1" "\n\t" // 14 | ||
"rjmp L%=end" "\n\t" // 15 | ||
"L%=minus2:" "\n\t" | ||
"subi r22, 2" "\n\t" | ||
"sbci r23, 0" "\n\t" | ||
"sbci r24, 0" "\n\t" | ||
"sbci r25, 0" "\n\t" | ||
"rjmp L%=store" "\n\t" | ||
"L%=minus1:" "\n\t" | ||
"subi r22, 1" "\n\t" | ||
"sbci r23, 0" "\n\t" | ||
"sbci r24, 0" "\n\t" | ||
"sbci r25, 0" "\n\t" | ||
"rjmp L%=store" "\n\t" | ||
"L%=plus2:" "\n\t" | ||
"subi r22, 254" "\n\t" | ||
"rjmp L%=z" "\n\t" | ||
"L%=plus1:" "\n\t" | ||
"subi r22, 255" "\n\t" | ||
"L%=z:" "sbci r23, 255" "\n\t" | ||
"sbci r24, 255" "\n\t" | ||
"sbci r25, 255" "\n\t" | ||
"L%=store:" "\n\t" | ||
"st -X, r25" "\n\t" | ||
"st -X, r24" "\n\t" | ||
"st -X, r23" "\n\t" | ||
"st -X, r22" "\n\t" | ||
"L%=end:" "\n" | ||
: : "x" (arg) : "r22", "r23", "r24", "r25", "r30", "r31"); | ||
#else | ||
uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask); | ||
uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask); | ||
uint8_t state = arg->state & 3; | ||
if (p1val) state |= 4; | ||
if (p2val) state |= 8; | ||
arg->state = (state >> 2); | ||
switch (state) { | ||
case 1: case 7: case 8: case 14: | ||
arg->position++; | ||
return; | ||
case 2: case 4: case 11: case 13: | ||
arg->position--; | ||
return; | ||
case 3: case 12: | ||
arg->position += 2; | ||
return; | ||
case 6: case 9: | ||
arg->position -= 2; | ||
return; | ||
} | ||
#endif | ||
} | ||
|
||
#if defined(ENCODER_USE_INTERRUPTS) && !defined(ENCODER_OPTIMIZE_INTERRUPTS) | ||
#ifdef CORE_INT0_PIN | ||
void Encoder::isr0(void) ENCODER_ISR_ATTR { update(interruptArgs[0]); } | ||
#endif | ||
#ifdef CORE_INT1_PIN | ||
void Encoder::isr1(void) ENCODER_ISR_ATTR { update(interruptArgs[1]); } | ||
#endif | ||
#ifdef CORE_INT2_PIN | ||
void Encoder::isr2(void) ENCODER_ISR_ATTR { update(interruptArgs[2]); } | ||
#endif | ||
#ifdef CORE_INT3_PIN | ||
void Encoder::isr3(void) ENCODER_ISR_ATTR { update(interruptArgs[3]); } | ||
#endif | ||
#ifdef CORE_INT4_PIN | ||
void Encoder::isr4(void) ENCODER_ISR_ATTR { update(interruptArgs[4]); } | ||
#endif | ||
#ifdef CORE_INT5_PIN | ||
void Encoder::isr5(void) ENCODER_ISR_ATTR { update(interruptArgs[5]); } | ||
#endif | ||
#ifdef CORE_INT6_PIN | ||
void Encoder::isr6(void) ENCODER_ISR_ATTR { update(interruptArgs[6]); } | ||
#endif | ||
#ifdef CORE_INT7_PIN | ||
void Encoder::isr7(void) ENCODER_ISR_ATTR { update(interruptArgs[7]); } | ||
#endif | ||
#ifdef CORE_INT8_PIN | ||
void Encoder::isr8(void) ENCODER_ISR_ATTR { update(interruptArgs[8]); } | ||
#endif | ||
#ifdef CORE_INT9_PIN | ||
void Encoder::isr9(void) ENCODER_ISR_ATTR { update(interruptArgs[9]); } | ||
#endif | ||
#ifdef CORE_INT10_PIN | ||
void Encoder::isr10(void) ENCODER_ISR_ATTR { update(interruptArgs[10]); } | ||
#endif | ||
#ifdef CORE_INT11_PIN | ||
void Encoder::isr11(void) ENCODER_ISR_ATTR { update(interruptArgs[11]); } | ||
#endif | ||
#ifdef CORE_INT12_PIN | ||
void Encoder::isr12(void) ENCODER_ISR_ATTR { update(interruptArgs[12]); } | ||
#endif | ||
#ifdef CORE_INT13_PIN | ||
void Encoder::isr13(void) ENCODER_ISR_ATTR { update(interruptArgs[13]); } | ||
#endif | ||
#ifdef CORE_INT14_PIN | ||
void Encoder::isr14(void) ENCODER_ISR_ATTR { update(interruptArgs[14]); } | ||
#endif | ||
#ifdef CORE_INT15_PIN | ||
void Encoder::isr15(void) ENCODER_ISR_ATTR { update(interruptArgs[15]); } | ||
#endif | ||
#ifdef CORE_INT16_PIN | ||
void Encoder::isr16(void) ENCODER_ISR_ATTR { update(interruptArgs[16]); } | ||
#endif | ||
#ifdef CORE_INT17_PIN | ||
void Encoder::isr17(void) ENCODER_ISR_ATTR { update(interruptArgs[17]); } | ||
#endif | ||
#ifdef CORE_INT18_PIN | ||
void Encoder::isr18(void) ENCODER_ISR_ATTR { update(interruptArgs[18]); } | ||
#endif | ||
#ifdef CORE_INT19_PIN | ||
void Encoder::isr19(void) ENCODER_ISR_ATTR { update(interruptArgs[19]); } | ||
#endif | ||
#ifdef CORE_INT20_PIN | ||
void Encoder::isr20(void) ENCODER_ISR_ATTR { update(interruptArgs[20]); } | ||
#endif | ||
#ifdef CORE_INT21_PIN | ||
void Encoder::isr21(void) ENCODER_ISR_ATTR { update(interruptArgs[21]); } | ||
#endif | ||
#ifdef CORE_INT22_PIN | ||
void Encoder::isr22(void) ENCODER_ISR_ATTR { update(interruptArgs[22]); } | ||
#endif | ||
#ifdef CORE_INT23_PIN | ||
void Encoder::isr23(void) ENCODER_ISR_ATTR { update(interruptArgs[23]); } | ||
#endif | ||
#ifdef CORE_INT24_PIN | ||
void Encoder::isr24(void) ENCODER_ISR_ATTR { update(interruptArgs[24]); } | ||
#endif | ||
#ifdef CORE_INT25_PIN | ||
void Encoder::isr25(void) ENCODER_ISR_ATTR { update(interruptArgs[25]); } | ||
#endif | ||
#ifdef CORE_INT26_PIN | ||
void Encoder::isr26(void) ENCODER_ISR_ATTR { update(interruptArgs[26]); } | ||
#endif | ||
#ifdef CORE_INT27_PIN | ||
void Encoder::isr27(void) ENCODER_ISR_ATTR { update(interruptArgs[27]); } | ||
#endif | ||
#ifdef CORE_INT28_PIN | ||
void Encoder::isr28(void) ENCODER_ISR_ATTR { update(interruptArgs[28]); } | ||
#endif | ||
#ifdef CORE_INT29_PIN | ||
void Encoder::isr29(void) ENCODER_ISR_ATTR { update(interruptArgs[29]); } | ||
#endif | ||
#ifdef CORE_INT30_PIN | ||
void Encoder::isr30(void) ENCODER_ISR_ATTR { update(interruptArgs[30]); } | ||
#endif | ||
#ifdef CORE_INT31_PIN | ||
void Encoder::isr31(void) ENCODER_ISR_ATTR { update(interruptArgs[31]); } | ||
#endif | ||
#ifdef CORE_INT32_PIN | ||
void Encoder::isr32(void) ENCODER_ISR_ATTR { update(interruptArgs[32]); } | ||
#endif | ||
#ifdef CORE_INT33_PIN | ||
void Encoder::isr33(void) ENCODER_ISR_ATTR { update(interruptArgs[33]); } | ||
#endif | ||
#ifdef CORE_INT34_PIN | ||
void Encoder::isr34(void) ENCODER_ISR_ATTR { update(interruptArgs[34]); } | ||
#endif | ||
#ifdef CORE_INT35_PIN | ||
void Encoder::isr35(void) ENCODER_ISR_ATTR { update(interruptArgs[35]); } | ||
#endif | ||
#ifdef CORE_INT36_PIN | ||
void Encoder::isr36(void) ENCODER_ISR_ATTR { update(interruptArgs[36]); } | ||
#endif | ||
#ifdef CORE_INT37_PIN | ||
void Encoder::isr37(void) ENCODER_ISR_ATTR { update(interruptArgs[37]); } | ||
#endif | ||
#ifdef CORE_INT38_PIN | ||
void Encoder::isr38(void) ENCODER_ISR_ATTR { update(interruptArgs[38]); } | ||
#endif | ||
#ifdef CORE_INT39_PIN | ||
void Encoder::isr39(void) ENCODER_ISR_ATTR { update(interruptArgs[39]); } | ||
#endif | ||
#ifdef CORE_INT40_PIN | ||
void Encoder::isr40(void) ENCODER_ISR_ATTR { update(interruptArgs[40]); } | ||
#endif | ||
#ifdef CORE_INT41_PIN | ||
void Encoder::isr41(void) ENCODER_ISR_ATTR { update(interruptArgs[41]); } | ||
#endif | ||
#ifdef CORE_INT42_PIN | ||
void Encoder::isr42(void) ENCODER_ISR_ATTR { update(interruptArgs[42]); } | ||
#endif | ||
#ifdef CORE_INT43_PIN | ||
void Encoder::isr43(void) ENCODER_ISR_ATTR { update(interruptArgs[43]); } | ||
#endif | ||
#ifdef CORE_INT44_PIN | ||
void Encoder::isr44(void) ENCODER_ISR_ATTR { update(interruptArgs[44]); } | ||
#endif | ||
#ifdef CORE_INT45_PIN | ||
void Encoder::isr45(void) ENCODER_ISR_ATTR { update(interruptArgs[45]); } | ||
#endif | ||
#ifdef CORE_INT46_PIN | ||
void Encoder::isr46(void) ENCODER_ISR_ATTR { update(interruptArgs[46]); } | ||
#endif | ||
#ifdef CORE_INT47_PIN | ||
void Encoder::isr47(void) ENCODER_ISR_ATTR { update(interruptArgs[47]); } | ||
#endif | ||
#ifdef CORE_INT48_PIN | ||
void Encoder::isr48(void) ENCODER_ISR_ATTR { update(interruptArgs[48]); } | ||
#endif | ||
#ifdef CORE_INT49_PIN | ||
void Encoder::isr49(void) ENCODER_ISR_ATTR { update(interruptArgs[49]); } | ||
#endif | ||
#ifdef CORE_INT50_PIN | ||
void Encoder::isr50(void) ENCODER_ISR_ATTR { update(interruptArgs[50]); } | ||
#endif | ||
#ifdef CORE_INT51_PIN | ||
void Encoder::isr51(void) ENCODER_ISR_ATTR { update(interruptArgs[51]); } | ||
#endif | ||
#ifdef CORE_INT52_PIN | ||
void Encoder::isr52(void) ENCODER_ISR_ATTR { update(interruptArgs[52]); } | ||
#endif | ||
#ifdef CORE_INT53_PIN | ||
void Encoder::isr53(void) ENCODER_ISR_ATTR { update(interruptArgs[53]); } | ||
#endif | ||
#ifdef CORE_INT54_PIN | ||
void Encoder::isr54(void) ENCODER_ISR_ATTR { update(interruptArgs[54]); } | ||
#endif | ||
#ifdef CORE_INT55_PIN | ||
void Encoder::isr55(void) ENCODER_ISR_ATTR { update(interruptArgs[55]); } | ||
#endif | ||
#ifdef CORE_INT56_PIN | ||
void Encoder::isr56(void) ENCODER_ISR_ATTR { update(interruptArgs[56]); } | ||
#endif | ||
#ifdef CORE_INT57_PIN | ||
void Encoder::isr57(void) ENCODER_ISR_ATTR { update(interruptArgs[57]); } | ||
#endif | ||
#ifdef CORE_INT58_PIN | ||
void Encoder::isr58(void) ENCODER_ISR_ATTR { update(interruptArgs[58]); } | ||
#endif | ||
#ifdef CORE_INT59_PIN | ||
void Encoder::isr59(void) ENCODER_ISR_ATTR { update(interruptArgs[59]); } | ||
#endif | ||
#endif |
Oops, something went wrong.