I'm trying to detect the oscillation frequency of an LC tank.
Code is based on the ingenious work of MartinL : D1 outputs a fixed PWM that triggers the A2 pin interrupt and the ISR captures the TC4 count from D6.
The problem is that if my tank oscillates over 150/160 khz the counter starts acting funny and counts down to zero and then stops.
[....]
Frequency = 85325 Hz
Frequency = 84850 Hz
Frequency = 83725 Hz
Frequency = 83350 Hz
Frequency = 83125 Hz
Frequency = 83850 Hz
Frequency = 81600 Hz
Frequency = 81950 Hz
Frequency = 83425 Hz
Frequency = 81900 Hz
Frequency = 73450 Hz
Frequency = 82375 Hz
Frequency = 79900 Hz
Frequency = 81975 Hz
Frequency = 77400 Hz
Frequency = 80050 Hz
Frequency = 77925 Hz
Frequency = 82150 Hz
Frequency = 77800 Hz
Frequency = 77025 Hz
Frequency = 74775 Hz
Frequency = 77575 Hz
Frequency = 76900 Hz
Frequency = 70650 Hz
Frequency = 70975 Hz
Frequency = 65950 Hz
Frequency = 69650 Hz
[...]
Frequency = 65250 Hz
Frequency = 55275 Hz
[...]
Frequency = 45725 Hz
Frequency = 37100 Hz
Frequency = 26800 Hz
Frequency = 47250 Hz
Frequency = 40600 Hz
Frequency = 36975 Hz
Frequency = 36950 Hz
Frequency = 23250 Hz
Frequency = 50075 Hz
[...]
Frequency = 29225 Hz
[...]
Frequency = 0 Hz
Frequency = 0 Hz
Frequency = 0 Hz
Code is the following :
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) | // Divide the 48MHz system clock by 3 = 16MHz
GCLK_GENDIV_ID(4); // Set division on Generic Clock Generator (GCLK) 4
GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK 4
GCLK_GENCTRL_SRC_DFLL48M | // Set the clock source to 48MHz
GCLK_GENCTRL_ID(4); // Set clock source on GCLK 4
while (GCLK->STATUS.bit.SYNCBUSY)
; // Wait for synchronization
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Route GCLK4 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK4 | // GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TC4_TC5;
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Route GCLK4 to TCC0 and TCC1
GCLK_CLKCTRL_GEN_GCLK4 |
GCLK_CLKCTRL_ID_TCC0_TCC1;
while (GCLK->STATUS.bit.SYNCBUSY)
; // Wait for synchronization
// Enable the port multiplexer on digital pin D1
PORT->Group[PORTA].PINCFG[23].bit.PMUXEN = 1;
// Set-up the pin as an TCC0 PWM output on D1
PORT->Group[PORTA].PMUX[23 >> 1].reg |= PORT_PMUX_PMUXO_F;
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Enable Normal PWM (NPWM) mode
while (TCC0->SYNCBUSY.bit.WAVE)
; // Wait for synchronization
TCC0->PER.reg = 19999;
while (TCC0->SYNCBUSY.bit.PER)
; // Wait for synchronization
TCC0->CC[1].reg = 5000;
while (TCC0->SYNCBUSY.bit.CC1)
; // Wait for synchronization
TCC0->CTRLA.reg = TCC_CTRLA_PRESCSYNC_PRESC | // Reload timer on the next prescaler clock
TCC_CTRLA_PRESCALER_DIV16; // Set prescaler to 16, 16MHz/16 = 1MHz
TCC0->CTRLA.bit.ENABLE = 1; // Enable timer TCC0
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
// Enable the port multiplexer on digital pin D6
PORT->Group[PORTA].PINCFG[20].bit.PMUXEN = 1;
// Set-up the pin as an EIC (interrupt) peripheral on D6
PORT->Group[PORTA].PMUX[20 >> 1].reg |= PORT_PMUX_PMUXE_A;
EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4; // Enable event output on external interrupt 4
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH; //
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4; // Clear the interrupt flag on channel 4
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_TC4_EVU); // Set the event user (receiver) as timer TC4, event 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_EIC_EXTINT_4) | // Set event generator (sender) as external interrupt 4
EVSYS_CHANNEL_CHANNEL(0); // Attach the generator (sender) to channel 0
TC4->COUNT32.EVCTRL.reg |= TC_EVCTRL_TCEI | // Enable TC4 event input
TC_EVCTRL_EVACT_COUNT; //.Enable the match or capture channel 0 event input
NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
NVIC_EnableIRQ(TC4_IRQn);
TC4->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32; // Chain TC4 with TC5 to create a 32-bit timer
TC4->COUNT32.CTRLA.bit.ENABLE = 1; // Enable TC4
while (TC4->COUNT32.STATUS.bit.SYNCBUSY); // Wait for synchronization
TC4->COUNT32.READREQ.reg = TC_READREQ_RCONT | // Enable a continuous read request
TC_READREQ_ADDR(0x10);
/////
attachInterrupt(A2, trigger, RISING);
Then I have the void trigger :
void trigger()
{
frequency = ((TC4->COUNT32.COUNT.reg) * 25);
TC4->COUNT32.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER; // Reset the TC4 timer
while (TC4->COUNT32.STATUS.bit.SYNCBUSY);
}
I've already tried retriggering also TCC0, stopping and restarting the EIC and removing the prescaler with no luck.
Anyone know what I'm missing ? I'd really appreciate your help!