ATmega809 won't generate TCA0 CMP interrupt

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

Hello,

 

this is my code for an ATmega809 + Atmel Studio 7:

 

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU           20000000UL

#define TIM0_PRESCALER  16
#define TIM0_MS         30
#define TIM0_MS_FACTOR  ( (F_CPU) / (1000 * TIM0_PRESCALER) )
#define TIM0_COMP_VAL   (TIM0_MS * TIM0_MS_FACTOR)

ISR(TCA0_CMP0_vect) {
	/* Clear interrupt flag */
	TCA0.SINGLE.INTFLAGS |= (1 << TCA_SINGLE_CMP0EN_bp);
	PORTF.OUT ^= (1 << PIN0_bp);
}

void initTimer0() {
	/* Set Prescaler */
	TCA0.SINGLE.CTRLA |= TCA_SINGLE_CLKSEL_DIV16_gc;
	/* Set CMP value */
	TCA0.SINGLE.CMP0 = TIM0_COMP_VAL;
	/* Enable Compare Channel 0 Interrupt */
	TCA0.SINGLE.INTCTRL |= (1 << TCA_SINGLE_CMP0EN_bp);
	/* Enable Timer */
	TCA0.SINGLE.CTRLA |= (1 << TCA_SINGLE_ENABLE_bp);
	sei();
}

void initCPU() {
        CCP = 0xD8; /* Security */
	/* Set Clock source to 20MHz internal oscillator */
	CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc;
	/* Disable prescaler */
	CLKCTRL.MCLKCTRLB &= ~(1 << CLKCTRL_PEN_bp);

	/* Enable interrupts globally */
	sei();

	PORTF.DIR |= (1 << PIN0_bp);
}

int main(void)
{
	initCPU();
	initTimer0();
    while (1)
    {

    }
}

But for whatever reason the interrupt isn't called at all (neither if I try to debug the target via an Atmel-ICE nor if I measure the PINF0 directly with an oscilloscope).

What works though is just toggling the pin inside the while-loop.

 

Any ideas what I might be doing wrong?

This topic has a solution.
Last Edited: Sat. Dec 21, 2019 - 11:31 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Install the latest Atmel.ATmega_DFP, 1.4.346, from  http://packs.download.atmel.com.

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

Wait what? Why does this work (+ PC restart)?

 

Anyway - thank you so much! Trying to get the code running for the whole day

 

Edit: Okay, somehow the value of the CMP0-register isn't affecting the interrupt. If I change the value of "TCA0.SINGLE.PER", this actually changes the rate of the interrupt even though I set:

 

TCA0.SINGLE.INTCTRL |= (1 << TCA_SINGLE_CMP0EN_bp);

Edit: The "PER" and the "CMP0"-register have a weird relationship, one affecting the other one, but I can't tell how

 

Edit: Setting "TCA0.SINGLE.CNT = 0" inside the interrupt solved the problems finally - I think

Last Edited: Sun. Dec 22, 2019 - 12:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ARP wrote:

Wait what? Why does this work (+ PC restart)?

 

This chip has a silicon bug, incorrect size of interrupt vectors. See discussion here: https://www.avrfreaks.net/forum/...

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

>Edit: The "PER" and the "CMP0"-register have a weird relationship, one affecting the other one, but I can't tell how

 

In TCA normal mode, TOP is PER, so if you are trying to move your interrupt time around by changing CMP0, you are pretty much doing nothing.

 

If you want CMP0 to be TOP, you need to be in FREQ mode, or simply use PER as the value to change and use the OVF irq (in normal mode).

 

CLKCTRL.MCLKCTRLB is just as protected as CLKCTRL.MCLKCTRLA, so you are most likely not getting the prescale turned off. There is no need to set osc20m as that is the default out of reset, so just disable the prescale.

 

TCA0.SINGLE.INTFLAGS |= (1 << TCA_SINGLE_CMP0EN_bp);

will be better as-

TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP0_bm;

as you will only then be clearing one flag (also use the correct one even though the same value- CMP0 vs CMP0EN)

 

PORTF.OUT ^= (1 << PIN0_bp);

can be-

PORTF.OUTTGL = PIN0_bm;

or

VPORTF.IN = PIN0_bm;

 

 

I tested your code on a mega4809 with the above changes (and using PF6 as led), placed a counter in the isr (1000/30/2)  to blink at 1Hz, which worked (tca in FREQ mode)-

 

#include <avr/io.h>
#include <avr/interrupt.h>

 

#define F_CPU           20000000UL

#define TIM0_PRESCALER  16
#define TIM0_MS         30
#define TIM0_MS_FACTOR  ( (F_CPU) / (1000 * TIM0_PRESCALER) )
#define TIM0_COMP_VAL   (TIM0_MS * TIM0_MS_FACTOR)

 

ISR(TCA0_CMP0_vect) {
    TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP0_bm;
    static int count;
    if( ++count < 1000/30/2 ) return;
    count = 0;
    VPORTF.IN = PIN5_bm;
}

void initTimer0() {
    TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_FRQ_gc;
    TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc;
    TCA0.SINGLE.CMP0 = TIM0_COMP_VAL;
    TCA0.SINGLE.INTCTRL = TCA_SINGLE_CMP0_bm;
    TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
}

void initCPUfreq() {
    CCP = 0xD8;
    CLKCTRL.MCLKCTRLB = 0;
}

int main(void){
    initCPUfreq();
    initTimer0();
    VPORTF.DIR |= PIN5_bm;
    sei();
    for(;;){}
}

 

and for OVF irq, make a few changes-

 

ISR(TCA0_OVF_vect) { // <--
    TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; // <--

    //...

 

void initTimer0() {
    TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc;
    TCA0.SINGLE.PER = TIM0_COMP_VAL; // <--
    TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm; // <--
    TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
}

Last Edited: Sun. Dec 22, 2019 - 03:11 AM