Random Interrupt behavior in Attiny13A

Hello,

I am trying to learn about interrupts on Attiny13A and am particularly struggling with the pin change interrupts.

Here’s my code.

void setup() {
 // initialize pin 4 (ATtiny leg 3) as an output.
pinMode(4, OUTPUT); 
attachInterrupt(0, blink, RISING);
PCMSK = 0;
 
digitalWrite(4, LOW);
}
void loop() {
  ;
}

 void blink(){
digitalWrite(4, HIGH);
  delay(1000);             // wait for a second
 digitalWrite(4, LOW);
 }

Basically a variation on Blink, but the Attiny13A doesn’t work as expected, seems like blink function is being called randomly when I give interrupt on pins 5 and 6, PCMSK should mask the pin change interrupts but it is not. I am unable to comprehend what’s wrong, please help. Cheers.

Not familiar with the ATtiny.

What is connected to pin 0? A device or a button? In the latter case (or if the device has an open-collector output), you might suffer from floating inputs that randomly will read HGH or LOW depending on noise in the environment.

It's further not advisable to use delay() in an ISR; interrupts are disabled while an ISR is in progress and delay() relies on interrupts.

sterretje:
What is connected to pin 0? A device or a button?

Hi, thank you for your reply, I have pulled down the pin 7 (INT0) with a 10k resistor, the rising edge comes from a zero detection circuit which works fine on the Arduino Uno, I want to make a standalone really compact device therefore the Attiny13.

sterretje:
It's further not advisable to use delay() in an ISR; interrupts are disabled while an ISR is in progress and delay() relies on interrupts.

Thank you for this, I will try to make a basic delay function and check if that works out.

So, without the delay(), INT0 isnt triggering at all, LED wont glow. Unlike before when it was randomly glowing on its own.

May I make some suggestions?

If you simply removed the delay from the Blink() function you will not see the LED change.

An interrupt routine has to execute as fast as possible. I would not call digitalWrite's in it (use direct writing to the port if really needed). Definitely no delay().

My suggestion is to try:

  • Declare a global volatile (since you are changing it in an interrupt) boolean flag before any of your functions.
  • Initialize it to false in setup().
  • Set the flag to true in blink() (that is all - no other instructions).
  • In loop() check the flag and if true do your digitalWrites, with the delay as in your code above, and reset the flag to false.
    Does that help?

Willem.

The INT0 interrupt is not the same as a PCINT.

PCMSK does not control INT0 interrupts.

attachInterrupt() uses the INT0 interrupt, not a PCINT.

If you want to use a PCINT, you have to configure the registers and create the ISR using the ISR() macro (and it can use any pin, but only triggers on change, and you have to read the pins and figure out if it was a rising or falling edge).

If you want to use attachInterrupt(), you can either use detachInterrupt() to turn it off, or set/unset the INT0 byte in GIMSK.

See chapter 9 of datasheet.

Thank you Willem, your suggestions helped.

as for

DrAzzy:
If you want to use a PCINT, you have to configure the registers and create the ISR using the ISR() macro (and it can use any pin, but only triggers on change, and you have to read the pins and figure out if it was a rising or falling edge).

I indeed want to use INT0 and not PCINT.

As per all your suggestions, the following code works as it is expected to.

boolean flag = false; 
void setup() {
 // initialize pin 4 ( ATtiny leg 3) as an output.
pinMode(4, OUTPUT);
pinMode(0, INPUT);
pinMode(2, INPUT); 
attachInterrupt(0, blink, RISING);
GIMSK = 0x40;
PCMSK = 0;
digitalWrite(4, LOW);

}
void loop()
{
 if ( flag == true){
 digitalWrite(4, HIGH);
 
  else if (flag == false)
  {
    digitalWrite(4, LOW); 
    }          
}

 void blink()
 {
 flag = !flag;  
 }

However, If I want to add a certain delay, Attiny pin 3 doesn’t go high at all, attaching the code below.

boolean flag = false; 
void setup() {
 // initialize pin 4 ( ATtiny leg 3) as an output.
pinMode(4, OUTPUT);
pinMode(0, INPUT);
pinMode(2, INPUT); 
attachInterrupt(0, blink, RISING);
GIMSK = 0x40;
PCMSK = 0;
digitalWrite(4, LOW);

}
void loop()
{
 if ( flag == true){
 digitalWrite(4, HIGH);
 
 for(int i=0;i<1000;i++){
  for(int j=0;j<255;j++){}
  } 
 digitalWrite(4, LOW);
 flag = false;
  }/*
  else if (flag == false)
  {
    digitalWrite(4, LOW); 
    }        */  
}

 void blink()
 {
 flag = true;  
 }

Deliberately not using a delay() function as advised earlier.

Glad I could be of assistance. Some pointers.

Since the flag is changed in an interrupt, define your flag as:

volatile boolean flag = false;

I do not know how long those loops will take to execute, they may even be optimized out since they basically do nothing. May be the reason for not seeing the LED going high.

Delay() cannot be used inside an interrupt routine. You can use delay() in loop() to time the on period (it does not effect anything here in this code). Or, if you explicitly do not want to use it, try the following:

void loop() {
  static unsigned long StopMillis;

  if ( flag == true ) {
    digitalWrite(4, HIGH);
    
    StopMillis = millis() + 2000;
    while ( millis() < StopMillis );   // Hang on for 2 seconds
    
    digitalWrite(4, LOW);
    flag = false;
  }
}

Willem

Modified your code to wait for 10 milliseconds.

I am trying phase control on a 50Hhz AC signal.

StopMillis = millis() + 10;

Attaching the LED output, its not working as expected.

Capture123.PNG

Have you tried to leave the LED on for, say, a second? I have not tried to turn an LED on for 10ms to check if I can see it blink.

The resolution of attached png is a bit low to make any sense of the output.

Willem.

Hi Willem,

I did leave the LED on for a second and it works fine, although that’s not of much use to me because I’ll be getting an interrupt every 10ms (as in the screenshot) and I need to decide the duration of LED on (basically load ON) after every interrupt. I am trying to build a project similar to motor control or say AC fan speed controller.

Attaching the screenshot of CRO with a better resolution

Thanks for the reply. I can now see what is happening in your screen shot.

With the LED working when leaving it on for a second the basic interrupt works.

I assume the blue trace is your "LED" signal output. My interpretation is that 10ms is too long an ON time. You must remember that there will be some additional time overhead from the loop and even interrupt routine and it will most likely vary slightly. It appears that you stay on for about 13ms, try 5 and see what happens.

You will probably need to use a timer eventually to time your on time - start the timer with the interrupt.

Willem.

I realized 10ms is too long therefore I checked at 3ms and 5ms to my surprise, the output stays the same as the screenshot.

Unfortunately Tiny13 core has no support for the timer it has (I couldnt find it)

Although the datasheet has a timer0, I am looking at the possibilities to use TIMER0 for the application, but fundamentally, a small 3ms-5ms delay after the interrupt should have worked.

I would have thought it should.

I am at this stage out of suggestions.

Willem.

Hi Willem,

Thank you for your help so far, I tried something and it worked. :smiley:

 void loop()
{
 if ( flag == true){
 digitalWrite(4, HIGH);
 delay(3);
 digitalWrite(4, LOW);
 flag = !flag;
 attachInterrupt(0, blink, RISING);
 }

void blink()
 {
  detachInterrupt(0);
 flag = true;  
 }

So now proceeded to the next step of adding 2 push buttons for increasing and decreasing the delay.

Now everything goes berserk in the output, LED turns on randomly.

boolean flag = false; 
const int buttonPin = 0;   
int buttonState;            
int lastButtonState = LOW;   
unsigned long lastDebounceTime = 0;  
unsigned long debounceDelay = 50;  
const int buttonPin1 = 2;   
int buttonState1;            
int lastButtonState1 = HIGH;   
unsigned long lastDebounceTime1= 0;  
unsigned long debounceDelay1 = 50;  
int reading1;
int dim=5;
void setup() {
 // initialize pin 4 ( ATtiny leg 3) as an output.
pinMode(4, OUTPUT);
pinMode(0, INPUT);
pinMode(2, INPUT); 
attachInterrupt(0, blink, RISING);
GIMSK = 0x40;
PCMSK = 0;
digitalWrite(4, LOW);

}
void loop()
{
 if ( flag == true){
 digitalWrite(4, HIGH);
 delay(dim);
 digitalWrite(4, LOW);
 flag = !flag;
 attachInterrupt(0, blink, RISING);
 }

int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   
   lastDebounceTime = millis();
  }

 if ((millis() - lastDebounceTime) > debounceDelay) {
  
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {
       
       
    if (dim<9)  
   {
    dim = dim + 2;
    if (dim>8) 
    {
      dim=10;
    }
    }
 
   } 
   }lastButtonState = reading;

 } lastButtonState = reading;
   reading1 = digitalRead(buttonPin1);
 if (reading1 != lastButtonState1) {
   
   lastDebounceTime1 = millis();
  }

 if ((millis() - lastDebounceTime1) > debounceDelay1) {
  
   if (reading1 != buttonState1) {
     buttonState1 = reading1;
     if (buttonState1 == HIGH) {
       
  if (dim> 0)  
  {
     dim = dim - 2;
  if (dim<0) 
    {
      dim=0;  
    } }
   } 
   }
 } lastButtonState1 = reading1;
}
          

 void blink()
 {
  detachInterrupt(0);
 flag = true;  
 }

I am sure I have made a silly error, but I just cant notice it

Final working code. Thank you for all the support.

boolean flag = false; 
const int buttonPin = 0;   
int buttonState;            
int lastButtonState = LOW;   
unsigned long lastDebounceTime = 0;  
unsigned long debounceDelay = 50;  
const int buttonPin1 = 2;   
int buttonState1;            
int lastButtonState1 = LOW;   
unsigned long lastDebounceTime1= 0;  
unsigned long debounceDelay1 = 50;  
int reading1;
int dim=5;
void setup() {
pinMode(4, OUTPUT);
pinMode(0, INPUT);
pinMode(2, INPUT); 
pinMode(1, INPUT);
GIMSK = 0x40;
PCMSK = 0;
digitalWrite(4, LOW);
attachInterrupt(0, blink, RISING);
}
void loop()
{ 
 if ( flag == true){ 
 if(dim==1)
 {digitalWrite(4,HIGH);
 checkdim();}
 else if(dim==10){digitalWrite(4,LOW);
 checkdim();}
 else{
 digitalWrite(4, LOW);
 checkdim();
 delay(dim);
 digitalWrite(4, HIGH);
 flag = !flag;
 attachInterrupt(0, blink, RISING);
 }
   }
}      
 void blink()
 {
  detachInterrupt(0);
 flag = true;  
 }

 void checkdim()
 {
int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   lastDebounceTime = millis();
  }
 if ((millis() - lastDebounceTime) > debounceDelay) {
  
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {              
    if (dim<9)  
   {
    dim = dim + 2;
    if (dim>8) 
    {
      dim=10;
    }}}}
    lastButtonState = reading;
 } lastButtonState = reading;
   reading1 = digitalRead(buttonPin1);
 if (reading1 != lastButtonState1) {
   lastDebounceTime1 = millis();
  }
 if ((millis() - lastDebounceTime1) > debounceDelay1) {  
   if (reading1 != buttonState1) {
     buttonState1 = reading1;
     if (buttonState1 == HIGH) {
       
  if (dim> 0)  
  {
     dim = dim - 2;
  if (dim<0) 
    {
      dim=1;  
    }}}}}     
    lastButtonState1 = reading1;  
  }

Glad you got it working.

I do, however, find it very strange that you need to keep detaching and re-attaching the interrupt.

Enjoy
Willem.