Attiny84 and a disappearing global IE

Go To Last Post
57 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Freaks,

Re: Attiny84

I need to have the global interrupt enabled after an interrupt is entered. According to the documentation
this can be done by setting the interrupt enable flag in SREG after entering the handler.

I have tried this but the flag is reset not only on the interrupt call but also on the return.

Is this normal?

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

Is this normal?


Yes but harmless. RETI is literally just RET and set I. If I is already set nothing visible occurs in SREG.

BTW I have a distant memory that you maybe use avr-gcc? If so I highly recommend you investigate ISR_NOBLOCK:

http://www.nongnu.org/avr-libc/u...

I guess you understand the pitfalls of doing this? You are OK until you hit the situation where the non-blocking ISR occurs more often than the time it takes to service. Once they start to stack you are in trouble!

but if the attempt is to give something else a "higher priority" then it's OK as long as you have explored all the corner cases.

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

Cliff,

Thanks for the assistance. After I read you post I realized I was using return instead of reti();

Thanks again,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

Thanks for the assistance. After I read you post I realized I was using return instead of reti();


NOOOOO!!

the *ONLY* time you should ever use reti() is when you use ISR_NAKED. Otherwise just "return;" or simply hit the closing brace to leave an ISR and the compiler generates RETI rather than RET anyway (you can see this in the LSS).

Part of what you ask for when you use ISR() is "oh and when you get to the end I'd like a RETI not a RET please". Here's a very simple example:

ISR(INT0_vect) {
	PORTB = 0x55;
}

which generates:

__vector_1:
//==> ISR(INT0_vect) {
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
	push r24
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 4 */
.L__stack_usage = 4
//==> 	PORTB = 0x55;
	ldi r24,lo8(85)
	out 0x18,r24
/* epilogue start */
//==> }
	pop r24
	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti

Even if you make it:

ISR(INT0_vect, ISR_NOBLOCK) {
	PORTB = 0x55;
}

you get:

__vector_1:
//==> ISR(INT0_vect, ISR_NOBLOCK) {
	sei
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
	push r24
/* prologue: Interrupt */
/* frame size = 0 */
/* stack size = 4 */
.L__stack_usage = 4
//==> 	PORTB = 0x55;
	ldi r24,lo8(85)
	out 0x18,r24
/* epilogue start */
//==> }
	pop r24
	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti

All that really changes is the early insertion of SEI on entry.

Look how disastrous the use of reti() is:

ISR(INT0_vect, ISR_NOBLOCK) {
	PORTB = 0x55;
	reti();
}
__vector_1:
//==> ISR(INT0_vect, ISR_NOBLOCK) {
	sei
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
	push r24
/* prologue: Interrupt */
/* frame size = 0 */
/* stack size = 4 */
.L__stack_usage = 4
//==> 	PORTB = 0x55;
	ldi r24,lo8(85)
	out 0x18,r24
//==> 	reti();
/* #APP */
 ;  6 ".././test.c" 1
	reti
 ;  0 "" 2
/* epilogue start */
//==> }
/* #NOAPP */
	pop r24
	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti

So the first RETI in that occurs with the stack inbalanced by four PUSH's! The return will be to some mysterious combination of R24 and SREG!

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

Cliff,

reti() worked for one iteration and then crashed. Clearly it was eating the stack. I should have paid closer attention to the point you were trying to make.

How do I go about using the ISR_NOBLOCK attribute to prevent the global IE from being reset? The interrupt.h refers to using this in the ISR macro but I have no experience with this.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Cliff,

Tracked down one of your previous posts re: ISR_NOBLOCK;


ISR( INT0_vect, ISR_NOBLOCK )
{
 TIMSK1 |= (1<<TOIE1)
 sei();

 return;

}

This continues to reset IE on return.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:
How do I go about using the ISR_NOBLOCK attribute to prevent the global IE from being reset?
By this do you mean that you want the global interrupt flag to be clear after leaving the ISR? If so, ISR_NOBLOCK will not do that. It only makes the flag be set during the ISR. You would need ISR_NAKED, then use RET instead of RETI.

Regards,
Steve A.

The Board helps those that help themselves.

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

Steve,

I looking to have the global flag set after exiting the interrupt.
Is issue specific to the ATtiny parts? I have put together a few Atmel based microcontoller projects and this has never been an issue.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

I looking to have the global flag set after exiting the interrupt.

RETI does that. Please post your test case that "proves" otherwise.

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

Lee,

It ain't pretty but here goes.


//
// File:	DMMCU1.c
// Purpose:	Main for dot marker program
// Date:	February 25th, 2014
// Purpose:	Dot marker controller code with ADC input
//			for dot size, burst rate and burst time.
//
// Notes:	
//			Feb 27th 2014
//			Only dot size read, trigger and purge functional
//
// To do:	-	Add continuous and burst features
//

#include 
#include 
#include 
#include 
#include 		// Header file for externals.

volatile unsigned int ON_time_adc, BURST_rate_adc, BURST_time_adc;		// ADC readings
volatile unsigned int ON_time_val, BURST_rate_val, BURST_time_val;		// Comped values
volatile char ON_time_adc_cnt, BURST_rate_adc_cnt, BURST_time_adc_cnt;	// Reading counters
volatile unsigned int adc_switch;
volatile unsigned int TCNT1_buff;

union adc_u{
			unsigned int adc_val;
			char adc_data[2];
			}volatile adc_op;



// Main DM program
void main( void )
{
  IO_setup();

  adc_switch = 0;
  // ON_time_adc_cnt = 0, BURST_rate_adc_cnt = 0, BURST_time_adc_cnt = 0;	


  do{

		// ADC read cycle
		if( !(IS_purge) )
		if( FINISHED_con )		// Read and convert only if ADC complete
			{
				adc_op.adc_data[0] = ADCL;
				adc_op.adc_data[1] = ADCH;

				if( adc_switch == 2 )	// On time
					{
						ON_time_adc += adc_op.adc_val;	// Add to average
						ON_time_adc_cnt += 1;			// Count number of readings

							if( ON_time_adc_cnt > 31 )
								{	
									ON_time_val = (ON_time_adc>>5);	// Calc average div. by 4
									ON_time_adc_cnt = 0;
									ON_time_adc = 0;
									TCNT1_buff = 0xFFFF - 0x190 - ON_time_val;
								}
					}

				if( adc_switch == 0 )	// Burst rate
					{
						BURST_rate_adc += adc_op.adc_val;
						BURST_rate_adc_cnt += 1;

							if( BURST_rate_adc_cnt > 31 )
								{
									BURST_rate_val = (BURST_rate_adc>>5);
									BURST_rate_adc_cnt = 0;
									BURST_rate_adc = 0;
								}
					}

				if( adc_switch == 1 )	// Burst time
					{
						BURST_time_adc += adc_op.adc_val;
						BURST_time_adc_cnt += 1;

							if( BURST_time_adc_cnt > 31 )
								{
									BURST_time_val = (BURST_time_adc>>5);
									BURST_time_adc_cnt = 0;
									BURST_time_adc = 0;
								}
					}

				adc_switch += 1;
				if( adc_switch > 2 )
					{
						adc_switch = 0;
					}
				
				CLR_admux;
				ADMUX |= adc_switch;
								
				START_con;
			}

		// Purge routine
		if( IS_purge )
			{
				INT0_dis;	// Disable interrupt

				DRV_off;
				_delay_ms( 16 );		// About 60hz		
				DRV_on;					// Turn on valve
				_delay_us( 900 );		// About max. on time
				DRV_off;				// Turn it off
			}
		else
			{
				INT0_ena;		// Enable interrupt	
			}



  }while(1);

 return;				// Never used!!!
}

// Interrupt service routine for timer 1

ISR( TIM1_OVF_vect, ISR_NOBLOCK )
{

	// Turn off O/P driver
//	DRV_off;

	// For test only
//	BURST_led_off;

	// Stop timer
	TCNT1_stop;
	// Disable timer int
	TIMSK1 &= (~(1<<TOIE1));
	
	sei();
	
	reti();
}


// Interrupt service routine for INT0

ISR( INT0_vect )
{
	// INT0 disable
	 INT0_dis;

	// Load start count
	TCNT1 = TCNT1_buff = 0xFFFA; 

	// Turn on O/P driver
//	DRV_on;
	// For test only

	// Enable TCNT1 int
	TIMSK1 |= (1<<TOIE1);

	// Start timer
	TCNT1_start;

	sei();
				
	reti();
}




// I/O Setup

void IO_setup( void )
{
	// Remove clk fuse divider
	CLKPR = 0x80;
	CLKPR = 0x00;

	MCUSR = 0x00;			// Clear reset flags

	// PIN i/o setup
	DDRA &= (~(1<<DDA3));	// Set as i/p (PURGE)
	DDRA &= (~(1<<DDA4));	// Set as i/p (S_SHOT)
	DDRA &= (~(1<<DDA5));	// Set as i/p (CONT)
	DDRA &= (~(1<<DDA6));	// Set as i/p (BURST)

	DDRB &= (~(1<<DDB2));	// Set as i/p (TRIGGER)

	DDRA |= (1<<PA7);		// Burst LED driver
	BURST_led_off;			// Turn lamp off

//	DDRB |= (1<<PB3);		// Switch reset line for driver

	// ADC i/o setup
	ADMUX &= (~(1<<REFS1)); // Set ref for VCC
	ADMUX &= (~(1<<REFS0));

	// DDR set for ADC i/p pins
	DIDR0 |= ((1<<ADC0D)|(1<<ADC1D)|(1<<ADC2D));

	ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));	// Set ADC clock clk/128
	ADCSRA |= (1<<ADEN);							// Enable converter

	// INT0 Setup
		// If single shot or burst, set to rising edge
		if( IS_sshot != 0 )
			{
				MCUCR |= ((1<<ISC01)|(1<<ISC00) );	// Set to rising edge
				GIMSK |= (1<<INT0);					// Enable interrupt
			}

		// If continuous, set low level trig
		// if( IS_ont != 0 )
		//	{

		//	}


	// TCNT1 setup
		// Handled by INT0

	// Enable interrupts
	ENA_ints;

	return; 
}




// End of DMMCU1.c

The header contains:

//
// File:	DMMCU.c
// Purpose:	Main for dot marker program
// Date:	February 25th, 2014
//

#define ON_time		0x02		// On time address
#define BURST_rate	0x01		// Burst rate address
#define BURST_time	0x00		// Burst period address


// ADC stuff
#define START_con		(ADCSRA |= (1<<ADSC))			// Start ADC conversion
#define FINISHED_con 	(!((ADCSRA & (1<<ADSC)) != 0 ))	// Is conversion finished?
#define CLR_admux		(ADMUX &= (~(0x07)))			// Clear selected input
#define SEL_ot			(ADMUX |= ON_time)
#define SEL_br			(ADMUX |= BURST_rate)
#define SEL_bt			(ADMUX |= BURST_time)

#define IS_sshot		((~PINA) & (1<<PINA4))
#define IS_cont			((~PINA) & (1<<PINA5))
#define IS_burst		((~PINA) & (1<<PINA6))

#define ENA_ints		SREG |= 0x80
#define DIS_ints		SREG &= (~(0x80))

// Timer 1 stuff
#define TCNT1_stop		TCCR1B &= (~((1<<CS12)|(1<<CS11)|(1<<CS10))) // Stop
#define TCNT1_start		TCCR1B |= ((1<<CS11)|(1<<CS11)|(1<<CS10))	// Start

// INT0 stuff
#define	INT0_ena		GIMSK |= (1<<INT0);					// Enable interrupt
#define	INT0_dis		GIMSK &= (~(1<<INT0))				// Disable interrupt

// O/P driver control
#define DRV_on			PORTB &= (~(1<<PB3))
#define DRV_off			PORTB |= (1<<PB3)

// Purge and trig detect
#define IS_purge		(((PINA) & (1<<PA3)) != 0 )		// High if enabled
#define IS_trig			(((PINB) & (1<<PB2)) != 0 )		// High if enabled

#define BURST_led_on	(PORTA &= (~(1<<PA7)))
#define BURST_led_off	(PORTA |= (1<<PA7))		

extern void IO_setup( void );

// End of DMMCU1.h

Thanks for the assistance.

A.[/code]

PS: ISR_NAKED was removed.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Let me start over, then--

Why in the world do you feel it is necessary to "NOBLOCK"/re-enable interrupts in an AVR8 program? Especially one as you've shown? I've done scores of AVR8 production apps over the past decade+ and have never yet found a compelling reason. Your ISRs are short, a few microseconds. Why introduce possible interrupt-nesting effects, especially on a Tiny with limited SRAM resources?

If indeed the NOBLOCK re-enables interrupts at the start of the ISR, then what is the purpose for the sei()'s near the end of the ISRs?

There is no reason to have the reti() at the end of the ISR, and might cause stack corruption?

How are you determining that the global I bit is not set upon return from your ISRs?

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

Lee,

The program controls a proprietary high speed valve. It is critical that the on time of the valve be controlled within +/- an few micro seconds. Most importantly the on time must not exceed 900us. At times the valve runs at around 600hz. I did not want any of the code in main() to prevent the valve from turning off. To do so would trip the protection circuit in the valve driver.

That being said, I get your point. In fact had already revised the code to reset the IE in main. But given that the data sheet states this is not an issue, I would like to understand how it's done.

Thanks,

A.

PS. Not understanding what exactly NO_BLOCK does, I was trying to work it out before I did the cut and paste to the post.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

In fact had alredy revised the code to reset the IE in main.

Say what?!?

If you have IS off in main() then the ISRs will never fire. "Problem" solved.

In any case, I still want to here about this situation where RETI did not turn on the global I bit.

Indeed. for a short pulse of a few microseconds by all means sit in one place wit interrupts off and count with NOPs or whatever. An alternative is to set up to use a timer and OC pin to generate the pulse, the timer hardware turn it on/off, and then there is a rather long gap to service the disable.

(I re-read your code, and if it were me I'd probably either do the pulse inline with interrupts off since it is no longer than a millisecond; or alternately let a timer handle the pulse. Either way, K.I.S.S.)

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

Lee,

ENA_ints at the end of IO_setup() sets IE. ( I know its obfuscated.) Perhaps I am totally out to lunch on this. I have attached the source. High on PB2 triggers the int. If you have a moment let me know what I missed.

Thanks,

A.

Attachment(s): 

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

ENA_ints at the end of IO_setup() sets IE.

What does that have to do with:
Quote:

I have tried this but the flag is reset not only on the interrupt call but also on the return.

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

Lee,

Quote:

If you have IE off in main() then the ISRs will never fire. "Problem" solved.

I am enabling the interrupts.

Triggering INT0 calls the int.
The IE flag gets reset.
I set IE in the interrupt.
When the interrupt returns the IE is again reset.

I don't know why.
These are just my obsevations.

Thank you,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

When the interrupt returns the IE is again reset.


Again: How are you determining that?

Re:

Quote:

I am enabling the interrupts.

When the occasion rises to fire your shortish pulse with an accurate duration and you want to do it in the mainline, then turn off global interrupts, fire the pulse, turn it off after the prescribed interval, and then turn global interrupts back on.

If you want to let the OC hardware do the pulse, then with the timer stopped you fully configure it to do the job except for starting it. You clear the timer interrupt flags. You turn on global interrupts if off, and start the timer and go in your merry way. Maybe 10 instructions, if that.

Now, you then have (as a guess) two ways to get off the merry-go-round. (See the clever use of "merry" in consecutive sentences?) You can sit and wait for the pulse to be done (watching the OCIF), or you can configure an ISR to handle the disable.

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

Cliff have already told you: Do not use reti() in the ISR! You will exit the ISR before the epilogue have been executed and that will corrupt the stack. That means you will return from the ISR to some random location and start executing random instructions that may not even be instructions. Cliff also showed you the disaster with a short example.

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

Lee,

Quote:

Again: How are you determining that?

Using AS6 I am viewing the processor flags in the Processor window.

I am sure there are 100 ways to skin this cat. I like to know why something doesn't work as expected before abandoning the plan.

Thanks again for taking a look at this.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

snigelen,

I should have removed those before posting.

My bad.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

Using AS6 I am viewing the processor flags in the Processor window.


With the simulator, or debugWire?

In any case, I don't believe that an AVR8 will execute an RETI and not have the I bit set an instruction or so later. It wouldn't be an AVR8, then.

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

Lee,

In the simulator now but initially I was struggling with this over dwire.

Quote:

In any case, I don't believe that an AVR8 will execute an RETI and not have the I bit set an instruction or so later. It wouldn't be an AVR8, then.

I don't doubt for a minute that you are correct. At this point a one day project has blown up my JTAGICE mkII and eaten up about two days of my time. Simple problems like this one are tough for me to walk away from.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

As others have said, your problem is that you are putting reti() into your code. ISR() automatically puts the RETI for you (unless you specify ISR_NAKED). Putting it in yourself causes the ISR to return before it can clean up the stack.

As far as ISR_NOBLOCK is concerned, what it does is put in a SEI at the earliest point it can in the ISR. It is your choice to use ISR_NOBLOCK or to put in the sei() yourself.

Regards,
Steve A.

The Board helps those that help themselves.

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

Steve,

I understand the point you and others are making. reti() doesn't clean up the stack. At this point I am down to trying to figure out why this code resets IE on the ISR call and on ISR return.

ISR( INT0_vect )
{
 SREG |= 0x80;
 return;
}

As others have suggested, there are dozens of ways to get the desired result. As far as the original problem goes, I still don't know why this happens.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

I am down to trying to figure out why this code resets IE on the ISR call and on ISR return.

The AVR interrupt vectoring mechanism always sets I in SREG to 0 - there's no getting away from that - it's simply how ISR vectoring on an AVR CPU works.

but your first line there (could have been "sei();") wil set that bit to 1.

When this ISR executes the RETI that *will* be present then one instruction later I will be set to 1 if it isn't already.

these things are bound to happen - if you see something else your observation technique is wrong.

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

Cliff,

If I understand you correctly, the code as posted in my
previous post should result in IE being enabled after
the return from the ISR. This does not happen.

How am I making my observations?

In AS6 I am stepping through the following:
1. Load and run the program so things will settle down.
2. Open the I/O window and set PIN PB2.
3. Open the Processor window.
4. Step through the ISR and observe.

I will not have time to "prove" this on hardware until
tomorrow morning. Like most, I just don't like unsolved riddles.

I am using AS6 version 6.0 1843.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

If I understand you correctly, the code as posted in my
previous post should result in IE being enabled after
the return from the ISR. This does not happen.

I simply don't believe you. If you write:

ISR(ANYTHING_vect) {
 // absolutely nothing else here
}

Then I 100% guarantee that this will end in RETI and I further 100% guarantee that one opcode after the return is made the I bit *WILL* be set. If you 9observe otherwise your observation technique is at fault.

Even if you replace "//absolutely nothing else here" with something that messes with the I flag then I still guarantee that one opcode execution after this returns I will be set. Of course if the stuff you put in the ISR does, itself, set I then you won't notice the I related activity of RETI as the bit that is set will just appear to remain set.

If your claim is that you step the RETI (AND one further opcode) and whatever you are looking at shows the I bit at 0 after that then the thing you are looking at is not working like an AVR.

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

Quote:

If your claim is that you step the RETI (AND one further opcode) and whatever you are looking at shows the I bit at 0 after that then the thing you are looking at is not working like an AVR.


Cliff--

The only thing I can think of that might explain the symptoms (given the posted code with two ISRs) is that if stepping (especially through C code and not machine code) is that another interrupt is pending when the previous one completes. Then, a C step might (or might not?) even land in the mainline.

For example, the posted code enables timer1 and an interrupt based on an INT0 event. The timer is set up but I don't see where e.g. the timer overflow flag is cleared (which may be set from unrelated operation) and the overflow interrupt might immediately fire.

OP should make a minimal test program with one enabled ISR, that everyone can use to try to replicate OP's environment.

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

Lee,

Will do.

Cliff,

I stripped the ISR. Same result. I will do as Lee suggests.

Something I should have mentioned but I don't think it
is relevant is that the project started out in an AS4
environment and was moved using Atmel's conversion
utility to AS6.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Cliff / Lee,

I am at a loss to explain why this snippet does not
set IE. I have checked the assembly and it just isn't there.

#include 
#include 

volatile int a;


int main(void)
{


	MCUCR |= ((1<<ISC01)|(1<<ISC00) );	// Set to rising edge
	GIMSK |= (1<<INT0);					// Enable interrupt
	DDRA = 0xFF;

	sei();
	SREG |= 0x80;			// Force enable

    while(1)
    {
		a++;
		PORTA = a;
    }
}


ISR( INT0_vect )
{
	a--;
}

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

Then, a C step might (or might not?) even land in the mainline.

If you are concerned about low level stuff like I operation why would you do C steps? I'd switch to the mixed C+asm code where "step" means one opcode rather than one C statement and observe what happens on an opcode by opcode basis as it comes out of the ISR. As I say the guarantee from Atmel is that RETI will return and execute one opcode in the main() calling code then I will be enabled and on that next opcode fetch if any of the pending interrupt flags is set then a vector jumping processes to the relevant ISR wil start again (and it will start by disabling I).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
I am at a loss to explain why this snippet does not
set IE.

But it does. Here:

sei();

here:

SREG |= 0x80;

and here:

ISR( INT0_vect )
{
   a--;
}// IE set on return 

Quote:
I have checked the assembly and it just isn't there.
Then show us the assembly and prove it to us.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

I have checked the assembly and it just isn't there.

Eh? I just built this in 6.2B/4.8.1 and it says:

main:
//==> {
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
//==>    MCUCR |= ((1<<ISC01)|(1<<ISC00) );   // Set to rising edge
	in r24,0x35
	ori r24,lo8(3)
	out 0x35,r24
//==>    GIMSK |= (1<<INT0);               // Enable interrupt
	in r24,0x3b
	ori r24,lo8(64)
	out 0x3b,r24
//==>    DDRA = 0xFF;
	ldi r24,lo8(-1)
	out 0x1a,r24
//==>    sei();
/* #APP */
 ;  15 ".././test.c" 1
	sei
 ;  0 "" 2
//==>    SREG |= 0x80;         // Force enable
/* #NOAPP */
	in r24,__SREG__
	ori r24,lo8(-128)
	out __SREG__,r24
.L2:
//==>       a++;
	lds r24,a
	lds r25,a+1
	adiw r24,1
	sts a+1,r25
	sts a,r24
//==>       PORTA = a;
	lds r24,a
	lds r25,a+1
	out 0x1b,r24
	rjmp .L2

With the ISR containing:

.global	__vector_1
	.type	__vector_1, @function
__vector_1:
//==> {
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
	push r24
	push r25
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 5 */
.L__stack_usage = 5
//==>    a--;
	lds r24,a
	lds r25,a+1
	sbiw r24,1
	sts a+1,r25
	sts a,r24
/* epilogue start */
//==> }
	pop r25
	pop r24
	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti

As expected the ISR ends with RETI but also in the main() code:

//==>    sei();
/* #APP */
 ;  15 ".././test.c" 1
	sei
 ;  0 "" 2
//==>    SREG |= 0x80;         // Force enable
/* #NOAPP */
	in r24,__SREG__
	ori r24,lo8(-128)
	out __SREG__,r24

So, as you requested, it actually sets I in two different ways.

EDIT: Further I simulated this in AS6.2B. I put a break in the a-- in the ISR and then did as you said an ticked the PB2 pin in the IO view. As you say it then hits the break in the ISR. At the break the I bit is 0. I then step (in Asm view) to the RETI. In my case it then returned to an LDS in main as part of the PORTA=a statement. The Processor view shows I to be set at this point. It remains set and I can just keep looping the nine opcodes in the heart of the while() loop.

AFAICS this is all behaving exactly as one would expect.

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

Cliff / Lee,

I was stepping through the disassembled code not the "C".

Here is the top of the lss file.

00000000 <__vectors>:
   0:	10 c0       	rjmp	.+32     	; 0x22 <__ctors_end>
   2:	17 c0       	rjmp	.+46     	; 0x32 <__bad_interrupt>
   4:	16 c0       	rjmp	.+44     	; 0x32 <__bad_interrupt>
   6:	15 c0       	rjmp	.+42     	; 0x32 <__bad_interrupt>
   8:	14 c0       	rjmp	.+40     	; 0x32 <__bad_interrupt>
   a:	13 c0       	rjmp	.+38     	; 0x32 <__bad_interrupt>
   c:	12 c0       	rjmp	.+36     	; 0x32 <__bad_interrupt>
   e:	11 c0       	rjmp	.+34     	; 0x32 <__bad_interrupt>
  10:	10 c0       	rjmp	.+32     	; 0x32 <__bad_interrupt>
  12:	0f c0       	rjmp	.+30     	; 0x32 <__bad_interrupt>
  14:	0e c0       	rjmp	.+28     	; 0x32 <__bad_interrupt>
  16:	0d c0       	rjmp	.+26     	; 0x32 <__bad_interrupt>
  18:	0c c0       	rjmp	.+24     	; 0x32 <__bad_interrupt>
  1a:	0b c0       	rjmp	.+22     	; 0x32 <__bad_interrupt>
  1c:	0a c0       	rjmp	.+20     	; 0x32 <__bad_interrupt>
  1e:	09 c0       	rjmp	.+18     	; 0x32 <__bad_interrupt>
  20:	08 c0       	rjmp	.+16     	; 0x32 <__bad_interrupt>

00000022 <__ctors_end>:
  22:	11 24       	eor	r1, r1
  24:	1f be       	out	0x3f, r1	; 63
  26:	cf e5       	ldi	r28, 0x5F	; 95
  28:	d2 e0       	ldi	r29, 0x02	; 2
  2a:	de bf       	out	0x3e, r29	; 62
  2c:	cd bf       	out	0x3d, r28	; 61
  2e:	02 d0       	rcall	.+4      	; 0x34 
30: 02 c0 rjmp .+4 ; 0x36 <_exit> 00000032 <__bad_interrupt>: 32: e6 cf rjmp .-52 ; 0x0 <__vectors> 00000034
: #include int main(void) { 34: ff cf rjmp .-2 ; 0x34
00000036 <_exit>: 36: f8 94 cli 00000038 <__stop_program>: 38: ff cf rjmp .-2 ; 0x38 <__stop_program>

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

I copied the code above into a new Studio 6.1 project, Tiny84, simulator. Stepped (in C view) through the startup, saw the I bit set in Processor view, and remained set a few times through the infinite loop.

Opened the I/O view and tickled the INTF0 bit. Next step took me into the ISR. Switched back to Processor view and I is off. Step again to end of ISR; step again back to main loop and I turned on and stayed on. As expected.

[edit] I repeated the exercise with Dissasembly view. The I bit turned on after stepping past the RETI back to the main loop, and stayed on.

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: Tue. Mar 4, 2014 - 05:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lee,

So given the posted dis-assembly, where have I messed up?

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

The LSS above appears to be a null program, not your posted source 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

Quote:

appears to be a null program

Indeed - so you are probably also debugging the wrong thing too. Perhaps this has resulted from a project import accident?

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

Cliff / Lee,

I guess I am doing too many things at once. I did not in fact have the file I was working on in the project. :oops:

GccApplication3.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000000c8  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .bss          00000002  00800060  00800060  0000013c  2**0
                  ALLOC
  2 .debug_aranges 00000020  00000000  00000000  0000013c  2**0
                  CONTENTS, READONLY, DEBUGGING
  3 .debug_pubnames 00000030  00000000  00000000  0000015c  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .debug_info   0000009f  00000000  00000000  0000018c  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_abbrev 0000006f  00000000  00000000  0000022b  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_line   000000e7  00000000  00000000  0000029a  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_frame  00000030  00000000  00000000  00000384  2**2
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_str    000000b6  00000000  00000000  000003b4  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:	10 c0       	rjmp	.+32     	; 0x22 <__ctors_end>
   2:	43 c0       	rjmp	.+134    	; 0x8a <__vector_1>
   4:	1e c0       	rjmp	.+60     	; 0x42 <__bad_interrupt>
   6:	1d c0       	rjmp	.+58     	; 0x42 <__bad_interrupt>
   8:	1c c0       	rjmp	.+56     	; 0x42 <__bad_interrupt>
   a:	1b c0       	rjmp	.+54     	; 0x42 <__bad_interrupt>
   c:	1a c0       	rjmp	.+52     	; 0x42 <__bad_interrupt>
   e:	19 c0       	rjmp	.+50     	; 0x42 <__bad_interrupt>
  10:	18 c0       	rjmp	.+48     	; 0x42 <__bad_interrupt>
  12:	17 c0       	rjmp	.+46     	; 0x42 <__bad_interrupt>
  14:	16 c0       	rjmp	.+44     	; 0x42 <__bad_interrupt>
  16:	15 c0       	rjmp	.+42     	; 0x42 <__bad_interrupt>
  18:	14 c0       	rjmp	.+40     	; 0x42 <__bad_interrupt>
  1a:	13 c0       	rjmp	.+38     	; 0x42 <__bad_interrupt>
  1c:	12 c0       	rjmp	.+36     	; 0x42 <__bad_interrupt>
  1e:	11 c0       	rjmp	.+34     	; 0x42 <__bad_interrupt>
  20:	10 c0       	rjmp	.+32     	; 0x42 <__bad_interrupt>

00000022 <__ctors_end>:
  22:	11 24       	eor	r1, r1
  24:	1f be       	out	0x3f, r1	; 63
  26:	cf e5       	ldi	r28, 0x5F	; 95
  28:	d2 e0       	ldi	r29, 0x02	; 2
  2a:	de bf       	out	0x3e, r29	; 62
  2c:	cd bf       	out	0x3d, r28	; 61

0000002e <__do_clear_bss>:
  2e:	10 e0       	ldi	r17, 0x00	; 0
  30:	a0 e6       	ldi	r26, 0x60	; 96
  32:	b0 e0       	ldi	r27, 0x00	; 0
  34:	01 c0       	rjmp	.+2      	; 0x38 <.do_clear_bss_start>

00000036 <.do_clear_bss_loop>:
  36:	1d 92       	st	X+, r1

00000038 <.do_clear_bss_start>:
  38:	a2 36       	cpi	r26, 0x62	; 98
  3a:	b1 07       	cpc	r27, r17
  3c:	e1 f7       	brne	.-8      	; 0x36 <.do_clear_bss_loop>
  3e:	02 d0       	rcall	.+4      	; 0x44 
40: 41 c0 rjmp .+130 ; 0xc4 <_exit> 00000042 <__bad_interrupt>: 42: de cf rjmp .-68 ; 0x0 <__vectors> 00000044
: int main(void) { MCUCR |= ((1<<ISC01)|(1<<ISC00) ); // Set to rising edge 44: e5 e5 ldi r30, 0x55 ; 85 46: f0 e0 ldi r31, 0x00 ; 0 48: 80 81 ld r24, Z 4a: 83 60 ori r24, 0x03 ; 3 4c: 80 83 st Z, r24 GIMSK |= (1<<INT0); // Enable interrupt 4e: eb e5 ldi r30, 0x5B ; 91 50: f0 e0 ldi r31, 0x00 ; 0 52: 80 81 ld r24, Z 54: 80 64 ori r24, 0x40 ; 64 56: 80 83 st Z, r24 DDRA = 0xFF; 58: 8f ef ldi r24, 0xFF ; 255 5a: 8a bb out 0x1a, r24 ; 26 sei(); 5c: 78 94 sei SREG |= 0x80; // Force enable 5e: ef e5 ldi r30, 0x5F ; 95 60: f0 e0 ldi r31, 0x00 ; 0 62: 80 81 ld r24, Z 64: 80 68 ori r24, 0x80 ; 128 66: 80 83 st Z, r24 while(1) { a++; PORTA = a; 68: eb e3 ldi r30, 0x3B ; 59 6a: f0 e0 ldi r31, 0x00 ; 0 sei(); SREG |= 0x80; // Force enable while(1) { a++; 6c: 80 91 60 00 lds r24, 0x0060 70: 90 91 61 00 lds r25, 0x0061 74: 01 96 adiw r24, 0x01 ; 1 76: 90 93 61 00 sts 0x0061, r25 7a: 80 93 60 00 sts 0x0060, r24 PORTA = a; 7e: 80 91 60 00 lds r24, 0x0060 82: 90 91 61 00 lds r25, 0x0061 86: 80 83 st Z, r24 88: f1 cf rjmp .-30 ; 0x6c 0000008a <__vector_1>: } } ISR( INT0_vect ) { 8a: 1f 92 push r1 8c: 0f 92 push r0 8e: 0f b6 in r0, 0x3f ; 63 90: 0f 92 push r0 92: 11 24 eor r1, r1 94: 8f 93 push r24 96: 9f 93 push r25 a--; 98: 80 91 60 00 lds r24, 0x0060 9c: 90 91 61 00 lds r25, 0x0061 a0: 01 97 sbiw r24, 0x01 ; 1 a2: 90 93 61 00 sts 0x0061, r25 a6: 80 93 60 00 sts 0x0060, r24 PORTA = a; aa: 80 91 60 00 lds r24, 0x0060 ae: 90 91 61 00 lds r25, 0x0061 b2: 8b bb out 0x1b, r24 ; 27 sei(); b4: 78 94 sei b6: 9f 91 pop r25 b8: 8f 91 pop r24 ba: 0f 90 pop r0 bc: 0f be out 0x3f, r0 ; 63 be: 0f 90 pop r0 c0: 1f 90 pop r1 c2: 18 95 reti 000000c4 <_exit>: c4: f8 94 cli 000000c6 <__stop_program>: c6: ff cf rjmp .-2 ; 0xc6 <__stop_program>

Clearly the SEI appears in the interrupt. When I step through the dis-assembled code. The SEI instruction does not set IE in SREG.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

Clearly the SEI appears in the interrupt. When I step through the dis-assembled code. The SEI instruction does not set in SREG.


Now we have apples and oranges again.

I really really want to back up to the program you showed and that I tested. Remember your first assertion: "I have tried this but the flag is reset not only on the interrupt call but also on the return."

Let's do that program first, and tell your results.

(As an exercise we can then indeed proceed to the sei() in the ISR. But in practice, why?)

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
ISR( INT0_vect )
{
	sei();
	a--;
}

I put a breakpoint on the sei() line. When reached, I was off as expected. Step, and I turns on. And stays on through the remainder of the ISR and the main loop. Again, as expected.

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

Quote:

The SEI instruction does not set IE in SREG.


Once again HOW are you observing this? Take a look at these two pictures. Spot the difference? How does your experience differ?

Attachment(s): 

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

Cliff / Lee,

Please see the screen grabs attached.

A.

Attachment(s): 

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Cliff,

After taking a closer look at your screen grabs, I realized that what you were looking for at the nop. The flag is not set by sei()!

A.

Attachment(s): 

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Cliff,

This will set the IE flag but it still clears on return.

A.

Attachment(s): 

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

I realized that what you were looking for at the nop. The flag is not set by sei()

I changes one opcode AFTER SEI or RETI so you need to let it execute one more opcode.

BTW just checking that you are using 6.2Beta - don't accept anything prior which might have faults in either the toolchain, debugger or the simulator.

Also why do you persist in using both SREG |= 0x80 and sei()? I cannot think of any conceivable reason not to sei() when you want to SEI because that's exactly what it does!

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

Cliff,

In this case sei() is not setting the flag. I just wanted to know if setting another way would change the result.

AS6 6.0. I will update and see what happens.

Thanks,

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Quote:

In this case sei() is not setting the flag.

Are you sure you realize what Cliff said?

Quote:

I changes one opcode AFTER SEI or RETI so you need to let it execute one more opcode.

In fact, this one-cycle delay is an AVR feature, used in certain race situations. We don't need to go into it here as this thread deals with the "basics". But you gotta step one more time.

I still want to see the I bit get turned off when you step out of the ISR back to the mainline.

BTW, whatever happened to the basic test program that I asked you to compose and run, and which you agreed to and posted, and which I tested with? PLEASE run that one first before starting to sprinkle superfluous sei() and such in the ISR. Get the basic test going first. Please.

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

Lee,

I inserted the nop after the sei. As you can see from the screen grabs sei does not set the flag. I will post the individual screens as I step through sei.

I will also posts the grabs of the originally posted program.

Thanks for looking at this.

A.

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Lee / Cliff,

sei() does not set IE at all. In fact, if I manually set IE in SREG, toggling PB2 still does nothing! If I do not use SREG |= 0x80 , I cannot set this flag.

At this point, I'm thinking I've got problem with my version of AS6.

Please see below.

Thanks again for all the help.

A.

Attachment(s): 

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

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

Sigh. That is not the plain vanilla program that I want to start with. You posted the program. You made the assertion in your first post that when you got back to the main loop, the I bit was off. I ran that in the Studio simulator, and that isn't true for me.

Baby steps. PLEASE do that sanity check first. And indeed it might uncover ...

Quote:

I'm thinking I've got problem with my version of AS6.

... or not.

Lessee--I'm using 6.1.2730 Service Pack 2.

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.

Pages