Code execution in ISR too slow


I have code inside an ISR that evaluates the pulse info of a PWM pulse from one of the digital I/O pins. I checked the time it takes for the ISR to execute which turned out to be 10us, but I need to be able to sample the PWM input at a rate of less than 1 us.

Is there anything I can do to solve this? I’ve skimmed down the code within the ISR as much as possible. Do I have to go look for a faster controller?

For accurate timing of external signals, don’t use software (neither polling nor interrupts). Use the hardware timer in Input Capture Mode instead. There is lots of useful information for how to do that on Atmel chips in this tutorial:

I don’t think that’s quite what I am looking for. Although I do need accurate timing of external inputs my current problem is that the ISR doesn’t execute fast enough to capture the 1us pulses my encoder can deliver (it’s a rotary encoder than generates pulses with varied length from 1us to 1025us). The execution time of just that is around 1.5us. Is there a way to get it to below 1us?

I don’t know if it is possible to get below 1 us, but your present coding seems very inefficient. For example, never make a call to a function from an interrupt, because the compiler doesn’t know which registers to save upon entry and so it saves ALL of them.

(if a function and not a macro) is probably slow and the effect can be accomplished with one line of assembly or C. Assuming an ATmegaxx8, this is the same as PORTC &= ~(1<<PC3);
but the latter can be an order of magnitude faster (certainly so for the Arduino function digitalWrite()).

You can check the generated assembly language for the interrupt routine, in the compiler list output file to know for sure.

Finally, using the external interrupts rather than pin change interrupts would also be faster, because you don’t need to check which pin changed.

The function calls to set a pin high and low were my debug method of generating pulses on the o-scope to see the time it takes the ISR to execute. They will be taken out during the real execution.

But I am interested in your suggestion of using the external interrupt. How would an external interrupt work connected to the encoder that generates a variable length pulse? Does it not have to detect the change of the encoder state which is dependent on a pin change?

Function calls can dramatically affect the interrupt execution timing, so your debugging approach does not give a reliable measure. As I said, look at the compiled code to know for sure.

External interrupts can be used in conjunction with a timer to very accurately measure a pulse length. Set the interrupt first to trigger on a rising edge, start the timer in the ISR, then set the interrupt to trigger on a falling edge. Read the timer in the next event.

Ok. Just out of curiosity, can an interrupt in the Orangutan be interrupted by another interrupt or would that interrupt be queued until the present one is finished executing?

By default only one interrupt runs at a time, and effectively they are queued. There are other possibilities; see the ATMega328 data sheet section 6.7 for the details.