Arduino/Attiny85: Delay in ISR and port manipuation

1.1k views Asked by At

I'm trying to have on a pin an output inverted related to another output playing a tone(), but there is a delay of 35us @8MHz or 158us @1MHz clock. It seems there is a fixed 16us +142 clock cycles delay, because delay is not inversely proportional to the clock frequency. They are very, very long! Why?

This is the code:

/* Per ATTINY85:
1: I/O5 PB5 A0 RS 
2: I/O3 PB3 A3          - Geiger inverted earphone out
3: I/O4 PB4 A2          - Geiger earphone out
4: GND
5: I/O0 PB0    MOSI SDA - Battery test/Geiger LED out
6: I/O1 PB1    MISO     
7: I/O2 PB2 A1 SCLK SCL INT0 - Geiger probe in (via NPN transistor)
8: Vcc
*/

#include<avr/sleep.h>

byte state;
volatile byte P;
int B;
int Bo;
byte LED=0;
unsigned long t=0;

void particella() 
{
    P=1;
}

ISR(PCINT0_vect)
{
    if (!(PINB & (1<<PB4)))
        PORTB |= (1<<PB3);
    else 
        PORTB &= ~(1<<PB3);
}

void setup()
{
    pinMode(0, OUTPUT); // Al LED.
    pinMode(2, INPUT); // Dal transistor dal tubo Geiger.
    pinMode(2, INPUT_PULLUP); // Pull-up per il collettore del transistor.
    pinMode(4, OUTPUT); // All'auricolare.
    pinMode(3, OUTPUT); // All'auricolare (copia invertita del 4).

    GIMSK = 0x60;    // turns on external and pin change interrupts.
    PCMSK = 0x10;    // turn on interrupts on pin PB4.
    sei();           // set interrupts (enable).

    tone(4,2000,100); // Power on beep
    PORTB|=0b00000001;
    delay(700);
    PORTB&=0b11111110;
    delay(1000);
    readVcc();

    for(byte n=1; n<=state; n++)
    {
        PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
        tone(4,2000,25); // Bip acuto a ogni lampo.
        delay(30);
        PORTB&=0b11111110; //  Spegne il LED su I/O0 = PB0
        delay(250);
    }
    delay(350);

    attachInterrupt(0, particella, FALLING);
}


void loop()
{
    if(P)
    {
        P=0;
        t=millis();
        PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
        LED=1;
        tone(4,1000,5); // Fa TIC nell'auricolare.
    }

    if(millis()-t>=10 && LED==1) 
    {
        LED=0; PORTB&=0b11111110; //  I/O0 = PB0 LED OFF after 10ms.
    }
}
1

There are 1 answers

6
bigjosh On

There are many delays before the code of an ISR gets executed.

Firstly are hardware delays. These are documented in the datasheets and include the time to notice and latch that the input changed, finish the current instruction, push the instruction pointer on the stack, and execute the jump to the ISR. enter image description here enter image description here

Next are the software delays. First there is the jump from the interrupt vector to the IST address, then the compiler puts a series of instructions at the beginning of an ISR to make sure all the registers are saved and also have the correct expected values. This is called the "preamble".

https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

There is not much you can do about the hardware delay, but you can reduce the software delay significantly - especially for a very simple ISR like yours. One way would be to make a "naked" ISR that only saves the registers you change. For your code above, you could likely get by only changing one register.

I think it might also be possible to do your ISR function without using any data registers by using the trick of writing to the PIN register to flip a bit. enter image description here

You should be able to find more info on all this by googling, or report back here if you need some specific guidance on any of these points!

An alternative approach - use the built in hardware inverted output

The Timer1 on this chip has a built-in inverting output that will automatically output the inverted signal you are looking for, and there will be much less than 1 cycle delay between the inverted and non-inverted outputs (assuming you do not intentionally add dead time between the transitions).

enter image description here

This would require programming the timer registers to enable the inverted output and the inverted outputs are only available on specific pins - but this is usually not a problem.