ISR vectors priority (in ATMEGA328p? ) and other loose questions

Hi everyone! this is indeed a brand new world! (first post on the forum!... or actually in any forum!)

loving arduino Duemilanove (w ATMEGA328p). love the whole *.PDE , c++ libraries saving us all the b.... ache of going through datasheets and knocking our head on the wall!

That said, although great to do stuff fast, the catch is we lose a bit of control.

My previous experience was limited to PIC18. Where ISR levels could be defined and hence we could flag several interrupts and define a high priority one that would always take well.. priority.

going into the juicy bits:

-I have a timer (TMR1) clocking sequences of pulses out as a stimulus to another device. the timer overflow is generating a routine and on top of that I needed to have a second external interrupt routine to listen for a response.
sort of ... (pulse_count>mythreshold)? good_response:bad_response;

Now design wise I am not worried about the external interrupts being queued,its not time critical , as long as they are not lost. On the other hand the timed sequence (signal out of MCU) is something I don't wanna screw up as it messes the response.

Q.a
Can i have the tmr1 ISR I already have being defined as high priority and an external INT0/INT1 as a low priority?

Q.b
one more, I have ready most of docs on AVR i still dont get how does it work we dont have to clear any flags in the routine?

also I have a side question for the master Jedi's of embbedded stuff and AVR Freaks. A lot of real time code I have seen uses register setup of the form

REG &= ~(1<<bit); // Clear bit
REG |= (1<<bit); // set bit

Q.c
Can you guys walk newbies trying to go into the deep end, apart from readibility is there any clock instructions savings, or any space savings, or safety benifit?

Q.d
also in AVR arquitec is this bit shift having a carrier if a one is already stored in REG? and where is it temporarily written from?

Sorry prob a lot of questions for one post but here it is my first post...! =)

Arturo

Q.a
Can i have the tmr1 ISR I already have being defined as high priority and an external INT0/INT1 as a low priority?

I've never heard of the interrupt priorities being programmable in the AVR mega processors, but I don't know for sure. Certainly one can disable and enable individual interrupts with user code. Need a real Jedi for this one.

Q.b
one more, I have ready most of docs on AVR i still dont get how does it work we dont have to clear any flags in the routine?

Disabling of global interrupts while entering a ISR happens automatically and re-enabling of global interrupts upon return of the ISR is also done automatically. How? That's a Jedi question also.

also I have a side question for the master Jedi's of embbedded stuff and AVR Freaks. A lot of real time code I have seen uses register setup of the form

REG &= ~(1<<bit); // Clear bit
REG |= (1<<bit); // set bit

Q.c
Can you guys walk newbies trying to go into the deep end, apart from readibility is there any clock instructions savings, or any space savings, or safety benifit?

That form is mostly use so that the code can use the offical AVR names for the registers (REG in you example) and bit names (the bit used in your example) used in the AVR datasheet. Helps cut down on errors. Example:

EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);

Those names EICRA, ISC00, and ISC01 should be found straight from the Atmel datasheet for the chip being programmed. So the poor programmer doesn't have to convert from those names to actual hex values and possibly screw it up. Not sure if this method saves cycles or not, but I've been told the gcc compiler does a very good job of obtimization, so many times it may make changes to get the same results but with fewer instructions.

Q.d
also in AVR arquitec is this bit shift having a carrier if a one is already stored in REG? and where is it temporarily written from?

That's a question for the compiler and he and I aren't on the best of terms these days. :wink:

Lefty

almost_there:
My previous experience was limited to PIC18. Where ISR levels could be defined and hence we could flag several interrupts and define a high priority one that would always take well.. priority.

According to the Atmega328 spec:

The complete list of vectors is shown in ”Interrupts” on page 57. The list also determines the priority levels of the different interrupts. The lower the address the higher is the priority level. RESET has the highest priority, and next is INT0 – the External Interrupt Request 0.

So each interrupt has a predefined priority level.

Judging by page 57 the timers have higher priority than the serial data comms interrupts, so you should be OK.

According to page 14 interrupts are remembered if multiple (different) interrupts occur.

It doesn't look as if you can move INT0/INT1 into lower priority than a timer interrupt, however you have some leeway on timers. As long as you handle the higher priority interrupt quickly it shouldn't be a problem.

one more, I have ready most of docs on AVR i still dont get how does it work we dont have to clear any flags in the routine?

Entering an interrupt routine (according to the spec) disables the interrupt-enable flag, which is restored when you return from that interrupt. At the point where the interrupt is entered that particular interrupt flag is cleared.

also in AVR arquitec is this bit shift having a carrier if a one is already stored in REG? and where is it temporarily written from?

I don't understand this question.

Hi retrolefty and Nick,

Thank you for your replies and the info.

I appreciate the walk throught the datasheet obviously I missed a lot of bits of important info. And also I didnt know the priority was determined by the address it is written to.

Ok so to recap. TMR1 is actually lower priority than INT0 (or INT1 for that matter) , and that cant be changed.

the INT0 ISR is pretty nimble and i am doing everything in a scale of the milisecond order so I asssume it should be ok.

void the_interruptEXT(){ //external input interrupt

	// the time stamp at which it happened
	mylatch=myCLK; 
	
	// keep track of how many rising edges where detected
	pulse_count++;
 
 }

//---------

Serial data comms wasnt an issue initially cause i have a small 'cooldown' period between sequences to upload a logging string to the hyperterminal, so that too should be fine.

//-----------

I guess its difficult to explain my question on shifting bits to write a bit in a register.

Say for instance retrolefty's example:

  EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (1<< ISC00);ISC00

If I had by some random act of electronics gods already a '1' at ISC00, would a left shift one 'overspill' to ISCO1? or is there no carrier in this sort of operations ?

maybe the problem is just that i am not breaking down each individual operation in this line of code correctly..

Also so I am struggle in real time systems to avoid global variables! =(

can anyone recommend good code examples or literature, sort of real time systems "good practice" examples reagarding use of pointers and references. I know there is plenty online but not all is targeted at real time applications and not all is good quality... much rather take advice from someone that has traveled this road rather than take whatever google digs out.

Once again thanks for putting me on the right track

Best

Arturo

almost_there:
I guess its difficult to explain my question on shifting bits to write a bit in a register.

Say for instance retrolefty's example:

  EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (1<< ISC00);ISC00

If I had by some random act of electronics gods already a '1' at ISC00, would a left shift one 'overspill' to ISCO1? or is there no carrier in this sort of operations ?

I don't really understand this question. Given:

#define ISC00   0
#define ISC01   1

First, there is no "1" at ISC00, so this is one of those question like "if the moon was made of chocolate what would happen if ...".

But even if you asked about ISC01, these are defines, effectively constants. No operation at runtime is going to change the values of ISC00 or ISC01.

Anyway, to work through Lefty's example:

  EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);

Working from the brackets out:

(1 << ISC00)   == 1 << 0 == 1

(1 << ISC01)   == 1 << 1 == 2

(mode << ISC00) == mode << 0 == mode

Now:

~((1 << ISC00) | (1 << ISC01))

is really taking the 1's complement of 3 (that is inverting 0x03, giving 0xFC)

So:

 (EICRA & ~((1 << ISC00) | (1 << ISC01)))

is clearing the two low-order bits (EICRA & 0xFC)

And:

| (mode << ISC00);

is or'ing in the new value of mode over the two low-order bits, leaving the rest unchanged (assuming mode is in the range 0 to 3).

So really that line is saying "clear the low order bits of EICRA, and then "or" in some new value, which is in mode".

can anyone recommend good code examples or literature, sort of real time systems "good practice" examples reagarding use of pointers and references.

How about posting some sample code and we can critique it? Your question is almost too general to answer.

Also so I am struggle in real time systems to avoid global variables!

Why do you need to?