Advertisement
Guest User

Untitled

a guest
Apr 4th, 2020
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.47 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[3].ulPort].PINCFG[g_APinDescription[3].ulPin].bit.PMUXEN = 1;
  37. PORT->Group[g_APinDescription[2].ulPort].PINCFG[g_APinDescription[2].ulPin].bit.PMUXEN = 1;
  38. PORT->Group[g_APinDescription[8].ulPort].PINCFG[g_APinDescription[8].ulPin].bit.PMUXEN = 1;
  39. PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;
  40.  
  41. // Set-up the pin multiplexers
  42. //PORT->Group[g_APinDescription[3].ulPort].PMUX[g_APinDescription[3].ulPin >> 1].reg = PORT_PMUX_PMUXO_E;// | PORT_PMUX_PMUXE_E;
  43. PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
  44. PORT->Group[g_APinDescription[8].ulPort].PMUX[g_APinDescription[8].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
  45. // Set-up the pin as an EIC (interrupt) peripheral on D12 (PA19) TCC0 WO[3]
  46. // D12 ----> interrupt 3
  47. PORT->Group[g_APinDescription[12].ulPort].PMUX[g_APinDescription[12].ulPin >> 1].reg |= PORT_PMUX_PMUXO_A;//PORT_PMUX_PMUXE_E|PORT_PMUX_PMUXO_E ;//PORT_PMUX_PMUXO_A;
  48.  
  49. // External Interrupt Controller (EIC) (Input) ///////////////////////////////////////////////////////////
  50. // Input signal ---> interrupt 3
  51. EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO3; // Enable event output on external interrupt 3
  52. EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE3_HIGH; // Set event detecting a HIGH level
  53. EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3; // Clear the interrupt flag on channel 3
  54. EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Enable EIC peripheral
  55. while (EIC->STATUS.bit.SYNCBUSY); // Wait for synchronization
  56.  
  57. // Event System /////////////////////////////////////////////////////////////////////////////////////////
  58.  
  59. PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
  60.  
  61. // REG_EVSYS_USER : gateway to the event system multiplexer
  62. // connect un cannal d'évènement à un périphérique comme un capteur
  63. // It's possible to write to this register multiple times to connect various event channels to different users.
  64.  
  65. // Interrupt 3 is generated by D12. This code links Int3 and TC4 via channel 0
  66. // interrupt 3 -> channel 0
  67. EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
  68. EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
  69. EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_3) | // Set event generator (sender) as external interrupt 3
  70. EVSYS_CHANNEL_CHANNEL(0); // Attach the generator (sender) to channel 0
  71.  
  72. // channel 0 ---> TC4
  73. EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Attach the event user (receiver) to channel 0 (n + 1)
  74. EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU); // Set the event user (receiver) as timer TC4 event
  75.  
  76. /*
  77. // TC4 ---> channel 1
  78. EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
  79. EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
  80. EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_TC4_MCX_0) | // Set event generator (sender) as TC4 Match Compare channel 0
  81. EVSYS_CHANNEL_CHANNEL(1); // Attach the generator (sender) to channel 1
  82.  
  83. // channel 1 --> TCC0
  84. EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) | // Attach the event user (receiver) to channel 1 (n + 1)
  85. EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event 1
  86.  
  87. TC4->COUNT32.EVCTRL.reg |= TC_EVCTRL_MCEO0 | // Output/generate an event on Match Compare channel 0
  88. TC_EVCTRL_TCEI | // Enable the TC event input
  89. TC_EVCTRL_EVACT_RETRIGGER; // Set event to RETRIGGER timer TC4
  90. */
  91. // Links TC5 and TCC0 via channel 1
  92. // TC5 ---> channel 1
  93. EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
  94. EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
  95. EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_TC5_MCX_0) | // Set event generator (sender) as TC4 Match Compare channel 0
  96. EVSYS_CHANNEL_CHANNEL(1); // Attach the generator (sender) to channel 1
  97.  
  98. // channel 1 --> TCC0
  99. EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) | // Attach the event user (receiver) to channel 1 (n + 1)
  100. EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event 1
  101.  
  102. TC5->COUNT16.EVCTRL.reg |= TC_EVCTRL_MCEO0 | // Output/generate an event on Match Compare channel 0
  103. TC_EVCTRL_TCEI | // Enable the TC event input
  104. TC_EVCTRL_EVACT_RETRIGGER; // Set event to RETRIGGER timer TC5
  105.  
  106. TCC0->EVCTRL.reg |= TCC_EVCTRL_TCEI0 | // Enable the TCC event 0 input
  107. TCC_EVCTRL_EVACT0_RETRIGGER; // Set event 0 to count the incoming events
  108.  
  109. // FREQUENCY COUNTER
  110. REG_TC4_EVCTRL |= TC_EVCTRL_TCEI | // Enable the TC Event Input TCEI
  111. TC_EVCTRL_EVACT_PPW;
  112.  
  113. // FREQUENCY COUNTER END
  114.  
  115. // Timer TCC1 /////////////////////////////////////////////////////////
  116. // D8
  117. TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC1 timer counter to normal PWM mode (NPWM)
  118. while (TCC1->SYNCBUSY.bit.WAVE); // Wait for synchronization
  119.  
  120. TCC1->CC[0].reg = 1; // Set duty cycle to 1 tic ( 20 us )
  121. while (TCC1->SYNCBUSY.bit.CC0); // Wait for synchronization
  122.  
  123. TCC1->PER.reg = 4; // Set period to 5 tic ( 100 us )
  124. while (TCC1->SYNCBUSY.bit.PER); // Wait for synchronization
  125.  
  126. REG_TCC1_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us per tic
  127. TC_CTRLA_MODE_COUNT16 |
  128. TCC_CTRLA_ENABLE;
  129. while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
  130.  
  131. // Timer TC4 (Frequency counter) /////////////////////////////////////////////////////////////////////////////
  132. // FREQUENCY COUNTER
  133. REG_TC4_CTRLC |= TC_CTRLC_CPTEN1 | // Enable capture on CC1
  134. TC_CTRLC_CPTEN0; // Enable capture on CC0
  135. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  136.  
  137. NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest)
  138. NVIC_EnableIRQ(TC4_IRQn); // Connect the TC3 timer to the Nested Vector Interrupt Controller (NVIC)
  139.  
  140. REG_TC4_INTENSET = TC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
  141. TC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts
  142.  
  143. REG_TC4_READREQ = TC_READREQ_RREQ |
  144. TC_READREQ_ADDR(REG_TC4_CTRLA);
  145. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  146.  
  147. REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
  148. TC_CTRLA_MODE_COUNT16 |
  149. TC_CTRLA_ENABLE; // Enable TCC0
  150. while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization*/
  151. // FREQUENCY COUNTER END
  152.  
  153. //TC4->COUNT32.CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ | // Set TC4 to normal frequency mode (NFRQ)
  154. // TC_CTRLA_MODE_COUNT32; // Enable 32-bit timer mode (in conjuction with TC5)
  155.  
  156. //TC4->COUNT32.CC[0].reg = 97999; // Set the delay to 1ms
  157. //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
  158.  
  159. //TC4->COUNT32.CTRLBSET.reg = TC_CTRLBSET_ONESHOT; // Enable oneshot operation
  160. //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
  161. //
  162. //TC4->COUNT32.CTRLA.bit.ENABLE = 1; // Enable TC4
  163. //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
  164.  
  165.  
  166. // Timer TC5 (Delay Timer) ////////////////////////////////////////////////////////////////////////////
  167. TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ | // Set TC4 to normal frequency mode (NFRQ)
  168. TC_CTRLA_MODE_COUNT16; // Enable 16-bit timer mode
  169.  
  170. TC5->COUNT16.CC[0].reg = 1; // Set the delay to 1 tic ( 20 us )
  171. while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
  172.  
  173. TC5->COUNT16.CTRLBSET.reg |= TC_CTRLBSET_ONESHOT; // Enable oneshot operation
  174. while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
  175.  
  176. REG_TC5_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
  177. TC_CTRLA_MODE_COUNT16 |
  178. TC_CTRLA_ENABLE; // Enable TC5
  179. while (TC5->COUNT16.STATUS.bit.SYNCBUSY);
  180.  
  181.  
  182. // Timer TCC0 (PWM Output) /////////////////////////////////////////////////////////////////////////////////
  183. // D2 output
  184. TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC0 timer counter to normal PWM mode (NPWM)
  185. while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
  186.  
  187. TCC0->CC[0].reg = 1; // Set duty cycle 100%. 1 tic = 20 us
  188. while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization
  189.  
  190. TCC0->PER.reg = 2; // Set period to 20 us
  191. while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
  192.  
  193. TCC0->CTRLBSET.reg |= TCC_CTRLBSET_ONESHOT; // Enable oneshot operation
  194. while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
  195.  
  196. TCC0->DRVCTRL.reg |= TCC_DRVCTRL_NRE1; // Set the non-recoverable state output to 0 when inactive ???
  197.  
  198. REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
  199. TC_CTRLA_MODE_COUNT16 |
  200. TCC_CTRLA_ENABLE; // Enable TCC0
  201. while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
  202. }
  203.  
  204. volatile long periodInTic = 0;
  205. unsigned long t = 0;
  206. void loop() {
  207. unsigned long t1 = micros();
  208. if(t1 - t > 1000000) // 1 s
  209. {
  210. t = t1;
  211. SerialUSB.println(TC4->COUNT16.COUNT.reg); // Period in tics. Should output 5 ( 100 us )
  212. }
  213.  
  214. // Test with no delay
  215. /*if (TCC0->STATUS.bit.STOP) // Check if the previous pulse is complete
  216. {
  217. TCC0->CTRLBSET.reg |= TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
  218. while (TCC0->SYNCBUSY.bit.CTRLB);
  219. }*/
  220. }
  221.  
  222. // FREQUENCY COUNTER
  223. void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
  224. {
  225. // Check for match counter 0 (MC0) interrupt
  226. if (TC4->COUNT16.INTFLAG.bit.MC0)
  227. {
  228. REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
  229. TC_READREQ_ADDR(REG_TC4_COUNT16_CC0);
  230. while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
  231. periodInTic = REG_TC4_COUNT16_CC0;
  232.  
  233. // Retrigger delay timer wich will trigger TCC0
  234. if (TC5->COUNT16.STATUS.bit.STOP) // Check if the previous pulse is complete
  235. {
  236. TC5->COUNT16.CTRLBSET.reg |= TC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
  237. while (TC5->COUNT16.STATUS.bit.SYNCBUSY);
  238. }
  239. /*
  240. // Test with no delay
  241. if (TCC0->STATUS.bit.STOP) // Check if the previous pulse is complete
  242. {
  243. TCC0->CTRLBSET.reg |= TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
  244. while (TCC0->SYNCBUSY.bit.CTRLB);
  245. }*/
  246. }
  247.  
  248. // Check for match counter 1 (MC1) interrupt
  249. if (TC4->COUNT16.INTFLAG.bit.MC1)
  250. {
  251. REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
  252. TC_READREQ_ADDR(REG_TC4_COUNT16_CC1);
  253. while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for (read) synchronization
  254. }
  255. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement