External interrupt INT0 triggering just once

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

I've been using the Atmega 328p's INT0 interrupt to trigger on the rising edge of a signal, but the interrupt triggers just once and does so intermittently. I find this strange considering that INT1 and PCINT, configured on PD6, work without any issues. I've been looking through the forums and can't seem to find anyone who's had the same issue. The datasheet did have something that seemed interesting pertaining to  automatically clearing the interrupt flag when using level detection, but after testing I doubt that it is the issue.

 

So far I've experimented with:

1) Clearing the flag by "hand"

2) Use level detection rather then edge detection

3) Using an oscilloscope to troubleshoot electrical problems

      A. Checked signal integrity

      B. Signal gets from point A to point B

      C. Signal respects logic levels

4) Other inputs (Hooked up directly to VCC (switch) ,used a known signal from another board, function generator)

5) Commenting all of the code except initIO(), initInterrupt() and the ISR

 

The issue still persists, so I suspect it's either a configuration error or a hardware issue.  I'll swap in another chip, but in the mean time I wanted to see if anyone else had a similar problem or could provide some insight.

ISR(INT0_vect) 
{
	PORTB|= _BV(PORTB2);
	uint8_t tempState = (uint8_t)EV_BUTTON;
	writeRingBuffer(&eventBuf,&tempState);
	//EIFR = _BV(INTF0); // Clears the INT0 and INT1 flags
}

// Ready detect
ISR(INT1_vect)
{
	if(bit_is_set(PIND, PD3) != 0)
	{
		uint8_t tempState = (uint8_t)EV_READY;
		writeRingBuffer(&eventBuf,&tempState);
	}
	else
	{
		uint8_t tempState = (uint8_t)EV_NOT_READY;
		writeRingBuffer(&eventBuf,&tempState);
	}
}

// Carrier detect
ISR(PCINT2_vect)
{
	if(bit_is_set(PIND, PD6) != 0)
	{
		uint8_t tempState = (uint8_t)EV_CONNECTED;
		writeRingBuffer(&eventBuf,&tempState);
	}
	else
	{ 
		uint8_t tempState = (uint8_t)EV_CONNECTION_CLOSED;
		writeRingBuffer(&eventBuf,&tempState);
	}
}

// UART interrupt
ISR(USART_RX_vect){
   unsigned char temp = (unsigned char)UDR0;             //read UART register into value
   writeRingBuffer(&recBuf,&temp); 

}

// Timer overflow interrupt
// This frequency should be 488Hz, 8MHZ/(256*64)
ISR(TIMER0_OVF_vect){

	// Look at the clock preformance and figure the possible drift as well as the impacts on your time out functions
	// Consider using the 8MHz clock if drift is too great

   tickCount +=1;
	
	if((tickCount&0xFF) == 0) // Mask increases freq
	{	
		checkCurrentState = true;
	}
	
	if((tickCount&0x07) < 2 && currentState.associatedState > ST_REBOOT) // Mask increases freq
	{	
			
		PORTB|= _BV(PORTB1);
		if(currentState.associatedState > ST_CONNECTED)
			PORTD |= _BV(PORTD7);
	}
	else 
	{
		//
		PORTD &= ~_BV(PORTD7) ;
		PORTB &= ~_BV(PORTB1);
		
	}
	

}




int main(void) {
   // Reception and event buffers
	unsigned char recievingBuffer[MAX_REC_BUFFER_SIZE],eventBuffer[MAX_EVENT_BUFFER_SIZE];
	initRingBuffer(&recBuf,MAX_REC_BUFFER_SIZE,recievingBuffer,false);
	initRingBuffer(&eventBuf,MAX_EVENT_BUFFER_SIZE,eventBuffer,false);
	
	
	// Init tick counter
	tickCount = 0;
	
	// Init state
	// Makes sure we start in the correct state
	currentState.associatedState = 99; // Magic number to trigger the protection condition
	uint8_t tempState = (uint8_t)EV_NO_EVENT;
	writeRingBuffer(&eventBuf,&tempState);
	updateState(&eventBuf); // Finds initial state
	
	// Init peripheral devices
	initIO();
	initTimer();
	initUART();
	initInterrupts();
	reset();
	
	// Possibly implement brownout
	// Brown-out Detection chapter 11.5
	
	// Turn off unused peripherals 
	powerOffPeripheralDevices();
	
	
#if PRINT_DEBUG_STATEMENTS
	// Debug port
	dbg_tx_init();
#endif // End of PRINT_DEBUG_STATEMENTS	


   while (1) 
   {

#if DEBUG_STATE_MATRIX
	printStateTransitions();
	for(int i = 0; i <400;i++)
		_delay_ms(10);
#else
	PRINT_DEBUG_STATEMENT(currentState.associatedState +40); // +40 makes the state visible
	currentState.func();
#endif // End of DEBUG_STATE_MATRIX 

   }
   
}
void initInterrupts()
{


	UCSR0B |= _BV(RXCIE0); // Sets Rx interupt enable (KEEP THE PIPE)
	EICRA =  _BV(ISC01) | _BV(ISC00) | _BV(ISC10); // Rising edge detection for INT0 and logic change detection for INT0   
	EIMSK = _BV(INT1) | _BV(INT0); // Enables both INT0&INT1
	PCICR = _BV(PCIF2); // Enables PCINT[23:16]
	PCMSK2 = _BV(DDD6); // Sets the interupt on PD6
	TIMSK0 = _BV(TOIE0); // Enables timer overflow interrupt
	sei(); // Enable global interrupt
}

void powerOffPeripheralDevices()
{
	// Can we shut off the SPI and still reprogram?
	PRR = _BV(PRTWI) | _BV(PRTIM2) | _BV(PRTIM1) | _BV(PRADC); // Consider adding SPI, not sure if that impacts the programmer..
}

void initIO()
{

	DDRB = _BV(DDB5); // To be removed later, currently used to debug
	DDRB |= _BV(DDB2); // To be removed later, currently used to debug
	DDRB |= _BV(DDB1); // Ready state light
	
	DDRD = _BV(DDD7); // Carrier detect light
	DDRD |= _BV(DDD4); // PTT
	DDRD |= _BV(DDD5); // RESET
	DDRD &= ~_BV(DDD2); // User input
	DDRD &= ~_BV(DDD3); // Ready state input
	DDRD &= ~_BV(DDD6); // CD state input
	
	if(bit_is_set(PIND, PD3))
		PORTB |= _BV(PORTB1);
	else
		PORTB &= ~_BV(PORTB1);
		
	if(bit_is_set(PIND, PD6))
		PORTD |= _BV(PORTD7);
	else 
		PORTD &= ~_BV(PORTD7);
}


void initTimer()
{
	TCCR0A = 0;
	TCCR0B = _BV(CS00) | _BV(CS01);  
}

void initUART()
{
	UBRR0H = (BAUD_PRESCALER>>8);
	UBRR0L = (BAUD_PRESCALER);
	UCSR0A = _BV(U2X0);
	UCSR0B = _BV(RXEN0) | _BV(TXEN0);
	UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
	
}

If you feel the need to see more code, don't hesitate to ask. Thank you ahead of time,

Felix

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

I remember vaguely having this problem with an AVR mega8.  I suggest manually clearing the INT0 interrupt flag in the INT0 interrupt routine by writing a logic one to the interrupt flag.

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

This sounds like https://www.avrfreaks.net/forum/m... except that that poster had it working on INT1 but not INT1.  Perhaps you two could get together.  ;)

 

Simonetta wrote:
I remember vaguely having this problem with an AVR mega8. I suggest manually clearing the INT0 interrupt flag in the INT0 interrupt routine by writing a logic one to the interrupt flag.

Now, I will start exploring trigger circuit and debouncing and such.  But tell me, Simonetta, if properly set up for edge triggering as OP said in the original post, and the datasheet says the flag is cleared when the ISR is invoked -- why would the flag still be set?  Is it coming from an 8MHz square wave from a function generator?  Then the AVR would never catch up.  Is it because , meh, the external interrupts kinda work the way the datasheet suggests but not really reliably.  Summary:  You will need more info to convince me.

 

Now, back to OP:  Tell the connections to the pins in question.  Tell the triggering mechanism.  Tel the level >>right at the AVR pins<< when testing, triggered and not triggered.

 

All Vcc and ground pairs connected and decoupled?   Tell AVR model, toolchain, and version.  Tell optimization settings.  Clean build?  Any warnings?  Vcc level?

 

I see that you apparently have some indicator LEDs.  So tell all your connections with the shown code, and tell what happens when you trigger stuff.  I.e., tell how you are testing; tell what you expect to happen; tell what is happening.

 

 

 

 

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.

Last Edited: Wed. Nov 29, 2017 - 09:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the code above it's commented out, but adding it back changes nothing. Maybe the problem is related to triggering and not just resetting.. I'll look into that

ISR(INT0_vect) 
{
	PORTB|= _BV(PORTB2);
	uint8_t tempState = (uint8_t)EV_BUTTON;
	writeRingBuffer(&eventBuf,&tempState);
	//EIFR = _BV(INTF0); // Clears the INT0 flag
}

 

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

Tell AVR clock speed.  Post a complete simple test program.  (what you posted doesn't have all the #defines, baud calculation, macros, and similar)

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

Flabelle wrote:
I find this strange considering that INT1 and PCINT, configured on PD6, work without any issues.
Flabelle wrote:
using the Atmega 328p

I'm starting to get a bit confused...I guess a complete schematic might help.  PD6?  How is that related to INT1 (PD3 in my datasheet)?

 

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

theusch wrote:

Flabelle wrote:
I find this strange considering that INT1 and PCINT, configured on PD6, work without any issues.
Flabelle wrote:
using the Atmega 328p

I'm starting to get a bit confused...I guess a complete schematic might help.  PD6?  How is that related to INT1 (PD3 in my datasheet)?

 

 

What I meant to say was that  PCINT is configured on PD6. INT1 is indeed mapped to PD3.

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

In short, there is still too much structure in your posted test program to go further. a working UART link indeed might help with printing results, but a mystery "ring buffer" mechanism, no TX ISRs or other consumption of the ring buffer, and no UART interrupt sources enabled makes it difficult.

 

My recommendation is a test program a couple/few screenfuls, to test external interrupt sources.  Remember that "buttons bounce".  Find an output mechanism, whether LEDs or USART bytes or EEPROM logs or whatever.

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

theusch wrote:

This sounds like https://www.avrfreaks.net/forum/m... except that that poster had it working on INT1 but not INT1.  Perhaps you two could get together.  ;)

 

Thanks for the link, I'll look into that other post and see if I can get anything useful out of it!

 

theusch wrote:

Tell the connections to the pins in question.  Tell the triggering mechanism.  Tel the level >>right at the AVR pins<< when testing, triggered and not triggered.

 

The connections are relatively simple, there is UART going to another devkit. PD2 is currently connected to a hardware debounced button. PD3 is connected to a devkit, PB1 is an LED, PD7 is another LED, PD4 is a  discrete output, PD6 is another discrete input from a devkit. 

 

theusch wrote:

All Vcc and ground pairs connected and decoupled?   Tell AVR model, toolchain, and version.  Tell optimization settings.  Clean build?  Any warnings?  Vcc level?

 

 

On the PCB Vcc is decoupled with a 0.1uF ceramic cap, but there are empty pads to add others if necessary. I'm currently debugging on a breadboard, using an arduino promini.  I have not decoupled on the breadboard, but I'm banking on the cap (0.1uF) on the pro-mini. I'll snap a picture of the bread board and post it when I get back to my desk.

 

theusch wrote:

I see that you apparently have some indicator LEDs.  So tell all your connections with the shown code, and tell what happens when you trigger stuff.  I.e., tell how you are testing; tell what you expect to happen; tell what is happening.

Testing consists of hooking up one probe to PD2, which when triggered should light one of the debug leds. In theory pressing the button should toggle the led. Pressing the button once sometimes triggers the interrupt, but it's not even reliable. Once it is lit, it does not toggle again. 

 

There are no warnings, although I haven't increased the warning level (is that an option for avr-gcc?). I'm not sure I understand what you mean by clean build. There's nothing that strikes me as odd if that is your question.

 

Optimization: s
Toolchain: Winavr
Version: avr-gcc (WinAVR 20100110) 4.3.3
Vcc: 3.3v
Clock speed: 8MHz

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

Flabelle wrote:
In theory pressing the button should toggle the led. Pressing the button once sometimes triggers the interrupt, but it's not even reliable. Once it is lit, it does not toggle again.

 

That's not what your posted code does -- it sets the LED.  No toggle.

Flabelle wrote:
ISR(INT0_vect) { PORTB|= _BV(PORTB2);

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

In short, there is still too much structure in your posted test program to go further. a working UART link indeed might help with printing results, but a mystery "ring buffer" mechanism, no TX ISRs or other consumption of the ring buffer, and no UART interrupt sources enabled makes it difficult.

 

My recommendation is a test program a couple/few screenfuls, to test external interrupt sources.  Remember that "buttons bounce".  Find an output mechanism, whether LEDs or USART bytes or EEPROM logs or whatever.

I'll get started on that tomorrow, I'll write a very simple program that just contains the INT0 and INT1 interrupts. I'll test that tomorrow and work backwards to isolate the problem.

 

As far as bounce goes I think I'm covered, the breadboard has an RC filter with a  cut off frequency of ~3 Hz and it looks clean on the oscilloscope. I'll pay more attention to it though. For output mechanism I'm using the programmer (USB to UART, with a software UART implemented in the code) and teraterm for printed statements as well as LEDs for boolean values or position in the code. 

 

 

 

 

Last Edited: Wed. Nov 29, 2017 - 10:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

Flabelle wrote:
In theory pressing the button should toggle the led. Pressing the button once sometimes triggers the interrupt, but it's not even reliable. Once it is lit, it does not toggle again.

 

That's not what your posted code does -- it sets the LED.  No toggle.

Flabelle wrote:
ISR(INT0_vect) { PORTB|= _BV(PORTB2);

 

Whoops... I don't think that's the only issue though, before putting the LED I was having problems as well. The code contains a finite state machine and the button is one of the events, and after pressing it once it stopped transitioning to that other state, but would transition to other states with no problem.

 

I'll fix the LED and try commenting out everything again, see if that solves the problem. If it does I'll work backwards from that and slowly add code back.

EDIT:

The LED is fixed. I think it's a problem with the connection, when I press on the chip or "shake it" the debug light starts toggling. The odd thing is that it still fails to detect the rising edge reliably , even if I directly apply VCC to it.  I'll rework the soldering and see if that helps.

Last Edited: Wed. Nov 29, 2017 - 10:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Flabelle wrote:
The code contains a finite state machine and the button is one of the events, and after pressing it once it stopped transitioning to that other state, but would transition to other states with no problem.

So, what would your state machine transitions have to do with the ISR not triggering?

 

As you suggested, get a simple program to test your subsystems.  If indeed you are using interrupt-driven state transitions, then concentrate on that, up to max rate and no bouncing. 

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

I did that and found the problem. It's a combination of simple things. Some of it is user error, I naively debugged on a breadboard rather than the board. The setups aren't identical like they should be, so I was debugging two separate problems at once. The other is that there is an intermittent connection, after reworking the board the issue is gone.

 

Thanks a lot for your help!