Samd51 pwm capture

Continuing the discussion from SAMD51 TC PWP mode for measuring frequency - Inputs?:

Hi MartinL,

I tried your Program, I am Geting frequency Output.

But PWM capture Part is not Working... I am Using METRO M4 EXPRESS Board from Adafruit.

I am pasting the code written by you.

Request to help

Thanks & Regards,

Ravi

// Adafruit Feather M4: Setup TC0 to count pulse width and period on analog pin A4
// 100kHz test frequency on digtial pin D10

volatile uint16_t period;
volatile uint16_t pulsewidth;

void setup()
{
Serial.begin(115200); // Open the serial port at 115200 baud
while(!Serial); // Wait for the console to open

MCLK->APBBMASK.reg |= MCLK_APBBMASK_EVSYS; // Switch on the event system peripheral

// Set up the generic clock (GCLK7) used to clock timers
GCLK->GENCTRL[7].reg = GCLK_GENCTRL_DIV(1) | // Divide the 120MHz clock source by divisor 1: 120MHz/1 = 120MHz
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK7
//GCLK_GENCTRL_SRC_DFLL; // Generate from 48MHz DFLL clock source
GCLK_GENCTRL_SRC_DPLL0; // Generate from 120MHz DPLL clock source
//GCLK_GENCTRL_SRC_DFLL1; // Generate from 100MHz DPLL clock source
while (GCLK->SYNCBUSY.bit.GENCTRL7); // Wait for synchronization

GCLK->PCHCTRL[TC0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | // Enable perhipheral TC0
GCLK_PCHCTRL_GEN_GCLK7; // Connect 120MHz generic clock 7 to TC0

GCLK->PCHCTRL[TCC0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | // Enable perhipheral TCC0
GCLK_PCHCTRL_GEN_GCLK7; // Connect 120MHz generic clock 7 to TCC0

// Enable the peripheral multiplexer on pin D10
PORT->Group[g_APinDescription[10].ulPort].PINCFG[g_APinDescription[10].ulPin].bit.PMUXEN = 1;

// Set the D10 (PORT_PA20) peripheral multiplexer to peripheral (even port number) G(6): TCC0, Channel 0
PORT->Group[g_APinDescription[10].ulPort].PMUX[g_APinDescription[10].ulPin >> 1].reg |= PORT_PMUX_PMUXE(MUX_PA20G_TCC0_WO0);

TCC0->WAVE.reg = TCC_WAVE_CICCEN0 | // Set-up TCC0 to alternate duty-cycle between CC0 and CCBUF0 registers
TCC_WAVE_WAVEGEN_NPWM; // Set-up TCC0 timer for Normal (single slope) PWM mode (NPWM)
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization

TCC0->PER.reg = 1199; // Set-up the PER (period) register for 100KHz output
while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization

TCC0->CC[0].reg = 300; // Set-up 25% duty-cycle
while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization

TCC0->CCBUF[0].reg = 900; // Set-up 75% duty-cycle

TCC0->CTRLA.bit.ENABLE = 1; // Enable timer TCC0
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization

// Enable the port multiplexer on analog pin A4
PORT->Group[g_APinDescription[A4].ulPort].PINCFG[g_APinDescription[A4].ulPin].bit.PMUXEN = 1;

// Set-up the pin as an EIC (interrupt) peripheral on analog pin A4
PORT->Group[g_APinDescription[A4].ulPort].PMUX[g_APinDescription[A4].ulPin >> 1].reg |= PORT_PMUX_PMUXE(MUX_PA04A_EIC_EXTINT4);

EIC->CTRLA.bit.ENABLE = 0; // Disable the EIC peripheral
while (EIC->SYNCBUSY.bit.ENABLE); // Wait for synchronization
EIC->CONFIG[0].reg = EIC_CONFIG_SENSE4_HIGH; // Set event on detecting a HIGH level
EIC->EVCTRL.reg = 1 << 4; // Enable event output on external interrupt 4
EIC->INTENCLR.reg = 1 << 4; // Clear interrupt on external interrupt 4
EIC->ASYNCH.reg = 1 << 4; // Set-up interrupt as asynchronous input
EIC->CTRLA.bit.ENABLE = 1; // Enable the EIC peripheral
while (EIC->SYNCBUSY.bit.ENABLE); // Wait for synchronization

// Select the event system user on channel 0 (USER number = channel number + 1)
EVSYS->USER[EVSYS_ID_USER_TC0_EVU].reg = EVSYS_USER_CHANNEL(1); // Set the event user (receiver) as timer TC0

// Select the event system generator on channel 0
EVSYS->Channel[0].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

TC0->COUNT16.EVCTRL.reg = TC_EVCTRL_TCEI | // Enable the TCC event input
//TC_EVCTRL_TCINV | // Invert the event input
TC_EVCTRL_EVACT_PPW; // Set up the timer for capture: CC0 period, CC1 pulsewidth

NVIC_SetPriority(TC0_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC0 to 0 (highest)
NVIC_EnableIRQ(TC0_IRQn); // Connect the TC0 timer to the Nested Vector Interrupt Controller (NVIC)

TC0->COUNT16.INTENSET.reg = TC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
TC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts

TC0->COUNT16.CTRLA.reg = TC_CTRLA_CAPTEN1 | // Enable pulse capture on CC1
TC_CTRLA_CAPTEN0 | // Enable pulse capture on CC0
//TC_CTRLA_PRESCSYNC_PRESC | // Roll over on prescaler clock
//TC_CTRLA_PRESCALER_DIV1 | // Set the prescaler
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode

TC0->COUNT16.CTRLA.bit.ENABLE = 1; // Enable the TC0 timer
while (TC0->COUNT16.SYNCBUSY.bit.ENABLE); // Wait for synchronization
}

void loop()
{
TC0->COUNT16.INTENSET.reg = TC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
TC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts
while (TC0->COUNT16.INTENSET.bit.MC1 || // Wait for the pulse width and period to be read
TC0->COUNT16.INTENSET.bit.MC0);
Serial.print(pulsewidth); // Output the results
Serial.print(F(" "));
Serial.println(period);
delay(1000); // Wait for 1 second
}

void TC0_Handler() // Interrupt Service Routine (ISR) for timer TC0
{
if (TC0->COUNT16.INTFLAG.bit.MC0) // Check for match counter 0 (MC0) interrupt
{
period = TC0->COUNT16.CC[0].reg; // Copy the period
TC0->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0; // Disable compare channel 0 (CC0) interrupts
}

if (TC0->COUNT16.INTFLAG.bit.MC1) // Check for match counter 1 (MC1) interrupt
{
pulsewidth = TC0->COUNT16.CC[1].reg; // Copy the pulse width
TC0->COUNT16.INTENCLR.reg = TC_INTENCLR_MC1; // Disable compare channel 1 (CC1) interrupts
}
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.