Timer with period Y does not generate interrupt for CCx when CCx is Y.

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

I set up my timer with period 0x7fff and I can verify that the max value I get is 0x7fff. However when I set CCA to the max value (0x7fff), the interrupt flag is never set. The interrupt is generated with anything between 0x00 - 0x7ffe, but not for 0x7fff. Why is this happening and how can I correctly fix this issue (setting the period to 0x8000 doesn't seem like valid solution to me). MCU is atxmega32e5. Thanks.

 

Here is my init code that cascades two timers (I use TCC4's CCA):

void timer_init() {
	uint8_t sreg = SREG; cli();

	/////////// Init Timer
	TCC4.CTRLA = (TCC4.CTRLA & 0xF0) | 0b0101; // prescaler=64
	TCC4.CTRLB = 0b01 << 4;
	TCC4.INTCTRLA = 0; // No interrupts (I enable the interrupt for CCA later)
    TCC4.CNT = 0;
	TCC4.PER = 0x7FFF;

	// Init event channel 1 - on TCC4_OVF
	// This creates 32-bit counter from two 16bit counters - TCC4 containing
	// 15 LSBits (shifted by one left after reading) and TCC5 containing 16 MSBits
	EVSYS.CH1MUX = (0b1100<<4) | 0b0000; // generate event 1 on TCC4_OVF
	//EVSYS.CH1CTRL = 0; // one sample, no quadrature

	// Configure TCC5 to receive impulses from event channel 1
	TCC5.CTRLA = 0b1001; // source = event 1
    TCC5.PER = 0xffff;
    TCC5.CNT = 0;

	SREG = sreg;
}

 

This topic has a solution.
Last Edited: Wed. Aug 12, 2020 - 02:58 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was able to think of only two not-so-clean solutions. The first one is using TCC4.OVF interrupt instead of CCA when CCA == 0x7FFF, and the other one which I actually use was just incrementing the CCA by one (so I get 0) if its value equals to 0x7FFF. Don't understand why they designed this functionality this weird way, but whatever.

Last Edited: Wed. Aug 12, 2020 - 11:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

well you want to detect an overflow, so why not use that interrupt then? nothing dirty about it as far as I can see, on the contrary... the overflow interrupt is exactly what you seem to be wanting in this case.

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

Yes, but the point is the CCA value can be anything in the range 0 - 0x7FFF, it is calculated at run time and adding a special case for 0x7FFF seems like dirty solution to me.

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

Then you need to check the datasheet. IIRC for the megas there is a warning that there might be trouble if this specific case is made you need to keep at least a couple of cpu clock cycles away. I think it was not written down all to clear Might also be the case for the Xmegas, those I have never used other than doing a small application thing were no low level things had to change only a couple of Io lines toggled differently. So I suggest re-reading the datasheet on the use of the specific timers.

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

Your initialization code seems to be incorrect.

 

TCC4.CTRLB = 0b01 << 4;

 

enables some strange feature, called circular buffer.

What it actually does - it swaps PER and PERBUF registers on every overflow, but your code doesn't initialize PERBUF register.

Is it really what your try to do? Disabling this feature seems to eliminate your problem

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

I have removed this line meanwhile because of the unneeded feature, but this didn't solve the problem. I no longer have access to the hardware, but it does not seem to work in simulator - the 4th bit of INTFLAGS is never set with CCA=0x7fff, only gets set with 0x7ffe and lower.

 

#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
/*
 * 
 */

void timer_init();

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/cpufunc.h>
int main(void){

    // PMIC
    PMIC.CTRL = PMIC_MEDLVLEX_bm;

    timer_init();
    TCC4.CCA = 0x7fff; // works with 0x7ffe
    
    sei();
    while (1);
}


void timer_init() {
	uint8_t sreg = SREG; cli();

	/////////// Init Timer
	TCC4.CTRLA = (TCC4.CTRLA & 0xF0) | 0b0101; // prescaler=64
	TCC4.INTCTRLA = 0; // No interrupts
    TCC4.CNT = 0;
	TCC4.PER = 0x7FFF;

	// Init event channel 1 - on TCC4_OVF
	// This creates 32-bit counter from two 16bit counters - TCC4 containing
	// 15 LSBits (shifted by one left after reading) and TCC5 containing 16 MSBits
	EVSYS.CH1MUX = (0b1100<<4) | 0b0000; // generate event 1 on TCC4_OVF
	//EVSYS.CH1CTRL = 0; // one sample, no quadrature

	// Configure TCC5 to receive impulses from event channel 1
	TCC5.CTRLA = 0b1001; // source = event 1
    TCC5.PER = 0xffff;
    TCC5.CNT = 0;

	SREG = sreg;
}