Advertisement
Guest User

Untitled

a guest
Apr 5th, 2020
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.96 KB | None | 0 0
  1. // Setup timer TC5 to trigger on input event and set time delay for TCC0 output pulse, (TCC1 test input)
  2. // Test output: D8, Input: D12, PWM Output: D2
  3. // Code tested on a M0 PRO
  4.  
  5. // IMPORTANT: need to connect D8 and D12 physically !!!!
  6.  
  7. void setup()
  8. {
  9. REG_GCLK_GENDIV = GCLK_GENDIV_DIV(120) | // Divide the 48MHz system clock GCLK5 by 120 = 0.4 MHz
  10. GCLK_GENDIV_ID(5); // Set division on Generic Clock Generator (GCLK) 5
  11. while (GCLK->STATUS.bit.SYNCBUSY);
  12.  
  13. REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW ?
  14. GCLK_GENCTRL_GENEN | // Enable GCLK 5
  15. GCLK_GENCTRL_SRC_DFLL48M | // Set the clock source to 48MHz
  16. GCLK_GENCTRL_ID(5); // Set clock source on GCLK 5
  17. while (GCLK->STATUS.bit.SYNCBUSY);
  18.  
  19. // Generic Clocks (GCLK) //////////////////////////////////////////////////////////////////////////////
  20. // For D2
  21. GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
  22. GCLK_CLKCTRL_GEN_GCLK5 | // Select the 48MHz GCLK0
  23. GCLK_CLKCTRL_ID_TCC0_TCC1; // Set GCLK0 as a clock source for TCC0 and TCC1
  24. while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
  25.  
  26. // Internal delay
  27. GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
  28. GCLK_CLKCTRL_GEN_GCLK5 | // Select the 48MHz GCLK0
  29. GCLK_CLKCTRL_ID_TC4_TC5; // Set GCLK0 as a clock source for TC4 and TC5
  30. while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
  31.  
  32. // Port Multiplexing //////////////////////////////////////////////////////////////////////////////////
  33.  
  34. // Enable the port multiplexer D2, D8 and D12
  35. // D8 (inpout) ---> D12 ---> D2
  36. PORT->Group[g_APinDescription[2].ulPort].PINCFG[g_APinDescription[2].ulPin].bit.PMUXEN = 1;
  37. PORT->Group[g_APinDescription[8].ulPort].PINCFG[g_APinDescription[8].ulPin].bit.PMUXEN = 1;
  38. PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;
  39.  
  40. // Set-up the pin multiplexers
  41. PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
  42. PORT->Group[g_APinDescription[8].ulPort].PMUX[g_APinDescription[8].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
  43. // Set-up the pin as an EIC (interrupt) peripheral on D12 (PA19) TCC0 WO[3]
  44. // D12 ----> interrupt 3
  45. PORT->Group[g_APinDescription[12].ulPort].PMUX[g_APinDescription[12].ulPin >> 1].reg |= PORT_PMUX_PMUXO_A;
  46.  
  47. // External Interrupt Controller (EIC) (Input) ///////////////////////////////////////////////////////////
  48. // Input signal ---> interrupt 3
  49. EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO3; // Enable event output on external interrupt 3
  50. EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE3_HIGH; // Set event detecting a HIGH level
  51. EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3; // Clear the interrupt flag on channel 3
  52. EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Enable EIC peripheral
  53. while (EIC->STATUS.bit.SYNCBUSY); // Wait for synchronization
  54.  
  55. // Event System /////////////////////////////////////////////////////////////////////////////////////////
  56.  
  57. PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
  58.  
  59. // REG_EVSYS_USER : gateway to the event system multiplexer
  60. // It's possible to write to this register multiple times to connect various event channels to different users.
  61.  
  62. // Interrupt 3 is generated by D12. This code links Int3 and TC4 via channel 0
  63. // interrupt 3 -> channel 0
  64. EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
  65. EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
  66. EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_3) | // Set event generator (sender) as external interrupt 3
  67. EVSYS_CHANNEL_CHANNEL(0); // Attach the generator (sender) to channel 0
  68.  
  69. // channel 0 ---> TC4
  70. EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Attach the event user (receiver) to channel 0 (n + 1)
  71. EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU); // Set the event user (receiver) as timer TC4 event
  72.  
  73. // channel 0 ---> TC5
  74. EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Attach the event user (receiver) to channel 0 (n + 1)
  75. EVSYS_USER_USER(EVSYS_ID_USER_TC5_EVU); // Set the event user (receiver) as timer TC4 event
  76.  
  77. #if 1 // link TC5 and TCC0 together
  78. // TC5 -> channel 1
  79. EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
  80. EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
  81. EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_TC5_MCX_0) | // Set event generator (sender) as TC4 Match Compare channel 0
  82. EVSYS_CHANNEL_CHANNEL(1); // Attach the generator (sender) to channel 1
  83.  
  84. TC5->COUNT32.EVCTRL.reg |= TC_EVCTRL_MCEO0 | // Output event on Match Compare channel 0
  85. TC_EVCTRL_TCEI | // Enable the TC event input
  86. TC_EVCTRL_EVACT_RETRIGGER; // Set event to RETRIGGER timer TC4
  87.  
  88. TCC0->EVCTRL.reg |= TCC_EVCTRL_TCEI0 | // Enable the TCC event 0 input
  89. TCC_EVCTRL_EVACT0_RETRIGGER; // Set event 0 to count the incoming events
  90.  
  91. // channekl 1 -> TCC0
  92. EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) | // Attach the event user (receiver) to channel 1 (n + 1)
  93. EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event
  94.  
  95. TCC0->CTRLBSET.reg = TCC_CTRLBSET_ONESHOT; // Enable oneshot operation
  96. while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
  97.  
  98. //TCC0->DRVCTRL.reg |= TCC_DRVCTRL_NRE1; // Set the non-recoverable state output to 0 when inactive
  99. #endif
  100.  
  101. // FREQUENCY COUNTER
  102. REG_TC4_EVCTRL |= TC_EVCTRL_TCEI | // Enable the TC Event Input TCEI
  103. TC_EVCTRL_EVACT_PPW;
  104.  
  105. // FREQUENCY COUNTER END
  106.  
  107. // Timer TCC1 /////////////////////////////////////////////////////////
  108. // D8
  109. TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC1 timer counter to normal PWM mode (NPWM)
  110. while (TCC1->SYNCBUSY.bit.WAVE); // Wait for synchronization
  111.  
  112. TCC1->CC[0].reg = 1; // Set duty cycle to 1 tic ( 20 us )
  113. while (TCC1->SYNCBUSY.bit.CC0); // Wait for synchronization
  114.  
  115. TCC1->PER.reg = 4; // Set period to 5 tic ( 100 us )
  116. while (TCC1->SYNCBUSY.bit.PER); // Wait for synchronization
  117.  
  118. REG_TCC1_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us per tic
  119. TC_CTRLA_MODE_COUNT16 |
  120. TCC_CTRLA_ENABLE;
  121. while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
  122.  
  123. #if 1
  124. // Timer TC4 (Frequency counter) /////////////////////////////////////////////////////////////////////////////
  125. REG_TC4_CTRLC |= TC_CTRLC_CPTEN1 | // Enable capture on CC1
  126. TC_CTRLC_CPTEN0; // Enable capture on CC0
  127. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  128.  
  129. NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest)
  130. NVIC_EnableIRQ(TC4_IRQn); // Connect the TC3 timer to the Nested Vector Interrupt Controller (NVIC)
  131.  
  132. REG_TC4_INTENSET = TC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
  133. TC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts
  134.  
  135. REG_TC4_READREQ = TC_READREQ_RREQ |
  136. TC_READREQ_ADDR(REG_TC4_CTRLA);
  137. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  138.  
  139. REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
  140. TC_CTRLA_MODE_COUNT16 |
  141. TC_CTRLA_ENABLE; // Enable TCC0
  142. while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization*/
  143. #endif
  144.  
  145. #if 1
  146. // Timer TC5 (Delay Timer) ////////////////////////////////////////////////////////////////////////////
  147. TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ | // Set TC4 to normal frequency mode (NFRQ)
  148. TC_CTRLA_MODE_COUNT16; // Enable 32-bit timer mode (in conjuction with TC5)
  149.  
  150. TC5->COUNT16.CC[0].reg = 0; // Set the delay to 1ms
  151. while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
  152.  
  153. TC5->COUNT16.CTRLBSET.reg = TC_CTRLBSET_ONESHOT; // Enable oneshot operation
  154. while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
  155.  
  156. REG_TC5_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
  157. TC_CTRLA_ENABLE;
  158. while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
  159. #endif
  160.  
  161. // Timer TCC0 (PWM Output) /////////////////////////////////////////////////////////////////////////////////
  162. TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC0 timer counter to normal PWM mode (NPWM)
  163. while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
  164.  
  165. // CC0 is D2
  166. // 8 tics because prescaler on TCC0 breaks the code on TCC0 ... ????
  167. TCC0->CC[0].reg = 8; // Set duty cycle 100% with 1ms pulse on channel 1
  168. while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization
  169.  
  170. TCC0->PER.reg = 8; // Set period to 1ms
  171. while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
  172.  
  173. //REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | TCC_CTRLA_ENABLE; // DOES NOT WORK ??
  174.  
  175. TCC0->CTRLA.bit.ENABLE = 1; // Enable TCC0
  176. while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
  177. }
  178.  
  179. void reTriggerTCC0WithNoDelay() {
  180. if (TCC0->STATUS.bit.STOP) // Check if the previous pulse is complete
  181. {
  182. TCC0->CTRLBSET.reg |= TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
  183. while (TCC0->SYNCBUSY.bit.CTRLB);
  184. }
  185. }
  186.  
  187. volatile long periodInTic = 0;
  188. unsigned long t = 0;
  189. void loop() {
  190. unsigned long t1 = micros();
  191. if(t1 - t > 1000000) // 1 s
  192. {
  193. t = t1;
  194. SerialUSB.println(TC4->COUNT16.COUNT.reg); // Period in tics. Should output 5 ( 100 us )
  195. }
  196.  
  197. //reTriggerTCC0WithNoDelay();
  198. }
  199.  
  200. // FREQUENCY COUNTER
  201. void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
  202. {
  203. // Check for match counter 0 (MC0) interrupt
  204. if (TC4->COUNT16.INTFLAG.bit.MC0)
  205. {
  206. REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
  207. TC_READREQ_ADDR(REG_TC4_COUNT16_CC0);
  208. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  209. periodInTic = REG_TC4_COUNT16_CC0;
  210. }
  211.  
  212. // Check for match counter 1 (MC1) interrupt
  213. if (TC4->COUNT16.INTFLAG.bit.MC1)
  214. {
  215. REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
  216. TC_READREQ_ADDR(REG_TC4_COUNT16_CC1);
  217. while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for (read) synchronization
  218. }
  219. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement