Page 1 of 1

ISR questions

Posted: 08 January 2009, 5:02 AM
by sturgessb
Just a few (probably silly) questions regarding Interrupt Routines.

Q1:
I know that Interrupts have different priorities. Does that mean that if you have ISRa running and ISRb (with a higher priority) gets triggered mid way though, does ISRa continue running once ISRb is finished or does it get forgotten about?

Q2:
Does 'Lock Task' work inside an ISR so that it is guaranteed to run in full? if ISRb is triggered while ISRa is mid way though but has 'Lock Task' around its contents, what happens? does ISRb get run when ISRa is finished?

Q3:
Is it possible to get and ISR to run on each TIMER Clock Period? Or would i just have to have a loop that checks when timervalue = 1 and then reset to 0 each time?

Thanks

Ben

Re: ISR questions

Posted: 08 January 2009, 7:13 AM
by dkinzer
sturgessb wrote:Does that mean that if you have ISRa running and ISRb (with a higher priority) gets triggered mid way though, does ISRa continue running once ISRb is finished or does it get forgotten about?
A pending interrupt is never ignored. Multiple, near simultaneous, interrupts are handled in one of two ways, sequentially or nested, with the former being recommended.

In the case of two or more simultaneously triggered interrupts, the ISRs will be handled based on the priority of the interrupt. The interrupt priority is indicated by the position of the interrupt vector in the interrupt vector table; the lower the address, the higher the priority. The layout of the interrupt vector table can be found in the datasheet for the corresponding AVR.

Under sequential handling, when an ISR begins executing, interrupts are globally disabled and when it completes execution, it re-enables interrupts. If another interrupt fired during that time, its ISR will then execute very shortly after interrupts are globally enabled.

For nested handling, interrupts are not globally disabled in the ISR. If another interrupt triggers, its ISR will begin execution immediately and when that ISR completes the interrupted ISR will resume execution. The reason that this method is highly discouraged is that stack use is potentially much greater than in the sequential case.

If you define an ISR in ZBasic, it is configured for sequential processing unless you define it with the Naked attribute in which case you have complete control and can configure it for either sequential or nested handling.
sturgessb wrote:Does 'Lock Task' work inside an ISR so that it is guaranteed to run in full?
As described above, a typical ISR will always run to completion without interruption. Invoking LockTask() in an ISR has no effect on ISR execution. Rather, it will lock the task that was running at the time the ISR was invoked.
sturgessb wrote:Is it possible to get and ISR to run on each TIMER Clock Period?
If you mean each time the TCNT increments, the answer is no. There are two basic types of interrupt handlers related to timers: overflow and compare match. The overflow interrupt will be triggered when the timer reaches its maximum count (and also when the timer counting changes direction at zero in PWM modes). The compare match interrupt will be triggered when the TCNT register matches the corresponding OCR register, of which timers may have one, two or three.

It is considered "best practice" to keep ISR execution time as short as possible, performing only the absolute minimum operations necessary. Often, this means just setting a global flag that is later recognized by the Main() task or an auxillary task. In other cases, the minimum processing is necessarily more involved but an effort should be made to keep the processing as short as possible.

Re: ISR questions

Posted: 08 January 2009, 9:58 AM
by spamiam
dkinzer wrote:
sturgessb wrote:
sturgessb wrote:Is it possible to get and ISR to run on each TIMER Clock Period?
If you mean each time the TCNT increments, the answer is no. There are two basic types of interrupt handlers related to timers: overflow and compare match....
Using the "compare match", you can set the matching value to zero and then the compare match interrupt will fire on every other clock cycle of the timer.

Needless to say, it is not reasonable to have very small prescaler settings on the timer because the timer will fire again even before the last interrupt is processed. In general, there are 10-20 clock cycles of overhead in processing an interrupt, plus whatever code is in the interrupt. So, a prescaler of /32 or more might be reasonable with the interrupt firing every 64 main clock cycles.

Setting a prescaler as above would create interrupts about as frequently as using a prescaler of /1 and then setting the compare match value to 63. [I believe this is accurate, but I always need to refer to the datasheet and figure it out again every time I try something like that.]

Using the "naked" attribute will probably will reduce the ISR overhead, but I believe then you must manually handle all the pushing and popping as well as controlling interrupts.

-Tony

Posted: 08 January 2009, 15:46 PM
by sturgessb
Thanks Guys

Posted: 08 January 2009, 17:04 PM
by sturgessb
Am i missing something, I have the folowing

Code: Select all

Register.TCCR2B = &H03
Register.OCR2A = 100
Register.TIMSK2 = Bx0000_0010
with...

Code: Select all

ISR Timer2_CompA()
	tempuint = tempuint + 1
END ISR
I would expect this to increment tempuint every time that timer2 TCNT2 value reached 100. but this does not seem to be true, the ISR is running but not to that expected pattern and changing the ocr2a value seems to not make any difference. i must be not following 100%

cheers

ben

Posted: 08 January 2009, 19:11 PM
by dkinzer
sturgessb wrote:Am i missing something
You really should set the other timer control registers, too. In the case of Timer2, that means Register.TCCR2A. Timer1 has one additional control register. Also, you should clear the TIFR bits (see my earlier posts) just to be certain that you won't get an interrupt immediately when you set TIMSK.

Assuming that TCCR2A is zero, I would guess that Timer2 counts from zero to 100 at which time you should get a compare match interrupt. The timer will continue to count upward to 255 and then wrap to zero and repeat the process.

The timer can be programmed in a mode so that it will reset to zero when it gets to the OCRA value. Perhaps that's what you expected but it isn't configured that way. Consult the "waveform generation mode" table and look for CTC mode if that's what you want.

Posted: 09 January 2009, 1:51 AM
by sturgessb
Ah yes that will be it, as its wrapping the trigger point will always be the same whether i set it to 1 or 255. Register.TCCR2A = Bx0000_0010 does the job.

Thanks Don

Posted: 09 January 2009, 4:05 AM
by sturgessb
Is it possible on the 24n to use timer0? i know its used for the RTC, but seeing as i dont want to use any RTC functions, could i take control of it and use for my own purpose?

Re: ISR questions

Posted: 11 January 2009, 8:46 AM
by sturgessb
spamiam wrote: Using the "naked" attribute will probably will reduce the ISR overhead, but I believe then you must manually handle all the pushing and popping as well as controlling interrupts.
If this a fact, if so what kindof speed improvement could be acheived?

Ben

Re: ISR questions

Posted: 11 January 2009, 19:50 PM
by dkinzer
sturgessb wrote:If this a fact, if so what kindof speed improvement could be acheived?
Sometimes not much, sometimes a lot. Much depends on the ZBasic code that you write, the C code that the ZBasic compiler generates from it and the assembly language code the avr-gcc compiler generates from the C code.

Generally speaking, it is recommended to pursue hand optimization of ISRs (or any other code) if performance measurements show that it is necessary. If and when performance needs to be improved, you are well advised to ponder the design to see if you can change the algorithm or some of the design criteria to fundamentally improve the performance.

After you've gotten the best performance that you can get with the best design/algorithm that you can envision and the performance still falls short of the goal, that is the time to look at more esoteric optimization techniques like using C or assembly language code.

In any event, if you're interested in looking at the AVR assembly language code that gets generated for your application, add the --list and --keep-files options to your project. After compilation, you should find a file named zxTempDir/<proj>/<proj>.lss below your project directory, where <proj> is the name of your project. The .lss file contains assembly language code representing the actual instructions that the AVR will be executing. To understand the meaning of the instructions in this file, you need to understand AVR assembly language instructions and know something about the interrupt vector table. You also need to be able to relate the generated assembly language back to the original code that you wrote. If you've not studied compiler construction and understand common code generation idioms, this may be a daunting prospect.

If you already understand the fundamentals of assembly language code, you can probably dive right into the Atmel documentation for the AVR Instruction Set. If you don't yet understand the fundamentals, you can probably find some sites on the Internet or find some books on the subject at a technical bookstore.