Hi All,
I have found in this Forum a very clever piece of code by MartinL that I have adapted to my purpose of counting the number of pulses of an external signal occurring within a gate interval (https://forum.arduino.cc/t/isr-timer-capture-on-samd21/685456). The original code was referring to an old MKR ZERO schematic, I have changed the PAxx used to match latest v.5 release.
The code, reported at the bottom, performs 3 tasks:
- generates a 1s gate signal using the 32768 kHz RTC signal at output pin 8 (PA16)
- sets pin 6 as the gate input for counting (therefore to use the gate signal generated at point 1, pin 8 and pin 6 must be wired together; a different external gate signal can be utilized fed to pin 6, voiding the need of the piece of code of point 1 above, for example I am using a 28Hz external square wave)
- counts the number of pulses (in the gate interval) of a measuring signal input at pin 10 (PA19)
Can anybody address me on how to modify this code in order to count within the external gate at pin 6 no longer the pulses of a signal applied to pin 10, but rather the internal clock pulses ?
Moreover, since I need extremely precise counting, is it possible to use the doubled 96MHz clock instead of the standard 48MHz ?
Thanks in advance,
Marco
Here is the code:
// Count the number of pulses on pin 10 (PA19) using 1 second test trigger pulse on pin 8 (PA16)
// for a trigger input on pin 6
// pin 8 (PA16) is the gate output of 1s, pin 6 is the external trigger input, pin 10 (PA19) is the external input of the pulses to measure
// connect pin 8 to pin 6 and the signal to measure to pin 10
#define MAXDATA 20
volatile boolean countRead = false; // Count read flag
volatile uint32_t count; // Variable to hold the TCC0 count value
void setup()
{
SerialUSB.begin(115200); // Initialise the native serial port
while(!SerialUSB); // Wait for the console to open
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; // Switch on the event system peripheral
////////////////////////////////////////////////////////////////////////////////////////
// Generic Clock Initialisation
////////////////////////////////////////////////////////////////////////////////////////
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | // Select clock divisor to 1
GCLK_GENDIV_ID(4); // Select GLCK4
GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK
GCLK_GENCTRL_SRC_XOSC32K | // Select GCLK source as external 32.768kHz crystal (XOSC32K)
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
GCLK_CLKCTRL_GEN_GCLK0 | // GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TC4_TC5; // As a clock source for TC4 and TC5
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
GCLK_CLKCTRL_GEN_GCLK4 | // GCLK4 at 32.768kHz
GCLK_CLKCTRL_ID_TCC2_TC3; // As a clock source for TCC2 and TC3
//////////////////////////////////////////////////////////////////////////////////////////////
// TCC2 Initialisation - reference timer: measures a 1s period
//////////////////////////////////////////////////////////////////////////////////////////////
PORT->Group[PORTA].PINCFG[16].bit.PMUXEN = 1; // Enable the port multiplexer on port pin PA16 (D11)
PORT->Group[PORTA].PMUX[16 >> 1].reg |= PORT_PMUX_PMUXE_E; // Set-up PA16 (D11) as an EIC (interrupt)
TCC2->PER.reg = 32767; // Set the period (PER) register for a PWM period of 1s
while (TCC2->SYNCBUSY.bit.PER); // Wait for synchronization
TCC2->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Set timer to Normal PWM mode (NPWM)
while (TCC2->SYNCBUSY.bit.WAVE); // Wait for synchronization
TCC2->CC[0].reg = 16384; // Set the duty cycle to 50%
while (TCC2->SYNCBUSY.bit.CC0); // Wait for synchronization
TCC2->CTRLA.bit.ENABLE = 1; // Enable TCC2
while (TCC2->SYNCBUSY.bit.ENABLE); // Wait for synchronization
////////////////////////////////////////////////////////////////////////////////////////
// TC4 Initialisation - measurement counter: counts the number incoming of pulses
////////////////////////////////////////////////////////////////////////////////////////
PORT->Group[PORTA].PINCFG[19].bit.PMUXEN = 1; // Enable the port multiplexer on port pin PA19 (D12)
PORT->Group[PORTA].PMUX[19 >> 1].reg |= PORT_PMUX_PMUXO_A; // Set-up PA12 (D12) as an EIC (interrupt)
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.bit.ENABLE = 1; // 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
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
TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI | // Enable TC4 event input
TC_EVCTRL_EVACT_COUNT; // Increment the TC4 counter upon receiving an event
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); // Offset of the 32-bit COUNT register
attachInterrupt(6, trigger, RISING); // Initialise the trigger pin 6
}
void loop()
{
static uint32_t prevcount;
uint32_t delta;
uint32_t dta[MAXDATA];
static int turn = 0;
int i;
for(i=0; i < MAXDATA; i++)
{
while(!countRead); // Block until the trigger() function returns
countRead = false; // Reset the count read flag
dta[i] = count - prevcount;
prevcount = count;
}
for(i=0; i < MAXDATA; i++)
{
SerialUSB.print("turn ");
SerialUSB.print(turn);
SerialUSB.print(" ");
SerialUSB.println(dta[i]); // Print the result
}
turn++;
}
void trigger()
{
count = TC4->COUNT32.COUNT.reg; // Read the COUNT register
countRead = true; // Set the count read flag
}