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.

TimerOne.h 19KB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. /*
  2. * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
  3. * Original code by Jesse Tane for http://labs.ideo.com August 2008
  4. * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
  5. * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
  6. * Modified April 2012 by Paul Stoffregen - portable to other AVR chips, use inline functions
  7. * Modified again, June 2014 by Paul Stoffregen - support Teensy 3.x & even more AVR chips
  8. * Modified July 2017 by Stoyko Dimitrov - added support for ATTiny85 except for the PWM functionality
  9. *
  10. *
  11. * This is free software. You can redistribute it and/or modify it under
  12. * the terms of Creative Commons Attribution 3.0 United States License.
  13. * To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
  14. * or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
  15. *
  16. */
  17. #ifndef TimerOne_h_
  18. #define TimerOne_h_
  19. #if defined(ARDUINO) && ARDUINO >= 100
  20. #include "Arduino.h"
  21. #else
  22. #include "WProgram.h"
  23. #endif
  24. #include "config/known_16bit_timers.h"
  25. #if defined (__AVR_ATtiny85__)
  26. #define TIMER1_RESOLUTION 256UL // Timer1 is 8 bit
  27. #elif defined(__AVR__)
  28. #define TIMER1_RESOLUTION 65536UL // Timer1 is 16 bit
  29. #else
  30. #define TIMER1_RESOLUTION 65536UL // assume 16 bits for non-AVR chips
  31. #endif
  32. // Placing nearly all the code in this .h file allows the functions to be
  33. // inlined by the compiler. In the very common case with constant values
  34. // the compiler will perform all calculations and simply write constants
  35. // to the hardware registers (for example, setPeriod).
  36. class TimerOne
  37. {
  38. #if defined (__AVR_ATtiny85__)
  39. public:
  40. //****************************
  41. // Configuration
  42. //****************************
  43. void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
  44. TCCR1 = _BV(CTC1); //clear timer1 when it matches the value in OCR1C
  45. TIMSK |= _BV(OCIE1A); //enable interrupt when OCR1A matches the timer value
  46. setPeriod(microseconds);
  47. }
  48. void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
  49. const unsigned long cycles = microseconds * ratio;
  50. if (cycles < TIMER1_RESOLUTION) {
  51. clockSelectBits = _BV(CS10);
  52. pwmPeriod = cycles;
  53. } else
  54. if (cycles < TIMER1_RESOLUTION * 2UL) {
  55. clockSelectBits = _BV(CS11);
  56. pwmPeriod = cycles / 2;
  57. } else
  58. if (cycles < TIMER1_RESOLUTION * 4UL) {
  59. clockSelectBits = _BV(CS11) | _BV(CS10);
  60. pwmPeriod = cycles / 4;
  61. } else
  62. if (cycles < TIMER1_RESOLUTION * 8UL) {
  63. clockSelectBits = _BV(CS12);
  64. pwmPeriod = cycles / 8;
  65. } else
  66. if (cycles < TIMER1_RESOLUTION * 16UL) {
  67. clockSelectBits = _BV(CS12) | _BV(CS10);
  68. pwmPeriod = cycles / 16;
  69. } else
  70. if (cycles < TIMER1_RESOLUTION * 32UL) {
  71. clockSelectBits = _BV(CS12) | _BV(CS11);
  72. pwmPeriod = cycles / 32;
  73. } else
  74. if (cycles < TIMER1_RESOLUTION * 64UL) {
  75. clockSelectBits = _BV(CS12) | _BV(CS11) | _BV(CS10);
  76. pwmPeriod = cycles / 64UL;
  77. } else
  78. if (cycles < TIMER1_RESOLUTION * 128UL) {
  79. clockSelectBits = _BV(CS13);
  80. pwmPeriod = cycles / 128;
  81. } else
  82. if (cycles < TIMER1_RESOLUTION * 256UL) {
  83. clockSelectBits = _BV(CS13) | _BV(CS10);
  84. pwmPeriod = cycles / 256;
  85. } else
  86. if (cycles < TIMER1_RESOLUTION * 512UL) {
  87. clockSelectBits = _BV(CS13) | _BV(CS11);
  88. pwmPeriod = cycles / 512;
  89. } else
  90. if (cycles < TIMER1_RESOLUTION * 1024UL) {
  91. clockSelectBits = _BV(CS13) | _BV(CS11) | _BV(CS10);
  92. pwmPeriod = cycles / 1024;
  93. } else
  94. if (cycles < TIMER1_RESOLUTION * 2048UL) {
  95. clockSelectBits = _BV(CS13) | _BV(CS12);
  96. pwmPeriod = cycles / 2048;
  97. } else
  98. if (cycles < TIMER1_RESOLUTION * 4096UL) {
  99. clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS10);
  100. pwmPeriod = cycles / 4096;
  101. } else
  102. if (cycles < TIMER1_RESOLUTION * 8192UL) {
  103. clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11);
  104. pwmPeriod = cycles / 8192;
  105. } else
  106. if (cycles < TIMER1_RESOLUTION * 16384UL) {
  107. clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11) | _BV(CS10);
  108. pwmPeriod = cycles / 16384;
  109. } else {
  110. clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11) | _BV(CS10);
  111. pwmPeriod = TIMER1_RESOLUTION - 1;
  112. }
  113. OCR1A = pwmPeriod;
  114. OCR1C = pwmPeriod;
  115. TCCR1 = _BV(CTC1) | clockSelectBits;
  116. }
  117. //****************************
  118. // Run Control
  119. //****************************
  120. void start() __attribute__((always_inline)) {
  121. TCCR1 = 0;
  122. TCNT1 = 0;
  123. resume();
  124. }
  125. void stop() __attribute__((always_inline)) {
  126. TCCR1 = _BV(CTC1);
  127. }
  128. void restart() __attribute__((always_inline)) {
  129. start();
  130. }
  131. void resume() __attribute__((always_inline)) {
  132. TCCR1 = _BV(CTC1) | clockSelectBits;
  133. }
  134. //****************************
  135. // PWM outputs
  136. //****************************
  137. //Not implemented yet for ATTiny85
  138. //TO DO
  139. //****************************
  140. // Interrupt Function
  141. //****************************
  142. void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
  143. isrCallback = isr;
  144. TIMSK |= _BV(OCIE1A);
  145. }
  146. void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
  147. if(microseconds > 0) setPeriod(microseconds);
  148. attachInterrupt(isr);
  149. }
  150. void detachInterrupt() __attribute__((always_inline)) {
  151. //TIMSK = 0; // Timer 0 and Timer 1 both use TIMSK register so setting it to 0 will override settings for Timer1 as well
  152. TIMSK &= ~_BV(OCIE1A);
  153. }
  154. static void (*isrCallback)();
  155. static void isrDefaultUnused();
  156. private:
  157. static unsigned short pwmPeriod;
  158. static unsigned char clockSelectBits;
  159. static const byte ratio = (F_CPU)/ ( 1000000 );
  160. #elif defined(__AVR__)
  161. #if defined (__AVR_ATmega8__)
  162. //in some io definitions for older microcontrollers TIMSK is used instead of TIMSK1
  163. #define TIMSK1 TIMSK
  164. #endif
  165. public:
  166. //****************************
  167. // Configuration
  168. //****************************
  169. void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
  170. TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer
  171. TCCR1A = 0; // clear control register A
  172. setPeriod(microseconds);
  173. }
  174. void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
  175. const unsigned long cycles = ((F_CPU/100000 * microseconds) / 20);
  176. if (cycles < TIMER1_RESOLUTION) {
  177. clockSelectBits = _BV(CS10);
  178. pwmPeriod = cycles;
  179. } else
  180. if (cycles < TIMER1_RESOLUTION * 8) {
  181. clockSelectBits = _BV(CS11);
  182. pwmPeriod = cycles / 8;
  183. } else
  184. if (cycles < TIMER1_RESOLUTION * 64) {
  185. clockSelectBits = _BV(CS11) | _BV(CS10);
  186. pwmPeriod = cycles / 64;
  187. } else
  188. if (cycles < TIMER1_RESOLUTION * 256) {
  189. clockSelectBits = _BV(CS12);
  190. pwmPeriod = cycles / 256;
  191. } else
  192. if (cycles < TIMER1_RESOLUTION * 1024) {
  193. clockSelectBits = _BV(CS12) | _BV(CS10);
  194. pwmPeriod = cycles / 1024;
  195. } else {
  196. clockSelectBits = _BV(CS12) | _BV(CS10);
  197. pwmPeriod = TIMER1_RESOLUTION - 1;
  198. }
  199. ICR1 = pwmPeriod;
  200. TCCR1B = _BV(WGM13) | clockSelectBits;
  201. }
  202. //****************************
  203. // Run Control
  204. //****************************
  205. void start() __attribute__((always_inline)) {
  206. TCCR1B = 0;
  207. TCNT1 = 0; // TODO: does this cause an undesired interrupt?
  208. resume();
  209. }
  210. void stop() __attribute__((always_inline)) {
  211. TCCR1B = _BV(WGM13);
  212. }
  213. void restart() __attribute__((always_inline)) {
  214. start();
  215. }
  216. void resume() __attribute__((always_inline)) {
  217. TCCR1B = _BV(WGM13) | clockSelectBits;
  218. }
  219. //****************************
  220. // PWM outputs
  221. //****************************
  222. void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
  223. unsigned long dutyCycle = pwmPeriod;
  224. dutyCycle *= duty;
  225. dutyCycle >>= 10;
  226. if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
  227. #ifdef TIMER1_B_PIN
  228. else if (pin == TIMER1_B_PIN) OCR1B = dutyCycle;
  229. #endif
  230. #ifdef TIMER1_C_PIN
  231. else if (pin == TIMER1_C_PIN) OCR1C = dutyCycle;
  232. #endif
  233. }
  234. void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
  235. if (pin == TIMER1_A_PIN) { pinMode(TIMER1_A_PIN, OUTPUT); TCCR1A |= _BV(COM1A1); }
  236. #ifdef TIMER1_B_PIN
  237. else if (pin == TIMER1_B_PIN) { pinMode(TIMER1_B_PIN, OUTPUT); TCCR1A |= _BV(COM1B1); }
  238. #endif
  239. #ifdef TIMER1_C_PIN
  240. else if (pin == TIMER1_C_PIN) { pinMode(TIMER1_C_PIN, OUTPUT); TCCR1A |= _BV(COM1C1); }
  241. #endif
  242. setPwmDuty(pin, duty);
  243. TCCR1B = _BV(WGM13) | clockSelectBits;
  244. }
  245. void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
  246. if (microseconds > 0) setPeriod(microseconds);
  247. pwm(pin, duty);
  248. }
  249. void disablePwm(char pin) __attribute__((always_inline)) {
  250. if (pin == TIMER1_A_PIN) TCCR1A &= ~_BV(COM1A1);
  251. #ifdef TIMER1_B_PIN
  252. else if (pin == TIMER1_B_PIN) TCCR1A &= ~_BV(COM1B1);
  253. #endif
  254. #ifdef TIMER1_C_PIN
  255. else if (pin == TIMER1_C_PIN) TCCR1A &= ~_BV(COM1C1);
  256. #endif
  257. }
  258. //****************************
  259. // Interrupt Function
  260. //****************************
  261. void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
  262. isrCallback = isr;
  263. TIMSK1 = _BV(TOIE1);
  264. }
  265. void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
  266. if(microseconds > 0) setPeriod(microseconds);
  267. attachInterrupt(isr);
  268. }
  269. void detachInterrupt() __attribute__((always_inline)) {
  270. TIMSK1 = 0;
  271. }
  272. static void (*isrCallback)();
  273. static void isrDefaultUnused();
  274. private:
  275. // properties
  276. static unsigned short pwmPeriod;
  277. static unsigned char clockSelectBits;
  278. #elif defined(__arm__) && defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL))
  279. #if defined(KINETISK)
  280. #define F_TIMER F_BUS
  281. #elif defined(KINETISL)
  282. #define F_TIMER (F_PLL/2)
  283. #endif
  284. // Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
  285. // The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
  286. // period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
  287. // kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
  288. // ambiguous results.
  289. #undef TIMER1_RESOLUTION
  290. #define TIMER1_RESOLUTION 32768
  291. public:
  292. //****************************
  293. // Configuration
  294. //****************************
  295. void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
  296. setPeriod(microseconds);
  297. }
  298. void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
  299. const unsigned long cycles = (F_TIMER / 2000000) * microseconds;
  300. // A much faster if-else
  301. // This is like a binary serch tree and no more than 3 conditions are evaluated.
  302. // I haven't checked if this becomes significantly longer ASM than the simple ladder.
  303. // It looks very similar to the ladder tho: same # of if's and else's
  304. /*
  305. // This code does not work properly in all cases :(
  306. // https://github.com/PaulStoffregen/TimerOne/issues/17
  307. if (cycles < TIMER1_RESOLUTION * 16) {
  308. if (cycles < TIMER1_RESOLUTION * 4) {
  309. if (cycles < TIMER1_RESOLUTION) {
  310. clockSelectBits = 0;
  311. pwmPeriod = cycles;
  312. }else{
  313. clockSelectBits = 1;
  314. pwmPeriod = cycles >> 1;
  315. }
  316. }else{
  317. if (cycles < TIMER1_RESOLUTION * 8) {
  318. clockSelectBits = 3;
  319. pwmPeriod = cycles >> 3;
  320. }else{
  321. clockSelectBits = 4;
  322. pwmPeriod = cycles >> 4;
  323. }
  324. }
  325. }else{
  326. if (cycles > TIMER1_RESOLUTION * 64) {
  327. if (cycles > TIMER1_RESOLUTION * 128) {
  328. clockSelectBits = 7;
  329. pwmPeriod = TIMER1_RESOLUTION - 1;
  330. }else{
  331. clockSelectBits = 7;
  332. pwmPeriod = cycles >> 7;
  333. }
  334. }
  335. else{
  336. if (cycles > TIMER1_RESOLUTION * 32) {
  337. clockSelectBits = 6;
  338. pwmPeriod = cycles >> 6;
  339. }else{
  340. clockSelectBits = 5;
  341. pwmPeriod = cycles >> 5;
  342. }
  343. }
  344. }
  345. */
  346. if (cycles < TIMER1_RESOLUTION) {
  347. clockSelectBits = 0;
  348. pwmPeriod = cycles;
  349. } else
  350. if (cycles < TIMER1_RESOLUTION * 2) {
  351. clockSelectBits = 1;
  352. pwmPeriod = cycles >> 1;
  353. } else
  354. if (cycles < TIMER1_RESOLUTION * 4) {
  355. clockSelectBits = 2;
  356. pwmPeriod = cycles >> 2;
  357. } else
  358. if (cycles < TIMER1_RESOLUTION * 8) {
  359. clockSelectBits = 3;
  360. pwmPeriod = cycles >> 3;
  361. } else
  362. if (cycles < TIMER1_RESOLUTION * 16) {
  363. clockSelectBits = 4;
  364. pwmPeriod = cycles >> 4;
  365. } else
  366. if (cycles < TIMER1_RESOLUTION * 32) {
  367. clockSelectBits = 5;
  368. pwmPeriod = cycles >> 5;
  369. } else
  370. if (cycles < TIMER1_RESOLUTION * 64) {
  371. clockSelectBits = 6;
  372. pwmPeriod = cycles >> 6;
  373. } else
  374. if (cycles < TIMER1_RESOLUTION * 128) {
  375. clockSelectBits = 7;
  376. pwmPeriod = cycles >> 7;
  377. } else {
  378. clockSelectBits = 7;
  379. pwmPeriod = TIMER1_RESOLUTION - 1;
  380. }
  381. uint32_t sc = FTM1_SC;
  382. FTM1_SC = 0;
  383. FTM1_MOD = pwmPeriod;
  384. FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);
  385. }
  386. //****************************
  387. // Run Control
  388. //****************************
  389. void start() __attribute__((always_inline)) {
  390. stop();
  391. FTM1_CNT = 0;
  392. resume();
  393. }
  394. void stop() __attribute__((always_inline)) {
  395. FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
  396. }
  397. void restart() __attribute__((always_inline)) {
  398. start();
  399. }
  400. void resume() __attribute__((always_inline)) {
  401. FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
  402. }
  403. //****************************
  404. // PWM outputs
  405. //****************************
  406. void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
  407. unsigned long dutyCycle = pwmPeriod;
  408. dutyCycle *= duty;
  409. dutyCycle >>= 10;
  410. if (pin == TIMER1_A_PIN) {
  411. FTM1_C0V = dutyCycle;
  412. } else if (pin == TIMER1_B_PIN) {
  413. FTM1_C1V = dutyCycle;
  414. }
  415. }
  416. void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
  417. setPwmDuty(pin, duty);
  418. if (pin == TIMER1_A_PIN) {
  419. *portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
  420. } else if (pin == TIMER1_B_PIN) {
  421. *portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
  422. }
  423. }
  424. void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
  425. if (microseconds > 0) setPeriod(microseconds);
  426. pwm(pin, duty);
  427. }
  428. void disablePwm(char pin) __attribute__((always_inline)) {
  429. if (pin == TIMER1_A_PIN) {
  430. *portConfigRegister(TIMER1_A_PIN) = 0;
  431. } else if (pin == TIMER1_B_PIN) {
  432. *portConfigRegister(TIMER1_B_PIN) = 0;
  433. }
  434. }
  435. //****************************
  436. // Interrupt Function
  437. //****************************
  438. void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
  439. isrCallback = isr;
  440. FTM1_SC |= FTM_SC_TOIE;
  441. NVIC_ENABLE_IRQ(IRQ_FTM1);
  442. }
  443. void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
  444. if(microseconds > 0) setPeriod(microseconds);
  445. attachInterrupt(isr);
  446. }
  447. void detachInterrupt() __attribute__((always_inline)) {
  448. FTM1_SC &= ~FTM_SC_TOIE;
  449. NVIC_DISABLE_IRQ(IRQ_FTM1);
  450. }
  451. static void (*isrCallback)();
  452. static void isrDefaultUnused();
  453. private:
  454. // properties
  455. static unsigned short pwmPeriod;
  456. static unsigned char clockSelectBits;
  457. #undef F_TIMER
  458. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(__IMXRT1062__)
  459. public:
  460. //****************************
  461. // Configuration
  462. //****************************
  463. void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
  464. setPeriod(microseconds);
  465. }
  466. void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
  467. uint32_t period = (float)F_BUS_ACTUAL * (float)microseconds * 0.0000005f;
  468. uint32_t prescale = 0;
  469. while (period > 32767) {
  470. period = period >> 1;
  471. if (++prescale > 7) {
  472. prescale = 7; // when F_BUS is 150 MHz, longest
  473. period = 32767; // period is 55922 us (~17.9 Hz)
  474. break;
  475. }
  476. }
  477. //Serial.printf("setPeriod, period=%u, prescale=%u\n", period, prescale);
  478. FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8); // logic high = fault
  479. FLEXPWM1_FSTS0 = 0x0008; // clear fault status
  480. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
  481. FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP;
  482. FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
  483. FLEXPWM1_SM3INIT = -period;
  484. FLEXPWM1_SM3VAL0 = 0;
  485. FLEXPWM1_SM3VAL1 = period;
  486. FLEXPWM1_SM3VAL2 = 0;
  487. FLEXPWM1_SM3VAL3 = 0;
  488. FLEXPWM1_SM3VAL4 = 0;
  489. FLEXPWM1_SM3VAL5 = 0;
  490. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8);
  491. pwmPeriod = period;
  492. }
  493. //****************************
  494. // Run Control
  495. //****************************
  496. void start() __attribute__((always_inline)) {
  497. stop();
  498. // TODO: how to force counter back to zero?
  499. resume();
  500. }
  501. void stop() __attribute__((always_inline)) {
  502. FLEXPWM1_MCTRL &= ~FLEXPWM_MCTRL_RUN(8);
  503. }
  504. void restart() __attribute__((always_inline)) {
  505. start();
  506. }
  507. void resume() __attribute__((always_inline)) {
  508. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_RUN(8);
  509. }
  510. //****************************
  511. // PWM outputs
  512. //****************************
  513. void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
  514. if (duty > 1023) duty = 1023;
  515. int dutyCycle = (pwmPeriod * duty) >> 10;
  516. //Serial.printf("setPwmDuty, period=%u\n", dutyCycle);
  517. if (pin == TIMER1_A_PIN) {
  518. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
  519. FLEXPWM1_SM3VAL5 = dutyCycle;
  520. FLEXPWM1_SM3VAL4 = -dutyCycle;
  521. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8);
  522. } else if (pin == TIMER1_B_PIN) {
  523. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
  524. FLEXPWM1_SM3VAL3 = dutyCycle;
  525. FLEXPWM1_SM3VAL2 = -dutyCycle;
  526. FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8);
  527. }
  528. }
  529. void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
  530. setPwmDuty(pin, duty);
  531. if (pin == TIMER1_A_PIN) {
  532. FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMB_EN(8);
  533. IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_01 = 6; // pin 7 FLEXPWM1_PWM3_B
  534. } else if (pin == TIMER1_B_PIN) {
  535. FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(8);
  536. IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6; // pin 8 FLEXPWM1_PWM3_A
  537. }
  538. }
  539. void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
  540. if (microseconds > 0) setPeriod(microseconds);
  541. pwm(pin, duty);
  542. }
  543. void disablePwm(char pin) __attribute__((always_inline)) {
  544. if (pin == TIMER1_A_PIN) {
  545. IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_01 = 5; // pin 7 FLEXPWM1_PWM3_B
  546. FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMB_EN(8);
  547. } else if (pin == TIMER1_B_PIN) {
  548. IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 5; // pin 8 FLEXPWM1_PWM3_A
  549. FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMA_EN(8);
  550. }
  551. }
  552. //****************************
  553. // Interrupt Function
  554. //****************************
  555. void attachInterrupt(void (*f)()) __attribute__((always_inline)) {
  556. isrCallback = f;
  557. attachInterruptVector(IRQ_FLEXPWM1_3, &isr);
  558. FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
  559. FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE;
  560. NVIC_ENABLE_IRQ(IRQ_FLEXPWM1_3);
  561. }
  562. void attachInterrupt(void (*f)(), unsigned long microseconds) __attribute__((always_inline)) {
  563. if(microseconds > 0) setPeriod(microseconds);
  564. attachInterrupt(f);
  565. }
  566. void detachInterrupt() __attribute__((always_inline)) {
  567. NVIC_DISABLE_IRQ(IRQ_FLEXPWM1_3);
  568. FLEXPWM1_SM3INTEN = 0;
  569. }
  570. static void isr(void);
  571. static void (*isrCallback)();
  572. static void isrDefaultUnused();
  573. private:
  574. // properties
  575. static unsigned short pwmPeriod;
  576. static unsigned char clockSelectBits;
  577. #endif
  578. };
  579. extern TimerOne Timer1;
  580. #endif