Changing interrupt type (in EICRA) during interrupt

Uno with shaft encoder on a motor giving 384 interrupts/rev on INT0 and index (once per rev) on INT1. There is another pin-change interrupt which occurs twice during 1 rev.

At low speed, below 2500 RPM, I need to do about 25us of computation which works OK with

void setup(){
  attachInterrupt(digitalPinToInterrupt(3), indexISR, CHANGE;
  attachInterrupt(digitalPinToInterrupt(2), encoderISR, CHANGE;
}

This picks up the rise and fall of the index which occurs during the second quarter of the INT0 pulse on channel A of the encoder.

Above 2000RPM to 4500RPM, the computation time is reduced to about 20us and works OK with

void setup(){
  attachInterrupt(digitalPinToInterrupt(3), indexISR, RISING;
  attachInterrupt(digitalPinToInterrupt(2), encoderISR, FALLING;
}

I've tried many options including changing EIRCA at the end of the INT0 encoder ISR ...

void encoderISR(){
  if (!HISPD){
    ....
  }
    ....
    if (!HISPD && dtstroke < 13043){      // above 2300RPM
      HISPD = true;                                    // high speed
      EICRA = 14;     // INT1,index, RISING ; INT0, encoder, FALLING  
    }
    if (HISPD && dtstroke > 13636){       // below 2200RPM
      HISPD = false;                                    //low speed
      EICRA = 5;     // INT1,index, CHANGE ; INT0, encoder, CHANGE     
    } 
}     

(the variable HISPD is used in the INT0 ISR to reduce the ISR code computation time at high speeds) but none work.

I'm stuck. Can anyone help?

Too general. Please post your entire code.

..... and specify what the actual problem is.

The entire code is large. I consider that the problem is adequately described viz. how to change the EIRCA of an interrupt during the process of the fast recurring of that interrupt. The method that I've exampled does not work.
I do agree, however, that it would have been helpful to revise the last section of code to

void encoderISR(){ ....... if (!HISPD && dtstroke < 13043){ // 2300RPM HISPD = true; EICRA = 14; // INT1,index, RISING ; INT0, encoder, FALLING } if (HISPD && dtstroke > 13636){ // 2200RPM HISPD = false; EICRA = 5; // INT1,index, CHANGE ; INT0, encoder, CHANGE } }
I don't know how to do that. Can you assist?

What is the issue with using RISING or FALLING at the lower speeds? What is gained by using CHANGE?

The issue is with EMI interference from the machine at low speeds that the UNO is controlling. The use of CHANGE at low speeds enables this to be eliminated by the software. But the additional interrupts that are used compared with RISING and FALLING take too long at high speeds.

It may be a stupid idea, but can you eliminate this EMI interference you speak of?

a7

The machine generates sparks. I've tried everything I can to eliminate the interference - but without success except by using the software.

Sounds like a rough environment. Can you draw a simple schematic of the various pieces of this?

Above my pay grade, but it seems like there should be way to do this w/o a software kluge or kludge.

a7

Can you please post the INT0 ISR and the computations done at high and low speed.

The machine is to test magnetos and consists simply of a DC brushed motor driving the magneto which is connected to an array of spark gaps. Sparks are notoriously good at generating signals over a wide frequency spectrum and difficult to shield against. It was a great success when I found that I could eliminate the effects with software. Using 2 Uno's (!), one for high speed and another for low speed, would solve the problem but surely this clumsy solution is not necessary?

void encoderISR(){         //< xx microsecs with encoder set to 384ppr 
  int PWM, PWMcorr, pRPM2;
  unsigned long tpulse, dtpulse;
  static byte spkpulse1;
  static int spRPM2;  
  static unsigned long tpulsex, tstrokex;   
  static bool INDEX, FAILtrig, DATAflag1, Astate, state;

  if (!HISPD){        // below 2300RPM only 
    // For every encoder pin change
    state = PIND & B00000100;  // read encA on D2
    if (state == Astate)return;     // EMI corrn
    Astate = state;        
    if (Astate)return;              // trigger on FALLING
    if (INDEXcnt == 2)INDEX = true; 
    INDEXcnt = 0;        
  } else {
    if (INDEXH)INDEX = true;;
    INDEXH = false;
  }
  tpulse = micros();
  pulse++;
  
  // MOTOR DRIVE SHARP END
  PWMcorr = PWM4;
  PWM = (PWMcorr>>2);      // get spkpulse1 ...
  if (sync == 1 && SPK && (pulse == spkpulse + 1))spkpulse1 = spkpulse; 
  // BELOW 2300RPM 
  if (!HISPD){            // neglect above 2300RPM   
    ........
  } 
  analogWrite(pinoPWM, PWM);

  // END OF STROKE   
  if (INDEX){        
    INDEX = false;      
    if (sync == 2 && pulse == strokecnt){     
      dtstroke = tpulse - tstrokex;        // for RPM           
      DATAflag1 = true;           
    } else {      
      ERR1 = true;
      pindexfail = pulse;       // pulse number at index failure
      DATAflag1 = false;               
    }
    pulse = 0;
    sync = 1;
    tstrokex = tpulse;        
  }
  if (sync == 1 && pulse == strokecnt){   // post-index stroke completion        
    pulse = 0;
    sync++;
    if (!SPK)FAILtrig = true;     // FAIL tests at end of all strokes
    SPK = false;         
  }
  if (sync == 2 && pulse == strokecnt){   //for missing index
    pulse = 0;
    sync = 1;
    tstrokex = tpulse;      
    SPK = false;       
  }
  if (DATAflag1 && pulse == 2){   // data output               
      if (!SPK || FAILtrig){      // FAIL tests at end of all strokes
        FAIL = true;              // set FAIL if spark fail since last index
        FAILtrig = false;        
      } else {
        SPKSflag = true;                                 
        spk1 = spkpulse1;         // for spark timing      
        sRPM2 = spRPM2;           // for sRPM
        spktot1 += 2;
      }
    SPK = false;      
    DATAflag = true;                                               
  }
  if (DATAflag1 && pulse == 3){     // interrupt changes with RPM    
    DATAflag1 = false;         
    if (!HISPD && dtstroke < 13043){      // 2300RPM
      HISPD = true;
      EICRA = 14;     // INT1,index, RISING ; INT0, encoder, FALLING  
    }
    if (HISPD && dtstroke > 13636){       // 2200RPM
      HISPD = false;
      EICRA = 5;     // INT1,index, CHANGE ; INT0, encoder, CHANGE     
    }                   
  }  
} 
//_____________________________________________________________________________
void indexISR(){      // read once per rotation index
  INDEXcnt++;  
  if (PINB && B00001000)INDEXH = true;     
}
//_____________________________________________________________________________

ISR code sent with an irrelevant section used only below 500RPM removed.

Do you have current limiting resistors for each of the spark gaps?
Paul

You are likely right that this could help but the test specifications require no such.

OMG! I've found that I've miscalculated the trigger values of dtstroke defining the RPM values at which the interrupt changes occur. The code works OK as specified. My humble apologies and thanks to those who tried to help. A lesson learnt.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.