Skip to main content
deleted 75 characters in body
Source Link
ocrdu
  • 1.8k
  • 3
  • 11
  • 24

You did not specify the kind of Arduino you are using but, based on another another recent question of yours, I will assume it is an AVR-based Arduino Arduino.

You cannot have an interrupt automatically triggered by a variable reaching reaching zero. What you can do, instead, is trigger an interrupt by software software, by toggling a pin that is configured both as an output and as an an interrupt source:

However, if you do that, you will discover that interrupts are slow. slow; Awfullyawfully slow compared with a simple if test:

  1. digitalWrite() itself is awfully slow. This can be overcome by using using direct port access, but that is still two cycles for toggling the the pin in each direction.

  2. You will looselose an extra cycle in the pin synchronizer.

  3. Once the IRQ is raised, the CPU needs four cycles to prepare itself for for servicing it.

  4. The interrupt vector is a jmp instruction, which takes 3 cycles.

  5. The ISR then has to save every single register it is going to use, including including the status register. That takes two cycles per register. And And there are quite a lot of registers to save...

  6. This ISR, which is provided by the Arduino core, will then look for the the interrupt handler you provided with attachInterrupt(). This also also involves checking that the pointer to the handler is not zero    (the kind of test you seem to be worried about). It then has to    call (4 cycles) your handler, which will have to return    (4 cycles) to the ISR. You could avoid this indirection by defining the the ISR yourself instead of relying on attachInterrupt().

  7. Once the job is done, all the saved registers have to be restored    (2 cycles times many register), and the reti instruction (4 cycles) is is issued in order to restore control to the interrupted program.

  8. Last but not least, since amp will be modified in interrupt context context, you will have to qualify it as volatile. This keyword prevents prevents the compiler tofrom perform optimizations that are unsafe in this this situation, and you will loose a lot of time to these missed optimization optimization opportunities.

The whole sequence takes 3 cycles, irrespective of whether the if condition condition was true or false. That is at least one order of magnitude faster faster than the interrupt-based solution.

You did not specify the kind of Arduino you are using but, based on another recent question of yours, I will assume it is an AVR-based Arduino.

You cannot have an interrupt automatically triggered by a variable reaching zero. What you can do, instead, is trigger an interrupt by software, by toggling a pin that is configured both as an output and as an interrupt source:

However, if you do that, you will discover that interrupts are slow. Awfully slow compared with a simple if test:

  1. digitalWrite() itself is awfully slow. This can be overcome by using direct port access, but that is still two cycles for toggling the pin in each direction.

  2. You will loose an extra cycle in the pin synchronizer.

  3. Once the IRQ is raised, the CPU needs four cycles to prepare itself for servicing it.

  4. The interrupt vector is a jmp instruction, which takes 3 cycles.

  5. The ISR then has to save every single register it is going to use, including the status register. That takes two cycles per register. And there are quite a lot of registers to save...

  6. This ISR, which is provided by the Arduino core, will then look for the interrupt handler you provided with attachInterrupt(). This also involves checking that the pointer to the handler is not zero  (the kind of test you seem to be worried about). It then has to  call (4 cycles) your handler, which will have to return  (4 cycles) to the ISR. You could avoid this indirection by defining the ISR yourself instead of relying on attachInterrupt().

  7. Once the job is done, all the saved registers have to be restored  (2 cycles times many register), and the reti instruction (4 cycles) is issued in order to restore control to the interrupted program.

  8. Last but not least, since amp will be modified in interrupt context, you will have to qualify it as volatile. This keyword prevents the compiler to perform optimizations that are unsafe in this situation, and you will loose a lot of time to these missed optimization opportunities.

The whole sequence takes 3 cycles, irrespective of whether the if condition was true or false. That is at least one order of magnitude faster than the interrupt-based solution.

You did not specify the kind of Arduino you are using but, based on another recent question of yours, I will assume it is an AVR-based Arduino.

You cannot have an interrupt automatically triggered by a variable reaching zero. What you can do, instead, is trigger an interrupt by software, by toggling a pin that is configured both as an output and as an interrupt source:

However, if you do that, you will discover that interrupts are slow; awfully slow compared with a simple if test:

  1. digitalWrite() itself is awfully slow. This can be overcome by using direct port access, but that is still two cycles for toggling the pin in each direction.

  2. You will lose an extra cycle in the pin synchronizer.

  3. Once the IRQ is raised, the CPU needs four cycles to prepare itself for servicing it.

  4. The interrupt vector is a jmp instruction, which takes 3 cycles.

  5. The ISR then has to save every single register it is going to use, including the status register. That takes two cycles per register. And there are quite a lot of registers to save...

  6. This ISR, which is provided by the Arduino core, will then look for the interrupt handler you provided with attachInterrupt(). This also involves checking that the pointer to the handler is not zero  (the kind of test you seem to be worried about). It then has to  call (4 cycles) your handler, which will have to return  (4 cycles) to the ISR. You could avoid this indirection by defining the ISR yourself instead of relying on attachInterrupt().

  7. Once the job is done, all the saved registers have to be restored  (2 cycles times many register), and the reti instruction (4 cycles) is issued in order to restore control to the interrupted program.

  8. Last but not least, since amp will be modified in interrupt context, you will have to qualify it as volatile. This keyword prevents the compiler from perform optimizations that are unsafe in this situation, and you will loose a lot of time to these missed optimization opportunities.

The whole sequence takes 3 cycles, irrespective of whether the if condition was true or false. That is at least one order of magnitude faster than the interrupt-based solution.

Source Link
Edgar Bonet
  • 44.3k
  • 4
  • 41
  • 79

You did not specify the kind of Arduino you are using but, based on another recent question of yours, I will assume it is an AVR-based Arduino.

You cannot have an interrupt automatically triggered by a variable reaching zero. What you can do, instead, is trigger an interrupt by software, by toggling a pin that is configured both as an output and as an interrupt source:

const uint8_t int_pin = 2;  // pin used for interrupt

void setup() {
    digitalWrite(int_pin, LOW);
    pinMode(int_pin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(int_pin, reset, RISING));
}

static inline void trigger_interrupt() {
    digitalWrite(int_pin, HIGH);
    digitalWrite(int_pin, LOW);
}

// Within loop():
if (!amp) trigger_interrupt();

However, if you do that, you will discover that interrupts are slow. Awfully slow compared with a simple if test:

  1. digitalWrite() itself is awfully slow. This can be overcome by using direct port access, but that is still two cycles for toggling the pin in each direction.

  2. You will loose an extra cycle in the pin synchronizer.

  3. Once the IRQ is raised, the CPU needs four cycles to prepare itself for servicing it.

  4. The interrupt vector is a jmp instruction, which takes 3 cycles.

  5. The ISR then has to save every single register it is going to use, including the status register. That takes two cycles per register. And there are quite a lot of registers to save...

  6. This ISR, which is provided by the Arduino core, will then look for the interrupt handler you provided with attachInterrupt(). This also involves checking that the pointer to the handler is not zero (the kind of test you seem to be worried about). It then has to call (4 cycles) your handler, which will have to return (4 cycles) to the ISR. You could avoid this indirection by defining the ISR yourself instead of relying on attachInterrupt().

  7. Once the job is done, all the saved registers have to be restored (2 cycles times many register), and the reti instruction (4 cycles) is issued in order to restore control to the interrupted program.

  8. Last but not least, since amp will be modified in interrupt context, you will have to qualify it as volatile. This keyword prevents the compiler to perform optimizations that are unsafe in this situation, and you will loose a lot of time to these missed optimization opportunities.

In contrast, this line:

if (--amp == 0) amp = 10;

would be translated by the compiler into something like this:

   dec  amp     ; --amp, as amp is likely already in a register
   brne 1f      ; if (amp != 0) skip the following
   ldi  amp, 10 ; amp = 10
1:

The whole sequence takes 3 cycles, irrespective of whether the if condition was true or false. That is at least one order of magnitude faster than the interrupt-based solution.