0
\$\begingroup\$

After countless of tries, I still didn't figure, why I cant get it to work...

I'm using an ATMEGA1608 (Datasheet) with the following code. Pin D6 has a LED connected.

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

int main() {
    PORTD.DIRSET = (1 << 6);  //output
    TCB0.CCMP    = 128;
    TCB0.INTCTRL = 1;
    TCB0.CTRLA |= TCB_ENABLE_bm;
    sei();
    while(1);
}

ISR(TCB0_INT_vect) {
    PORTD.OUTTGL = (1 << 6);
}

But no matter, what I am trying, the interrupt is not beeing executed.

What I have tried:

  • as per datasheet section "21.3.2 Initialization", I tried without "the line TCB0.INTCTRL = 1;"
  • If put the "PORTD.OUTTGL = (1 << 7);" into the while loop, the LED works.
  • Thinking, I am missing something, I have resorted to the ArduinoCode-MegaAvr code on github.

From wiring.c init() function I can see, that the timer is initialized in the same way...

_timer->CCMP = TIME_TRACKING_TIMER_PERIOD;
/* Enable timer interrupt */
_timer->INTCTRL |= TCB_CAPT_bm;
/* Clock selection -> same as TCA (F_CPU/64 -- 250kHz) */
_timer->CTRLA = TCB_CLKSEL_CLKTCA_gc;
/* Enable & start */
_timer->CTRLA |= TCB_ENABLE_bm;
sei();

So my question: What am I doing wrong / how to get the periodic timer on TCB0 work?


Edit 1:

I now figured, if I compile it for ATMEGA1608 and then flash the HEX file to my 808 the interrupt is executed - but with a fixed frequency of 46kHz (no matter what I write in the CCMP register or in the TCB0.CTRLA - clock pre-scaler bits)...


Edit 2:

Downloaded ATMEL Studio 7 with the latest device packages 2.0.401 - as I suspected an issue with my buildchain - also not with the desired result. I get the interrupt to be executed - but not with the CCMP value as top. The frequency remains 46kHz...

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Yeah, the mega0, AVR-Dx, etc. series are different; they're based on XMEGA, so share some features there, but also many differences. Always check whether INTFLAGS need to be cleared.

Examples: USARTs are still cleared by read/write of RX/TX registers, except for TXC (which isn't necessarily associated with a register, so that's understandable). PORTs need to be cleared manually. ADC cleared by reading ADCn.RES. Etc.

There is some interrupt management (CPUINT), much less advanced than XMEGA's (PMIC = Programmable Multilevel Interrupt Controller), but more than the none that plain MEGAs have -- which are, I think, always self-resetting (when interrupt executes)?

Note that, in XMEGA and derived architectures, the CPU interrupt enable remains set -- this allows a higher priority interrupt to fire during a lower one, without any extra effort. The interrupt controller prevents an interrupt overlapping itself. Whereas in MEGA, you could sei() to permit other interrupts while one is executing -- including itself (the same interrupt), which is something to beware of. Because of the interrupt controller, overlapping the same interrupt is impossible on XMEGA+, at least not without some serious hackery (patching in an IRET that returns to just after itself?).

Aside: since your main() is empty (spin loop), you wouldn't notice eternal interrupts, aside from their direct effect (here, max-frequency toggle). You may find it useful to have something twiddling thumbs in main(), perhaps a _delay_ms(500); toggle_pin();, which will very noticeably slow down, or stop completely, if an interrupt is stuck on. I'm partial to running a debug console here, myself: https://github.com/T3sl4co1l/Reverb/blob/master/console.c

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for the more detail explanation! Do you also know, why it works when I compile for 1608 (or 4808 i tried as well), but for 808 it's still not working. \$\endgroup\$ Commented Jul 17, 2022 at 0:59
  • \$\begingroup\$ @KarlKarlsom What do you mean "compile for", is it also uploaded and tested on those chips? Or "mis"compiled and tested on one? Alas, I'm not familiar with the mega0, would have to look through the datasheets. \$\endgroup\$ Commented Jul 17, 2022 at 2:03
  • \$\begingroup\$ I mean like this. When I set the compile flag -mmcu=atmega808 and upload the resulting hex file to the physical device (ATMEGA808), then it's not working - the LED remains off with the code shown in the questn (+clearing the interrupt flag, as my answer). When I change nothing but -mmcu=atmega1608 and then upload it to the ATMEGA808, it works. \$\endgroup\$ Commented Jul 17, 2022 at 8:38
1
\$\begingroup\$

Doh... I found the issue. In this devices, the INTFLAG has to be cleared manually - otherwise the interrupt fires and fires again (which with the default clk frequency of results in the 46kHz, i've seen. This seems to be incosistent with other Atmel series (e.g. ATTINY88), where I used timer interrupts, without manually reseting, the INTFLAG.

So changing the ISR to this, solves the problem:

ISR(TCB0_INT_vect) {
    PORTD.OUTTGL = (1 << 6);
    TCB0.INTFLAGS = TCB_CAPT_bm;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.