USART RECEIVE INTERRUPT -ATmega 808 - Not Working

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

Hello All,

I am trying to use the USART1 Receive interrupt feature of the ATmega 808. USART polling works, but I can't for the life of me get the program to jump to the ISR. This is for a 3 port RS485 diff bus. The program echos what comes in on USART1 to USART2. Works flawlessly. Once 0xA9 comes in on USART1, interrupts are enabled and I expect the next byte that comes in on USART1 to jump to the ISR where I simply turn off an LED. Doesn't work. In debug mode, the breakpoint set in the ISR is never reached. I am sure I am missing something simple.

 

Here is my code:

 

/*
 * USART_INTERRUPT.c
 *
 * Created: 10/16/2019 1:50:16 PM
 * Author : hellji01
 */ 

 

#define F_CPU 20000000UL                    //Need for Delay

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

 

//LED's i/o pins
#define BUS_HIGH_ON PORTA.OUTCLR = PIN7_bm;    //High On, Low Off
#define BUS_LOW_ON PORTA.OUTSET = PIN7_bm;    //Low On, High Off

 

//USART i/o Pin Enables
#define SEG_IN PORTA.OUTCLR = PIN3_bm;        //Segment in receive mode
#define SEG_OUT PORTA.OUTSET = PIN3_bm;        //Segment Out
#define INGRESS_IN PORTD.OUTCLR = PIN7_bm;    //Ingress in receive mode
#define INGRESS_OUT PORTD.OUTSET = PIN7_bm;    //Ingress Out
#define EGRESS_IN PORTC.OUTCLR = PIN3_bm;    //Egress in receive mode
#define EGRESS_OUT PORTC.OUTSET = PIN3_bm;    //Egress Out

 

int main(void)
{

//Variables
uint8_t i;                                //loop variable

 

//Oscillator
CCP = 0xD8;                                //This allows CLKCTRL.MCLKCTRLB to be changed - next line.
CLKCTRL.MCLKCTRLB = 0x00;                //No Prescaler,  20 MHz clock

 

//Outputs
PORTA.DIRSET = 0xFD;                    //Port A, RA7=BUS H/L LED, RA3=U0 EN, RA1=IN, RA0=out (Segment)
PORTC.DIRSET = 0xFD;                    //PORT C, b3=U1 EN, b1=IN, b0=Out (EGRESS)
PORTD.DIRSET = 0xFF;                    //Port D, RD7=U2EN Ingress, PD2=PWR LED
PORTF.DIRSET = 0xFD;                    //PORT F, b1=U2 REC, b0=TX (Ingress)

 

//USART Inputs
PORTA.DIRCLR = PIN1_bm;                    //Port A_1, Input, U0, Seg In
PORTC.DIRCLR = PIN1_bm;                    //Port C_1, Input, U1, Egress In
PORTF.DIRCLR = PIN1_bm;                    //Port F_1, Input, U2, Ingress In

//PORTA.DIRCLR = PIN6_bm;                    //Port A_6, Input, U0, Seg In

/*###################################### FUNCTIONS ##################################*/

//Flash PWR Led ***************************************************************
void FLASH_PWR(){
    for (i=0;i<50;i++){                    //delay
        _delay_ms(10);
    }
    PORTD.DIRTGL = 0x04;            //Toggle PWR LED, RD2
}

//Flash BUS H/L Led **************************************************************
void FLASH_BUS(){
    for (i=0;i<50;i++){                    //delay
        _delay_ms(10);
    }
    PORTA.DIRTGL = 0x80;            //Toggle Bus LED, RA7
}

 

PORTD.OUTCLR = PIN2_bm;                    //Turn PWR LED on (0)
PORTA.OUTCLR = PIN7_bm;                    //Turn High on, Low Off (0)
FLASH_PWR();                            //off
FLASH_BUS();                            //High off
FLASH_PWR();                            //ON
FLASH_BUS();                            //High on
FLASH_PWR();                            //off
FLASH_BUS();                            //High Off
FLASH_PWR();                            //ON
FLASH_BUS();                            //High on

 

//Configure USART's
USART0.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART0.CTRLC = 0x33;                    //8 data bits, Odd
USART0.BAUD = 0x8235;                    //4800 baud
//USART0.BAUD = 0x1046;                    //38400 baud

 
//USART1_CTRLA |= USART_RXCIE_bm;            //Enable RXCIE Interrupt
USART1_CTRLA |= (1 << 7); 
USART1.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART1.CTRLC = 0x33;                    //8 data bits, Odd
USART1.BAUD = 0x8235;                    //4800 baud
//USART1.BAUD = 0x1046;                    //38400 baud

 

USART2.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART2.CTRLC = 0x33;                    //8 data bits,
USART2.BAUD = 0x8235;                    //4800 baud
//USART2.BAUD = 0x1046;                    //38400 baud

 

//put U0, U1 trans in rec mode
SEG_IN;
EGRESS_IN;

//U2 in Tx Mode
INGRESS_OUT;

 

//Enable USARTS Receivers (SET)
USART0_CTRLB |= USART_RXEN_bm;            //USART0
USART1_CTRLB |= USART_RXEN_bm;            //USART1
USART2_CTRLB |= USART_RXEN_bm;            //USART2

 

//Enable USARTs Tx (SET)
USART0.CTRLB |= USART_TXEN_bm;            //USART0
USART1.CTRLB |= USART_TXEN_bm;            //USART1
USART2.CTRLB |= USART_TXEN_bm;            //USART2

   

while (1) 
    {
        
        while (USART1.STATUS & (1<<7)){                    //If RXCIF = 1 byte received,
            
            uint8_t TEMP = USART1_RXDATAL;                //input hex value

            while (!(USART2.STATUS & USART_DREIF_bm)){    //Wait for Tx Buffer register to be empty (0)
            }
            USART2.TXDATAL = TEMP;                            //echo byte
            
            while (!(USART2.STATUS & USART_TXCIF_bm)){    //Wait for TX Complete
            }        
            
            if (TEMP == 0xA9){  
                sei();
                while(1){               //do nothing until interrupt
                }
            }
        }            
    }
} //main bracket

ISR (USART1_RXC_vect)
{
    uint8_t INT_TEMP = USART1_RXDATAL;
    PORTD.OUTSET = PIN2_bm;                    //Turn PWR LED off
}
 

Last Edited: Thu. Oct 17, 2019 - 01:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please supplement what you do when you actually receive 0xA9.
Whether to continue or stop the redirect.

 

When USART1 seems to have received 0xA9, pause and check the contents of the SFR.
Also check the global interrupt flag in the CPU status.

 

Last Edited: Thu. Oct 17, 2019 - 02:38 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As there is no indentation I guess you cannot see this but that code appears to have functions within functions ?!?

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

It will compile successfully.
It's strange.

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

kabasan wrote:
It's strange.
Not entirely. GCC has an extension that allows you to do this but it is a VERY bad habit to get into !

 

https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

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

I simplified the code to only focus on the USART1 RECEIVE interrupt as listed. Global interrupt flag is set. Program does nothing until USART1 Rec interrupt occurs. Still  can't get it to jump to ISR.

 

#define F_CPU 20000000UL                    //Need for Delay

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

 

//LED's i/o pins
#define BUS_HIGH_ON PORTA.OUTCLR = PIN7_bm;    //High On, Low Off
#define BUS_LOW_ON PORTA.OUTSET = PIN7_bm;    //Low On, High Off

 

//USART i/o Pin Enables
#define SEG_IN PORTA.OUTCLR = PIN3_bm;        //Segment in receive mode
#define SEG_OUT PORTA.OUTSET = PIN3_bm;        //Segment Out
#define INGRESS_IN PORTD.OUTCLR = PIN7_bm;    //Ingress in receive mode
#define INGRESS_OUT PORTD.OUTSET = PIN7_bm;    //Ingress Out
#define EGRESS_IN PORTC.OUTCLR = PIN3_bm;    //Egress in receive mode
#define EGRESS_OUT PORTC.OUTSET = PIN3_bm;    //Egress Out

 

int main(void)
{

//Variables
uint8_t i;                                //loop variable

 

//Oscillator
CCP = 0xD8;                                //This allows CLKCTRL.MCLKCTRLB to be changed - next line.
CLKCTRL.MCLKCTRLB = 0x00;                //No Prescaler,  20 MHz clock

 

//Outputs
PORTA.DIRSET = 0xFD;                    //Port A, RA7=BUS H/L LED, RA3=U0 EN, RA1=IN, RA0=out (Segment)
PORTC.DIRSET = 0xFD;                    //PORT C, b3=U1 EN, b1=IN, b0=Out (EGRESS)
PORTD.DIRSET = 0xFF;                    //Port D, RD7=U2EN Ingress, PD2=PWR LED
PORTF.DIRSET = 0xFD;                    //PORT F, b1=U2 REC, b0=TX (Ingress)

 

PORTD.OUTCLR = PIN2_bm;                    //Turn PWR LED on (0)
PORTA.OUTCLR = PIN7_bm;                    //Turn High on, Low Off (0)

 

//Configure USART's
USART0.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART0.CTRLC = 0x33;                    //8 data bits, Odd
USART0.BAUD = 0x8235;                    //4800 baud
//USART0.BAUD = 0x1046;                    //38400 baud

 
//USART1_CTRLA |= USART_RXCIE_bm;            //Enable RXCIE Interrupt
USART1_CTRLA |= (1 << 7); 
USART1.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART1.CTRLC = 0x33;                    //8 data bits, Odd
USART1.BAUD = 0x8235;                    //4800 baud
//USART1.BAUD = 0x1046;                    //38400 baud

 

USART2.CTRLB = 0x02;                    //Rec/Trans off, double transmission speed, s = 8
USART2.CTRLC = 0x33;                    //8 data bits,
USART2.BAUD = 0x8235;                    //4800 baud
//USART2.BAUD = 0x1046;                    //38400 baud

 

//put U0, U1 trans in rec mode
SEG_IN;
EGRESS_IN;

//U2 in Tx Mode
INGRESS_OUT;

 

//Enable USARTS Receivers (SET)
USART0_CTRLB |= USART_RXEN_bm;            //USART0
USART1_CTRLB |= USART_RXEN_bm;            //USART1
USART2_CTRLB |= USART_RXEN_bm;            //USART2

 

//Enable USARTs Tx (SET)
USART0.CTRLB |= USART_TXEN_bm;            //USART0
USART1.CTRLB |= USART_TXEN_bm;            //USART1
USART2.CTRLB |= USART_TXEN_bm;            //USART2

   

SREG = 0x80;
sei();

 

while (1) 

   {                          
                              //do nothing until interrupt              
    }
}                           //main bracket

 

ISR (USART1_RXC_vect)
{
    uint8_t INT_TEMP = USART1_RXDATAL;
    PORTD.OUTSET = PIN2_bm;                    //Turn PWR LED off
}

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

I ran the code with a bare mega3208.
A receive interrupt occurred when RXD1 (PC1) was dropped to GND.
What is happening in your circuit?

 

 

Because the circuit is bare, PC1 has an internal pull-up setting.

PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // RXD1(PC1) pullup

 

 

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

Try uncommenting

//USART1_CTRLA |= USART_RXCIE_bm;            //Enable RXCIE Interrupt

 

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

The interrupt is enabled on the next line, only the parameter format is different.

I confirmed in # 7 that an interrupt occurs on the actual chip.

//USART1_CTRLA |= USART_RXCIE_bm;            //Enable RXCIE Interrupt
USART1_CTRLA |= (1 << 7);

However, it is not recommended to use |=.

Last Edited: Sat. Oct 19, 2019 - 09:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ran a simple test on a mega 4809, using C code. I have my own C++ drivers, but thought I would give the C method a try to see what may be wrong with the posted code. I had a similar problem that caused me to scratch my head- the isr would fire but end up 'in the weeds' somewhere beyond my code. Eventually I realized the problem, and its not the first time it happened- I had been creating a bootloader and had the fuses set for the sections, which means when the irq fires it is going to the app section offset for the vector address (and no reti either, so eventually you end up back at the reset vector and code starts again but irq's will no longer fire again as the lvl0ex bit is still set- this is why I blink an led on startup, so I can see when I got a 'reset' of any kind- real or or not).

 

So, if you happen to have the boot/app fuses anything other than default, and still have the app sitting at 0, it all appears to be fine until you start using interrupts. I doubt its the case here, but its possible. 

 

C example (just using invert on rx pin to simulate start bits)-

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 3333333ul
#include <util/delay.h>

static void ledOn(){ PORTF.OUTCLR = PIN5_bm; }
static void ledOff(){ PORTF.OUTSET = PIN5_bm; }

int main(void){
    PORTF.DIRSET = PIN5_bm; //led output
    //app start = 2sec led on, then 2sec off
    ledOn(); _delay_ms(2000);
    ledOff(); _delay_ms(2000);
    USART1.BAUD = 1388; //3.33MHz*4/9600baud
    USART1_CTRLA = USART_RXCIE_bm;
    USART1.CTRLB = USART_RXEN_bm;
    PORTC.PIN1CTRL = PORT_PULLUPEN_bm; //PC1 = RX1
    sei();

    for(;;){
        PORTC.PIN1CTRL |= PORT_INVEN_bm;    //trigger start bit
        while(PORTF.OUT & PIN5_bm);         //wait until led on from isr
        PORTC.PIN1CTRL &= ~PORT_INVEN_bm;   //back to idle
        _delay_ms(50); ledOff();            //let led run for 50ms
        _delay_ms(50);                      //off time before trigger again
    }
}

ISR (USART1_RXC_vect){
    USART1_RXDATAL; //remove rx data
    ledOn();
}

The C++ version, just to contrast-

//headers here

PF5_OUTL_t led; //led on PF5 (on=low)
Usart< Usart0_Alt, 0 > usart0;  //usart0 alternate pins, no buffer

int main(){

    //show when startup so can see any restart problems
    led.on();  Delay::wait(2_sec);
    led.off(); Delay::wait(2_sec);
    usart0.setup_UART( 9600, usart0.RX );
    usart0.irq( usart0.RXCOMPLETE_IRQ, true );

    Cpuint::vectorFunc( Cpuint::USART0_RXC,     //set rxc function
        [](){ led.on(); usart0.getch(); }
    );
    Cpuint::irqGlobalOn();

    for(;;){
        PC1_t::invert( true );
        while( led.isOff() );
        PC1_t::invert( false );
        Delay::wait(50_ms); 
        led.off();
        Delay::wait(50_ms);
    }
}

 

Last Edited: Sun. Oct 20, 2019 - 07:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for all the comments and suggestions. The program still does not work. At this point I will temporary suspend the design and move to a PIC18 as the product I am designing must launch 2/2020. I will revisit the '808 design after that.