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.

FrequencyTimer2.cpp 7.9KB

3 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. FrequencyTimer2.h - A frequency generator and interrupt generator library
  3. Author: Jim Studt, jim@federated.com
  4. Copyright (c) 2007 David A. Mellis. All right reserved.
  5. http://www.arduino.cc/playground/Code/FrequencyTimer2
  6. Version 2.1 - updated by Paul Stoffregen, paul@pjrc.com
  7. for compatibility with Teensy 3.1
  8. Version 2 - updated by Paul Stoffregen, paul@pjrc.com
  9. for compatibility with newer hardware and Arduino 1.0
  10. This library is free software; you can redistribute it and/or
  11. modify it under the terms of the GNU Lesser General Public
  12. License as published by the Free Software Foundation; either
  13. version 2.1 of the License, or (at your option) any later version.
  14. This library is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. Lesser General Public License for more details.
  18. You should have received a copy of the GNU Lesser General Public
  19. License along with this library; if not, write to the Free Software
  20. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <FrequencyTimer2.h>
  23. #include <avr/interrupt.h>
  24. void (*FrequencyTimer2::onOverflow)() = 0;
  25. uint8_t FrequencyTimer2::enabled = 0;
  26. #if defined(__AVR__)
  27. #if defined(TIMER2_COMPA_vect)
  28. ISR(TIMER2_COMPA_vect)
  29. #elif defined(TIMER2_COMP_vect)
  30. ISR(TIMER2_COMP_vect)
  31. #else
  32. #error "This board does not have a hardware timer which is compatible with FrequencyTimer2"
  33. void dummy_function(void)
  34. #endif
  35. {
  36. static uint8_t inHandler = 0; // protect us from recursion if our handler enables interrupts
  37. if ( !inHandler && FrequencyTimer2::onOverflow) {
  38. inHandler = 1;
  39. (*FrequencyTimer2::onOverflow)();
  40. inHandler = 0;
  41. }
  42. }
  43. void FrequencyTimer2::setOnOverflow( void (*func)() )
  44. {
  45. FrequencyTimer2::onOverflow = func;
  46. #if defined(TIMSK2)
  47. if ( func) TIMSK2 |= _BV(OCIE2A);
  48. else TIMSK2 &= ~_BV(OCIE2A);
  49. #elif defined(TIMSK)
  50. if ( func) TIMSK |= _BV(OCIE2);
  51. else TIMSK &= ~_BV(OCIE2);
  52. #endif
  53. }
  54. void FrequencyTimer2::setPeriod(unsigned long period)
  55. {
  56. uint8_t pre, top;
  57. if ( period == 0) period = 1;
  58. period *= clockCyclesPerMicrosecond();
  59. period /= 2; // we work with half-cycles before the toggle
  60. if ( period <= 256) {
  61. pre = 1;
  62. top = period-1;
  63. } else if ( period <= 256L*8) {
  64. pre = 2;
  65. top = period/8-1;
  66. } else if ( period <= 256L*32) {
  67. pre = 3;
  68. top = period/32-1;
  69. } else if ( period <= 256L*64) {
  70. pre = 4;
  71. top = period/64-1;
  72. } else if ( period <= 256L*128) {
  73. pre = 5;
  74. top = period/128-1;
  75. } else if ( period <= 256L*256) {
  76. pre = 6;
  77. top = period/256-1;
  78. } else if ( period <= 256L*1024) {
  79. pre = 7;
  80. top = period/1024-1;
  81. } else {
  82. pre = 7;
  83. top = 255;
  84. }
  85. #if defined(TCCR2A)
  86. TCCR2B = 0;
  87. TCCR2A = 0;
  88. TCNT2 = 0;
  89. #if defined(ASSR) && defined(AS2)
  90. ASSR &= ~_BV(AS2); // use clock, not T2 pin
  91. #endif
  92. OCR2A = top;
  93. TCCR2A = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM2A0) : 0));
  94. TCCR2B = pre;
  95. #elif defined(TCCR2)
  96. TCCR2 = 0;
  97. TCNT2 = 0;
  98. ASSR &= ~_BV(AS2); // use clock, not T2 pin
  99. OCR2 = top;
  100. TCCR2 = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM20) : 0) | pre);
  101. #endif
  102. }
  103. unsigned long FrequencyTimer2::getPeriod()
  104. {
  105. #if defined(TCCR2B)
  106. uint8_t p = (TCCR2B & 7);
  107. unsigned long v = OCR2A;
  108. #elif defined(TCCR2)
  109. uint8_t p = (TCCR2 & 7);
  110. unsigned long v = OCR2;
  111. #endif
  112. uint8_t shift=0;
  113. switch(p) {
  114. case 0 ... 1:
  115. shift = 0;
  116. break;
  117. case 2:
  118. shift = 3;
  119. break;
  120. case 3:
  121. shift = 5;
  122. break;
  123. case 4:
  124. shift = 6;
  125. break;
  126. case 5:
  127. shift = 7;
  128. break;
  129. case 6:
  130. shift = 8;
  131. break;
  132. case 7:
  133. shift = 10;
  134. break;
  135. }
  136. return (((v+1) << (shift+1)) + 1) / clockCyclesPerMicrosecond(); // shift+1 converts from half-period to period
  137. }
  138. void FrequencyTimer2::enable()
  139. {
  140. FrequencyTimer2::enabled = 1;
  141. #if defined(TCCR2A)
  142. TCCR2A |= _BV(COM2A0);
  143. #elif defined(TCCR2)
  144. TCCR2 |= _BV(COM20);
  145. #endif
  146. }
  147. void FrequencyTimer2::disable()
  148. {
  149. FrequencyTimer2::enabled = 0;
  150. #if defined(TCCR2A)
  151. TCCR2A &= ~_BV(COM2A0);
  152. #elif defined(TCCR2)
  153. TCCR2 &= ~_BV(COM20);
  154. #endif
  155. }
  156. #elif defined(__arm__) && defined(TEENSYDUINO)
  157. void FrequencyTimer2::setPeriod(unsigned long period)
  158. {
  159. uint8_t bdiv, cdiv=0;
  160. if (period == 0) period = 1;
  161. period *= (F_BUS / 1000000);
  162. if (period < 65535*16) {
  163. bdiv = 0;
  164. } else if (period < 65535*2*16) {
  165. bdiv = 1;
  166. } else if (period < 65535*3*16) {
  167. bdiv = 2;
  168. } else if (period < 65535*4*16) {
  169. bdiv = 3;
  170. } else if (period < 65535*5*16) {
  171. bdiv = 4;
  172. } else if (period < 65535*6*16) {
  173. bdiv = 5;
  174. } else if (period < 65535*7*16) {
  175. bdiv = 6;
  176. } else if (period < 65535*8*16) {
  177. bdiv = 7;
  178. } else if (period < 65535*9*16) {
  179. bdiv = 8;
  180. } else if (period < 65535*10*16) {
  181. bdiv = 9;
  182. } else if (period < 65535*11*16) {
  183. bdiv = 10;
  184. } else if (period < 65535*12*16) {
  185. bdiv = 11;
  186. } else if (period < 65535*13*16) {
  187. bdiv = 12;
  188. } else if (period < 65535*14*16) {
  189. bdiv = 13;
  190. } else if (period < 65535*15*16) {
  191. bdiv = 14;
  192. } else if (period < 65535*16*16) {
  193. bdiv = 15;
  194. } else if (period < 65535*18*16) {
  195. bdiv = 8;
  196. cdiv = 1;
  197. } else if (period < 65535*20*16) {
  198. bdiv = 9;
  199. cdiv = 1;
  200. } else if (period < 65535*22*16) {
  201. bdiv = 10;
  202. cdiv = 1;
  203. } else if (period < 65535*24*16) {
  204. bdiv = 11;
  205. cdiv = 1;
  206. } else if (period < 65535*26*16) {
  207. bdiv = 12;
  208. cdiv = 1;
  209. } else if (period < 65535*28*16) {
  210. bdiv = 13;
  211. cdiv = 1;
  212. } else if (period < 65535*30*16) {
  213. bdiv = 14;
  214. cdiv = 1;
  215. } else if (period < 65535*32*16) {
  216. bdiv = 15;
  217. cdiv = 1;
  218. } else if (period < 65535*36*16) {
  219. bdiv = 8;
  220. cdiv = 2;
  221. } else if (period < 65535*40*16) {
  222. bdiv = 9;
  223. cdiv = 2;
  224. } else if (period < 65535*44*16) {
  225. bdiv = 10;
  226. cdiv = 2;
  227. } else if (period < 65535*48*16) {
  228. bdiv = 11;
  229. cdiv = 2;
  230. } else if (period < 65535*52*16) {
  231. bdiv = 12;
  232. cdiv = 2;
  233. } else if (period < 65535*56*16) {
  234. bdiv = 13;
  235. cdiv = 2;
  236. } else if (period < 65535*60*16) {
  237. bdiv = 14;
  238. cdiv = 2;
  239. } else if (period < 65535*64*16) {
  240. bdiv = 15;
  241. cdiv = 2;
  242. } else if (period < 65535*72*16) {
  243. bdiv = 8;
  244. cdiv = 3;
  245. } else if (period < 65535*80*16) {
  246. bdiv = 9;
  247. cdiv = 3;
  248. } else if (period < 65535*88*16) {
  249. bdiv = 10;
  250. cdiv = 3;
  251. } else if (period < 65535*96*16) {
  252. bdiv = 11;
  253. cdiv = 3;
  254. } else if (period < 65535*104*16) {
  255. bdiv = 12;
  256. cdiv = 3;
  257. } else if (period < 65535*112*16) {
  258. bdiv = 13;
  259. cdiv = 3;
  260. } else if (period < 65535*120*16) {
  261. bdiv = 14;
  262. cdiv = 3;
  263. } else {
  264. bdiv = 15;
  265. cdiv = 3;
  266. }
  267. period /= (bdiv + 1);
  268. period >>= (cdiv + 4);
  269. if (period > 65535) period = 65535;
  270. // high time = (CMD1:CMD2 + 1) ÷ (fCMTCLK ÷ 8)
  271. // low time = CMD3:CMD4 ÷ (fCMTCLK ÷ 8)
  272. SIM_SCGC4 |= SIM_SCGC4_CMT;
  273. CMT_MSC = 0;
  274. CMT_PPS = bdiv;
  275. CMT_CMD1 = ((period - 1) >> 8) & 255;
  276. CMT_CMD2 = (period - 1) & 255;
  277. CMT_CMD3 = (period >> 8) & 255;
  278. CMT_CMD4 = period & 255;
  279. CMT_OC = 0x60;
  280. CMT_MSC = (cdiv << 5) | 0x0B; // baseband mode
  281. }
  282. unsigned long FrequencyTimer2::getPeriod()
  283. {
  284. uint32_t period;
  285. period = (CMT_CMD3 << 8) | CMT_CMD4;
  286. period *= (CMT_PPS + 1);
  287. period <<= ((CMT_MSC >> 5) & 3) + 4;
  288. period /= (F_BUS / 1000000);
  289. return period;
  290. }
  291. void FrequencyTimer2::enable()
  292. {
  293. FrequencyTimer2::enabled = 1;
  294. CORE_PIN5_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_DSE|PORT_PCR_SRE;
  295. }
  296. void FrequencyTimer2::disable()
  297. {
  298. FrequencyTimer2::enabled = 0;
  299. CORE_PIN5_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE;
  300. digitalWriteFast(5, LOW);
  301. }
  302. void FrequencyTimer2::setOnOverflow( void (*func)() )
  303. {
  304. if (func) {
  305. FrequencyTimer2::onOverflow = func;
  306. NVIC_ENABLE_IRQ(IRQ_CMT);
  307. } else {
  308. NVIC_DISABLE_IRQ(IRQ_CMT);
  309. FrequencyTimer2::onOverflow = func;
  310. }
  311. }
  312. void cmt_isr(void)
  313. {
  314. static uint8_t inHandler = 0;
  315. uint8_t __attribute__((unused)) tmp = CMT_MSC;
  316. tmp = CMT_CMD2;
  317. if ( !inHandler && FrequencyTimer2::onOverflow) {
  318. inHandler = 1;
  319. (*FrequencyTimer2::onOverflow)();
  320. inHandler = 0;
  321. }
  322. }
  323. #endif