PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

518 lines
18KB

  1. /* PulsePosition Library for Teensy 3.x, LC, and 4.0
  2. * High resolution input and output of PPM encoded signals
  3. * http://www.pjrc.com/teensy/td_libs_PulsePosition.html
  4. * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
  5. *
  6. * Development of this library was funded by PJRC.COM, LLC by sales of Teensy
  7. * boards. Please support PJRC's efforts to develop open source software by
  8. * purchasing Teensy or other PJRC products.
  9. *
  10. * Permission is hereby granted, free of charge, to any person obtaining a copy
  11. * of this software and associated documentation files (the "Software"), to deal
  12. * in the Software without restriction, including without limitation the rights
  13. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. * copies of the Software, and to permit persons to whom the Software is
  15. * furnished to do so, subject to the following conditions:
  16. *
  17. * The above copyright notice, development funding notice, and this permission
  18. * notice shall be included in all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26. * THE SOFTWARE.
  27. */
  28. #if defined(__IMXRT1062__)
  29. #include "Arduino.h"
  30. #include "PulsePositionIMXRT.h"
  31. // Some debug defines
  32. //#define DEBUG_IO_PINS
  33. //#define DEBUG_OUTPUT
  34. #ifdef DEBUG_IO_PINS
  35. #define DBGdigitalWriteFast(pin, state) digitalWriteFast(pin, state);
  36. #else
  37. inline void DBGdigitalWriteFast(uint8_t pin, uint8_t state) {};
  38. #endif
  39. // Timing parameters, in microseconds.
  40. // The shortest time allowed between any 2 rising edges. This should be at
  41. // least double TX_PULSE_WIDTH.
  42. #define TX_MINIMUM_SIGNAL 300.0
  43. // The longest time allowed between any 2 rising edges for a normal signal.
  44. #define TX_MAXIMUM_SIGNAL 2500.0
  45. // The default signal to send if nothing has been written.
  46. #define TX_DEFAULT_SIGNAL 1500.0
  47. // When transmitting with a single pin, the minimum space signal that marks
  48. // the end of a frame. Single wire receivers recognize the end of a frame
  49. // by looking for a gap longer than the maximum data size. When viewing the
  50. // waveform on an oscilloscope, set the trigger "holdoff" time to slightly
  51. // less than TX_MINIMUM_SPACE, for the most reliable display. This parameter
  52. // is not used when transmitting with 2 pins.
  53. #define TX_MINIMUM_SPACE 5000.0
  54. // The minimum total frame size. Some servo motors or other devices may not
  55. // work with pulses the repeat more often than 50 Hz. To allow transmission
  56. // as fast as possible, set this to the same as TX_MINIMUM_SIGNAL.
  57. #define TX_MINIMUM_FRAME 20000.0
  58. // The length of all transmitted pulses. This must be longer than the worst
  59. // case interrupt latency, which depends on how long any other library may
  60. // disable interrupts. This must also be no more than half TX_MINIMUM_SIGNAL.
  61. // Most libraries disable interrupts for no more than a few microseconds.
  62. // The OneWire library is a notable exception, so this may need to be lengthened
  63. // if a library that imposes unusual interrupt latency is in use.
  64. #define TX_PULSE_WIDTH 100.0
  65. // When receiving, any time between rising edges longer than this will be
  66. // treated as the end-of-frame marker.
  67. #define RX_MINIMUM_SPACE 3500.0
  68. // convert from microseconds to I/O clock ticks
  69. #define CLOCKS_PER_MICROSECOND (150./4) // pcs 8+2
  70. #define TX_MINIMUM_SPACE_CLOCKS (uint32_t)(TX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND)
  71. #define TX_MINIMUM_FRAME_CLOCKS (uint32_t)(TX_MINIMUM_FRAME * CLOCKS_PER_MICROSECOND)
  72. #define TX_PULSE_WIDTH_CLOCKS (uint32_t)(TX_PULSE_WIDTH * CLOCKS_PER_MICROSECOND)
  73. #define TX_DEFAULT_SIGNAL_CLOCKS (uint32_t)(TX_DEFAULT_SIGNAL * CLOCKS_PER_MICROSECOND)
  74. #define RX_MINIMUM_SPACE_CLOCKS (uint32_t)(RX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND)
  75. //Leave Frame stuff for now
  76. //
  77. //
  78. // Output
  79. #define CTRL_SET TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_LENGTH |TMR_CTRL_OUTMODE(2)
  80. #define CTRL_CLEAR TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_LENGTH |TMR_CTRL_OUTMODE(1)
  81. #define PULSEPOSITION_MAXCHANNELS 16
  82. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  83. //-----------------------------------------------------------------------------
  84. // PulsePositionBase - defines and code.
  85. //-----------------------------------------------------------------------------
  86. PulsePositionBase * PulsePositionBase::list[10];
  87. const PulsePositionBase::TMR_Hardware_t PulsePositionBase::hardware[] = {
  88. { 6,1, &IMXRT_TMR4, &CCM_CCGR6, CCM_CCGR6_QTIMER4(CCM_CCGR_ON), IRQ_QTIMER4, &PulsePositionInput::isrTimer4, nullptr, 0},
  89. { 9,2, &IMXRT_TMR4, &CCM_CCGR6, CCM_CCGR6_QTIMER4(CCM_CCGR_ON), IRQ_QTIMER4, &PulsePositionInput::isrTimer4, nullptr, 0},
  90. {10,0, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1, nullptr, 0},
  91. {11,2, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1, nullptr, 0},
  92. {12,1, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1, nullptr, 0},
  93. {13,0, &IMXRT_TMR2, &CCM_CCGR6, CCM_CCGR6_QTIMER2(CCM_CCGR_ON), IRQ_QTIMER2, &PulsePositionInput::isrTimer2, &IOMUXC_QTIMER2_TIMER0_SELECT_INPUT, 1 },
  94. {14,2, &IMXRT_TMR3, &CCM_CCGR6, CCM_CCGR6_QTIMER3(CCM_CCGR_ON), IRQ_QTIMER3, &PulsePositionInput::isrTimer3, &IOMUXC_QTIMER3_TIMER2_SELECT_INPUT, 1 },
  95. {15,3, &IMXRT_TMR3, &CCM_CCGR6, CCM_CCGR6_QTIMER3(CCM_CCGR_ON), IRQ_QTIMER3, &PulsePositionInput::isrTimer3, &IOMUXC_QTIMER3_TIMER3_SELECT_INPUT, 1 },
  96. {18,1, &IMXRT_TMR3, &CCM_CCGR6, CCM_CCGR6_QTIMER3(CCM_CCGR_ON), IRQ_QTIMER3, &PulsePositionInput::isrTimer3, &IOMUXC_QTIMER3_TIMER1_SELECT_INPUT, 0 },
  97. {19,0, &IMXRT_TMR3, &CCM_CCGR6, CCM_CCGR6_QTIMER3(CCM_CCGR_ON), IRQ_QTIMER3, &PulsePositionInput::isrTimer3, &IOMUXC_QTIMER3_TIMER0_SELECT_INPUT, 1 }
  98. };
  99. const uint8_t PulsePositionBase::_hardware_count = (sizeof(PulsePositionBase::hardware)/sizeof(PulsePositionBase::hardware[0]));
  100. inline void PulsePositionBase::checkAndProcessTimerCHInPending(uint8_t index, volatile IMXRT_TMR_CH_t *tmr_ch) {
  101. if (((tmr_ch->CSCTRL & (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN)) == (TMR_CSCTRL_TCF1 | TMR_CSCTRL_TCF1EN))
  102. || ((tmr_ch->SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE)) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))) {
  103. // Interrupt condtion is set.
  104. if (list[index]) {
  105. list[index]->isr();
  106. } else {
  107. // no one registered to process clear out the conditions.
  108. tmr_ch->CSCTRL &= ~TMR_CSCTRL_TCF1;
  109. tmr_ch->SCTRL &= ~TMR_SCTRL_IEF;
  110. }
  111. }
  112. }
  113. void PulsePositionBase::isrTimer1()
  114. {
  115. DBGdigitalWriteFast(2, HIGH);
  116. checkAndProcessTimerCHInPending(2, &IMXRT_TMR1.CH[0]);
  117. checkAndProcessTimerCHInPending(3, &IMXRT_TMR1.CH[2]);
  118. checkAndProcessTimerCHInPending(4, &IMXRT_TMR1.CH[1]);
  119. asm volatile ("dsb"); // wait for clear memory barrier
  120. DBGdigitalWriteFast(2, LOW);
  121. }
  122. void PulsePositionBase::isrTimer2()
  123. {
  124. DBGdigitalWriteFast(2, HIGH);
  125. checkAndProcessTimerCHInPending(5, &IMXRT_TMR2.CH[0]);
  126. asm volatile ("dsb"); // wait for clear memory barrier
  127. DBGdigitalWriteFast(2, LOW);
  128. }
  129. void PulsePositionBase::isrTimer3()
  130. {
  131. DBGdigitalWriteFast(2, HIGH);
  132. checkAndProcessTimerCHInPending(6, &IMXRT_TMR3.CH[2]);
  133. checkAndProcessTimerCHInPending(7, &IMXRT_TMR3.CH[3]);
  134. checkAndProcessTimerCHInPending(8, &IMXRT_TMR3.CH[1]);
  135. checkAndProcessTimerCHInPending(9, &IMXRT_TMR3.CH[0]);
  136. asm volatile ("dsb"); // wait for clear memory barrier
  137. DBGdigitalWriteFast(2, LOW);
  138. }
  139. void PulsePositionBase::isrTimer4()
  140. {
  141. DBGdigitalWriteFast(2, HIGH);
  142. checkAndProcessTimerCHInPending(0, &IMXRT_TMR4.CH[1]);
  143. checkAndProcessTimerCHInPending(1, &IMXRT_TMR4.CH[2]);
  144. asm volatile ("dsb"); // wait for clear memory barrier
  145. DBGdigitalWriteFast(2, LOW);
  146. }
  147. //-----------------------------------------------------------------------------
  148. // PulsePositionOutput
  149. //-----------------------------------------------------------------------------
  150. PulsePositionOutput::PulsePositionOutput(void)
  151. {
  152. pulse_width[0] = TX_MINIMUM_FRAME_CLOCKS;
  153. for (int i=1; i <= PULSEPOSITION_MAXCHANNELS; i++) {
  154. pulse_width[i] = TX_DEFAULT_SIGNAL_CLOCKS;
  155. }
  156. }
  157. PulsePositionOutput::PulsePositionOutput(int polarity)
  158. {
  159. pulse_width[0] = TX_MINIMUM_FRAME_CLOCKS;
  160. for (int i=1; i <= PULSEPOSITION_MAXCHANNELS; i++) {
  161. pulse_width[i] = TX_DEFAULT_SIGNAL_CLOCKS;
  162. }
  163. if (polarity == FALLING) {
  164. outPolarity = 0;
  165. } else {
  166. outPolarity = 1;
  167. }
  168. }
  169. bool PulsePositionOutput::begin(uint8_t txPin)
  170. {
  171. return begin(txPin, 255);
  172. }
  173. bool PulsePositionOutput::begin(uint8_t txPin, uint32_t _framePin)
  174. {
  175. #ifdef DEBUG_OUTPUT
  176. Serial.println(txPin);
  177. #endif
  178. for (idx_channel = 0; idx_channel < _hardware_count; idx_channel++) {
  179. if (hardware[idx_channel].pin == txPin) break;
  180. }
  181. if (idx_channel == _hardware_count) return false;
  182. // make sure the appropriate clock gate is enabled.
  183. *hardware[idx_channel].clock_gate_register |= hardware[idx_channel].clock_gate_mask;
  184. uint8_t channel = hardware[idx_channel].channel;
  185. volatile IMXRT_TMR_CH_t *tmr_ch = &hardware[idx_channel].tmr->CH[channel];
  186. tmr_ch->CTRL = 0; // stop
  187. tmr_ch->CNTR = 0;
  188. tmr_ch->LOAD = 0;
  189. //framePin = 2; // optional select a framePin
  190. if (_framePin < NUM_DIGITAL_PINS) {
  191. framePin = _framePin;
  192. pinMode(framePin,OUTPUT);
  193. digitalWriteFast(framePin,HIGH);
  194. }
  195. tmr_ch->COMP1 = 200; // first time
  196. state = 0;
  197. tmr_ch->CMPLD1 = TX_PULSE_WIDTH_CLOCKS;
  198. //TMR1_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_OPS to make falling
  199. if(outPolarity == 0){
  200. tmr_ch->SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS;
  201. } else {
  202. tmr_ch->SCTRL = TMR_SCTRL_OEN ;
  203. }
  204. tmr_ch->CSCTRL = TMR_CSCTRL_CL1(1);
  205. attachInterruptVector(hardware[idx_channel].interrupt, hardware[idx_channel].isr);
  206. tmr_ch->CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear
  207. tmr_ch->CSCTRL |= TMR_CSCTRL_TCF1EN; // enable interrupt
  208. NVIC_SET_PRIORITY(hardware[idx_channel].interrupt, 32);
  209. NVIC_ENABLE_IRQ(hardware[idx_channel].interrupt);
  210. tmr_ch->CTRL = CTRL_SET;
  211. list[idx_channel] = this;
  212. //set Mux for Tx Pin - all timers on ALT1
  213. *(portConfigRegister(txPin)) = 1;
  214. return true;
  215. }
  216. bool PulsePositionOutput::write(uint8_t channel, float microseconds)
  217. {
  218. uint32_t i, sum, space, clocks, num_channels;
  219. if (channel < 1 || channel > PULSEPOSITION_MAXCHANNELS) return false;
  220. if (microseconds < TX_MINIMUM_SIGNAL || microseconds > TX_MAXIMUM_SIGNAL) return false;
  221. clocks = microseconds * CLOCKS_PER_MICROSECOND;
  222. num_channels = total_channels;
  223. if (channel > num_channels) num_channels = channel;
  224. sum = clocks;
  225. for (i = 1; i < channel; i++) sum += pulse_width[i];
  226. for (i = channel + 1; i <= num_channels; i++) sum += pulse_width[i];
  227. if (sum < TX_MINIMUM_FRAME_CLOCKS - TX_MINIMUM_SPACE_CLOCKS) {
  228. space = TX_MINIMUM_FRAME_CLOCKS - sum;
  229. } else {
  230. if (framePin < NUM_DIGITAL_PINS) {
  231. space = TX_PULSE_WIDTH_CLOCKS;
  232. } else {
  233. space = TX_MINIMUM_SPACE_CLOCKS;
  234. }
  235. }
  236. __disable_irq();
  237. pulse_width[0] = space;
  238. pulse_width[channel] = clocks;
  239. total_channels = num_channels;
  240. __enable_irq();
  241. return true;
  242. }
  243. void PulsePositionOutput::isr()
  244. {
  245. DBGdigitalWriteFast(3, HIGH);
  246. uint8_t channel = hardware[idx_channel].channel;
  247. volatile IMXRT_TMR_CH_t *tmr_ch = &hardware[idx_channel].tmr->CH[channel];
  248. ticks++;
  249. // Clear out the Compare match interrupt.
  250. tmr_ch->CSCTRL &= ~(TMR_CSCTRL_TCF1);
  251. if (state == 0) {
  252. // pin was just set high, schedule it to go low
  253. tmr_ch->COMP1 = tmr_ch->CMPLD1 = TX_PULSE_WIDTH_CLOCKS;
  254. tmr_ch->CTRL = CTRL_CLEAR;
  255. state = 1;
  256. } else {
  257. // pin just went low
  258. uint32_t width, channel;
  259. if (state == 1) {
  260. channel = current_channel;
  261. if (channel == 0) {
  262. total_channels_buffer = total_channels;
  263. for (uint32_t i = 0; i <= total_channels_buffer; i++) {
  264. pulse_buffer[i] = pulse_width[i];
  265. }
  266. }
  267. width = pulse_buffer[channel] - TX_PULSE_WIDTH_CLOCKS;
  268. if (++channel > total_channels_buffer) {
  269. channel = 0;
  270. }
  271. if (framePin < NUM_DIGITAL_PINS) {
  272. if (channel == 1) {
  273. digitalWriteFast(framePin,HIGH);
  274. } else {
  275. digitalWriteFast(framePin,LOW);
  276. }
  277. }
  278. current_channel = channel;
  279. } else {
  280. width = pulse_remaining;
  281. }
  282. if (width <= 60000) {
  283. tmr_ch->COMP1 = tmr_ch->CMPLD1 = width;
  284. tmr_ch->CTRL = CTRL_SET; // set on compare match & interrupt
  285. state = 0;
  286. } else {
  287. tmr_ch->COMP1 =tmr_ch->CMPLD1 = 58000;
  288. tmr_ch->CTRL = CTRL_CLEAR; // clear on compare match & interrupt
  289. pulse_remaining = width - 58000;
  290. state = 2;
  291. }
  292. }
  293. DBGdigitalWriteFast(3, LOW);
  294. }
  295. //-----------------------------------------------------------------------------
  296. // PulsePositionOutput
  297. //-----------------------------------------------------------------------------
  298. PulsePositionInput::PulsePositionInput(void)
  299. {
  300. outPolarity = 1;
  301. }
  302. PulsePositionInput::PulsePositionInput(int polarity)
  303. {
  304. if (polarity == FALLING) {
  305. outPolarity = 0;
  306. } else {
  307. outPolarity = 1;
  308. }
  309. }
  310. bool PulsePositionInput::begin(uint8_t rxPin)
  311. {
  312. for (idx_channel = 0; idx_channel < _hardware_count; idx_channel++) {
  313. if (hardware[idx_channel].pin == rxPin) break;
  314. }
  315. if (idx_channel == _hardware_count) return false;
  316. // make sure the appropriate clock gate is enabled.
  317. *hardware[idx_channel].clock_gate_register |= hardware[idx_channel].clock_gate_mask;
  318. uint8_t channel = hardware[idx_channel].channel;
  319. volatile IMXRT_TMR_CH_t *tmr_ch = &hardware[idx_channel].tmr->CH[channel];
  320. tmr_ch->CTRL = 0; // stop
  321. tmr_ch->CNTR = 0;
  322. tmr_ch->LOAD = 0;
  323. tmr_ch->CSCTRL = 0;
  324. tmr_ch->LOAD = 0; // start val after compare
  325. tmr_ch->COMP1 = 0xffff; // count up to this val, interrupt, and start again
  326. tmr_ch->CMPLD1 = 0xffff;
  327. if(outPolarity == 0){
  328. tmr_ch->SCTRL = TMR_SCTRL_CAPTURE_MODE(1) | TMR_SCTRL_IPS; //falling
  329. } else {
  330. tmr_ch->SCTRL = TMR_SCTRL_CAPTURE_MODE(1); //rising
  331. }
  332. attachInterruptVector(hardware[idx_channel].interrupt, hardware[idx_channel].isr);
  333. #if 1
  334. // uses timer match condition.
  335. tmr_ch->SCTRL |= TMR_SCTRL_IEFIE; // enable compare interrupt as well as overflow
  336. tmr_ch->CSCTRL = TMR_CSCTRL_TCF1EN; // enable capture interrupt
  337. #else
  338. // tries to use overflow condition
  339. tmr_ch->SCTRL |= TMR_SCTRL_IEFIE | TMR_SCTRL_TOFIE; // enable compare interrupt as well as overflow
  340. // tmr_ch->CSCTRL = TMR_CSCTRL_TCF1EN; // enable capture interrupt
  341. #endif
  342. NVIC_SET_PRIORITY(hardware[idx_channel].interrupt, 32);
  343. NVIC_ENABLE_IRQ(hardware[idx_channel].interrupt);
  344. tmr_ch->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(channel) | TMR_CTRL_LENGTH ; // prescale
  345. //tmr_ch->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(channel) ; // prescale
  346. list[idx_channel] = this;
  347. #ifdef DEBUG_OUTPUT
  348. Serial.printf("PulsePositionInput::begin pin:%d idx: %d CH:%d SC:%x CSC:%x\n", rxPin, idx_channel, channel, tmr_ch->SCTRL, tmr_ch->CSCTRL); Serial.flush();
  349. //set Mux for Tx Pin - all timers on ALT1
  350. Serial.printf("Select Input Regster: %x %d\n", (uint32_t)hardware[idx_channel].select_input_register, hardware[idx_channel].select_val); Serial.flush();
  351. #endif
  352. if (hardware[idx_channel].select_input_register) {
  353. *hardware[idx_channel].select_input_register = hardware[idx_channel].select_val;
  354. #ifdef DEBUG_OUTPUT
  355. Serial.println("Select Input completed");Serial.flush();
  356. #endif
  357. }
  358. *(portConfigRegister(rxPin)) = 1 | 0x10;
  359. #ifdef DEBUG_OUTPUT
  360. Serial.printf(" CP1:%x CP2:%x CAPT:%x LOAD:%x \n", (uint16_t)tmr_ch->COMP1, (uint16_t)tmr_ch->COMP2,
  361. (uint16_t)tmr_ch->CAPT, (uint16_t)tmr_ch->LOAD);
  362. Serial.flush();
  363. Serial.printf(" HOLD:%x CNTR:%x CTRL:%x SCTRL:%x\n", (uint16_t)tmr_ch->HOLD, (uint16_t)tmr_ch->CNTR, (uint16_t)tmr_ch->CTRL, (uint32_t)tmr_ch->SCTRL);
  364. Serial.flush();
  365. Serial.printf(" CMPLD1:%x, CMPLD2:%x, FILT:%x DMA:%x ENBL:%x\n",tmr_ch->CMPLD1,
  366. tmr_ch->CMPLD2, tmr_ch->FILT, tmr_ch->DMA, tmr_ch->ENBL);
  367. Serial.flush();
  368. #endif
  369. return true;
  370. }
  371. int PulsePositionInput::available(void)
  372. {
  373. uint32_t total;
  374. bool flag;
  375. __disable_irq();
  376. flag = available_flag;
  377. total = total_channels;
  378. __enable_irq();
  379. if (flag) return total;
  380. return -1;
  381. }
  382. float PulsePositionInput::read(uint8_t channel)
  383. {
  384. uint32_t total, index, value=0;
  385. if (channel == 0) return 0.0;
  386. index = channel - 1;
  387. __disable_irq();
  388. total = total_channels;
  389. if (index < total) value = pulse_buffer[index];
  390. if (channel >= total) available_flag = false;
  391. __enable_irq();
  392. return (float)value / (float)CLOCKS_PER_MICROSECOND;
  393. }
  394. void PulsePositionInput::isr() { // capture and compare
  395. DBGdigitalWriteFast(4, HIGH);
  396. uint8_t channel = hardware[idx_channel].channel;
  397. volatile IMXRT_TMR_CH_t *tmr_ch = &hardware[idx_channel].tmr->CH[channel];
  398. #if 1
  399. // uses match
  400. // tries to use overflow
  401. if (tmr_ch->CSCTRL & TMR_CSCTRL_TCF1) { // compare rollover
  402. tmr_ch->CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear
  403. overflow_count++;
  404. overflow_inc = true;
  405. }
  406. #else
  407. // tries to use overflow
  408. if (tmr_ch->SCTRL & TMR_SCTRL_TOF) { // compare rollover
  409. tmr_ch->SCTRL &= ~(TMR_SCTRL_TOF); // clear
  410. overflow_count++;
  411. overflow_inc = true;
  412. }
  413. #endif
  414. if (tmr_ch->SCTRL & TMR_SCTRL_IEF) { // capture
  415. uint32_t val, count;
  416. tmr_ch->SCTRL &= ~(TMR_SCTRL_IEF); // clear
  417. val = tmr_ch->CAPT;
  418. count = overflow_count;
  419. if (val > 0xE000 && overflow_inc) count--;
  420. val |= (count << 16);
  421. count = val - prev;
  422. prev = val;
  423. if (count >= RX_MINIMUM_SPACE_CLOCKS) {
  424. if (write_index < 255) {
  425. for (int i = 0; i < write_index; i++) {
  426. pulse_buffer[i] = pulse_width[i];
  427. }
  428. total_channels = write_index;
  429. available_flag = true;
  430. }
  431. write_index = 0;
  432. } else {
  433. if (write_index < PULSEPOSITION_MAXCHANNELS) {
  434. pulse_width[write_index++] = count;
  435. }
  436. }
  437. }
  438. ticks++;
  439. asm volatile ("dsb"); // wait for clear memory barrier
  440. overflow_inc = false;
  441. DBGdigitalWriteFast(4, LOW);
  442. }
  443. #endif