TCC0 retrigger on pin falling edge [no ASF]

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As the title mentioned, I'm looking for retrigger my TCC0 timer from pin falling edge. I'm currently moving from Arduino to Atmel studio, so I know this code has worked before, but for some reason it doesn't retrigger the timer on any pin change level. The normal PWM operation however, works OK when I enable this. For some reason, I'm not able to retrigger via the pin EXTINT. 

 

The first init part that I added in the Atmel Studio project:

    NVIC_DisableIRQ(EIC_IRQn);
    NVIC_ClearPendingIRQ(EIC_IRQn);
    NVIC_SetPriority(EIC_IRQn, 0);
    NVIC_EnableIRQ(EIC_IRQn);

    // Enable GCLK for IEC (External Interrupt Controller)
    GCLK->CLKCTRL.reg |= (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(5)); // 5 = GCLK_EIC
    while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

    // Enable GCLK for EVSYS (Event system)
    GCLK->CLKCTRL.reg |= (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(7)); // 7 = GCLK_EVSYS_CHANNEL_0
    while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

    // Clock PORT for Digital I/O
    PM->APBBMASK.reg |= PM_APBBMASK_PORT;

    // Clock EIC for I/O interrupts
    PM->APBAMASK.reg |= PM_APBAMASK_EIC;

    // Clock SERCOM for Serial
    PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5;

    // Clock for EVSYS
    PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;

    // Clock TC/TCC for Pulse and Analog
    PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5;

    // Clock ADC/DAC for Analog
    PM->APBCMASK.reg |= PM_APBCMASK_ADC | PM_APBCMASK_DAC;

The second part that is more or less copy/paste from Arduino project:

 void init_timer()
 {

	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

	// 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->DRVCTRL.reg |= TCC_DRVCTRL_NRE4;             // make sure last pulse will be set low instead of tri-state

	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 = 4800;                              // Set the period (PER) register
	while(TCC0->SYNCBUSY.bit.PER);                     // Wait for synchronization

	TCC0->CC[0].reg = 2400;           					// Set the counter compare 0 (CC0) register
	while(TCC0->SYNCBUSY.bit.CC0);                     // Wait for synchronization

	// 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 2
	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 2
	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

	REG_TCC0_INTFLAG = TCC_INTFLAG_OVF;										// Clear the interrupt flags
	REG_TCC0_INTENSET = TCC_INTENSET_OVF;									// Enable TCC0 interrupts
	NVIC_EnableIRQ(TCC0_IRQn);												// Enable TCC0 Interrupt

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

	REG_TCC0_CTRLBSET = TCC_CTRLBSET_CMD_STOP;
	while(TCC0->SYNCBUSY.bit.CTRLB);

	//TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER;						// Retrigger timer
	//while (TCC0->SYNCBUSY.bit.CTRLB);										// Wait for synchronization

 }

void TCC0_Handler()
{

	if (TCC0->INTFLAG.bit.OVF && TCC0->INTENSET.bit.OVF)
	{
		REG_TCC0_INTFLAG = TCC_INTFLAG_OVF;         // Clear the OVF interrupt flag
	}

}

GCLK_CLKCTRL_GEN_GCLK0 is configured as 48MHz clock. The TCC0_Handler OVF works OK.

 

What can be the problem?

This topic has a solution.
Last Edited: Sun. Oct 25, 2020 - 01:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MarcelH wrote:
I know this code has worked before,

So go back to the code that worked, and see what it does differently ?

 

You realise that Atmel Studio can import an Arduino "sketch" - so you can use the AS debugger on it ...

 

https://www.avrfreaks.net/forum/microchip-trying-wean-people-arduino-atmel-studio

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Assign (= not  |=) CLKCTRL.

    GCLK->CLKCTRL.reg |= (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(5)); // 5 = GCLK_EIC
    while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

    // Enable GCLK for EVSYS (Event system)
    GCLK->CLKCTRL.reg |= (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(7)); // 7 = GCLK_EVSYS_CHANNEL_0

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Lars, thanks! That was the solution :)