Problem with xmega32e5 timer interrupt

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

Hi,

I have used a lot of the "normal" mega and tiny avr's and now testing an xmega for the fist time. I am running a xmega32e5 at 32 MHz and tryed to set up the timer 4. I would like to have an interrupt every 10 ms. So prescaler to 1024 and PER to 312. Here is the code: 

TCC4.CTRLA = 0b00000111;		// timer 4 clock div 1024
TCC4.INTCTRLA = 0b00000010;		// timer 4 medium interrupt
TCC4.CNT = 0;
TCC4.PER = 312;					// 10 ms
PMIC.CTRL = 0b00000111;			// enable hi, med and lo interrupts
sei();

and my ISR:

ISR(TCC4_OVF_vect)
{
	//toggle pin
}

But now the first period after reset is 10 ms and then the pin toggles at about 545 KHz. It seems the interrupt is fireing all the time after the first correct period. Can anyone help with this? How can I setup the timer for continuous periods of the 10 ms?

 

Thanks!

Regards

Last Edited: Wed. Apr 26, 2017 - 04:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your ISR needs to clear the timer's interrupt flag register. This difference tripped me up at first. You write a 1 to the bit for the interrupt you handled.

The largest known prime number: 282589933-1

Without adult supervision.

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

Torby wrote:
Your ISR needs to clear the timer's interrupt flag register. This difference tripped me up at first. You write a 1 to the bit for the interrupt you handled.

FWIW, I plugged in your 10ms. requirement to CodeVisionAVR Wizard to see what I get.  (the first time I used the Wizard for Xmega...)  More or less arbitrary values.

 

timers_init.c has the ISR stub as well, with a flag clear as Torby suggested:

// I/O Registers definitions
#include <io.h>

// Disable a Timer/Counter type TC4
void tc4_disable(TC4_t *ptc)
{
// Timer/Counter off
ptc->CTRLA=TC45_CLKSEL_OFF_gc;
// Issue a reset command
ptc->CTRLGSET=TC45_CMD_RESET_gc;
}

// Timer/Counter TCC4 initialization
void tcc4_init(void)
{
unsigned char s;

// Note: The correct PORTC direction for the Compare Channels
// outputs is configured in the ports_init function.

// Save interrupts enabled/disabled state
s=SREG;
// Disable interrupts
#asm("cli")

// Disable and reset the timer/counter just to be sure
tc4_disable(&TCC4);
// Clock source: ClkPer/1
// Events and timer commands are synchronized with: ClkPer
TCC4.CTRLA=TC45_CLKSEL_DIV1_gc | (0<<TC4_SYNCHEN_bp);
// Mode: Normal Operation, Overflow Int./Event on TOP
// Timer/Counter in 8bit mode: Off
// Circular buffer disabled
TCC4.CTRLB=TC45_BYTEM_NORMAL_gc | TC45_CIRCEN_DISABLE_gc | TC45_WGMODE_NORMAL_gc;
TCC4.CTRLC=(0<<TC4_POLD_bp) | (0<<TC4_POLC_bp) | (0<<TC4_POLB_bp) | (0<<TC4_POLA_bp) |
	(0<<TC4_CMPD_bp) | (0<<TC4_CMPC_bp) | (0<<TC4_CMPB_bp) | (0<<TC4_CMPA_bp);
// Compare/Capture channel A mode: Compare output and Capture input disabled
// Compare/Capture channel B mode: Compare output and Capture input disabled
// Compare/Capture channel C mode: Compare output and Capture input disabled
// Compare/Capture channel D mode: Compare output and Capture input disabled
TCC4.CTRLE=TC45_CCDMODE_DISABLE_gc | TC45_CCCMODE_DISABLE_gc | TC45_CCBMODE_DISABLE_gc | TC45_CCAMODE_DISABLE_gc;
// Capture event source: None
// Capture event action: None
TCC4.CTRLD=TC45_EVACT_OFF_gc | TC45_EVSEL_OFF_gc;

// Overflow interrupt: Medium Level
// Error interrupt: Disabled
TCC4.INTCTRLA=TC45_ERRINTLVL_OFF_gc | TC45_OVFINTLVL_MED_gc;

// Compare/Capture channel A interrupt: Disabled
// Compare/Capture channel B interrupt: Disabled
// Compare/Capture channel C interrupt: Disabled
// Compare/Capture channel D interrupt: Disabled
TCC4.INTCTRLB=TC45_CCDINTLVL_OFF_gc | TC45_CCCINTLVL_OFF_gc | TC45_CCBINTLVL_OFF_gc | TC45_CCAINTLVL_OFF_gc;

// High resolution extension: Off
// High resolution plus extension: Off
HIRESC.CTRLA&= ~(HIRES_HRPLUS0_bm | HIRES_HREN0_bm);

// Clear the interrupt flags
TCC4.INTFLAGS=TCC4.INTFLAGS;
// Set Counter register
TCC4.CNT=0x0000;
// Set Period register
TCC4.PER=0x4E1F;
// Set channel A Compare/Capture register
TCC4.CCA=0x0000;
// Set channel B Compare/Capture register
TCC4.CCB=0x0000;
// Set channel C Compare/Capture register
TCC4.CCC=0x0000;
// Set channel D Compare/Capture register
TCC4.CCD=0x0000;

// Restore interrupts enabled/disabled state
SREG=s;
}

// Timer/Counter TCC4 Overflow/Underflow interrupt service routine
interrupt [TCC4_OVF_vect] void tcc4_overflow_isr(void)
{
if (TCC4.INTFLAGS & TC4_OVFIF_bm)
   {
   // Clear the Overflow/Underflow Flag
   TCC4.INTFLAGS|=TC4_OVFIF_bm;
   // Write your code here

   }
if (TCC4.INTFLAGS & TC4_TRGIF_bm)
   {
   // Clear the Trigger Restart Flag
   TCC4.INTFLAGS|=TC4_TRGIF_bm;
   // Write your code here

   }
// Write your code here

}

Hmmm--no mention of the 10ms. "Requirement" in the C comments, as there would be for an AVR8.

 

Part of the main() setup:

 

// I/O Registers definitions
#include <io.h>

// Standard Input/Output functions
#include <stdio.h>

// Clock System initialization function
#include "clock_init.h"

// Event System initialization function
#include "event_system_init.h"

// I/O Ports initialization function
#include "ports_init.h"

// Timers/Counters initialization functions
#include "timers_init.h"

// Declare your global variables here

void main(void)
{
// Declare your local variables here
unsigned char n;

// Interrupt system initialization
// Optimize for speed
#pragma optsize-
// Make sure the interrupts are disabled
#asm("cli")
// Low level interrupt: On
// Round-robin scheduling for low level interrupt: Off
// Medium level interrupt: On
// High level interrupt: On
// The interrupt vectors will be placed at the start of the Application FLASH section
n=(PMIC.CTRL & (~(PMIC_RREN_bm | PMIC_IVSEL_bm | PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm))) |
	PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
CCP=CCP_IOREG_gc;
PMIC.CTRL=n;
// Set the default priority for round-robin scheduling
PMIC.INTPRI=0x00;
// Restore optimization for size if needed
#pragma optsize_default

// System clocks initialization
system_clocks_init();

// Event system initialization
event_system_init();

// Ports initialization
ports_init();

// Timer/Counter TCC4 initialization
tcc4_init();

// Globally enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      }
}

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Wed. Apr 26, 2017 - 06:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think many who have used the E5's have missed this in the instruction manual(s), and had to go looking to find the cause when the ISR didn't run as expected.

 

In my version of the manual:

 

13.12.10 INTFLAGS-Interrupt Flags Register

Bit 0 is the OVFIF flag, the Overflow Interrupt Flag.

 

The Bit description says:

 

Bit 0 – OVFIF: Overflow/Underflow Interrupt Flag

This flag is set either on a TOP (overflow) or BOTTOM (underflow) condition, depending on the WGMODE setting.

The flag is cleared by writing a one to its bit location.

OVFIF can also be used for requesting an EDMA transfer. An EDMA write access of CNT, PER, or PERBUF will

then clear the OVFIF bit.

 

So, within your ISR you have to write a 1 to that bit to clear the flag, as just executing the ISR routine itself will NOT automatically clear (set) the bit.

 

JC

 

Edit: Typo

 

 

Last Edited: Wed. Apr 26, 2017 - 09:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is this for the overflow flag only? I'm not clearing any flags in the ISRs and I use up to 3 timers in "CTC" mode.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

The data sheet is, IMHO, a little bit cryptic when discussing the other modes of operation.

It says: "The CCxIF, (Compare or Capture Channel x Interrupt Flag), is automatically cleared when the corresponding interrupt vector is executed.

 

But, that  does not apply to Input Capture operations, or Overflow operations.

 

For Input Capture, reading the CCx register is what clears the interrupt flag, executing the ISR routine itself does not clear the flag.

 

The Overflow was mentioned above.

 

The OP mentioned:

ISR(TCC4_OVF_vect)

 

Which, even I, (C illiterate), recognized as an ISR related Overflow Vector!!

Hence the comment to reinforce Torby's comment above.

 

Note that Atmel Doublespeak applies to this section of the datasheet, where "Clearing" the Interrupt Flag means Setting it to = 1.

 

At least in this section that is specifically spelled out in one or two locations.

IIRC that isn't always the case, which, at least for me, can at times be confusing.

 

(But nothing a simple test routine can't quickly sort out!)

 

JC

 

Edit: Typo

  

Last Edited: Thu. Apr 27, 2017 - 12:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Torby wrote:

Your ISR needs to clear the timer's interrupt flag register. This difference tripped me up at first. You write a 1 to the bit for the interrupt you handled.

 

+1

 

The XMegas are weird in this respect. Some interrupts are cleared automatically, some are not. The timer overflow interrupts are NOT cleared automatically, it's the programmer's responsibility.

 

-Patick

"Some people die at 25 and aren't buried until 75." -Benjamin Franklin

 

What is life's greatest illusion?"  "Innocence, my brother." -Skyrim

 

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

@Torby: thank you, I did stupidly miss that... I presumed it gets cleared when the ISR gets called and that it is only necessary to clear it manually if only the flag is used as indicator without the actual interrupt.

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

Nickelgrass wrote:

@Torby: thank you, I did stupidly miss that... I presumed it gets cleared when the ISR gets called and that it is only necessary to clear it manually if only the flag is used as indicator without the actual interrupt.

 

Yup. That tripped me up once. The ISR starts again as soon as it exits. Experience is a wonderful thing. I recognize that mistake every time I make it.

The largest known prime number: 282589933-1

Without adult supervision.

Last Edited: Fri. Apr 28, 2017 - 05:08 PM