Stopping interrupts to let rest of the program run.

I am trying to read PWM values from an RC receiver and then use them to control a vehicle on an arduino due. Pulsein() was taking too long to execute, even when I lowered the timeout values so I am now trying an interrupt based approach.

I am running into a problem where nothing else in the code is working now. It seems to me that the interrupts are being triggered so fast they are constantly being ran. I can't disable interrupts within the ISRs since they'll just be reenabled when the ISR exits and the rest of the code never executes so I can't turn them off there.

Any thoughts on how I can tackle this? I am thinking the Scheduler library will be of help but I don't know how yet.

//////PWM Input
volatile int16_t pwm1 = 0; //pwm value
volatile int16_t trig1 = 0; //timer value

volatile int16_t pwm2 = 0; //pwm value
volatile int16_t trig2 = 0; //timer value

volatile int16_t pwm3 = 0; //pwm value
volatile int16_t trig3 = 0; //timer value

volatile int16_t pwm4 = 0; //pwm value
volatile int16_t trig4 = 0; //timer value

#define PWMpin1 52 //pin the interrupt is attached to
#define PWMpin2 50//pin the interrupt is attached to
#define PWMpin3 48 //pin the interrupt is attached to
#define PWMpin4 46//pin the interrupt is attached to


///PWM Input Functions
void intHandler1() //function to call on interrupt
{    if(digitalRead(PWMpin1)) //if the pin is HIGH, note the time
  {    trig1 = micros();}
  else
  {    pwm1 = micros()-trig1; }//if it is low, end the time}
}

void intHandler2() //function to call on interrupt
{    if(digitalRead(PWMpin2)) //if the pin is HIGH, note the time
  {    trig2 = micros();}
  else
  {    pwm2 = micros()-trig2; }//if it is low, end the time}
}


void intHandler3() //function to call on interrupt
{    if(digitalRead(PWMpin3)) //if the pin is HIGH, note the time
  {    trig3 = micros();}
  else
  {    pwm3 = micros()-trig3; }//if it is low, end the time}
}


void intHandler4() //function to call on interrupt
{    if(digitalRead(PWMpin4)) //if the pin is HIGH, note the time
  {    trig4 = micros();}
  else
  {    pwm4 = micros()-trig4; }//if it is low, end the time}
}


void setup(){
///PWM Input
  
  pinMode(PWMpin1, INPUT); //set the pin to input
  pinMode(PWMpin2, INPUT); //set the pin to input
  pinMode(PWMpin3, INPUT); //set the pin to input
  pinMode(PWMpin4, INPUT); //set the pin to input
  
attachInterrupt(PWMpin1,intHandler1,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes
  attachInterrupt(PWMpin2,intHandler2,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes
  attachInterrupt(PWMpin3,intHandler3,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes
  attachInterrupt(PWMpin4,intHandler4,CHANGE); //attach the interrupt function "intHandler" to "pin" whenever the state changes


}

void loop()
{
///do other stuff
  


}

I am thinking the Scheduler library will be of help but I don't know how yet.

How could it possibly be? The Due has one processor. Emulating multi-tasking will be slower that interrupt handling.

If you have too many interrupts occurring then of course nothing else can happen. Apart from detaching the interrupts and ignoring the data there is not much you can do.

Using the digitalWriteFast library (it also has a read function) will significantly reduce the time taken by an ISR. Using Port Manipulation would speed it up a bit more at the expense of being a bit more complicated to code. But I don't know if digitalwriteFast will work on a Due and i don't know how to do Port Manipulation on a Due.

A much better approach IMHO is to use a more sophisticated wireless system that communicates directly without the kludge of trying to measure pulse widths. Have a look at this Simple nRF24L01+ Tutorial.

...R

There isn't any way that a reasonable number of channels from an RC receiver should "overwhelm" an Arduino Due. (Pulses on the order of 1ms, occuring every 20ms or so.) There must be some error in the logic of your program (perhaps not resetting the source of the interrupt, causing it to immediately interrupt again. Some sources are reset automatically, some require an explicit reset, some require more complicated programming. (to measure 1ms pulse widths, I'd expect to use some sort of pin-change interrupt to detect the first edge, and then swap the edge causing an interrupt in the ISR, so that you could then detect the other edge.)

There is a lot which is wrong here.

First you cannot read PWM from an RC Rx as it RC does not use PWM it uses PPM.

Second you can not be over loading the system with interrupts from PPM as you only get one pulse per 25 (or so) mill's. So you must be misusing the interrupts

Look for change not the high or low

Mark

Thank you both. It seems to work now. I was able to determine (at least I think I was) that the program was actually executing a few lines of code in between interrupts so that gave me enough time to turn off interrupts.

The problem I was seeing was that I was using noInterrupts(), which also was turning off all Serial.println. So when I was println troubleshooting, nothing would work. I switched to a DetachInterrupt/AttachInterrupt approach within a timed if statement (100hz) and that seems to work.

I do think there is a more elegant approach which is beyond me...

A cursory google search leads me to believe that digitalwriteFast won't work on the Due.

First you cannot read PWM from an RC Rx as it RC does not use PWM it uses PPM.

That depends on whether you're reading directly out of the receiver, or whether you're reading the servo outputs (do receivers even have the PPM output available these days?)
There's usually a decoder built into the receiver that converts the PPM output of the radio into the individual PWM signals that the servos want.