PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
7.3KB

  1. /* FreqMeasure Library, for measuring relatively low frequencies
  2. * http://www.pjrc.com/teensy/td_libs_FreqMeasure.html
  3. * Copyright (c) 2015 PJRC.COM, LLC - Paul Stoffregen <paul@pjrc.com>
  4. * Extended 2016 by Thierry Frenkel <theremingenieur@gmail.com>
  5. *
  6. * Version 0.22
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include "FreqMeasureMulti.h"
  27. #if ! defined(__IMXRT1062__)
  28. #define FTM_SC_VALUE (FTM_SC_TOIE | FTM_SC_CLKS(1) | FTM_SC_PS(0))
  29. #define FTM_CSC_RAISING (FTM_CSC_CHIE | FTM_CSC_ELSA)
  30. #define FTM_CSC_FALLING (FTM_CSC_CHIE | FTM_CSC_ELSB)
  31. #define UPDATE_ON_RAISING 1
  32. #define UPDATE_ON_FALLING 2
  33. #define UPDATE_DIFFERENCE 4
  34. static uint8_t channelmask = 0;
  35. static uint16_t capture_msw = 0;
  36. static FreqMeasureMulti * list[8];
  37. bool FreqMeasureMulti::begin(uint32_t pin) {
  38. return begin(pin, FREQMEASUREMULTI_RAISING);
  39. }
  40. bool FreqMeasureMulti::begin(uint32_t pin, uint8_t mode)
  41. {
  42. uint8_t capture_mode;
  43. switch (pin) {
  44. case 22: channel = 0; CORE_PIN22_CONFIG = PORT_PCR_MUX(4); break;
  45. case 23: channel = 1; CORE_PIN23_CONFIG = PORT_PCR_MUX(4); break;
  46. case 9: channel = 2; CORE_PIN9_CONFIG = PORT_PCR_MUX(4); break;
  47. case 10: channel = 3; CORE_PIN10_CONFIG = PORT_PCR_MUX(4); break;
  48. case 6: channel = 4; CORE_PIN6_CONFIG = PORT_PCR_MUX(4); break;
  49. case 20: channel = 5; CORE_PIN20_CONFIG = PORT_PCR_MUX(4); break;
  50. #if defined(KINETISK)
  51. case 21: channel = 6; CORE_PIN21_CONFIG = PORT_PCR_MUX(4); break;
  52. case 5: channel = 7; CORE_PIN5_CONFIG = PORT_PCR_MUX(4); break;
  53. #endif
  54. default:
  55. channel = 8;
  56. return false;
  57. }
  58. switch (mode) {
  59. case FREQMEASUREMULTI_FALLING:
  60. case FREQMEASUREMULTI_INTERLEAVE:
  61. case FREQMEASUREMULTI_MARK_ONLY:
  62. case FREQMEASUREMULTI_SPACE_ONLY:
  63. case FREQMEASUREMULTI_ALTERNATE:
  64. capture_mode = mode;
  65. break;
  66. default:
  67. capture_mode = FREQMEASUREMULTI_RAISING;
  68. }
  69. act_on_raise = (capture_mode & UPDATE_ON_RAISING);
  70. act_on_fall = (capture_mode & UPDATE_ON_FALLING);
  71. read_diff = (capture_mode & UPDATE_DIFFERENCE);
  72. NVIC_DISABLE_IRQ(IRQ_FTM0);
  73. if (FTM0_MOD != 0xFFFF || (FTM0_SC & 0x7F) != FTM_SC_VALUE) {
  74. FTM0_SC = 0;
  75. FTM0_CNT = 0;
  76. FTM0_MOD = 0xFFFF;
  77. FTM0_SC = FTM_SC_VALUE;
  78. #ifdef KINETISK
  79. FTM0_MODE = FTM_MODE_WPDIS; //allow reconfiguring the CSC on the fly
  80. #endif
  81. }
  82. capture_msw = 0;
  83. raiscap_previous = 0;
  84. fallcap_previous = 0;
  85. next_is_falling = false;
  86. buffer_head = 0;
  87. buffer_tail = 0;
  88. volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
  89. #if defined(KINETISL)
  90. *csc = 0;
  91. delayMicroseconds(1);
  92. #endif
  93. *csc = FTM_CSC_RAISING; // first capture is always rising
  94. list[channel] = this;
  95. channelmask |= (1 << channel);
  96. NVIC_SET_PRIORITY(IRQ_FTM0, 48);
  97. NVIC_ENABLE_IRQ(IRQ_FTM0);
  98. return true;
  99. }
  100. uint32_t FreqMeasureMulti::available(void)
  101. {
  102. uint32_t head = buffer_head;
  103. uint32_t tail = buffer_tail;
  104. if (head >= tail) return head - tail;
  105. return FREQMEASUREMULTI_BUFFER_LEN + head - tail;
  106. }
  107. uint32_t FreqMeasureMulti::read(void)
  108. {
  109. uint32_t head = buffer_head;
  110. uint32_t tail = buffer_tail;
  111. if (head == tail) return 0xFFFFFFFF;
  112. tail = tail + 1;
  113. if (tail >= FREQMEASUREMULTI_BUFFER_LEN) tail = 0;
  114. uint32_t value = buffer_value[tail].count;
  115. last_read_level = buffer_value[tail].level;
  116. buffer_tail = tail;
  117. return value;
  118. }
  119. uint8_t FreqMeasureMulti::readLevel(void)
  120. {
  121. return last_read_level;
  122. }
  123. float FreqMeasureMulti::countToFrequency(uint32_t count)
  124. {
  125. #if defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
  126. return (float)F_BUS / (float)count;
  127. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
  128. return (float)(F_PLL/2) / (float)count;
  129. #else
  130. return 0.0;
  131. #endif
  132. }
  133. float FreqMeasureMulti::countToNanoseconds(uint32_t count)
  134. {
  135. #if defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
  136. return (float)count * (1000000000.0f / (float)F_BUS);
  137. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
  138. return (float)count * (2000000000.0f / (float)F_PLL);
  139. #else
  140. return 0.0;
  141. #endif
  142. }
  143. void FreqMeasureMulti::end(void)
  144. {
  145. switch (channel) {
  146. case 0: CORE_PIN22_CONFIG = 0; break;
  147. case 1: CORE_PIN23_CONFIG = 0; break;
  148. case 2: CORE_PIN9_CONFIG = 0; break;
  149. case 3: CORE_PIN10_CONFIG = 0; break;
  150. case 4: CORE_PIN6_CONFIG = 0; break;
  151. case 5: CORE_PIN20_CONFIG = 0; break;
  152. #if defined(KINETISK)
  153. case 6: CORE_PIN21_CONFIG = 0; break;
  154. case 7: CORE_PIN5_CONFIG = 0; break;
  155. #endif
  156. default: return;
  157. }
  158. channelmask &= ~(1 << channel);
  159. volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
  160. *csc = 0;
  161. }
  162. void ftm0_isr(void)
  163. {
  164. bool inc = false;
  165. if (FTM0_SC & FTM_SC_TOF) {
  166. #if defined(KINETISK)
  167. FTM0_SC = FTM_SC_VALUE;
  168. #elif defined(KINETISL)
  169. FTM0_SC = FTM_SC_VALUE | FTM_SC_TOF;
  170. #endif
  171. capture_msw++;
  172. inc = true;
  173. }
  174. uint8_t mask = FTM0_STATUS & channelmask;
  175. if ((mask & 0x01)) list[0]->isr(inc);
  176. if ((mask & 0x02)) list[1]->isr(inc);
  177. if ((mask & 0x04)) list[2]->isr(inc);
  178. if ((mask & 0x08)) list[3]->isr(inc);
  179. if ((mask & 0x10)) list[4]->isr(inc);
  180. if ((mask & 0x20)) list[5]->isr(inc);
  181. #if defined(KINETISK)
  182. if ((mask & 0x40)) list[6]->isr(inc);
  183. if ((mask & 0x80)) list[7]->isr(inc);
  184. #endif
  185. }
  186. void FreqMeasureMulti::isr(bool inc)
  187. {
  188. uint32_t period = 0;
  189. uint8_t level = LEVEL_UNDEFINED;
  190. volatile uint32_t *csc = &FTM0_C0SC + channel * 2;
  191. uint32_t capture = csc[1];
  192. next_is_falling = !next_is_falling; // toggle capture mode
  193. #if defined(KINETISK)
  194. csc[0] = (next_is_falling ? FTM_CSC_FALLING : FTM_CSC_RAISING);
  195. #elif defined(KINETISL)
  196. csc[0] = 0; // disable
  197. asm volatile ("nop");
  198. asm volatile ("nop");
  199. csc[0] = (next_is_falling ? FTM_CSC_FALLING : FTM_CSC_RAISING) | FTM_CSC_CHF;
  200. #endif
  201. if (capture <= 0xE000 || !inc) {
  202. capture |= (capture_msw << 16);
  203. } else {
  204. capture |= ((capture_msw - 1) << 16);
  205. }
  206. // compute the waveform period
  207. if (next_is_falling) {
  208. if (act_on_raise) period = capture - (read_diff ? fallcap_previous : raiscap_previous);
  209. raiscap_previous = capture;
  210. level = (read_diff ? LEVEL_SPACE_ONLY : LEVEL_MARK_SPACE);
  211. } else if (!next_is_falling ) {
  212. if (act_on_fall) period = capture - (read_diff ? raiscap_previous : fallcap_previous);
  213. fallcap_previous = capture;
  214. level = (read_diff ? LEVEL_MARK_ONLY : LEVEL_SPACE_MARK);
  215. }
  216. if (period != 0) {
  217. uint32_t i = buffer_head + 1;
  218. if (i >= FREQMEASUREMULTI_BUFFER_LEN) i = 0;
  219. if (i != buffer_tail) {
  220. buffer_value[i].level = level;
  221. buffer_value[i].count = period;
  222. buffer_head = i;
  223. }
  224. }
  225. }
  226. #endif