Electronic – AVR ISR causes unexpected behavior

avravr-gcc

Using avr-gcc 4.8.0 and avr-libc 1.8.0 on Arch Linux. Trying to get UART RX interrupts working on an ATtiny2313 with this simple code which should echo the received byte:

#define F_CPU 14745600

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

#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main(){
  DDRD |= _BV(PD6);

  UCSRB = (1 << RXEN) | (1 << TXEN);
  UCSRC = (1 << UCSZ0) | (1 << UCSZ1);

  UBRRH = (BAUD_PRESCALE >> 8);
  UBRRL = BAUD_PRESCALE;

  UCSRB |= (1 << RXCIE);
  sei();

  for (;;){ 
    PORTD ^= _BV(PD6);
    _delay_ms(50);
  }  

  return 0;
}

ISR(USART_RX_vect){
   char b;
   b = UDR;
   UDR = b;
}

I upload this with avrdude and the LED fails to pulse. If I comment out the ISR, it works as I'd expect it to. UART polling also works normally, so I'm quite sure that it is configured correctly. I've been able to reproduce this with an ATmega162 and an ATmega328p.

Other strange behavior: if I compile without optimization, the LED will pulse until I send a byte, then it stops pulsing.

I've really got no idea where the problem lies as every tutorial I've seen uses almost this exact code.

Best Answer

I hate myself for this. How I was compiling:

avr-gcc -o build/src/main.o -c -Wall -g -Os -mmcu=attiny2313 src/main.c 
avr-gcc -o build/main.elf build/src/main.o

How I should have been:

avr-gcc -o build/src/main.o -c -Wall -Os -mmcu=attiny2313 -std=c99 -ffunction-sections -fdata-sections src/main.c
avr-gcc -o build/main.elf -mmcu=attiny2313 build/src/main.o

The actual culprit was not passing the -mmcu flag to the linker, but adding -ffunction-sections and -fdata-sections also cured some weird problems I was having when using external header files.