/* FreqMeasure Library, for measuring relatively low frequencies * http://www.pjrc.com/teensy/td_libs_FreqMeasure.html * Copyright (c) 2011 PJRC.COM, LLC - Paul Stoffregen * * 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 FreqMeasure_capture_h_ #define FreqMeasure_capture_h_ // Arduino Uno, Duemilanove, LilyPad, Mini, Fio, etc #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) #define CAPTURE_USE_TIMER1 // ICP1 is pin 8 // Teensy 3.1, 3.2, 3.5, 3.6 #elif defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) #define CAPTURE_USE_FTM1_CH0 3 // FTM1 CH0 is pin 3 //#define CAPTURE_USE_FTM1_CH1 4 // FTM1 CH1 is pin 4 //#define CAPTURE_USE_FTM2_CH0 32 // FTM2 CH0 is pin 32 (Teensy 3.1 and 3.2) //#define CAPTURE_USE_FTM2_CH1 25 // FTM2 CH1 is pin 25 (Teensy 3.1 and 3.2) //#define CAPTURE_USE_FTM2_CH0 29 // FTM2 CH0 is pin 29 (Teensy 3.5 and 3.6) //#define CAPTURE_USE_FTM2_CH1 30 // FTM2 CH1 is pin 30 (Teensy 3.5 and 3.6) // Teensy 3.0 #elif defined(__MK20DX128__) #define CAPTURE_USE_FTM1_CH0 3 // FTM1 CH0 is pin 3 //#define CAPTURE_USE_FTM1_CH1 4 // FTM1 CH1 is pin 4 // Teensy-LC #elif defined(__MKL26Z64__) #define CAPTURE_USE_FTM1_CH0 16 // FTM1 CH0 is pin 16 //#define CAPTURE_USE_FTM1_CH1 17 // FTM1 CH1 is pin 17 //#define CAPTURE_USE_FTM2_CH0 3 // FTM2 CH0 is pin 3 //#define CAPTURE_USE_FTM2_CH1 4 // FTM2 CH1 is pin 4 #elif defined(__IMXRT1052__) || defined(__IMXRT1062__) #define CAPTURE_USE_FLEXPWM4_CH0A 22 // FlexPWM CH0-A is pin 22 // Teensy 2.0 #elif defined(__AVR_ATmega32U4__) // #define CAPTURE_USE_TIMER1 // ICP1 is pin 22 #define CAPTURE_USE_TIMER3 // ICP3 is pin 10 // Teensy++ 1.0 & 2.0 #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) // #define CAPTURE_USE_TIMER1 // ICP1 is pin 4 #define CAPTURE_USE_TIMER3 // ICP3 is pin 17 // Teensy 1.0 #elif defined(__AVR_AT90USB162__) #define CAPTURE_USE_TIMER1 // ICP1 is pin 16 // Sanguino #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) #define CAPTURE_USE_TIMER1 // ICP1 is pin 14 // Arduino Mega #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // #define CAPTURE_USE_TIMER1 // ICP1 is not connected // #define CAPTURE_USE_TIMER3 // ICP3 is not connected #define CAPTURE_USE_TIMER4 // ICP4 is pin 49 // #define CAPTURE_USE_TIMER5 // ICP5 is pin 48 #else #error "Unknown chip, please edit me with timer+counter definitions" #endif #if defined(CAPTURE_USE_FTM1_CH0) #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0)) #define FTM_ISR_NAME ftm1_isr static inline void capture_init(void) { if (FTM1_MOD != 0xFFFF || (FTM1_SC & 0x7F) != FTM_SC_VALUE) { FTM1_SC = 0; FTM1_CNT = 0; FTM1_MOD = 0xFFFF; FTM1_SC = FTM_SC_VALUE; #ifdef KINETISK FTM1_MODE = 0; #endif } NVIC_SET_PRIORITY(IRQ_FTM1, 48); } static inline void capture_start(void) { #if defined(KINETISL) FTM1_C0SC = 0; delayMicroseconds(1); #endif FTM1_C0SC = 0b01000100; *portConfigRegister(CAPTURE_USE_FTM1_CH0) = PORT_PCR_MUX(3); NVIC_ENABLE_IRQ(IRQ_FTM1); } static inline uint16_t capture_event(void) { return (FTM1_C0SC & 0x80) ? 1 : 0; } static inline uint32_t capture_read(void) { uint32_t val = FTM1_C0V; #if defined(KINETISK) FTM1_C0SC = 0b01000100; #elif defined(KINETISL) FTM1_C0SC = 0b01000100 | FTM_CSC_CHF; #endif return val; } static inline uint8_t capture_overflow(void) { return (FTM1_SC & FTM_SC_TOF) ? 1 : 0; } static inline void capture_overflow_reset(void) { #if defined(KINETISK) FTM1_SC = FTM_SC_VALUE; #elif defined(KINETISL) FTM1_SC = FTM_SC_VALUE | FTM_SC_TOF; #endif } static inline void capture_shutdown(void) { FTM1_C0SC = 0; *portConfigRegister(CAPTURE_USE_FTM1_CH0) = 0; NVIC_DISABLE_IRQ(IRQ_FTM1); } #elif defined(CAPTURE_USE_FTM1_CH1) #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0)) #define FTM_ISR_NAME ftm1_isr static inline void capture_init(void) { if (FTM1_MOD != 0xFFFF || (FTM1_SC & 0x7F) != FTM_SC_VALUE) { FTM1_SC = 0; FTM1_CNT = 0; FTM1_MOD = 0xFFFF; FTM1_SC = FTM_SC_VALUE; #ifdef KINETISK FTM1_MODE = 0; #endif } NVIC_SET_PRIORITY(IRQ_FTM1, 48); } static inline void capture_start(void) { #if defined(KINETISL) FTM1_C1SC = 0; delayMicroseconds(1); #endif FTM1_C1SC = 0b01000100; *portConfigRegister(CAPTURE_USE_FTM1_CH1) = PORT_PCR_MUX(3); NVIC_ENABLE_IRQ(IRQ_FTM1); } static inline uint16_t capture_event(void) { return (FTM1_C1SC & 0x80) ? 1 : 0; } static inline uint32_t capture_read(void) { uint32_t val = FTM1_C1V; #if defined(KINETISK) FTM1_C1SC = 0b01000100; #elif defined(KINETISL) FTM1_C1SC = 0b01000100 | FTM_CSC_CHF; #endif return val; } static inline uint8_t capture_overflow(void) { return (FTM1_SC & FTM_SC_TOF) ? 1 : 0; } static inline void capture_overflow_reset(void) { FTM1_SC = FTM_SC_VALUE; #if defined(KINETISK) FTM1_SC = FTM_SC_VALUE; #elif defined(KINETISL) FTM1_SC = FTM_SC_VALUE | FTM_SC_TOF; #endif } static inline void capture_shutdown(void) { FTM1_C1SC = 0; *portConfigRegister(CAPTURE_USE_FTM1_CH1) = 0; NVIC_DISABLE_IRQ(IRQ_FTM1); } #elif defined(CAPTURE_USE_FTM2_CH0) #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0)) #define FTM_ISR_NAME ftm2_isr static inline void capture_init(void) { if (FTM2_MOD != 0xFFFF || (FTM2_SC & 0x7F) != FTM_SC_VALUE) { FTM2_SC = 0; FTM2_CNT = 0; FTM2_MOD = 0xFFFF; FTM2_SC = FTM_SC_VALUE; #ifdef KINETISK FTM2_MODE = 0; #endif } NVIC_SET_PRIORITY(IRQ_FTM2, 48); } static inline void capture_start(void) { #if defined(KINETISL) FTM2_C0SC = 0; delayMicroseconds(1); #endif FTM2_C0SC = 0b01000100; *portConfigRegister(CAPTURE_USE_FTM2_CH0) = PORT_PCR_MUX(3); NVIC_ENABLE_IRQ(IRQ_FTM2); } static inline uint16_t capture_event(void) { return (FTM2_C0SC & 0x80) ? 1 : 0; } static inline uint32_t capture_read(void) { uint32_t val = FTM2_C0V; #if defined(KINETISK) FTM2_C0SC = 0b01000100; #elif defined(KINETISL) FTM2_C0SC = 0b01000100 | FTM_CSC_CHF; #endif return val; } static inline uint8_t capture_overflow(void) { return (FTM2_SC & FTM_SC_TOF) ? 1 : 0; } static inline void capture_overflow_reset(void) { #if defined(KINETISK) FTM2_SC = FTM_SC_VALUE; #elif defined(KINETISL) FTM2_SC = FTM_SC_VALUE | FTM_SC_TOF; #endif } static inline void capture_shutdown(void) { FTM2_C0SC = 0; *portConfigRegister(CAPTURE_USE_FTM2_CH0) = 0; NVIC_DISABLE_IRQ(IRQ_FTM2); } #elif defined(CAPTURE_USE_FTM2_CH1) #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0)) #define FTM_ISR_NAME ftm2_isr static inline void capture_init(void) { if (FTM2_MOD != 0xFFFF || (FTM2_SC & 0x7F) != FTM_SC_VALUE) { FTM2_SC = 0; FTM2_CNT = 0; FTM2_MOD = 0xFFFF; FTM2_SC = FTM_SC_VALUE; #ifdef KINETISK FTM2_MODE = 0; #endif } NVIC_SET_PRIORITY(IRQ_FTM2, 48); } static inline void capture_start(void) { #if defined(KINETISL) FTM2_C1SC = 0; delayMicroseconds(1); #endif FTM2_C1SC = 0b01000100; *portConfigRegister(CAPTURE_USE_FTM2_CH1) = PORT_PCR_MUX(3); NVIC_ENABLE_IRQ(IRQ_FTM2); } static inline uint16_t capture_event(void) { return (FTM2_C1SC & 0x80) ? 1 : 0; } static inline uint32_t capture_read(void) { uint32_t val = FTM2_C1V; #if defined(KINETISK) FTM2_C1SC = 0b01000100; #elif defined(KINETISL) FTM2_C1SC = 0b01000100 | FTM_CSC_CHF; #endif return val; } static inline uint8_t capture_overflow(void) { return (FTM2_SC & FTM_SC_TOF) ? 1 : 0; } static inline void capture_overflow_reset(void) { #if defined(KINETISK) FTM2_SC = FTM_SC_VALUE; #elif defined(KINETISL) FTM2_SC = FTM_SC_VALUE | FTM_SC_TOF; #endif } static inline void capture_shutdown(void) { FTM2_C1SC = 0; *portConfigRegister(CAPTURE_USE_FTM2_CH1) = 0; NVIC_DISABLE_IRQ(IRQ_FTM2); } #elif defined(CAPTURE_USE_FLEXPWM4_CH0A) #define FTM_ISR_NAME flexpwm_4_0_isr void flexpwm_4_0_isr(void); static inline void capture_init(void) { FLEXPWM4_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(1); FLEXPWM4_FSTS0 = 0x0001; FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_CLDOK(1); FLEXPWM4_SM0CTRL2 = FLEXPWM_SMCTRL2_INDEP; FLEXPWM4_SM0CTRL = FLEXPWM_SMCTRL_HALF; FLEXPWM4_SM0INIT = 0; FLEXPWM4_SM0VAL0 = 0; FLEXPWM4_SM0VAL1 = 65535; FLEXPWM4_SM0VAL2 = 0; FLEXPWM4_SM0VAL3 = 0; FLEXPWM4_SM0VAL4 = 0; FLEXPWM4_SM0VAL5 = 0; FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_LDOK(1) | FLEXPWM_MCTRL_RUN(1); attachInterruptVector(IRQ_FLEXPWM4_0, flexpwm_4_0_isr); NVIC_SET_PRIORITY(IRQ_FLEXPWM4_0, 48); FLEXPWM4_SM0INTEN = FLEXPWM_SMINTEN_CA0IE | FLEXPWM_SMINTEN_RIE; } static inline void capture_start(void) { FLEXPWM4_SM0CAPTCTRLA = FLEXPWM_SMCAPTCTRLA_EDGA0(2) | FLEXPWM_SMCAPTCTRLA_ARMA; IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08 = 1 | 0x10; // pin 22, AD_B1_08, FLEXPWM4_PWM0_A IOMUXC_FLEXPWM4_PWMA0_SELECT_INPUT = 1; FLEXPWM4_SM0STS = FLEXPWM_SMSTS_CFA0 | FLEXPWM_SMSTS_RF; NVIC_ENABLE_IRQ(IRQ_FLEXPWM4_0); } static inline uint16_t capture_event(void) { return (FLEXPWM4_SM0STS & FLEXPWM_SMSTS_CFA0) ? 1 : 0; } static inline uint32_t capture_read(void) { uint32_t val = FLEXPWM4_SM0CVAL2; FLEXPWM4_SM0STS = FLEXPWM_SMSTS_CFA0; return val; } static inline uint8_t capture_overflow(void) { return (FLEXPWM4_SM0STS & FLEXPWM_SMSTS_RF) ? 1 : 0; } static inline void capture_overflow_reset(void) { FLEXPWM4_SM0STS = FLEXPWM_SMSTS_RF; } static inline void capture_shutdown(void) { FLEXPWM4_SM0INTEN = 0; FLEXPWM4_SM0CAPTCTRLA = 0; IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08 = 5 | 0x10; NVIC_DISABLE_IRQ(IRQ_FLEXPWM4_0); } #elif defined(CAPTURE_USE_TIMER1) static uint8_t saveTCCR1A, saveTCCR1B; static inline void capture_init(void) { saveTCCR1A = TCCR1A; saveTCCR1B = TCCR1B; TCCR1B = 0; TCCR1A = 0; TCNT1 = 0; TIFR1 = (1<