Timer TCA 6X Slower Than Expected on ATTINY817

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

Hi,

I am having an issue with the TCA counter counting about ~6x slower than expected.  

I am running a ATTINY817 Xplained board running at 20MHz.

I am trying to execute the OVF interrupt every second using 'normal' mode.  Shouldn't my period just be 20000000/1024?

// Timer ISR vector
ISR(TCA0_OVF_vect)
{
	// Update Flag
	updateTempFlag = ON;
	// Reset interrupt
	TCA0_SINGLE_INTFLAGS |= (1<<TCA_SINGLE_OVF_bp);
}

// Initialize Timer
void Timer_Init()
{
	// Set up clock for 1024 division and start timer;
	TCA0_SINGLE_CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | TCA_SINGLE_ENABLE_bm;
	// Normal waveform
	TCA0_SINGLE_CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
	// Enable compare 0
	TCA0_SINGLE_INTCTRL = TCA_SINGLE_OVF_bm;
	// Set up compare for one second
	// F_CPU of 20mHz, divider of 1024 = 19531/s
	TCA0_SINGLE_PER = 19531;
}

Please let me know if you have any suggestions.

Thank you,
Tom

This topic has a solution.
Last Edited: Wed. Aug 8, 2018 - 05:03 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The chip powers on at 3.33MHz doesn't it (pretty sure I've seen that somewhere) and it just so happens 3.33MHz is 1/6th of 20Mhz so I would suggest you have failed to bump the speed.

 

Rather coincidentally there was a thread about almost this exact same thing just the other day and that turned out to be that CTRAL has CCP protection. So you may *think* you are writing to it, but you aren't.

 

EDIT: Crikey, the search engine here actually worked for once!! So this was the recent thread: https://www.avrfreaks.net/forum/...

 

EDIT2: Now I re-read that thread I realise that there's nothing in your code in #1 even making an attempt to change the system scaler from the 1/6th power on default? Aren't you supposed to be writing the PDIV bits in MCLKCTRLB somewhere? And when you do that is when you need the CCP unlock.

Last Edited: Wed. Aug 8, 2018 - 04:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

Thank you for the quick response.  I missed the section in the datasheet talking about the scaler for the peripheral clock:

 

After any Reset, CLK_MAIN is provided by the 16/20MHz oscillator (OSC20M) and with a Prescaler division factor of 6. Since the actual frequency of the OSC20M is determined by the Frequency Select bits (FREQSEL) of the Oscillator Configuration fuse (FUSE.OSCCFG), these frequencies are possible after Reset: Table 10-1. Peripheral Clock Frequencies after Reset CLK_MAIN as per FREQSEL in FUSE.OSCCFG Resulting CLK_PER 16MHz 2.66MHz 20MHz 3.33MHz See the OSC20M description for further details

 

Question - does the prescale of 6 only affect the peripheral clock, or does this affect my _delay_us function as well?

 

Regards,

Tom 

Last Edited: Wed. Aug 8, 2018 - 05:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TCA0_SINGLE_INTFLAGS |= (1<<TCA_SINGLE_OVF_bp);

As an aside, this is the wrong way to clear interrupt status flags.  In the general case you might have gotten another interrupt that is awaiting service, so its flag is also set.  By doing the RMW as you do, you will unknowingly clear that other interrupt flag as well as the flag you are trying to clear.  Just write a '1' to the desired flag bit, don't do a RMW operation.

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

Excuse my ignorance, I am new to Atmel controllers.  How can I write to just that bit?

Thank you,
Tom

 

Edit:  Answered my own question with a search (from user ka7ehk):

For interrupt flag registers, you CLEAR interrupt flags by writing a ONE to the corresponding bit. Writing a ZERO to an interrupt flag bit does nothing. That is just the way it works. So, for this special kind of register, you CAN do REG = bitmask; That writes ones to the bits in the bitmask and zeros to all other bits. Since these are interrupt flag bits, writing those zeros does not do anything. Again, it is not a matter of which is "better" - its a matter of which does what you want to do.

Last Edited: Wed. Aug 8, 2018 - 05:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Yes, you got it (regarding clearing the status flags).

 

This type of write-1-to-do-something-0-to-do-nothing register is common in more modern uC designs.  Another place where you will see them is in devices which have separate set-to-1 and set-to-0 GPIO registers in addition to the normal GPIO output register.  You write 1s to all the bits you want to set (or clear), and 0s to all the bits you want to leave alone.  This lets you set or clear chosen bits without any possibility of mistakenly clobbering other bits with a RMW sequence that gets interrupted, and it's also just faster.

Last Edited: Wed. Aug 8, 2018 - 05:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's right, often each register comes with an "assign", a "set", a "clear" and sometimes a "toggle" version.