Studio 6.2.1563 Simulation reset

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

I am running an ATmega329PB simulation with interrupts. The interrupts are encapsulated with sreg = SREG;, cli(); and SREG = sreg;. The program waits for two external inputs (PCINT2_vect), calculates a delay then loads the delay into OCR1A and OCR3A. When these timer interrupts fire they stop the timer, set an output then load another delay into OCR1B and OCR3B (separate interrupts are used to turn the outputs On then Off). The second delay timers are started with the next interrupt inputs. The problem is after the first COMPA interrupt (changing both inputs simultaneously in the simulation) the simulation resets between the two COMPA pair of interrupts. I tried putting breaks at all the interrupts but it does not catch where the reset is happening. The Watchdog timer is disabled. There are no pointers used in the program so it should not be that. Any idea of how to find what is causing the reset? Thanks.

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

magno_grail wrote:
The interrupts are encapsulated with sreg = SREG;, cli(); and SREG = sreg;.

What on earth are you talking about? You don't mean:

ISR(SOME_vect) {
    uint8_t sreg = SREG;
    cli();
    // do stuff
    SREG = sreg;
}

do you? Obviously that would be an atrocious idea!

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

Is this in C or assembler?

Can you post some code?

David (aka frog_jr)

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

frog_jr wrote:
Is this in C or assembler?
magno_grail wrote:
sreg = SREG;, cli();

If that isn't C then I'm a little perplexed.

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

clawson wrote:
If that isn't C

I'm still asleep...blush

David (aka frog_jr)

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

So I gather you do not like Atmel's sample coding. Page 26 of the ATmega328PB datasheet:

C Code Example

char cSREG;

cSREG = SREG; /* store SREG value */

/* disable interrupts during timed sequence */

_CLI();

EECR |= (1<<EEMPE); /* start EEPROM write */

EECR |= (1<<EEPE);

SREG = cSREG; /* restore SREG value (I-bit) */

 

From way back I have used cli() but maybe _CLI() is newer. cli() works with <avr/interrupt.h>, _CLI() does not.

Do the interrupts not have to be disabled in the interrupt routine to keep them from nesting? I tried the simulation without disabling the interrupts and the problem is the same, the simulation resets after the first of the two timer ISRs is completed and the main program is waiting for the next input in a while(!input).

 

// interrupt routines:

ISR (TIMER1_COMPA_vect)

{

            unsigned char sreg;

 

            sreg = SREG;

            cli();

            PORTB |= Cyl12_out;                                                                                                                

            TCCR1B = Zero8;

            Cyl12_out = Out0;

            set_Retard (Retard_count);

            SREG = sreg;

} // end TIMER1_COMPA_vect

 

 

ISR (TIMER1_COMPB_vect)

{

            unsigned char sreg;

 

            sreg = SREG;

            cli();

            PORTB &= ~Cyl12_out;

            TCCR1B = Zero8;

            SREG = sreg;

} // end TIMER1_COMPB_vect

 

...

 

(in main)

            while (!(last_cyl = Win_Flags & AnyIn));             // first window opened &  save which input

 

 

The  Timer1 COMPA match will execute but when it steps out and back to the while() the second interrupt Timer3 COMPA match does not happen. The simulation resets. The TIMER1 and Timer3 COMPA and B routines are the same except for which PORTB pins are changed.

 

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

The code example is for writing during a critical section:

EECR |= (1<<EEMPE); /* start EEPROM write */
EECR |= (1<<EEPE);

This must be executed within 4(?) clocks, so an interrupt occurring here could prevent the EEPROM from being written.

This is not needed for an ISR.

 

If you look at the .lss file generated, you will see that the handling of SREG is done for you.

 

On entry to the ISR, the interrupts are disabled so that when you execute the sreg = SREG; and cli();, interrupts are already disabled.

Why are you changing TCCR1B in the ISRs?

David (aka frog_jr)

Last Edited: Fri. Jul 1, 2016 - 04:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stopping the timer. Once the first delay time expires and the port pin is changed the timer is not used again until the external input is triggered through the while().

I removed all the _cli() and SREG statements but the same problem occurs although slightly different. The simulation does not reset after the TIMER1 COMPA and the TIMER3 COMPA but after whilst it is sitting in the while(!last_cyl).

I did find an error where both timers were being reset and restarted in the set_Retard() routine. That was changed so each COMPA ISR reloads its own timer for the COMPB.

I just noted the simulation does not fully reset. The timers and port pins still have their values but the simulation jumped to the beginning of the program.

Last Edited: Fri. Jul 1, 2016 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can you provide a minimal code example that shows:

  • timer initialization
  • definitions for Zero8, Cyl12_out
  • set_Retard() code (probably not good to call a function inside an ISR...)

 

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define Zero8			0x00
#define Zero16			0x0000

volatile unsigned char Cyl12_out;	// PORTB output state cyl 1/2 for retard
volatile unsigned char Cyl34_out;	// PORTB output state cyl 3/4 for retard

In main code:
		if (last_cyl & (Cyl1 | Cyl3))// if Cyl1 or Cyl3 fired then Cyl2 or Cyl4 fires next
		{
			Cyl12_out = Out2;
			Cyl34_out = Out4;
		}
		else 			// Cyl 1 or Cyl3 filres next
		{
			Cyl12_out = Out1;
			Cyl34_out = Out3;
		}


void set_Delay (unsigned int value)
{
		TIMSK3 = (1 << OCIE3A); 	// turn On output compare A interrupt Timer3	
		OCR3A = value;
		TCNT3 = Zero16;
		TCCR3B = T3clk64;								
		TIMSK1 = (1 << OCIE1A); 	// turn On output compare A interrupt Timer1
	OCR1A = value;
		TCNT1 = Zero16;
		TCCR1B = T1clk64;								
	return;
} // end set_Delay

void set_Retard (unsigned int value, unsigned char timer)
{
	if (timer)
	{
		TIMSK3 = (1 << OCIE3B);								// turn On output compare B interrupt Timer3
		OCR3B = value;
		TCNT3 = Zero16;
	}
	else
	{
		TIMSK1 = (1 << OCIE1B);								// turn On output compare B interrupt Timer1
		OCR1B = value;
		TCNT1 = Zero16;
	}
	return;
} // end set_Retard


The set_Retard has to be in the ISR because the main routine is waiting for the next input. Since the same timer is used for the delay then the retard function the timer counter has to be cleared and the TIMSK has to be changed to OCIExB. I could load OCRxB in the set_delay routine. When the input event occurs the timer is started for the retard. Doing all this after the input occurs adds more delay. If the retard value is already short then that would add a large error.

The set_Delay function is only called if there is enough time available before the next input. Otherwise the ports pins are changed in the main routine.

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

So I gather you do not like Atmel's sample coding. Page 26 of the ATmega328PB datasheet:

I'm afraid YOU have misunderstood. That sequence storing SREG, disabling interrupts, then finally putting SREG back is a perfectly valid thing to do. Indeed it's something you MUST do for atomic protection for an access to a non-atomic data object. But it's something you'd only ever do in your foreground, non-interrupt code. It is entirely pointless in an ISR as there is an implicit CLI during the jump through the vector. 

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

Yes, I did. I mistook your comment as disapproval of Atmel's coding, not that I got its usage wrong. I apologize.