As the title mention, I try to combine several timers/counters on Arduino Zero, this is what I have working so far:
- Oneshot counter (GCLK_CLKCTRL_ID_TCC0_TCC1)
- 50us timer ISR (GCLK_CLKCTRL_ID_TC4_TC5)
- 100us timer ISR (GCLK_CLKCTRL_ID_TCC2_TC3)
The oneshot timer:
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
////////////////////////////////////////////////////////////////////////////////////////
// Genric Clock Initialisation
////////////////////////////////////////////////////////////////////////////////////////
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable the generic clock...
GCLK_CLKCTRL_GEN_GCLK0 | // ....on GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed the GCLK0 to TCC0 and TCC1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
////////////////////////////////////////////////////////////////////////////////////////
// TCC0 Initialisation - output 10us oneshot pulse upon receiving an event on PA22
////////////////////////////////////////////////////////////////////////////////////////
// Enable the port multiplexer on port pin PA22
PORT->Group[PORTA].PINCFG[22].bit.PMUXEN = 1;
// Set-up the pin as TCC0/WO[4] peripheral on PA22
PORT->Group[PORTA].PMUX[22 >> 1].reg |= PORT_PMUX_PMUXE_F;
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Set the TCC0 timer to normal PWM mode (NPWM)
while(TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
TCC0->PER.reg = 96; // Set the period (PER) register for oneshot pulse width
while(TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
TCC0->CC[0].reg = 48; // Set the counter compare 0 (CC0) register for a pulse width of 1us
while(TCC0->SYNCBUSY.bit.CC0); // 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_NRE4; // Activate the Non Recoverable Fault Enable to drive pin low after oneshot
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Event System Initialisation - set up to allow TCC0 to receive incoming pulses on PA18
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Enable the port multiplexer on port pin PA18
PORT->Group[PORTA].PINCFG[18].bit.PMUXEN = 1;
// Set-up the pin as an EIC (interrupt) peripheral on PA18
PORT->Group[PORTA].PMUX[18 >> 1].reg |= PORT_PMUX_PMUXE_A;
//EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO2; // Enable event output on external interrupt 3
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE2_FALL; // Set event detecting a FALLING edge
//EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT2; // Disable interrupts on external interrupt 3
EIC->CTRL.reg |= EIC_CTRL_ENABLE; // Enable EIC peripheral
while (EIC->STATUS.bit.SYNCBUSY); // Wait for synchronization
EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) | // Attach the event user (receiver) to channel 0 (n + 1)
EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_0); // Set the event user (receiver) as timer TCC0, event 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_2) | // Set event generator (sender) as external interrupt 2
EVSYS_CHANNEL_CHANNEL(0); // Attach the generator (sender) to channel 0
TCC0->EVCTRL.reg |= TCC_EVCTRL_TCEI0 | // Enable TCC0 event 0 inputs
TCC_EVCTRL_EVACT0_RETRIGGER; // Retrigger timer TCC0 on receiving event
TCC0->CTRLA.bit.ENABLE = 1; // Enable TCC0 by default!
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
The 50us timer:
// Set up the generic clock (GCLK4) used to clock timers
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK4 to TC4 and TC5
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK4 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_COUNT16_CC0 = 0x12C0; // Set the TC4 CC0 register as the TOP value in match frequency mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
//NVIC_DisableIRQ(TC4_IRQn);
//NVIC_ClearPendingIRQ(TC4_IRQn);
NVIC_SetPriority(TC4_IRQn, 1); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)
REG_TC4_INTFLAG |= TC_INTFLAG_OVF; // Clear the interrupt flags
REG_TC4_INTENSET = TC_INTENSET_OVF; // Enable TC4 interrupts
// REG_TC4_INTENCLR = TC_INTENCLR_OVF; // Disable TC4 interrupts
REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 48MHz/1024 = 46.875kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC4 into match frequency (MFRQ) mode
TC_CTRLA_ENABLE; // Enable TC4
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
//code
}
The 100us timer:
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable the generic clock...
GCLK_CLKCTRL_GEN_GCLK0 | // ....on GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TCC2_TC3; // Feed the GCLK0 to TCC2 and TC3
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC3_COUNT16_CC0 = 0x12C0; // Set the TC3 CC0 register as the TOP value in match frequency mode
while (TC3->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
//NVIC_DisableIRQ(TC4_IRQn);
//NVIC_ClearPendingIRQ(TC4_IRQn);
NVIC_SetPriority(TC3_IRQn, 2); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 1 (medium)
NVIC_EnableIRQ(TC3_IRQn); // Connect TC3 to Nested Vector Interrupt Controller (NVIC)
REG_TC3_INTFLAG |= TC_INTFLAG_OVF; // Clear the interrupt flags
REG_TC3_INTENSET = TC_INTENSET_OVF; // Enable TC3 interrupts
// REG_TC3_INTENCLR = TC_INTENCLR_OVF; // Disable TC3 interrupts
REG_TC3_CTRLA |= TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 48MHz/1024 = 46.875kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC3 into match frequency (MFRQ) mode
TC_CTRLA_ENABLE; // Enable TC3
while (TC3->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
void TC3_Handler() // Interrupt Service Routine (ISR) for timer TC3
{
// code
}
Now, as an addition to the already implemented timers, I would like to have a pulse counter as described here: Link!
Is this possible at TC5 for instance? I would like to have a hardware pulse counter to determine the frequency of digital input: D10, this digital input is also used in the oneshot timer. The input signal will have freq around the 50KHz.