Newbie question: Enable interrupt on port

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

I am new to programming microcontrollers so forgive me my ignorance.

 

I have a XMEGA16E5 with some switches on port A and some LEDs on portC. I would like to control the status of the LEDs using the switches using interrupts. See my program below. For some reason unknown to me the interrupt routine is not called when I change one of the switches. What am I doing wrong?

 

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



int main(void)
{
	// Configure PORTA, The port is used to set the board id using  switches  11100001
	
	PORTA_DIR = 0x00;				// configure port A for input
	PORTCFG_MPCMASK=0xE1;				// configure bits 11100001 at the same time
	PORTA_PIN0CTRL = PORT_ISC_BOTHEDGES_gc|  PORT_OPC_PULLUP_gc;
	PORTA_INTCTRL=PORT_INTLVL_MED_gc;       	//Medium level interrupt
	PORTCFG_MPCMASK=0x0;				// Should i reset the mask?
	
	PORTC_DIR = 0xf0;				// Configure PORTC for output: pin 4-7 (LEDs) and input: pin 0-3 (Analog inputs)
	PORTC_OUT = 0x00;				// set the pns low
		
	PORTC_PIN0CTRL = 0x18;
	PORTC_PIN1CTRL = 0x18;
	PORTC_PIN2CTRL = 0x18;
	PORTC_PIN3CTRL = 0x18;
		
PORTC_OUT=0x80;						// set a LED on to make sure PortC is working as expected
	PMIC.CTRL |= PMIC_MEDLVLEX_bm;		        // Enabled medium level interrupts
	sei();						// enable interrupts

    while (1) 
    {
    }
}

ISR(PORTA_INT_vect)
{
	static unsigned char tog=0;
	tog = !tog;
	
	if (tog) PORTC_OUT=0x10;			// set a led and disable the others
	else 
	PORTC_OUT=0x20;					// set a different led and disable the others
}

 

This topic has a solution.
Last Edited: Tue. Sep 29, 2020 - 03:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AswinB wrote:
using the switches using interrupts
because switches bounce this is never a great idea unless your circuitry has hardware debouncing.

 

The usual approach is to poll the button states in a timer interrupt so that debouncing can be applied.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The interrupt mask setting is missing.

PORTA.INTMASK = 0xE1;

And the interrupt flag is not automatically released, so please do it yourself.

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

Thank you both for the replies. I got it working!

 

I would have never considered bouncing without you bringing it up. Is it an option to add a delay of 1 ms to the interrupt routine to take bouncing into account? I can rewrite it to a polling mechanism. The switches are used to set an address. I think this happens only once or twice in the life time of the board so it would be a waste of time to have the board poll the switches on a regular basis.

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

AswinB wrote:
this happens only once or twice in the life time of the board so it would be a waste of time to have the board poll the switches on a regular basis.

So just stop the polling once you're done with the switches?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AswinB wrote:
I am new to programming microcontrollers

The place to start is always the Product Page - there you will find the datasheet, Application Notes, examples, etc, etc:

 

https://www.avrfreaks.net/commen...

 

https://www.avrfreaks.net/commen...

 

whence:

 

 

AN_8050 - AVR1313: Using the XMEGA IO Pins and External Interrupts

 

AN_8043 - AVR1305: using the XMEGA Interrupts and the Programmable Multi-level Interrupt Controller

 

it'd worth spending some time browsing what's available ...

 

AswinB wrote:
I got it working!

 

Please see Tip #5 in my signature, below, for how to mark the solution:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is an example using int6 pin on AVR ( I use Atmega128 ):

 

Do not forget sei(); (enable global interrupt)

 

Important: The pin needs  a pullup resistor

 

Ellen

 

 

void init_INT6(void) //INT6 init function
{
    EICRB = 1 << ISC60 | 1 << ISC61; //trigger off the rising edge of INT6
    EIMSK = 0b01000000; //enable INT6 interrupt
}

 

// interruptservice routine:

ISR(INT6_vect)
{
cnt++;    
#ifdef ISROut
  PORTA = cnt;
 _delay_ms(510);
#endif

 

 

// using:

 

#ifdef ISROut
    init_INT6();
#endif

sei();
 

 

Senior electrical engineer

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

AswinB wrote:
Is it an option to add a delay of 1 ms to the interrupt routine to take bouncing into account?
Well a couple of things:

 

1) 1ms is nowhere near long enough and

2) NEVER put deliberate delays in ISRs

 

In the AVR (apart from later Xmega derivatives) the CPU will be "locked" while in an ISR - nothing else can occur - so other events can be missed. So an ISR should be "in" and "out" in microseconds so it does not disrupt anything else going on. Putting misllisec9ond delays in ISR (even just 1ms) is a very, very poor design.

 

The way to do buttons with interrupts is to set up a timer interrupt that also tracks button input activity. Only when a button has been seen in the same state for a number of subsequent interrupts (maybe every 4ms or something?) should you consider the button settled into a new state. This has been discussed many, many times here, the search term "Ganssle" should hit most of the threads. As you'll see there are two common solutions usually proposed. While some people will use Lee Theuch's solution I'm guessing the one from Peter Dannegger is probably the one most people go with. So I'd search that out and use it.

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

Thanks all. I discarded the idea of using interrupts in this case. I now use a polling mechanism. I poll every 10mSec and only use the port reading if it is constant for at least two iterations. Thinks do work.

One note. I do read the datasheets and all the application notes I can find but these documents are overwelming for a starter like me. And, if I hadn't asked I would never have been aware of bouncing.

Last Edited: Tue. Sep 29, 2020 - 09:50 PM