|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /* FreqMeasure Library, for measuring relatively low frequencies
- * http://www.pjrc.com/teensy/td_libs_FreqMeasure.html
- * Copyright (c) 2015 PJRC.COM, LLC - Paul Stoffregen <paul@pjrc.com>
- * Extended 2016 by Thierry Frenkel <theremingenieur@gmail.com>
- *
- * Version 0.22
- *
- * 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.
- */
-
- #include "FreqMeasureMulti.h"
- #if ! defined(__IMXRT1062__)
-
- #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
- #define FTM_CSC_RAISING (FTM_CSC_CHIE | FTM_CSC_ELSA)
- #define FTM_CSC_FALLING (FTM_CSC_CHIE | FTM_CSC_ELSB)
- #define UPDATE_ON_RAISING 1
- #define UPDATE_ON_FALLING 2
- #define UPDATE_DIFFERENCE 4
-
- static uint8_t channelmask = 0;
- static uint16_t capture_msw = 0;
- static FreqMeasureMulti * list[8];
-
- bool FreqMeasureMulti::begin(uint32_t pin) {
- return begin(pin, FREQMEASUREMULTI_RAISING);
- }
-
- bool FreqMeasureMulti::begin(uint32_t pin, uint8_t mode)
- {
- uint8_t capture_mode;
- switch (pin) {
- case 22: channel = 0; CORE_PIN22_CONFIG = PORT_PCR_MUX(4); break;
- case 23: channel = 1; CORE_PIN23_CONFIG = PORT_PCR_MUX(4); break;
- case 9: channel = 2; CORE_PIN9_CONFIG = PORT_PCR_MUX(4); break;
- case 10: channel = 3; CORE_PIN10_CONFIG = PORT_PCR_MUX(4); break;
- case 6: channel = 4; CORE_PIN6_CONFIG = PORT_PCR_MUX(4); break;
- case 20: channel = 5; CORE_PIN20_CONFIG = PORT_PCR_MUX(4); break;
- #if defined(KINETISK)
- case 21: channel = 6; CORE_PIN21_CONFIG = PORT_PCR_MUX(4); break;
- case 5: channel = 7; CORE_PIN5_CONFIG = PORT_PCR_MUX(4); break;
- #endif
- default:
- channel = 8;
- return false;
- }
- switch (mode) {
- case FREQMEASUREMULTI_FALLING:
- case FREQMEASUREMULTI_INTERLEAVE:
- case FREQMEASUREMULTI_MARK_ONLY:
- case FREQMEASUREMULTI_SPACE_ONLY:
- case FREQMEASUREMULTI_ALTERNATE:
- capture_mode = mode;
- break;
- default:
- capture_mode = FREQMEASUREMULTI_RAISING;
- }
- act_on_raise = (capture_mode & UPDATE_ON_RAISING);
- act_on_fall = (capture_mode & UPDATE_ON_FALLING);
- read_diff = (capture_mode & UPDATE_DIFFERENCE);
-
- NVIC_DISABLE_IRQ(IRQ_FTM0);
- if (FTM0_MOD != 0xFFFF || (FTM0_SC & 0x7F) != FTM_SC_VALUE) {
- FTM0_SC = 0;
- FTM0_CNT = 0;
- FTM0_MOD = 0xFFFF;
- FTM0_SC = FTM_SC_VALUE;
- #ifdef KINETISK
- FTM0_MODE = FTM_MODE_WPDIS; //allow reconfiguring the CSC on the fly
- #endif
- }
-
- capture_msw = 0;
- raiscap_previous = 0;
- fallcap_previous = 0;
- next_is_falling = false;
- buffer_head = 0;
- buffer_tail = 0;
-
- volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
- #if defined(KINETISL)
- *csc = 0;
- delayMicroseconds(1);
- #endif
- *csc = FTM_CSC_RAISING; // first capture is always rising
-
- list[channel] = this;
- channelmask |= (1 << channel);
- NVIC_SET_PRIORITY(IRQ_FTM0, 48);
- NVIC_ENABLE_IRQ(IRQ_FTM0);
- return true;
- }
-
- uint32_t FreqMeasureMulti::available(void)
- {
- uint32_t head = buffer_head;
- uint32_t tail = buffer_tail;
- if (head >= tail) return head - tail;
- return FREQMEASUREMULTI_BUFFER_LEN + head - tail;
- }
-
- uint32_t FreqMeasureMulti::read(void)
- {
- uint32_t head = buffer_head;
- uint32_t tail = buffer_tail;
- if (head == tail) return 0xFFFFFFFF;
- tail = tail + 1;
- if (tail >= FREQMEASUREMULTI_BUFFER_LEN) tail = 0;
- uint32_t value = buffer_value[tail].count;
- last_read_level = buffer_value[tail].level;
- buffer_tail = tail;
- return value;
- }
-
- uint8_t FreqMeasureMulti::readLevel(void)
- {
- return last_read_level;
- }
-
- float FreqMeasureMulti::countToFrequency(uint32_t count)
- {
- #if defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
- return (float)F_BUS / (float)count;
- #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
- return (float)(F_PLL/2) / (float)count;
- #else
- return 0.0;
- #endif
- }
-
- float FreqMeasureMulti::countToNanoseconds(uint32_t count)
- {
- #if defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
- return (float)count * (1000000000.0f / (float)F_BUS);
- #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
- return (float)count * (2000000000.0f / (float)F_PLL);
- #else
- return 0.0;
- #endif
- }
-
- void FreqMeasureMulti::end(void)
- {
- switch (channel) {
- case 0: CORE_PIN22_CONFIG = 0; break;
- case 1: CORE_PIN23_CONFIG = 0; break;
- case 2: CORE_PIN9_CONFIG = 0; break;
- case 3: CORE_PIN10_CONFIG = 0; break;
- case 4: CORE_PIN6_CONFIG = 0; break;
- case 5: CORE_PIN20_CONFIG = 0; break;
- #if defined(KINETISK)
- case 6: CORE_PIN21_CONFIG = 0; break;
- case 7: CORE_PIN5_CONFIG = 0; break;
- #endif
- default: return;
- }
- channelmask &= ~(1 << channel);
- volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
- *csc = 0;
- }
-
- void ftm0_isr(void)
- {
- bool inc = false;
- if (FTM0_SC & FTM_SC_TOF) {
- #if defined(KINETISK)
- FTM0_SC = FTM_SC_VALUE;
- #elif defined(KINETISL)
- FTM0_SC = FTM_SC_VALUE | FTM_SC_TOF;
- #endif
- capture_msw++;
- inc = true;
- }
- uint8_t mask = FTM0_STATUS & channelmask;
- if ((mask & 0x01)) list[0]->isr(inc);
- if ((mask & 0x02)) list[1]->isr(inc);
- if ((mask & 0x04)) list[2]->isr(inc);
- if ((mask & 0x08)) list[3]->isr(inc);
- if ((mask & 0x10)) list[4]->isr(inc);
- if ((mask & 0x20)) list[5]->isr(inc);
- #if defined(KINETISK)
- if ((mask & 0x40)) list[6]->isr(inc);
- if ((mask & 0x80)) list[7]->isr(inc);
- #endif
- }
-
- void FreqMeasureMulti::isr(bool inc)
- {
- uint32_t period = 0;
- uint8_t level = LEVEL_UNDEFINED;
- volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
- uint32_t capture = csc[1];
- next_is_falling = !next_is_falling; // toggle capture mode
- #if defined(KINETISK)
- csc[0] = (next_is_falling ? FTM_CSC_FALLING : FTM_CSC_RAISING);
- #elif defined(KINETISL)
- csc[0] = 0; // disable
- asm volatile ("nop");
- asm volatile ("nop");
- csc[0] = (next_is_falling ? FTM_CSC_FALLING : FTM_CSC_RAISING) | FTM_CSC_CHF;
- #endif
- if (capture <= 0xE000 || !inc) {
- capture |= (capture_msw << 16);
- } else {
- capture |= ((capture_msw - 1) << 16);
- }
- // compute the waveform period
- if (next_is_falling) {
- if (act_on_raise) period = capture - (read_diff ? fallcap_previous : raiscap_previous);
- raiscap_previous = capture;
- level = (read_diff ? LEVEL_SPACE_ONLY : LEVEL_MARK_SPACE);
- } else if (!next_is_falling ) {
- if (act_on_fall) period = capture - (read_diff ? raiscap_previous : fallcap_previous);
- fallcap_previous = capture;
- level = (read_diff ? LEVEL_MARK_ONLY : LEVEL_SPACE_MARK);
- }
- if (period != 0) {
- uint32_t i = buffer_head + 1;
- if (i >= FREQMEASUREMULTI_BUFFER_LEN) i = 0;
- if (i != buffer_tail) {
- buffer_value[i].level = level;
- buffer_value[i].count = period;
- buffer_head = i;
- }
- }
- }
-
- #endif
|