Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Setup timer TC5 to trigger on input event and set time delay for TCC0 output pulse, (TCC1 test input)
- // Test output: D8, Input: D12, PWM Output: D2
- // Code tested on a M0 PRO
- // IMPORTANT: need to connect D8 and D12 physically !!!!
- void setup()
- {
- REG_GCLK_GENDIV = GCLK_GENDIV_DIV(120) | // Divide the 48MHz system clock GCLK5 by 120 = 0.4 MHz
- GCLK_GENDIV_ID(5); // Set division on Generic Clock Generator (GCLK) 5
- while (GCLK->STATUS.bit.SYNCBUSY);
- REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW ?
- GCLK_GENCTRL_GENEN | // Enable GCLK 5
- GCLK_GENCTRL_SRC_DFLL48M | // Set the clock source to 48MHz
- GCLK_GENCTRL_ID(5); // Set clock source on GCLK 5
- while (GCLK->STATUS.bit.SYNCBUSY);
- // Generic Clocks (GCLK) //////////////////////////////////////////////////////////////////////////////
- // For D2
- GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
- GCLK_CLKCTRL_GEN_GCLK5 | // Select the 48MHz GCLK0
- GCLK_CLKCTRL_ID_TCC0_TCC1; // Set GCLK0 as a clock source for TCC0 and TCC1
- while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
- // Internal delay
- GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
- GCLK_CLKCTRL_GEN_GCLK5 | // Select the 48MHz GCLK0
- GCLK_CLKCTRL_ID_TC4_TC5; // Set GCLK0 as a clock source for TC4 and TC5
- while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
- // Port Multiplexing //////////////////////////////////////////////////////////////////////////////////
- // Enable the port multiplexer D2, D8 and D12
- // D8 (inpout) ---> D12 ---> D2
- //PORT->Group[g_APinDescription[3].ulPort].PINCFG[g_APinDescription[3].ulPin].bit.PMUXEN = 1;
- PORT->Group[g_APinDescription[2].ulPort].PINCFG[g_APinDescription[2].ulPin].bit.PMUXEN = 1;
- PORT->Group[g_APinDescription[8].ulPort].PINCFG[g_APinDescription[8].ulPin].bit.PMUXEN = 1;
- PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;
- // Set-up the pin multiplexers
- //PORT->Group[g_APinDescription[3].ulPort].PMUX[g_APinDescription[3].ulPin >> 1].reg = PORT_PMUX_PMUXO_E;// | PORT_PMUX_PMUXE_E;
- PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
- PORT->Group[g_APinDescription[8].ulPort].PMUX[g_APinDescription[8].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;
- // Set-up the pin as an EIC (interrupt) peripheral on D12 (PA19) TCC0 WO[3]
- // D12 ----> interrupt 3
- 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;
- // External Interrupt Controller (EIC) (Input) ///////////////////////////////////////////////////////////
- // Input signal ---> interrupt 3
- EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO3; // Enable event output on external interrupt 3
- EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE3_HIGH; // Set event detecting a HIGH level
- EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3; // Clear the interrupt flag on channel 3
- EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Enable EIC peripheral
- while (EIC->STATUS.bit.SYNCBUSY); // Wait for synchronization
- // Event System /////////////////////////////////////////////////////////////////////////////////////////
- PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
- // REG_EVSYS_USER : gateway to the event system multiplexer
- // connect un cannal d'évènement à un périphérique comme un capteur
- // It's possible to write to this register multiple times to connect various event channels to different users.
- // Interrupt 3 is generated by D12. This code links Int3 and TC4 via channel 0
- // interrupt 3 -> channel 0
- EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
- EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
- EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_3) | // Set event generator (sender) as external interrupt 3
- EVSYS_CHANNEL_CHANNEL(0); // Attach the generator (sender) to channel 0
- // channel 0 ---> TC4
- EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Attach the event user (receiver) to channel 0 (n + 1)
- EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU); // Set the event user (receiver) as timer TC4 event
- /*
- // TC4 ---> channel 1
- EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
- EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
- EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_TC4_MCX_0) | // Set event generator (sender) as TC4 Match Compare channel 0
- EVSYS_CHANNEL_CHANNEL(1); // Attach the generator (sender) to channel 1
- // channel 1 --> TCC0
- EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) | // Attach the event user (receiver) to channel 1 (n + 1)
- EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event 1
- TC4->COUNT32.EVCTRL.reg |= TC_EVCTRL_MCEO0 | // Output/generate an event on Match Compare channel 0
- TC_EVCTRL_TCEI | // Enable the TC event input
- TC_EVCTRL_EVACT_RETRIGGER; // Set event to RETRIGGER timer TC4
- */
- // Links TC5 and TCC0 via channel 1
- // TC5 ---> channel 1
- EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | // No event edge detection
- EVSYS_CHANNEL_PATH_ASYNCHRONOUS | // Set event path as asynchronous
- EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_TC5_MCX_0) | // Set event generator (sender) as TC4 Match Compare channel 0
- EVSYS_CHANNEL_CHANNEL(1); // Attach the generator (sender) to channel 1
- // channel 1 --> TCC0
- EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) | // Attach the event user (receiver) to channel 1 (n + 1)
- EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event 1
- TC5->COUNT16.EVCTRL.reg |= TC_EVCTRL_MCEO0 | // Output/generate an event on Match Compare channel 0
- TC_EVCTRL_TCEI | // Enable the TC event input
- TC_EVCTRL_EVACT_RETRIGGER; // Set event to RETRIGGER timer TC5
- TCC0->EVCTRL.reg |= TCC_EVCTRL_TCEI0 | // Enable the TCC event 0 input
- TCC_EVCTRL_EVACT0_RETRIGGER; // Set event 0 to count the incoming events
- // FREQUENCY COUNTER
- REG_TC4_EVCTRL |= TC_EVCTRL_TCEI | // Enable the TC Event Input TCEI
- TC_EVCTRL_EVACT_PPW;
- // FREQUENCY COUNTER END
- // Timer TCC1 /////////////////////////////////////////////////////////
- // D8
- TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC1 timer counter to normal PWM mode (NPWM)
- while (TCC1->SYNCBUSY.bit.WAVE); // Wait for synchronization
- TCC1->CC[0].reg = 1; // Set duty cycle to 1 tic ( 20 us )
- while (TCC1->SYNCBUSY.bit.CC0); // Wait for synchronization
- TCC1->PER.reg = 4; // Set period to 5 tic ( 100 us )
- while (TCC1->SYNCBUSY.bit.PER); // Wait for synchronization
- REG_TCC1_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us per tic
- TC_CTRLA_MODE_COUNT16 |
- TCC_CTRLA_ENABLE;
- while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
- // Timer TC4 (Frequency counter) /////////////////////////////////////////////////////////////////////////////
- // FREQUENCY COUNTER
- REG_TC4_CTRLC |= TC_CTRLC_CPTEN1 | // Enable capture on CC1
- TC_CTRLC_CPTEN0; // Enable capture on CC0
- while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
- NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest)
- NVIC_EnableIRQ(TC4_IRQn); // Connect the TC3 timer to the Nested Vector Interrupt Controller (NVIC)
- REG_TC4_INTENSET = TC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
- TC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts
- REG_TC4_READREQ = TC_READREQ_RREQ |
- TC_READREQ_ADDR(REG_TC4_CTRLA);
- while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
- REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
- TC_CTRLA_MODE_COUNT16 |
- TC_CTRLA_ENABLE; // Enable TCC0
- while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization*/
- // FREQUENCY COUNTER END
- //TC4->COUNT32.CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ | // Set TC4 to normal frequency mode (NFRQ)
- // TC_CTRLA_MODE_COUNT32; // Enable 32-bit timer mode (in conjuction with TC5)
- //TC4->COUNT32.CC[0].reg = 97999; // Set the delay to 1ms
- //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
- //TC4->COUNT32.CTRLBSET.reg = TC_CTRLBSET_ONESHOT; // Enable oneshot operation
- //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
- //
- //TC4->COUNT32.CTRLA.bit.ENABLE = 1; // Enable TC4
- //while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
- // Timer TC5 (Delay Timer) ////////////////////////////////////////////////////////////////////////////
- TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ | // Set TC4 to normal frequency mode (NFRQ)
- TC_CTRLA_MODE_COUNT16; // Enable 16-bit timer mode
- TC5->COUNT16.CC[0].reg = 1; // Set the delay to 1 tic ( 20 us )
- while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
- TC5->COUNT16.CTRLBSET.reg |= TC_CTRLBSET_ONESHOT; // Enable oneshot operation
- while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
- REG_TC5_CTRLA |= TC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
- TC_CTRLA_MODE_COUNT16 |
- TC_CTRLA_ENABLE; // Enable TC5
- while (TC5->COUNT16.STATUS.bit.SYNCBUSY);
- // Timer TCC0 (PWM Output) /////////////////////////////////////////////////////////////////////////////////
- // D2 output
- TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Set the TCC0 timer counter to normal PWM mode (NPWM)
- while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
- TCC0->CC[0].reg = 1; // Set duty cycle 100%. 1 tic = 20 us
- while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization
- TCC0->PER.reg = 2; // Set period to 20 us
- while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
- TCC0->CTRLBSET.reg |= TCC_CTRLBSET_ONESHOT; // Enable oneshot operation
- while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
- TCC0->DRVCTRL.reg |= TCC_DRVCTRL_NRE1; // Set the non-recoverable state output to 0 when inactive ???
- REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Set prescaler to 8, 0.4MHz DIV8 -> 50 000 Hz = 20 us par tic
- TC_CTRLA_MODE_COUNT16 |
- TCC_CTRLA_ENABLE; // Enable TCC0
- while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
- }
- volatile long periodInTic = 0;
- unsigned long t = 0;
- void loop() {
- unsigned long t1 = micros();
- if(t1 - t > 1000000) // 1 s
- {
- t = t1;
- SerialUSB.println(TC4->COUNT16.COUNT.reg); // Period in tics. Should output 5 ( 100 us )
- }
- // Test with no delay
- /*if (TCC0->STATUS.bit.STOP) // Check if the previous pulse is complete
- {
- TCC0->CTRLBSET.reg |= TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
- while (TCC0->SYNCBUSY.bit.CTRLB);
- }*/
- }
- // FREQUENCY COUNTER
- void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
- {
- // Check for match counter 0 (MC0) interrupt
- if (TC4->COUNT16.INTFLAG.bit.MC0)
- {
- REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
- TC_READREQ_ADDR(REG_TC4_COUNT16_CC0);
- while (TC4->COUNT16.STATUS.bit.SYNCBUSY);
- periodInTic = REG_TC4_COUNT16_CC0;
- // Retrigger delay timer wich will trigger TCC0
- if (TC5->COUNT16.STATUS.bit.STOP) // Check if the previous pulse is complete
- {
- TC5->COUNT16.CTRLBSET.reg |= TC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
- while (TC5->COUNT16.STATUS.bit.SYNCBUSY);
- }
- /*
- // Test with no delay
- if (TCC0->STATUS.bit.STOP) // Check if the previous pulse is complete
- {
- TCC0->CTRLBSET.reg |= TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger the timer's One/Multi-Shot pulse
- while (TCC0->SYNCBUSY.bit.CTRLB);
- }*/
- }
- // Check for match counter 1 (MC1) interrupt
- if (TC4->COUNT16.INTFLAG.bit.MC1)
- {
- REG_TC4_READREQ = TC_READREQ_RREQ | // Enable a read request
- TC_READREQ_ADDR(REG_TC4_COUNT16_CC1);
- while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for (read) synchronization
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement