diff --git a/Software/lib/Encoder/Encoder.cpp b/Software/lib/Encoder/Encoder.cpp new file mode 100644 index 00000000..52ec9bfa --- /dev/null +++ b/Software/lib/Encoder/Encoder.cpp @@ -0,0 +1,300 @@ + +#include "Encoder.h" + +// 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) { +#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_ISR_ATTR Encoder::isr0(void) { update(interruptArgs[0]); } + #endif + #ifdef CORE_INT1_PIN + void ENCODER_ISR_ATTR Encoder::isr1(void) { update(interruptArgs[1]); } + #endif + #ifdef CORE_INT2_PIN + void ENCODER_ISR_ATTR Encoder::isr2(void) { update(interruptArgs[2]); } + #endif + #ifdef CORE_INT3_PIN + void ENCODER_ISR_ATTR Encoder::isr3(void) { update(interruptArgs[3]); } + #endif + #ifdef CORE_INT4_PIN + void ENCODER_ISR_ATTR Encoder::isr4(void) { update(interruptArgs[4]); } + #endif + #ifdef CORE_INT5_PIN + void ENCODER_ISR_ATTR Encoder::isr5(void) { update(interruptArgs[5]); } + #endif + #ifdef CORE_INT6_PIN + void ENCODER_ISR_ATTR Encoder::isr6(void) { update(interruptArgs[6]); } + #endif + #ifdef CORE_INT7_PIN + void ENCODER_ISR_ATTR Encoder::isr7(void) { update(interruptArgs[7]); } + #endif + #ifdef CORE_INT8_PIN + void ENCODER_ISR_ATTR Encoder::isr8(void) { update(interruptArgs[8]); } + #endif + #ifdef CORE_INT9_PIN + void ENCODER_ISR_ATTR Encoder::isr9(void) { update(interruptArgs[9]); } + #endif + #ifdef CORE_INT10_PIN + void ENCODER_ISR_ATTR Encoder::isr10(void) { update(interruptArgs[10]); } + #endif + #ifdef CORE_INT11_PIN + void ENCODER_ISR_ATTR Encoder::isr11(void) { update(interruptArgs[11]); } + #endif + #ifdef CORE_INT12_PIN + void ENCODER_ISR_ATTR Encoder::isr12(void) { update(interruptArgs[12]); } + #endif + #ifdef CORE_INT13_PIN + void ENCODER_ISR_ATTR Encoder::isr13(void) { update(interruptArgs[13]); } + #endif + #ifdef CORE_INT14_PIN + void ENCODER_ISR_ATTR Encoder::isr14(void) { update(interruptArgs[14]); } + #endif + #ifdef CORE_INT15_PIN + void ENCODER_ISR_ATTR Encoder::isr15(void) { update(interruptArgs[15]); } + #endif + #ifdef CORE_INT16_PIN + void ENCODER_ISR_ATTR Encoder::isr16(void) { update(interruptArgs[16]); } + #endif + #ifdef CORE_INT17_PIN + void ENCODER_ISR_ATTR Encoder::isr17(void) { update(interruptArgs[17]); } + #endif + #ifdef CORE_INT18_PIN + void ENCODER_ISR_ATTR Encoder::isr18(void) { update(interruptArgs[18]); } + #endif + #ifdef CORE_INT19_PIN + void ENCODER_ISR_ATTR Encoder::isr19(void) { update(interruptArgs[19]); } + #endif + #ifdef CORE_INT20_PIN + void ENCODER_ISR_ATTR Encoder::isr20(void) { update(interruptArgs[20]); } + #endif + #ifdef CORE_INT21_PIN + void ENCODER_ISR_ATTR Encoder::isr21(void) { update(interruptArgs[21]); } + #endif + #ifdef CORE_INT22_PIN + void ENCODER_ISR_ATTR Encoder::isr22(void) { update(interruptArgs[22]); } + #endif + #ifdef CORE_INT23_PIN + void ENCODER_ISR_ATTR Encoder::isr23(void) { update(interruptArgs[23]); } + #endif + #ifdef CORE_INT24_PIN + void ENCODER_ISR_ATTR Encoder::isr24(void) { update(interruptArgs[24]); } + #endif + #ifdef CORE_INT25_PIN + void ENCODER_ISR_ATTR Encoder::isr25(void) { update(interruptArgs[25]); } + #endif + #ifdef CORE_INT26_PIN + void ENCODER_ISR_ATTR Encoder::isr26(void) { update(interruptArgs[26]); } + #endif + #ifdef CORE_INT27_PIN + void ENCODER_ISR_ATTR Encoder::isr27(void) { update(interruptArgs[27]); } + #endif + #ifdef CORE_INT28_PIN + void ENCODER_ISR_ATTR Encoder::isr28(void) { update(interruptArgs[28]); } + #endif + #ifdef CORE_INT29_PIN + void ENCODER_ISR_ATTR Encoder::isr29(void) { update(interruptArgs[29]); } + #endif + #ifdef CORE_INT30_PIN + void ENCODER_ISR_ATTR Encoder::isr30(void) { update(interruptArgs[30]); } + #endif + #ifdef CORE_INT31_PIN + void ENCODER_ISR_ATTR Encoder::isr31(void) { update(interruptArgs[31]); } + #endif + #ifdef CORE_INT32_PIN + void ENCODER_ISR_ATTR Encoder::isr32(void) { update(interruptArgs[32]); } + #endif + #ifdef CORE_INT33_PIN + void ENCODER_ISR_ATTR Encoder::isr33(void) { update(interruptArgs[33]); } + #endif + #ifdef CORE_INT34_PIN + void ENCODER_ISR_ATTR Encoder::isr34(void) { update(interruptArgs[34]); } + #endif + #ifdef CORE_INT35_PIN + void ENCODER_ISR_ATTR Encoder::isr35(void) { update(interruptArgs[35]); } + #endif + #ifdef CORE_INT36_PIN + void ENCODER_ISR_ATTR Encoder::isr36(void) { update(interruptArgs[36]); } + #endif + #ifdef CORE_INT37_PIN + void ENCODER_ISR_ATTR Encoder::isr37(void) { update(interruptArgs[37]); } + #endif + #ifdef CORE_INT38_PIN + void ENCODER_ISR_ATTR Encoder::isr38(void) { update(interruptArgs[38]); } + #endif + #ifdef CORE_INT39_PIN + void ENCODER_ISR_ATTR Encoder::isr39(void) { update(interruptArgs[39]); } + #endif + #ifdef CORE_INT40_PIN + void ENCODER_ISR_ATTR Encoder::isr40(void) { update(interruptArgs[40]); } + #endif + #ifdef CORE_INT41_PIN + void ENCODER_ISR_ATTR Encoder::isr41(void) { update(interruptArgs[41]); } + #endif + #ifdef CORE_INT42_PIN + void ENCODER_ISR_ATTR Encoder::isr42(void) { update(interruptArgs[42]); } + #endif + #ifdef CORE_INT43_PIN + void ENCODER_ISR_ATTR Encoder::isr43(void) { update(interruptArgs[43]); } + #endif + #ifdef CORE_INT44_PIN + void ENCODER_ISR_ATTR Encoder::isr44(void) { update(interruptArgs[44]); } + #endif + #ifdef CORE_INT45_PIN + void ENCODER_ISR_ATTR Encoder::isr45(void) { update(interruptArgs[45]); } + #endif + #ifdef CORE_INT46_PIN + void ENCODER_ISR_ATTR Encoder::isr46(void) { update(interruptArgs[46]); } + #endif + #ifdef CORE_INT47_PIN + void ENCODER_ISR_ATTR Encoder::isr47(void) { update(interruptArgs[47]); } + #endif + #ifdef CORE_INT48_PIN + void ENCODER_ISR_ATTR Encoder::isr48(void) { update(interruptArgs[48]); } + #endif + #ifdef CORE_INT49_PIN + void ENCODER_ISR_ATTR Encoder::isr49(void) { update(interruptArgs[49]); } + #endif + #ifdef CORE_INT50_PIN + void ENCODER_ISR_ATTR Encoder::isr50(void) { update(interruptArgs[50]); } + #endif + #ifdef CORE_INT51_PIN + void ENCODER_ISR_ATTR Encoder::isr51(void) { update(interruptArgs[51]); } + #endif + #ifdef CORE_INT52_PIN + void ENCODER_ISR_ATTR Encoder::isr52(void) { update(interruptArgs[52]); } + #endif + #ifdef CORE_INT53_PIN + void ENCODER_ISR_ATTR Encoder::isr53(void) { update(interruptArgs[53]); } + #endif + #ifdef CORE_INT54_PIN + void ENCODER_ISR_ATTR Encoder::isr54(void) { update(interruptArgs[54]); } + #endif + #ifdef CORE_INT55_PIN + void ENCODER_ISR_ATTR Encoder::isr55(void) { update(interruptArgs[55]); } + #endif + #ifdef CORE_INT56_PIN + void ENCODER_ISR_ATTR Encoder::isr56(void) { update(interruptArgs[56]); } + #endif + #ifdef CORE_INT57_PIN + void ENCODER_ISR_ATTR Encoder::isr57(void) { update(interruptArgs[57]); } + #endif + #ifdef CORE_INT58_PIN + void ENCODER_ISR_ATTR Encoder::isr58(void) { update(interruptArgs[58]); } + #endif + #ifdef CORE_INT59_PIN + void ENCODER_ISR_ATTR Encoder::isr59(void) { update(interruptArgs[59]); } + #endif +#endif diff --git a/Software/lib/Encoder/Encoder.h b/Software/lib/Encoder/Encoder.h new file mode 100644 index 00000000..02061a8d --- /dev/null +++ b/Software/lib/Encoder/Encoder.h @@ -0,0 +1,862 @@ +/* Encoder Library, for measuring quadrature encoded signals + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * Copyright (c) 2011,2013 PJRC.COM, LLC - Paul Stoffregen + * + * Version 1.2 - fix -2 bug in C-only code + * Version 1.1 - expand to support boards with up to 60 interrupts + * Version 1.0 - initial release + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef Encoder_h_ +#define Encoder_h_ + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#elif defined(WIRING) +#include "Wiring.h" +#else +#include "WProgram.h" +#include "pins_arduino.h" +#endif + +#include "utility/direct_pin_read.h" + +#if defined(ENCODER_USE_INTERRUPTS) || !defined(ENCODER_DO_NOT_USE_INTERRUPTS) +#define ENCODER_USE_INTERRUPTS +#define ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT +#include "utility/interrupt_pins.h" +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#include "utility/interrupt_config.h" +#endif +#else +#define ENCODER_ARGLIST_SIZE 0 +#endif + +// Use ICACHE_RAM_ATTR for ISRs to prevent ESP8266 resets +#if defined(ESP8266) || defined(ESP32) +#define ENCODER_ISR_ATTR IRAM_ATTR +#else +#define ENCODER_ISR_ATTR +#endif + + + +// All the data needed by interrupts is consolidated into this ugly struct +// to facilitate assembly language optimizing of the speed critical update. +// The assembly code uses auto-incrementing addressing modes, so the struct +// must remain in exactly this order. +typedef struct { + volatile IO_REG_TYPE * pin1_register; + volatile IO_REG_TYPE * pin2_register; + IO_REG_TYPE pin1_bitmask; + IO_REG_TYPE pin2_bitmask; + uint8_t state; + int32_t position; +} Encoder_internal_state_t; + +class Encoder +{ +public: + Encoder(uint8_t pin1, uint8_t pin2) { + pinMode(pin1, INPUT_PULLDOWN); + pinMode(pin2, INPUT_PULLDOWN); + encoder.pin1_register = PIN_TO_BASEREG(pin1); + encoder.pin1_bitmask = PIN_TO_BITMASK(pin1); + encoder.pin2_register = PIN_TO_BASEREG(pin2); + encoder.pin2_bitmask = PIN_TO_BITMASK(pin2); + encoder.position = 0; + // allow time for a passive R-C filter to charge + // through the pullup resistors, before reading + // the initial state + delayMicroseconds(2000); + uint8_t s = 0; + if (DIRECT_PIN_READ(encoder.pin1_register, encoder.pin1_bitmask)) s |= 1; + if (DIRECT_PIN_READ(encoder.pin2_register, encoder.pin2_bitmask)) s |= 2; + encoder.state = s; +#ifdef ENCODER_USE_INTERRUPTS + interrupts_in_use = attach_interrupt(pin1, &encoder); + interrupts_in_use += attach_interrupt(pin2, &encoder); +#endif + //update_finishup(); // to force linker to include the code (does not work) + } + + +#ifdef ENCODER_USE_INTERRUPTS + inline int32_t read() { + if (interrupts_in_use < 2) { + noInterrupts(); + update(&encoder); + } else { + noInterrupts(); + } + int32_t ret = encoder.position; + interrupts(); + return ret; + } + inline int32_t readAndReset() { + if (interrupts_in_use < 2) { + noInterrupts(); + update(&encoder); + } else { + noInterrupts(); + } + int32_t ret = encoder.position; + encoder.position = 0; + interrupts(); + return ret; + } + inline void write(int32_t p) { + noInterrupts(); + encoder.position = p; + interrupts(); + } +#else + inline int32_t read() { + update(&encoder); + return encoder.position; + } + inline int32_t readAndReset() { + update(&encoder); + int32_t ret = encoder.position; + encoder.position = 0; + return ret; + } + inline void write(int32_t p) { + encoder.position = p; + } +#endif +private: + Encoder_internal_state_t encoder; +#ifdef ENCODER_USE_INTERRUPTS + uint8_t interrupts_in_use; +#endif +public: + static Encoder_internal_state_t * interruptArgs[ENCODER_ARGLIST_SIZE]; + +// _______ _______ +// Pin1 ______| |_______| |______ Pin1 +// negative <--- _______ _______ __ --> positive +// Pin2 __| |_______| |_______| Pin2 + + // new new old old + // pin2 pin1 pin2 pin1 Result + // ---- ---- ---- ---- ------ + // 0 0 0 0 no movement + // 0 0 0 1 +1 + // 0 0 1 0 -1 + // 0 0 1 1 +2 (assume pin1 edges only) + // 0 1 0 0 -1 + // 0 1 0 1 no movement + // 0 1 1 0 -2 (assume pin1 edges only) + // 0 1 1 1 +1 + // 1 0 0 0 +1 + // 1 0 0 1 -2 (assume pin1 edges only) + // 1 0 1 0 no movement + // 1 0 1 1 -1 + // 1 1 0 0 +2 (assume pin1 edges only) + // 1 1 0 1 -1 + // 1 1 1 0 +1 + // 1 1 1 1 no movement +/* + // Simple, easy-to-read "documentation" version :-) + // + void update(void) { + uint8_t s = state & 3; + if (digitalRead(pin1)) s |= 4; + if (digitalRead(pin2)) s |= 8; + switch (s) { + case 0: case 5: case 10: case 15: + break; + case 1: case 7: case 8: case 14: + position++; break; + case 2: case 4: case 11: case 13: + position--; break; + case 3: case 12: + position += 2; break; + default: + position -= 2; break; + } + state = (s >> 2); + } +*/ + +public: + // update() is not meant to be called from outside Encoder, + // but it is public to allow static interrupt routines. + // DO NOT call update() directly from sketches. + static void update(Encoder_internal_state_t *arg); +private: +/* +#if defined(__AVR__) + // TODO: this must be a no inline function + // even noinline does not seem to solve difficult + // problems with this. Oh well, it was only meant + // to shrink code size - there's no performance + // improvement in this, only code size reduction. + __attribute__((noinline)) void update_finishup(void) { + asm volatile ( + "ldi r30, lo8(pm(Ltable))" "\n\t" + "ldi r31, hi8(pm(Ltable))" "\n\t" + "Ltable:" "\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" + : : : "r22", "r23", "r24", "r25", "r30", "r31"); + } +#endif +*/ + + +#ifdef ENCODER_USE_INTERRUPTS + // this giant function is an unfortunate consequence of Arduino's + // attachInterrupt function not supporting any way to pass a pointer + // or other context to the attached function. + static uint8_t attach_interrupt(uint8_t pin, Encoder_internal_state_t *state) { + switch (pin) { + #ifdef CORE_INT0_PIN + case CORE_INT0_PIN: + interruptArgs[0] = state; + attachInterrupt(0, isr0, CHANGE); + break; + #endif + #ifdef CORE_INT1_PIN + case CORE_INT1_PIN: + interruptArgs[1] = state; + attachInterrupt(1, isr1, CHANGE); + break; + #endif + #ifdef CORE_INT2_PIN + case CORE_INT2_PIN: + interruptArgs[2] = state; + attachInterrupt(2, isr2, CHANGE); + break; + #endif + #ifdef CORE_INT3_PIN + case CORE_INT3_PIN: + interruptArgs[3] = state; + attachInterrupt(3, isr3, CHANGE); + break; + #endif + #ifdef CORE_INT4_PIN + case CORE_INT4_PIN: + interruptArgs[4] = state; + attachInterrupt(4, isr4, CHANGE); + break; + #endif + #ifdef CORE_INT5_PIN + case CORE_INT5_PIN: + interruptArgs[5] = state; + attachInterrupt(5, isr5, CHANGE); + break; + #endif + #ifdef CORE_INT6_PIN + case CORE_INT6_PIN: + interruptArgs[6] = state; + attachInterrupt(6, isr6, CHANGE); + break; + #endif + #ifdef CORE_INT7_PIN + case CORE_INT7_PIN: + interruptArgs[7] = state; + attachInterrupt(7, isr7, CHANGE); + break; + #endif + #ifdef CORE_INT8_PIN + case CORE_INT8_PIN: + interruptArgs[8] = state; + attachInterrupt(8, isr8, CHANGE); + break; + #endif + #ifdef CORE_INT9_PIN + case CORE_INT9_PIN: + interruptArgs[9] = state; + attachInterrupt(9, isr9, CHANGE); + break; + #endif + #ifdef CORE_INT10_PIN + case CORE_INT10_PIN: + interruptArgs[10] = state; + attachInterrupt(10, isr10, CHANGE); + break; + #endif + #ifdef CORE_INT11_PIN + case CORE_INT11_PIN: + interruptArgs[11] = state; + attachInterrupt(11, isr11, CHANGE); + break; + #endif + #ifdef CORE_INT12_PIN + case CORE_INT12_PIN: + interruptArgs[12] = state; + attachInterrupt(12, isr12, CHANGE); + break; + #endif + #ifdef CORE_INT13_PIN + case CORE_INT13_PIN: + interruptArgs[13] = state; + attachInterrupt(13, isr13, CHANGE); + break; + #endif + #ifdef CORE_INT14_PIN + case CORE_INT14_PIN: + interruptArgs[14] = state; + attachInterrupt(14, isr14, CHANGE); + break; + #endif + #ifdef CORE_INT15_PIN + case CORE_INT15_PIN: + interruptArgs[15] = state; + attachInterrupt(15, isr15, CHANGE); + break; + #endif + #ifdef CORE_INT16_PIN + case CORE_INT16_PIN: + interruptArgs[16] = state; + attachInterrupt(16, isr16, CHANGE); + break; + #endif + #ifdef CORE_INT17_PIN + case CORE_INT17_PIN: + interruptArgs[17] = state; + attachInterrupt(17, isr17, CHANGE); + break; + #endif + #ifdef CORE_INT18_PIN + case CORE_INT18_PIN: + interruptArgs[18] = state; + attachInterrupt(18, isr18, CHANGE); + break; + #endif + #ifdef CORE_INT19_PIN + case CORE_INT19_PIN: + interruptArgs[19] = state; + attachInterrupt(19, isr19, CHANGE); + break; + #endif + #ifdef CORE_INT20_PIN + case CORE_INT20_PIN: + interruptArgs[20] = state; + attachInterrupt(20, isr20, CHANGE); + break; + #endif + #ifdef CORE_INT21_PIN + case CORE_INT21_PIN: + interruptArgs[21] = state; + attachInterrupt(21, isr21, CHANGE); + break; + #endif + #ifdef CORE_INT22_PIN + case CORE_INT22_PIN: + interruptArgs[22] = state; + attachInterrupt(22, isr22, CHANGE); + break; + #endif + #ifdef CORE_INT23_PIN + case CORE_INT23_PIN: + interruptArgs[23] = state; + attachInterrupt(23, isr23, CHANGE); + break; + #endif + #ifdef CORE_INT24_PIN + case CORE_INT24_PIN: + interruptArgs[24] = state; + attachInterrupt(24, isr24, CHANGE); + break; + #endif + #ifdef CORE_INT25_PIN + case CORE_INT25_PIN: + interruptArgs[25] = state; + attachInterrupt(25, isr25, CHANGE); + break; + #endif + #ifdef CORE_INT26_PIN + case CORE_INT26_PIN: + interruptArgs[26] = state; + attachInterrupt(26, isr26, CHANGE); + break; + #endif + #ifdef CORE_INT27_PIN + case CORE_INT27_PIN: + interruptArgs[27] = state; + attachInterrupt(27, isr27, CHANGE); + break; + #endif + #ifdef CORE_INT28_PIN + case CORE_INT28_PIN: + interruptArgs[28] = state; + attachInterrupt(28, isr28, CHANGE); + break; + #endif + #ifdef CORE_INT29_PIN + case CORE_INT29_PIN: + interruptArgs[29] = state; + attachInterrupt(29, isr29, CHANGE); + break; + #endif + + #ifdef CORE_INT30_PIN + case CORE_INT30_PIN: + interruptArgs[30] = state; + attachInterrupt(30, isr30, CHANGE); + break; + #endif + #ifdef CORE_INT31_PIN + case CORE_INT31_PIN: + interruptArgs[31] = state; + attachInterrupt(31, isr31, CHANGE); + break; + #endif + #ifdef CORE_INT32_PIN + case CORE_INT32_PIN: + interruptArgs[32] = state; + attachInterrupt(32, isr32, CHANGE); + break; + #endif + #ifdef CORE_INT33_PIN + case CORE_INT33_PIN: + interruptArgs[33] = state; + attachInterrupt(33, isr33, CHANGE); + break; + #endif + #ifdef CORE_INT34_PIN + case CORE_INT34_PIN: + interruptArgs[34] = state; + attachInterrupt(34, isr34, CHANGE); + break; + #endif + #ifdef CORE_INT35_PIN + case CORE_INT35_PIN: + interruptArgs[35] = state; + attachInterrupt(35, isr35, CHANGE); + break; + #endif + #ifdef CORE_INT36_PIN + case CORE_INT36_PIN: + interruptArgs[36] = state; + attachInterrupt(36, isr36, CHANGE); + break; + #endif + #ifdef CORE_INT37_PIN + case CORE_INT37_PIN: + interruptArgs[37] = state; + attachInterrupt(37, isr37, CHANGE); + break; + #endif + #ifdef CORE_INT38_PIN + case CORE_INT38_PIN: + interruptArgs[38] = state; + attachInterrupt(38, isr38, CHANGE); + break; + #endif + #ifdef CORE_INT39_PIN + case CORE_INT39_PIN: + interruptArgs[39] = state; + attachInterrupt(39, isr39, CHANGE); + break; + #endif + #ifdef CORE_INT40_PIN + case CORE_INT40_PIN: + interruptArgs[40] = state; + attachInterrupt(40, isr40, CHANGE); + break; + #endif + #ifdef CORE_INT41_PIN + case CORE_INT41_PIN: + interruptArgs[41] = state; + attachInterrupt(41, isr41, CHANGE); + break; + #endif + #ifdef CORE_INT42_PIN + case CORE_INT42_PIN: + interruptArgs[42] = state; + attachInterrupt(42, isr42, CHANGE); + break; + #endif + #ifdef CORE_INT43_PIN + case CORE_INT43_PIN: + interruptArgs[43] = state; + attachInterrupt(43, isr43, CHANGE); + break; + #endif + #ifdef CORE_INT44_PIN + case CORE_INT44_PIN: + interruptArgs[44] = state; + attachInterrupt(44, isr44, CHANGE); + break; + #endif + #ifdef CORE_INT45_PIN + case CORE_INT45_PIN: + interruptArgs[45] = state; + attachInterrupt(45, isr45, CHANGE); + break; + #endif + #ifdef CORE_INT46_PIN + case CORE_INT46_PIN: + interruptArgs[46] = state; + attachInterrupt(46, isr46, CHANGE); + break; + #endif + #ifdef CORE_INT47_PIN + case CORE_INT47_PIN: + interruptArgs[47] = state; + attachInterrupt(47, isr47, CHANGE); + break; + #endif + #ifdef CORE_INT48_PIN + case CORE_INT48_PIN: + interruptArgs[48] = state; + attachInterrupt(48, isr48, CHANGE); + break; + #endif + #ifdef CORE_INT49_PIN + case CORE_INT49_PIN: + interruptArgs[49] = state; + attachInterrupt(49, isr49, CHANGE); + break; + #endif + #ifdef CORE_INT50_PIN + case CORE_INT50_PIN: + interruptArgs[50] = state; + attachInterrupt(50, isr50, CHANGE); + break; + #endif + #ifdef CORE_INT51_PIN + case CORE_INT51_PIN: + interruptArgs[51] = state; + attachInterrupt(51, isr51, CHANGE); + break; + #endif + #ifdef CORE_INT52_PIN + case CORE_INT52_PIN: + interruptArgs[52] = state; + attachInterrupt(52, isr52, CHANGE); + break; + #endif + #ifdef CORE_INT53_PIN + case CORE_INT53_PIN: + interruptArgs[53] = state; + attachInterrupt(53, isr53, CHANGE); + break; + #endif + #ifdef CORE_INT54_PIN + case CORE_INT54_PIN: + interruptArgs[54] = state; + attachInterrupt(54, isr54, CHANGE); + break; + #endif + #ifdef CORE_INT55_PIN + case CORE_INT55_PIN: + interruptArgs[55] = state; + attachInterrupt(55, isr55, CHANGE); + break; + #endif + #ifdef CORE_INT56_PIN + case CORE_INT56_PIN: + interruptArgs[56] = state; + attachInterrupt(56, isr56, CHANGE); + break; + #endif + #ifdef CORE_INT57_PIN + case CORE_INT57_PIN: + interruptArgs[57] = state; + attachInterrupt(57, isr57, CHANGE); + break; + #endif + #ifdef CORE_INT58_PIN + case CORE_INT58_PIN: + interruptArgs[58] = state; + attachInterrupt(58, isr58, CHANGE); + break; + #endif + #ifdef CORE_INT59_PIN + case CORE_INT59_PIN: + interruptArgs[59] = state; + attachInterrupt(59, isr59, CHANGE); + break; + #endif + default: + return 0; + } + return 1; + } +#endif // ENCODER_USE_INTERRUPTS + + +#if defined(ENCODER_USE_INTERRUPTS) && !defined(ENCODER_OPTIMIZE_INTERRUPTS) + #ifdef CORE_INT0_PIN + static void isr0(void); + #endif + #ifdef CORE_INT1_PIN + static void isr1(void); + #endif + #ifdef CORE_INT2_PIN + static void isr2(void); + #endif + #ifdef CORE_INT3_PIN + static void isr3(void); + #endif + #ifdef CORE_INT4_PIN + static void isr4(void); + #endif + #ifdef CORE_INT5_PIN + static void isr5(void); + #endif + #ifdef CORE_INT6_PIN + static void isr6(void); + #endif + #ifdef CORE_INT7_PIN + static void isr7(void); + #endif + #ifdef CORE_INT8_PIN + static void isr8(void); + #endif + #ifdef CORE_INT9_PIN + static void isr9(void); + #endif + #ifdef CORE_INT10_PIN + static void isr10(void); + #endif + #ifdef CORE_INT11_PIN + static void isr11(void); + #endif + #ifdef CORE_INT12_PIN + static void isr12(void); + #endif + #ifdef CORE_INT13_PIN + static void isr13(void); + #endif + #ifdef CORE_INT14_PIN + static void isr14(void); + #endif + #ifdef CORE_INT15_PIN + static void isr15(void); + #endif + #ifdef CORE_INT16_PIN + static void isr16(void); + #endif + #ifdef CORE_INT17_PIN + static void isr17(void); + #endif + #ifdef CORE_INT18_PIN + static void isr18(void); + #endif + #ifdef CORE_INT19_PIN + static void isr19(void); + #endif + #ifdef CORE_INT20_PIN + static void isr20(void); + #endif + #ifdef CORE_INT21_PIN + static void isr21(void); + #endif + #ifdef CORE_INT22_PIN + static void isr22(void); + #endif + #ifdef CORE_INT23_PIN + static void isr23(void); + #endif + #ifdef CORE_INT24_PIN + static void isr24(void); + #endif + #ifdef CORE_INT25_PIN + static void isr25(void); + #endif + #ifdef CORE_INT26_PIN + static void isr26(void); + #endif + #ifdef CORE_INT27_PIN + static void isr27(void); + #endif + #ifdef CORE_INT28_PIN + static void isr28(void); + #endif + #ifdef CORE_INT29_PIN + static void isr29(void); + #endif + #ifdef CORE_INT30_PIN + static void isr30(void); + #endif + #ifdef CORE_INT31_PIN + static void isr31(void); + #endif + #ifdef CORE_INT32_PIN + static void isr32(void); + #endif + #ifdef CORE_INT33_PIN + static void isr33(void); + #endif + #ifdef CORE_INT34_PIN + static void isr34(void); + #endif + #ifdef CORE_INT35_PIN + static void isr35(void); + #endif + #ifdef CORE_INT36_PIN + static void isr36(void); + #endif + #ifdef CORE_INT37_PIN + static void isr37(void); + #endif + #ifdef CORE_INT38_PIN + static void isr38(void); + #endif + #ifdef CORE_INT39_PIN + static void isr39(void); + #endif + #ifdef CORE_INT40_PIN + static void isr40(void); + #endif + #ifdef CORE_INT41_PIN + static void isr41(void); + #endif + #ifdef CORE_INT42_PIN + static void isr42(void); + #endif + #ifdef CORE_INT43_PIN + static void isr43(void); + #endif + #ifdef CORE_INT44_PIN + static void isr44(void); + #endif + #ifdef CORE_INT45_PIN + static void isr45(void); + #endif + #ifdef CORE_INT46_PIN + static void isr46(void); + #endif + #ifdef CORE_INT47_PIN + static void isr47(void); + #endif + #ifdef CORE_INT48_PIN + static void isr48(void); + #endif + #ifdef CORE_INT49_PIN + static void isr49(void); + #endif + #ifdef CORE_INT50_PIN + static void isr50(void); + #endif + #ifdef CORE_INT51_PIN + static void isr51(void); + #endif + #ifdef CORE_INT52_PIN + static void isr52(void); + #endif + #ifdef CORE_INT53_PIN + static void isr53(void); + #endif + #ifdef CORE_INT54_PIN + static void isr54(void); + #endif + #ifdef CORE_INT55_PIN + static void isr55(void); + #endif + #ifdef CORE_INT56_PIN + static void isr56(void); + #endif + #ifdef CORE_INT57_PIN + static void isr57(void); + #endif + #ifdef CORE_INT58_PIN + static void isr58(void); + #endif + #ifdef CORE_INT59_PIN + static void isr59(void); + #endif +#endif +}; + +#if defined(ENCODER_USE_INTERRUPTS) && defined(ENCODER_OPTIMIZE_INTERRUPTS) +#if defined(__AVR__) +#if defined(INT0_vect) && CORE_NUM_INTERRUPT > 0 +ISR(INT0_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(0)]); } +#endif +#if defined(INT1_vect) && CORE_NUM_INTERRUPT > 1 +ISR(INT1_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(1)]); } +#endif +#if defined(INT2_vect) && CORE_NUM_INTERRUPT > 2 +ISR(INT2_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(2)]); } +#endif +#if defined(INT3_vect) && CORE_NUM_INTERRUPT > 3 +ISR(INT3_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(3)]); } +#endif +#if defined(INT4_vect) && CORE_NUM_INTERRUPT > 4 +ISR(INT4_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(4)]); } +#endif +#if defined(INT5_vect) && CORE_NUM_INTERRUPT > 5 +ISR(INT5_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(5)]); } +#endif +#if defined(INT6_vect) && CORE_NUM_INTERRUPT > 6 +ISR(INT6_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(6)]); } +#endif +#if defined(INT7_vect) && CORE_NUM_INTERRUPT > 7 +ISR(INT7_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(7)]); } +#endif +#endif // AVR +#if defined(attachInterrupt) +// Don't intefere with other libraries or sketch use of attachInterrupt() +// https://github.com/PaulStoffregen/Encoder/issues/8 +#undef attachInterrupt +#endif +#endif // ENCODER_OPTIMIZE_INTERRUPTS + + +#endif diff --git a/Software/lib/Encoder/README.md b/Software/lib/Encoder/README.md new file mode 100644 index 00000000..6a4f6383 --- /dev/null +++ b/Software/lib/Encoder/README.md @@ -0,0 +1,9 @@ +# Encoder Library + +Encoder counts pulses from quadrature encoded signals, which are commonly available from rotary knobs, motor or shaft sensors and other position sensors. + +http://www.pjrc.com/teensy/td_libs_Encoder.html + +http://www.youtube.com/watch?v=2puhIong-cs + +![Encoder Knobs Demo](http://www.pjrc.com/teensy/td_libs_Encoder_1.jpg) diff --git a/Software/lib/Encoder/docs/issue_template.md b/Software/lib/Encoder/docs/issue_template.md new file mode 100644 index 00000000..06109925 --- /dev/null +++ b/Software/lib/Encoder/docs/issue_template.md @@ -0,0 +1,64 @@ +Please use this form only to report code defects or bugs. + +For any question, even questions directly pertaining to this code, post your question on the forums related to the board you are using. + +Arduino: forum.arduino.cc +Teensy: forum.pjrc.com +ESP8266: www.esp8266.com +ESP32: www.esp32.com +Adafruit Feather/Metro/Trinket: forums.adafruit.com +Particle Photon: community.particle.io + +If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the appropriate forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code! + +Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software. + + +----------------------------- Remove above ----------------------------- + + + +### Description + +Describe your problem. + + + +### Steps To Reproduce Problem + +Please give detailed instructions needed for anyone to attempt to reproduce the problem. + + + +### Hardware & Software + +Board +Shields / modules used +Arduino IDE version +Teensyduino version (if using Teensy) +Version info & package name (from Tools > Boards > Board Manager) +Operating system & version +Any other software or hardware? + + +### Arduino Sketch + +```cpp +// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem) +#include + +// libraries: give links/details so anyone can compile your code for the same result + +void setup() { +} + +void loop() { +} +``` + + +### Errors or Incorrect Output + +If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears. + + diff --git a/Software/lib/Encoder/examples/Basic/Basic.pde b/Software/lib/Encoder/examples/Basic/Basic.pde new file mode 100644 index 00000000..3394b585 --- /dev/null +++ b/Software/lib/Encoder/examples/Basic/Basic.pde @@ -0,0 +1,29 @@ +/* Encoder Library - Basic Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +#include + +// Change these two numbers to the pins connected to your encoder. +// Best Performance: both pins have interrupt capability +// Good Performance: only the first pin has interrupt capability +// Low Performance: neither pin has interrupt capability +Encoder myEnc(5, 6); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("Basic Encoder Test:"); +} + +long oldPosition = -999; + +void loop() { + long newPosition = myEnc.read(); + if (newPosition != oldPosition) { + oldPosition = newPosition; + Serial.println(newPosition); + } +} diff --git a/Software/lib/Encoder/examples/NoInterrupts/NoInterrupts.pde b/Software/lib/Encoder/examples/NoInterrupts/NoInterrupts.pde new file mode 100644 index 00000000..b890652e --- /dev/null +++ b/Software/lib/Encoder/examples/NoInterrupts/NoInterrupts.pde @@ -0,0 +1,46 @@ +/* Encoder Library - NoInterrupts Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +// If you define ENCODER_DO_NOT_USE_INTERRUPTS *before* including +// Encoder, the library will never use interrupts. This is mainly +// useful to reduce the size of the library when you are using it +// with pins that do not support interrupts. Without interrupts, +// your program must call the read() function rapidly, or risk +// missing changes in position. +#define ENCODER_DO_NOT_USE_INTERRUPTS +#include + +// Beware of Serial.print() speed. Without interrupts, if you +// transmit too much data with Serial.print() it can slow your +// reading from Encoder. Arduino 1.0 has improved transmit code. +// Using the fastest baud rate also helps. Teensy has USB packet +// buffering. But all boards can experience problems if you print +// too much and fill up buffers. + +// Change these two numbers to the pins connected to your encoder. +// With ENCODER_DO_NOT_USE_INTERRUPTS, no interrupts are ever +// used, even if the pin has interrupt capability +Encoder myEnc(5, 6); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("Basic NoInterrupts Test:"); +} + +long position = -999; + +void loop() { + long newPos = myEnc.read(); + if (newPos != position) { + position = newPos; + Serial.println(position); + } + // With any substantial delay added, Encoder can only track + // very slow motion. You may uncomment this line to see + // how badly a delay affects your encoder. + //delay(50); +} diff --git a/Software/lib/Encoder/examples/SpeedTest/SpeedTest.pde b/Software/lib/Encoder/examples/SpeedTest/SpeedTest.pde new file mode 100644 index 00000000..f136fbb2 --- /dev/null +++ b/Software/lib/Encoder/examples/SpeedTest/SpeedTest.pde @@ -0,0 +1,113 @@ +/* Encoder Library - SpeedTest - for measuring maximum Encoder speed + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + + +// This SpeedTest example provides a simple way to verify how much +// CPU time Encoder is consuming. Connect a DC voltmeter to the +// output pin and measure the voltage while the encoder is stopped +// or running at a very slow speed. Even though the pin is rapidly +// pulsing, a DC voltmeter will show the average voltage. Due to +// software timing, it will read a number much less than a steady +// logic high, but this number will give you a baseline reading +// for output with minimal interrupt overhead. Then increase the +// encoder speed. The voltage will decrease as the processor spends +// more time in Encoder's interrupt routines counting the pulses +// and less time pulsing the output pin. When the voltage is +// close to zero and will not decrease any farther, you have reached +// the absolute speed limit. Or, if using a mechanical system where +// you reach a speed limit imposed by your motors or other hardware, +// the amount this voltage has decreased, compared to the baseline, +// should give you a good approximation of the portion of available +// CPU time Encoder is consuming at your maximum speed. + +// Encoder requires low latency interrupt response. Available CPU +// time does NOT necessarily prove or guarantee correct performance. +// If another library, like NewSoftSerial, is disabling interrupts +// for lengthy periods of time, Encoder can be prevented from +// properly counting the intput signals while interrupt are disabled. + + +// This optional setting causes Encoder to use more optimized code, +// but the downside is a conflict if any other part of your sketch +// or any other library you're using requires attachInterrupt(). +// It must be defined before Encoder.h is included. +//#define ENCODER_OPTIMIZE_INTERRUPTS + +#include +#include "pins_arduino.h" + +// Change these two numbers to the pins connected to your encoder +// or shift register circuit which emulates a quadrature encoder +// case 1: both pins are interrupts +// case 2: only first pin used as interrupt +Encoder myEnc(5, 6); + +// Connect a DC voltmeter to this pin. +const int outputPin = 12; + +/* This simple circuit, using a Dual Flip-Flop chip, can emulate + quadrature encoder signals. The clock can come from a fancy + function generator or a cheap 555 timer chip. The clock + frequency can be measured with another board running FreqCount + http://www.pjrc.com/teensy/td_libs_FreqCount.html + + +5V + | Quadrature Encoder Signal Emulator + Clock | + Input o----*-------------------------- ---------------------------o Output1 + | |14 | | + | _______|_______ | | _______________ + | | CD4013 | | | | CD4013 | + | 5 | | 1 | | 9 | | 13 + ---------| D Q |-----|----*----| D Q |------o Output2 + | | | | | | | + | | 3 | | | 11 | | + | ----|> Clk | ---------|> Clk | + | | | | | + | 6 | | 8 | | + | ----| S | ----| S | + | | | | | | | + | | 4 | _ | 2 | 10 | _ | 12 + | *----| R Q |--- *----| R Q |---- + | | | | | | | | + | | |_______________| | |_______________| | + | | | | | + | | | 7 | | + | | | | | + -------------------------------------------------------------- + | | | + | | | + ----- ----- ----- + --- --- --- + - - - +*/ + + +void setup() { + pinMode(outputPin, OUTPUT); +} + +#if defined(__AVR__) || defined(TEENSYDUINO) +#define REGTYPE unsigned char +#else +#define REGTYPE unsigned long +#endif + +void loop() { + volatile int count = 0; + volatile REGTYPE *reg = portOutputRegister(digitalPinToPort(outputPin)); + REGTYPE mask = digitalPinToBitMask(outputPin); + + while (1) { + myEnc.read(); // Read the encoder while interrupts are enabled. + noInterrupts(); + *reg |= mask; // Pulse the pin high, while interrupts are disabled. + count = count + 1; + *reg &= ~mask; + interrupts(); + } +} + diff --git a/Software/lib/Encoder/examples/TwoKnobs/TwoKnobs.pde b/Software/lib/Encoder/examples/TwoKnobs/TwoKnobs.pde new file mode 100644 index 00000000..306b33e7 --- /dev/null +++ b/Software/lib/Encoder/examples/TwoKnobs/TwoKnobs.pde @@ -0,0 +1,46 @@ +/* Encoder Library - TwoKnobs Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +#include + +// Change these pin numbers to the pins connected to your encoder. +// Best Performance: both pins have interrupt capability +// Good Performance: only the first pin has interrupt capability +// Low Performance: neither pin has interrupt capability +Encoder knobLeft(5, 6); +Encoder knobRight(7, 8); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("TwoKnobs Encoder Test:"); +} + +long positionLeft = -999; +long positionRight = -999; + +void loop() { + long newLeft, newRight; + newLeft = knobLeft.read(); + newRight = knobRight.read(); + if (newLeft != positionLeft || newRight != positionRight) { + Serial.print("Left = "); + Serial.print(newLeft); + Serial.print(", Right = "); + Serial.print(newRight); + Serial.println(); + positionLeft = newLeft; + positionRight = newRight; + } + // if a character is sent from the serial monitor, + // reset both back to zero. + if (Serial.available()) { + Serial.read(); + Serial.println("Reset both knobs to zero"); + knobLeft.write(0); + knobRight.write(0); + } +} diff --git a/Software/lib/Encoder/keywords.txt b/Software/lib/Encoder/keywords.txt new file mode 100644 index 00000000..a4baa016 --- /dev/null +++ b/Software/lib/Encoder/keywords.txt @@ -0,0 +1,4 @@ +ENCODER_USE_INTERRUPTS LITERAL1 +ENCODER_OPTIMIZE_INTERRUPTS LITERAL1 +ENCODER_DO_NOT_USE_INTERRUPTS LITERAL1 +Encoder KEYWORD1 diff --git a/Software/lib/Encoder/library.json b/Software/lib/Encoder/library.json new file mode 100644 index 00000000..0a0f653e --- /dev/null +++ b/Software/lib/Encoder/library.json @@ -0,0 +1,16 @@ +{ + "name": "Encoder", + "keywords": "encoder, signal, pulse", + "description": "Encoder counts pulses from quadrature encoded signals, which are commonly available from rotary knobs, motor or shaft sensors and other position sensors", + "repository": + { + "type": "git", + "url": "https://github.com/PaulStoffregen/Encoder.git" + }, + "frameworks": "arduino", + "platforms": + [ + "atmelavr", + "teensy" + ] +} diff --git a/Software/lib/Encoder/library.properties b/Software/lib/Encoder/library.properties new file mode 100644 index 00000000..712abd4a --- /dev/null +++ b/Software/lib/Encoder/library.properties @@ -0,0 +1,10 @@ +name=Encoder +version=1.4.2 +author=Paul Stoffregen +maintainer=Paul Stoffregen +sentence=Counts quadrature pulses from rotary & linear position encoders. +paragraph=Encoder counts pulses from quadrature encoded signals, which are commonly available from rotary knobs, motor or shaft sensors and other position sensors. +category=Signal Input/Output +url=http://www.pjrc.com/teensy/td_libs_Encoder.html +architectures=* + diff --git a/Software/lib/Encoder/utility/direct_pin_read.h b/Software/lib/Encoder/utility/direct_pin_read.h new file mode 100644 index 00000000..d5b26ef6 --- /dev/null +++ b/Software/lib/Encoder/utility/direct_pin_read.h @@ -0,0 +1,110 @@ +#ifndef direct_pin_read_h_ +#define direct_pin_read_h_ + +#if defined(__AVR__) + +#define IO_REG_TYPE uint8_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL)) + +#define IO_REG_TYPE uint8_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__SAM3X8E__) // || defined(ESP8266) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__PIC32MX__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) + +/* ESP8266 v2.0.0 Arduino workaround for bug https://github.com/esp8266/Arduino/issues/1110 */ +#elif defined(ESP8266) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)(0x60000000+(0x318))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +/* ESP32 Arduino (https://github.com/espressif/arduino-esp32) */ +#elif defined(ESP32) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) + +#elif defined(__SAMD51__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) portInputRegister(digitalPinToPort(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(RBL_NRF51822) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define DIRECT_PIN_READ(base, pin) nrf_gpio_pin_read(pin) + +#elif defined(ARDUINO_ARCH_NRF52840) +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) digitalPinToPinName(pin) +#define DIRECT_PIN_READ(base, pin) nrf_gpio_pin_read(pin) + +#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ + +#include "scss_registers.h" +#include "portable.h" +#include "avr/pgmspace.h" +#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) +#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) +#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) +#define EXT_PORT_OFFSET_SS 0x0A +#define EXT_PORT_OFFSET_SOC 0x50 +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) +#define PIN_TO_BITMASK(pin) pin +#define IO_REG_TYPE uint32_t +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + IO_REG_TYPE ret; + if (SS_GPIO == GPIO_TYPE(pin)) { + ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); + } else { + ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); + } + return ((ret >> GPIO_ID(pin)) & 0x01); +} +#define DIRECT_PIN_READ(base, pin) directRead(base, pin) + +#endif + +#endif diff --git a/Software/lib/Encoder/utility/interrupt_config.h b/Software/lib/Encoder/utility/interrupt_config.h new file mode 100644 index 00000000..cde6adf2 --- /dev/null +++ b/Software/lib/Encoder/utility/interrupt_config.h @@ -0,0 +1,87 @@ +#if defined(__AVR__) + +#include +#include + +#define attachInterrupt(num, func, mode) enableInterrupt(num) +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define SCRAMBLE_INT_ORDER(num) ((num < 4) ? num + 2 : ((num < 6) ? num - 4 : num)) +#define DESCRAMBLE_INT_ORDER(num) ((num < 2) ? num + 4 : ((num < 6) ? num - 2 : num)) +#else +#define SCRAMBLE_INT_ORDER(num) (num) +#define DESCRAMBLE_INT_ORDER(num) (num) +#endif + +static void enableInterrupt(uint8_t num) +{ + switch (DESCRAMBLE_INT_ORDER(num)) { + #if defined(EICRA) && defined(EIMSK) + case 0: + EICRA = (EICRA & 0xFC) | 0x01; + EIMSK |= 0x01; + return; + case 1: + EICRA = (EICRA & 0xF3) | 0x04; + EIMSK |= 0x02; + return; + case 2: + EICRA = (EICRA & 0xCF) | 0x10; + EIMSK |= 0x04; + return; + case 3: + EICRA = (EICRA & 0x3F) | 0x40; + EIMSK |= 0x08; + return; + #elif defined(MCUCR) && defined(GICR) + case 0: + MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + GICR |= (1 << INT0); + return; + case 1: + MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + GICR |= (1 << INT1); + return; + #elif defined(MCUCR) && defined(GIMSK) + case 0: + MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + GIMSK |= (1 << INT0); + return; + case 1: + MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + GIMSK |= (1 << INT1); + return; + #endif + #if defined(EICRB) && defined(EIMSK) + case 4: + EICRB = (EICRB & 0xFC) | 0x01; + EIMSK |= 0x10; + return; + case 5: + EICRB = (EICRB & 0xF3) | 0x04; + EIMSK |= 0x20; + return; + case 6: + EICRB = (EICRB & 0xCF) | 0x10; + EIMSK |= 0x40; + return; + case 7: + EICRB = (EICRB & 0x3F) | 0x40; + EIMSK |= 0x80; + return; + #endif + } +} + +#elif defined(__PIC32MX__) + +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#undef ENCODER_OPTIMIZE_INTERRUPTS +#endif + +#else + +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#undef ENCODER_OPTIMIZE_INTERRUPTS +#endif + +#endif diff --git a/Software/lib/Encoder/utility/interrupt_pins.h b/Software/lib/Encoder/utility/interrupt_pins.h new file mode 100644 index 00000000..ca82bf09 --- /dev/null +++ b/Software/lib/Encoder/utility/interrupt_pins.h @@ -0,0 +1,370 @@ +// interrupt pins for known boards + +// Teensy (and maybe others) define these automatically +#if !defined(CORE_NUM_INTERRUPT) + +// Wiring boards +#if defined(WIRING) + #define CORE_NUM_INTERRUPT NUM_EXTERNAL_INTERRUPTS + #if NUM_EXTERNAL_INTERRUPTS > 0 + #define CORE_INT0_PIN EI0 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 1 + #define CORE_INT1_PIN EI1 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 2 + #define CORE_INT2_PIN EI2 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 3 + #define CORE_INT3_PIN EI3 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 4 + #define CORE_INT4_PIN EI4 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 5 + #define CORE_INT5_PIN EI5 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 6 + #define CORE_INT6_PIN EI6 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 7 + #define CORE_INT7_PIN EI7 + #endif + +// Arduino Uno, Duemilanove, Diecimila, LilyPad, Mini, Fio, etc... +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) ||defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) + #define CORE_NUM_INTERRUPT 2 + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + +// Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + #define CORE_NUM_INTERRUPT 6 + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + #define CORE_INT2_PIN 21 + #define CORE_INT3_PIN 20 + #define CORE_INT4_PIN 19 + #define CORE_INT5_PIN 18 + +// Arduino Nano Every, Uno R2 Wifi +#elif defined(__AVR_ATmega4809__) + #define CORE_NUM_INTERRUPT 22 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT20_PIN 20 + #define CORE_INT21_PIN 21 + +// Arduino Leonardo (untested) +#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY) + #define CORE_NUM_INTERRUPT 5 + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 0 + #define CORE_INT3_PIN 1 + #define CORE_INT4_PIN 7 + +// Sanguino (untested) and ATmega1284P +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__) + #define CORE_NUM_INTERRUPT 3 + #define CORE_INT0_PIN 10 + #define CORE_INT1_PIN 11 + #define CORE_INT2_PIN 2 + +// ATmega32u2 and ATmega32u16 based boards with HoodLoader2 +#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) + #define CORE_NUM_INTERRUPT 8 + #define CORE_INT0_PIN 8 + #define CORE_INT1_PIN 17 + #define CORE_INT2_PIN 13 + #define CORE_INT3_PIN 14 + #define CORE_INT4_PIN 15 + #define CORE_INT5_PIN 16 + #define CORE_INT6_PIN 19 + #define CORE_INT7_PIN 20 + +// Chipkit Uno32 - attachInterrupt may not support CHANGE option +#elif defined(__PIC32MX__) && defined(_BOARD_UNO_) + #define CORE_NUM_INTERRUPT 5 + #define CORE_INT0_PIN 38 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 8 + #define CORE_INT4_PIN 35 + +// Chipkit Uno32 - attachInterrupt may not support CHANGE option +#elif defined(__PIC32MX__) && defined(_BOARD_MEGA_) + #define CORE_NUM_INTERRUPT 5 + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 21 + #define CORE_INT4_PIN 20 + +// http://hlt.media.mit.edu/?p=1229 +#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + #define CORE_NUM_INTERRUPT 1 + #define CORE_INT0_PIN 2 + + // ATtiny44 ATtiny84 +#elif defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + #define CORE_NUM_INTERRUPT 1 + #define CORE_INT0_PIN 8 + +// ATtiny441 ATtiny841 +#elif defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__) + #define CORE_NUM_INTERRUPT 1 + #define CORE_INT0_PIN 9 + +//https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x313.md +#elif defined(__AVR_ATtinyX313__) + #define CORE_NUM_INTERRUPT 2 + #define CORE_INT0_PIN 4 + #define CORE_INT1_PIN 5 + +// Attiny167 same core as abobe +#elif defined(__AVR_ATtiny167__) + #define CORE_NUM_INTERRUPT 2 + #define CORE_INT0_PIN 14 + #define CORE_INT1_PIN 3 + + +// Arduino Due +#elif defined(__SAM3X8E__) + #define CORE_NUM_INTERRUPT 54 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT20_PIN 20 + #define CORE_INT21_PIN 21 + #define CORE_INT22_PIN 22 + #define CORE_INT23_PIN 23 + #define CORE_INT24_PIN 24 + #define CORE_INT25_PIN 25 + #define CORE_INT26_PIN 26 + #define CORE_INT27_PIN 27 + #define CORE_INT28_PIN 28 + #define CORE_INT29_PIN 29 + #define CORE_INT30_PIN 30 + #define CORE_INT31_PIN 31 + #define CORE_INT32_PIN 32 + #define CORE_INT33_PIN 33 + #define CORE_INT34_PIN 34 + #define CORE_INT35_PIN 35 + #define CORE_INT36_PIN 36 + #define CORE_INT37_PIN 37 + #define CORE_INT38_PIN 38 + #define CORE_INT39_PIN 39 + #define CORE_INT40_PIN 40 + #define CORE_INT41_PIN 41 + #define CORE_INT42_PIN 42 + #define CORE_INT43_PIN 43 + #define CORE_INT44_PIN 44 + #define CORE_INT45_PIN 45 + #define CORE_INT46_PIN 46 + #define CORE_INT47_PIN 47 + #define CORE_INT48_PIN 48 + #define CORE_INT49_PIN 49 + #define CORE_INT50_PIN 50 + #define CORE_INT51_PIN 51 + #define CORE_INT52_PIN 52 + #define CORE_INT53_PIN 53 + +// ESP8266 (https://github.com/esp8266/Arduino/) +#elif defined(ESP8266) + #define CORE_NUM_INTERRUPT EXTERNAL_NUM_INTERRUPTS + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + // GPIO6-GPIO11 are typically used to interface with the flash memory IC on + // most esp8266 modules, so we should avoid adding interrupts to these pins. + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + +// ESP32 (https://github.com/espressif/arduino-esp32) +#elif defined(ESP32) + + #define CORE_NUM_INTERRUPT 40 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + // GPIO6-GPIO11 are typically used to interface with the flash memory IC on + // esp32, so we should avoid adding interrupts to these pins. + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT21_PIN 21 + #define CORE_INT22_PIN 22 + #define CORE_INT23_PIN 23 + #define CORE_INT25_PIN 25 + #define CORE_INT26_PIN 26 + #define CORE_INT27_PIN 27 + #define CORE_INT32_PIN 32 + #define CORE_INT33_PIN 33 + #define CORE_INT34_PIN 34 + #define CORE_INT35_PIN 35 + #define CORE_INT36_PIN 36 + #define CORE_INT39_PIN 39 + + +// Arduino Zero - TODO: interrupts do not seem to work +// please help, contribute a fix! +#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) + #define CORE_NUM_INTERRUPT 31 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT20_PIN 20 + #define CORE_INT21_PIN 21 + #define CORE_INT22_PIN 22 + #define CORE_INT23_PIN 23 + #define CORE_INT24_PIN 24 + #define CORE_INT25_PIN 25 + #define CORE_INT26_PIN 26 + #define CORE_INT27_PIN 27 + #define CORE_INT28_PIN 28 + #define CORE_INT29_PIN 29 + #define CORE_INT30_PIN 30 + +#elif defined(__SAMD51__) + #define CORE_NUM_INTERRUPT 26 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT20_PIN 20 + #define CORE_INT21_PIN 21 + #define CORE_INT22_PIN 22 + #define CORE_INT23_PIN 23 + #define CORE_INT24_PIN 24 + #define CORE_INT25_PIN 25 + +// Arduino 101 +#elif defined(__arc__) + #define CORE_NUM_INTERRUPT 14 + #define CORE_INT2_PIN 2 + #define CORE_INT5_PIN 5 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + +// Arduino Nano 33 BLE +#elif defined(ARDUINO_ARCH_NRF52840) + #define CORE_NUM_INTERRUPT 22 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN A0 + #define CORE_INT15_PIN A1 + #define CORE_INT16_PIN A2 + #define CORE_INT17_PIN A3 + #define CORE_INT18_PIN A4 + #define CORE_INT19_PIN A5 + #define CORE_INT20_PIN A6 + #define CORE_INT21_PIN A7 +#endif +#endif + +#if !defined(CORE_NUM_INTERRUPT) +#error "Interrupts are unknown for this board, please add to this code" +#endif +#if CORE_NUM_INTERRUPT <= 0 +#error "Encoder requires interrupt pins, but this board does not have any :(" +#error "You could try defining ENCODER_DO_NOT_USE_INTERRUPTS as a kludge." +#endif + diff --git a/Software/platformio.ini b/Software/platformio.ini index 016a5e3c..7a1a16b9 100644 --- a/Software/platformio.ini +++ b/Software/platformio.ini @@ -22,7 +22,6 @@ lib_deps = https://github.com/theelims/StrokeEngine.git thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.4.0 https://github.com/tzapu/WiFiManager.git - paulstoffregen/Encoder@^1.4.2 gin66/FastAccelStepper@^0.30.8 pkerspe/ESP-FlexyStepper@^1.4.9 bblanchon/ArduinoJson@^6.21.4