ATtiny external interrupt

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

Migrating from Arduino to AVR's & Atmel Studio 7 I'm having a hard time with external interrupts.  I've poured over the datasheet countless times, Googled the heck out of it, and looked at many examples.  I'm sure the information is there, I just seem to be either missing it or not translating things properly for this AVR.  Time to ask for help...

 

I've set up a simple test environment with a Tiny861, a test LED that the ISR should turn off, and a heartbeat LED that always blinks so I know it's alive.  The result is a happily blinking heartbeat and a test LED that stays on and never shuts off.

 

Because I want to fire on a rising edge I'm using vector INT0, in accordance with the datasheet...

 

GIMSK – General Interrupt Mask Register

Bit 6 – INT0: External Interrupt Request 0 Enable
When the INT0 bit is set (one) and the I-bit in the status register (SREG) is set (one), the external pin interrupt is enabled.
The interrupt sense control0 bits 1/0 (ISC01 and ISC00) in the MCU control register (MCUCR) define whether the external
interrupt is activated on rising and/or falling edge of the INT0 pin or level sensed.
Activity on the pin will cause an interrupt
request even if INT0 is configured as an output. The corresponding interrupt of external interrupt request 0 is executed from
the INT0 interrupt vector.

Interrupt 0 Sense Control

ISC01=1 & ISC00=1 The rising edge of INT0 or INT1 generates an interrupt request.

 

The Setup:

PB0 = LED Blinking forever (heartbeat)

PB1 = LED that starts ON and should be turned off when the interrupt is fired

PB2 = Interrupt Pin

 

Code:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

ISR(PCINT_vect)
{
	PORTB &= ~(1 << PB1);		// Turn off LED on PB1 when interrupt occurs
}

int main(void)
{
	//Configure Port IO
	DDRB = 0x03;			//00000011 PortB all inputs except PB0 & PB1 are outputs

	//Interrupt setup for pin PB2
	PCMSK1 |= (1<<PCINT10);		//Enable change detection on PB2 (PCINT10)
	GIMSK |= (1<<INT0);		//Enable interrupt vector
	MCUCR |= (1<<ISC01)|(1<<ISC00);	//Set fire condition: Rising Edge
	sei();				//Global interrupt flag enable	

	PORTB |=  (1 << PB1);		//Initialize PB1 LED as being ON

	//Loop to blink the LED on PB0, something to do
	while(1)
	{
		_delay_ms(25);
		PORTB &= ~(1 << PB0);   // Heartbeat LED off
		_delay_ms(25);
		PORTB |=  (1 << PB0);   // Heartbeat LED on
	}
}

I have tried external pullup and pulldown resistors on the interrupt pin with no difference in outcome.  I have also tried different sets of pins.  Any advice would be greatly appreciated.

 

Thank you.

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

Looks like you're enabling INT0, not PCINT (PCIE0)

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

Thanks for your response.  I had tried with PCIE0 many times during my troubleshooting but I think you might have unlocked a piece of the puzzle for me.  I didn't understand INT0 and INT1 as compared PCINT0-15.  I thought they were vectors but now, after going back to the datasheet, notice PB6=INT0 and PA2=INT1.  Are these perhaps the only two interrupt pins capable of firing on specific criteria such as a falling edge while the PCINT's just fire on any logic change?

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

Yes, you can only specify the edge (or level) for INT0 and INT1.

 

How are you triggering PB2?

 

BTW, you have an atomicity problem caused by manipulating PORTB in both main code and in an ISR, unless you disable interrupts (or at least the interrupt that can affect PORTB) in the main code while you're manipulating PORTB.

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

Those single bit port manipulations are usually optimized to a single SBI/CBI instruction, so the atomicity shouldn't be a problem until he uses more than one bit.

Computers don't make errors - What they do they do on purpose.

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

KIIV_cz wrote:

Those single bit port manipulations are usually optimized to a single SBI/CBI instruction, so the atomicity shouldn't be a problem until he uses more than one bit.

Agreed, it's probably not a problem in this case, but worth pointing out for those not yet in the know about the issue.

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

I'll rework things to use INT0 or INT1 and see what becomes of it.  Thanks for helping me!

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

I have reworked things however the behavior seemed very unexpected in that the heartbeat LED was briefly interrupted and the effects of the ISR never manifested.  I just read that if an appropriate ISR is not defined then the AVR will reset.  In order to know if the AVR is resetting I set up an LED that will only come on momentarily during initialization.  Sure enough when I trigger the interrupt the unit resets instead of firing the ISR.

 

To cover all my bases I proceeded to create ISR's for INT0_vect, INT1_vect, PCINT_vect, and BADISR_vect figuring if it works then I could start the process of elimination... the unit still resets.  

 

I think I need to take a step back and double check my fuse bits, wiring, datasheet, etc. before going further.  I'm either totally not grasping a major concept here or something in my test setup is incorrect.

 

 

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

Rooney wrote:
Are these perhaps the only two interrupt pins capable of firing on specific criteria such as a falling edge while the PCINT's just fire on any logic change?

Surely this depends on your AVR model.  (You are referring to Tiny861?)  What does the datasheet say?  When you run down the list of interrupt vectors, which might be candidates for either-edge triggering?  I'll give you a hint to start:  If your device has input capture, than can you pic an edge?  Analog comparator?  Timer-as_counter with external clock and a compare match at 0?  In a Mega there are one or two more -- there is an exhaustive thread on that.

 

In practice, I've never found it to be a problem.  At worst, it is a wasted microsecond on pin-change handling to check the edge.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Rooney wrote:
I just read that if an appropriate ISR is not defined then the AVR will reset.

Where did you read that?  Fake news.  When an enabled interrupt source is triggered, the AVR will execute the contents of flas at the address of the corresponding interrupt vector.  Typically this will be some type of jump to a handling routine, but needn't be. 

 

Your toolchain (have you explicitly stated that?  I guess we can infer) might have a mechanism for default handling of uncaught interrupt vectors.  What does the documentation for your chosen toolchain?  While the action may be a jump to address 0, it will >>not<< be a reset of the AVR.

 

What part of the above is not in the datasheet and the toolchain documentation?

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Rooney wrote:
To cover all my bases I proceeded to create ISR's for INT0_vect, INT1_vect, PCINT_vect, and BADISR_vect figuring if it works then I could start the process of elimination... the unit still resets. I think I need to take a step back and ...

...post the smallest complete test program that exhibits this behaviour.  Show schematic.  Tell how you are testing.

 

There are other possibilities, such as a hard short drawing down the power supply.  Give more basic information, and a bit less hand-wringing.  Start with a small sanity-chack program.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Perhaps reset was not the right term, more like restart.  Everyone's input was very helpful and has given me enough to work with for a bit.  I'll review everything and do some more troubleshooting before following up or asking for further assistance.  Thank you.

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

Following up... I was able to get this working, it must have been something with my mocked up circuit.  I picked up an AVR Dragon and it worked when socketed on it.  The input here was very helpful as I had not previously grasped that I really needed to use INT0 (or INT1) vs PCINT.  Thank you.