Where should interrupt handlers be located?

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

I have made a simple test program for EVK1101, which contained uses a timer interrupt and a USART interrupt. The program works nicely "“ I can communicate on the serial port, flash LEDs, read ADC values and such.

But when I ported the code for UC3C-EK (which has a UC3C0512C µC), the interrupts started creating problems. Basically, I don't think I use the interrupts correctly.

First: Should my interrupt handlers end up in the .exception section?

I can see that they certainly don't. The .exception section starts at 0x80003600, and my two interrupt handlers start at 0x8000210C and 0x8000217C. I can't figure out whether or not this is a problem.

Second: Can anybody point at a good interrupt handling example, that doesn't use ASF? I found a timer interrupt example some time ago, which I used for my first test, but now I can't find it anywhere. Yes, stupid me. I'd really appreciate a non-ASF example which uses multiple interrupts.

What really puszzles me is that whether my timer interrupt works or not, seems to depend on the size of the USART interrupt. Or maybe the general code size "“ I'm not quite sure. Right now, my USART interrupt is really short (read the receive register and toggle an LED). If I increase the code size a bit, the timer interrupt may run for a few seconds, and then it just stops. I have a feeling that it has something to do with where code ends up in the flash. The USART interrupt isn't event trigged "“ it just exists.

I declare and initialize the interrupts like this:

// Timer interrupt
__attribute__((__interrupt__)) static void tc_irq( void )
{
  // Clear the interrupt flag of TC channel 0
  AVR32_TC0.channel[0].sr;
  ...
}

// USART2 interrupt
__attribute__((__interrupt__)) static void usart2_irq( void )
{
  //USART receive interrupt 
  if (AVR32_USART2.csr & AVR32_USART_CSR_RXRDY_MASK)
  {
    ...
  }
}



// Initialization code
void Init(void)
{
  Disable_global_interrupt();
  ...
  INTC_init_evba();

  // Initialize interrupt vectors.
  INTC_init_interrupts();

  // Register interrupts
  INTC_register_interrupt(&tc_irq, AVR32_TC0_IRQ0, AVR32_INTC_INTLEVEL_INT0);
  INTC_register_interrupt(&usart2_irq, AVR32_USART2_IRQ, AVR32_INTC_INTLEVEL_INT0);
  ...
  Enable_global_interrupt(); 
}

Other definitions:

extern void _evba; // Defined in exception.S

#define Disable_global_interrupt()         ({__asm__ __volatile__ ("ssrf\t¤0" :  : "i" (AVR32_SR_GM_OFFSET));})
#define Enable_global_interrupt()          ({__asm__ __volatile__ ("csrf\t¤0" :  : "i" (AVR32_SR_GM_OFFSET));})

static void INTC_init_evba(void)
{
  __builtin_mtsr(AVR32_EVBA, (int)&_evba );
}

Please replace '¤' with percent sign.

Can anybody see if I'm going at this the right way? Or if I've missed something?

Br, E

You're absolutely right. This member is stupid. Please help.

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

I may have made some sort of progress. It seems that if I expand the code size (no matter if it is interrupt code or main application code) so that the .exception section moves from 0x80003600 to 0x80003800, the timer interrupt acts strangely, and then goes haywire. It is really easy to reproduce, so there must be some sort of connection. But can anybody enlighten me?

You're absolutely right. This member is stupid. Please help.

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

Hello Erik,

they should be placed no farther than within 16384 bytes from the base address which you can set in the EVBA register.

BR,
Menahem

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

Ok, now I think I'm beginning to understand something here, but I must say that I'm quite overwhelmed by the complexity of this interrupt stuff. Apparently, it is veeery difficult to determine just what happened when an interrupt occurred.

To me, it looks like this: INTC_register_interrupt sets up the INTC.ipr address offset, so the MCU starts executing code at a position called <_int0> (if priority is 0). I suspect that this branches to <_int0_normal>, which then calls an address taken from the table, which points at <_get_interrupt_handler>. Here I lose track of what happens. I assume that <_get_interrupt_handler> is supposed to put together the address of my timer interrupt, with a little help from <_int_handler_table>, store it in r12, and let <_int0_normal> make a jump to the actual interrupt code. But I can't be sure, because I'm not too skilled at deciphering AVR32 assembly language.

Anyway, to me this proves that only <_int0>, <_int0_normal> and such must be within that 16384 bytes boundary (which it is). It shouldn't matter at all where the other interrupt related functions end up.

Maybe I should start from scratch, rewrite the whole stuff, and gradually figure out what the hell is happening.

Br, E

You're absolutely right. This member is stupid. Please help.

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

Maybe it would help you to read some of the previous discussions about UC3A interrupt handling, how the ASF does it and how to do it without the ASF.

I posted a pretty well-received in-depth explanation in the topic UC3A Interrupts and EVBA. There’s also a link to the rather lengthy but useful topic Interrupthandling without ASF.

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

Yeah, I found those, but they didn't really help me. And now I know why.

This is really embarrassing. :oops:

It turns out, that my problem doesn't have anything to do with interrupts. Apparently, I have configured the PLL wrong, because after I turned it off, and run directly from the crystal oscillator, everything runs nicely. Although at a quarter of the intended speed.

The funny thing is, that whenever the microcontroller was running, it ran at the correct speed (64 MHz). So I assumed (incorrectly – never ever assume) that the clock was fine.

So now I'll dive into the PLL settings, and try to figure out where I went wrong.

But first I'll go get my cilice...

Best regards,
Erik

You're absolutely right. This member is stupid. Please help.

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

Dammit. Forgot the flash wait state in FLASHC.fcr...

Works fine now. Thanks for your assistance.

Br, E

P.S. There really should be an emoticon resembling a head beating itself on a desk...

You're absolutely right. This member is stupid. Please help.