First, some background on what I'm working on.
I have a custom board with ATmega324A that I designed as part of a project I'm working on. Originally, software for the uC was written for GCC in Atmel Studio. Now I need to port it from GCC to the IAR compiler. I'm using IAR Workbench with AVR toolchain.
The board uses UART to communicate with a Bluetooth module embedded on the board (irrelevant here). There is a button on the board which is HW debounced with a LPF and a Schmitt-Trigger so the ISR triggering signal is clean (checked over oscilloscope).
Triggering signal is connected to PB2 (INT2) of ATmega324A.
What is the issue?
I have a global variable (set as volatile) that is being changed by the ISR from 0 -> 1 everytime the input changes state (0 -> 1 or 1 -> 0). I have an if statement in main() that checks the value of the variable and does something if its set to 1.
This works fine in GCC and always has... for me at least.
However, something strange seems to be happening when the code is compiled with IAR compiler. The global variable is set to 1 inside the ISR but never changes value inside main().
Ok, let me add the code so this will be more clear.
Setup code for ports and interrupts:
#include <ioavr.h>
void Sys_Init(void)
{
DDRC |= (1<<DDRC5) | (1<<DDRC6) | (1<<DDRC7); // LED pins set as output
DDRB &= ~(1<<DDRB2); // pin set as input (interrupt pin)
EICRA |= (1<<ISC20); // interrupt triggered on both edges
EIMSK |= (1<<INT2); // enable interrupt on INT2
}
Code:
#include <ioavr.h>
#include <intrinsics.h>
#include "init.h"
#include "bluetooth.h"
#include "uart.h"
volatile unsigned char edge_level = 0;
volatile unsigned char btn_trig = 0;
int main(void)
{
__disable_interrupt();
Sys_Init(); // initialize ports etc.
USART0_Init(7); // sets UBRR value for 115200 baud rate
__enable_interrupt();
while (1)
{
if(btn_trig == 1) {
btn_trig = 0;
PORTC ^= (1 << PORTC6);
}
}
while(1); // makes sure that main is never exited
}
#pragma vector=INT2_vect
__interrupt void INT2_interrupt(void) // interrupt routine triggered by button press
{
edge_level = PINB & 0x04;
btn_trig = 1;
}
So, for some reason, this isn't working in IAR but works fine in GCC. However, if I move:
if(btn_trig == 1) {
btn_trig = 0;
PORTC ^= (1 << PORTC6);
}
... inside the ISR, the program works fine and the LED turns ON or OFF.
#pragma vector=INT2_vect
__interrupt void INT2_interrupt(void) // interrupt routine triggered by button press
{
edge_level = PINB & 0x04;
btn_trig = 1;
if(btn_trig == 1) {
btn_trig = 0;
PORTC ^= (1 << PORTC6);
}
}
Looks like the btn_trig is changed inside the ISR but not outside of it... What is going on here?
Thank you for your time!