external Interrupt priority not respected in combination with TIMER1_COMPA_vect and TIMER1_COMPB_vect on ATTINY85

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

Hello all,

 

I notice two strange behaviors when I'm using the external interrupt feature in combination with the TIMER1 COMPA and TIMER1 COMPB interrupts.

My goal is to measure the amount of pulse I receive on the INT0 pin of the ATTINTY85  within a timeframe of 1ms and 1.5 ms.

Timer 1 uses OCR1A and OCR1B to measure the amount of pulses in time intervals of  1 ms and 1,5 ms.

INT0 pin receives the external pulse signal.

 

STK600 development board.

The ATTINY 85 is used in his default clock mode meaning 1 Mhz/ 1us clock rate.

development tool Atmel studio 6.2 1502 SP1

standard compile options.

I measure all my signals with a SCANAPLUS logic analyzer module

 

 

Strange behavior 1

Although the ISC01 and ISC00 are set for rising edge (both 1) I get my IRQ on the falling edge.

If I define them for falling edge I get them on the rising edge.

 

Strange behavior 2

In the datasheet of the ATTINY85 we can find that the interrupt vector for INT0 has a higher priority then the IRQs on TIMER1 COMPA and TIMER1 COMPB .

At the moment I receive an interrupt of timer 1 the INT0 is delayed and TIMER 1 interrupts are handled first.

Can I not expect the opposite here?

INT0 with higher priority will halt the Interrupts from timer 1

after INT0 is handled the interrupts for timer 1 will further processed.

 

Snapshot with all IRQ's ena bled

 

Snapshot with only external IRQ

 

 

Code


//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>


//------------------------------------------------------------------------------
//Global constants
//------------------------------------------------------------------------------
volatile uint8_t Khz_tick = 0 ;


void Pin_config(void)
{
 DDRB = 0xFF;     // all pins as output 
 DDRB &=~(1<<DDB2);    // PB2 as input used as external interrupt
 PORTB &=~(1<<PB0) ;    // output low

 //external interrupt pin
 MCUCR |= (1<<ISC01)|(1<<ISC00); // external interrupt on rising edge ISC01:ISC00 = 11. (for falling edge = 10). Get IRQ on falling edge why ?
 GIMSK |= (1<<INT0);    // external pin interrupt enabled.
}

//------------------------------------------------------------------------------
// TIM1_configuration uses OCR1A and OCR1B to measure pulse on time interval 1 ms and 1,5 ms
// Prescaler sysclk/8
//------------------------------------------------------------------------------

void TIM1_config(void)
{
    // clean start
 TCCR1 = 0;                  //stop the timer
 TCNT1 = 0;                  //zero the timer
 GTCCR &=~(1<<PSR1);         //reset the prescaler
    
 //set the compare values ==>for 1ms and 1,5 ms period
 OCR1A = 125;                
 OCR1B = 188;    
 OCR1C = 188;
    
 //interrupts on Compare Match A and B
 TIMSK |= (1<<OCIE1A)|(1<<OCIE1B);        //interrupt on Compare Match A and B
    
 //ctc mode,  
 TCCR1 |= (1<<CTC1);

}

//------------------------------------------------------------------------------
// global Interrupt config
//------------------------------------------------------------------------------

void Interrupt_config()
{
   // Enable global interrupts in SREG register
  sei();       
}

//------------------------------------------------------------------------------
// Controller config
//------------------------------------------------------------------------------
void Init_controller(void)
 {
 Pin_config();  
 TIM1_config();
 Interrupt_config(); 
 }


//------------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------------
int main(void)
{
 Init_controller ();
 while(1)
 {
 }
 return 0;
} 
 

//------------------------------------------------------------------------------
// External Interrupt service routine
// ------------------------------------------------------------------------------
ISR (INT0_vect) //external interrupt routine  
{ 
 Khz_tick++;
 if (Khz_tick == 0)
 {
  //start timer with prescaler = clk/8
  TCCR1 |=(1<<CS12);
 }

 // toggle PB0 on/off
 PORTB |= (1<<PB0); 
 PORTB &=~(1<<PB0);
}

ISR(TIMER1_COMPA_vect)
{
 // toggle PB1 on/off 
 PORTB |= (1<<PB1); 
 PORTB &=~(1<<PB1);  
}

ISR(TIMER1_COMPB_vect)
{
 // toggle PB3 on/off 
 PORTB |= (1<<PB3);  
 PORTB &=~(1<<PB3); 
}

 

 

 

 

 

 

 

This topic has a solution.

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

Quote:
Can I not expect the opposite here?

INT0 with higher priority will halt the Interrupts from timer 1

after INT0 is handled the interrupts for timer 1 will further processed.

No.  Interrupt priority determines which of all pending interrupts will be serviced when the global interrupt flag is enabled.  When already in an ISR, global interrupts are disabled.  This is by design.  If TIMER1_COMPA_vect is running at the moment that INT0 comes along, the timer ISR will complete before the now pending INT0 interrupt is serviced.

 

    GTCCR &=~(1<<PSR1);                           //reset the prescaler

This does not reset the prescaler.   It clears the PSR1 bit in GTCCR.  To reset the prescaler you must set that bit:

    GTCCR |= (1<<PSR1);                           //reset the prescaler

This isn't your problem though.

 

The trace on channel 1 shows a period of about 45 µs.  With a 1 MHz clock, you've got just 45 cpu cycles between interrupts.  That's likely not enough for what you're doing.  Just entering and exiting the interrupt is likely to cost you 20 cycles, not including the actual code in the body of the ISR.

 

I suspect what you're seeing is the effects of accumulating interrupt latency.  Try running your t85 at 16 MHz.  Better yet, try injecting a much slower signal into INT0.  right now it's about 22 kHz.  Try a 1 kHz signal and see how many of your  'strange behaviours' disappear.

 

What optimisation did you build with?

 

Post the .hex file of your code which you uploaded to the AVR, or preferably the .lss.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

The priority system only applies to simultaneously-triggered interrupts.

An interrupt trigger will not normally occur within an ISR because the global interrupt flag is turned off.

 

If you are triggering your INT0 with short pulses,

you might be seeing the time required for the ISR to be reached and then to do its thing.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

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

In your init, try setting CLKPR = 0; to run at 8 MHz in addition to the above suggestions and see what happens. 

 

Jim

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

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

ki0bk wrote:

In your init, try setting CLKPR = 0; to run at 8 MHz in addition to the above suggestions and see what happens. 

 

Jim

...but remember to take effect, it must be done "right":

 

To avoid unintentional changes of clock frequency, a special write procedure must be followed to change the
CLKPS bits:
1. Write the Clock Prescaler Change Enable (CLKPCE) bit to one and all other bits in CLKPR to zero.
2. Within four cycles, write the desired value to CLKPS while writing a zero to CLKPCE.

 

As optimization can wreak havoc with the 4-cycle requirement, your toolchain has provided facilities for you:

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

 

 

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

The priority system only applies to simultaneously-triggered interrupts.

Not entirely true - they don't have to be exactly simultaneous - just "not handled yet".

 

So if you disable interrupts and INTy occurs then 350us later INTx occurs then 140us later INTz occurs (and by "INT here I don't just me ext-int - just any interrupt source) then when interrupts are re-enabled the AVR will execute one more opcode of the foreground code and then it will vector to a handler for the unhandled x,y,z - it picks which "goes first" simply based on their order in the vector table so if x,y,z are in that order in the IVT then x will be handled first. When it does RETI control will return to the main code, execute one opcode then vector off to handle y and so on. (unless INTw happened in the meantime so that w,y,z are oustanding - in this case w will be handled next). And so on....

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

As suggested I increased to operation speed of the ATTINY. and indeed my "strange behaviours are gone.

Slowing down the pulse stream (< 22Khz) was not an option as I need to work with these frequency.

 

Thx all for helping me out.

 

 

Last Edited: Fri. Jan 30, 2015 - 12:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

The priority system only applies to simultaneously-triggered interrupts.

Not entirely true - they don't have to be exactly simultaneous - just "not handled yet".

We were just using different definitions of triggered.

With the definition I was using, the usual cause of simultaneous triggering is RETI.

Quote:
So if you disable interrupts and INTy occurs then 350us later INTx occurs then 140us later INTz occurs (and by "INT here I don't just me ext-int - just any interrupt source) then when interrupts are re-enabled the AVR will execute one more opcode of the foreground code and then it will vector to a handler for the unhandled x,y,z - it picks which "goes first" simply based on their order in the vector table so if x,y,z are in that order in the IVT then x will be handled first. When it does RETI control will return to the main code, execute one opcode then vector off to handle y and so on. (unless INTw happened in the meantime so that w,y,z are oustanding - in this case w will be handled next). And so on....

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?