3

I am using Arduino mega with 4 interrupts to find the rotation speed of 4 motors . For this I have used INT2, INT3, INT4, INT5 and the code for the same is given below

struct Pulse {
  uint32_t last_toggle;
  uint32_t width;
  bool stateHigh;
  uint32_t get_width() {
    noInterrupts();
    uint32_t width_copy = width;
    interrupts();
    return width_copy;
  }
};

Pulse ch1, ch2, ch3, ch4;





void pin_initialization() {
  // Four engine configuration
  pinMode(19, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

}

volatile uint32_t ovfCount = 0;
ISR(TIMER3_OVF_vect) {
  ovfCount++;
}


void timer3_initialization() {
  TCCR3A = 0x00;

  TCNT3 = 0x1FF; // from datasheet
  TIFR3 = _BV(TOV3);
  TIMSK3 = _BV(TOIE3); // overflow enable
  TCCR3B = B00000011; // 64 prescaling
}

void pulseWidthCalculator(Pulse *channel){
  unsigned char sreg;
  sreg = SREG;
  cli();
  uint16_t tcnt3 = TCNT3;
  SREG = sreg;
  uint32_t ovf_count = ovfCount;

  if (bit_is_set(TIFR3, TOV3) && tcnt3 < 32768) {
    ovf_count++;
  }

  uint32_t time = ovf_count << 16 | tcnt3;

  if (!channel->stateHigh) {  // first high
    channel->stateHigh = true;
  } else if ( channel->stateHigh) {  // second High
    channel->width = time - channel->last_toggle;
    channel->stateHigh = false;
  }
  channel->last_toggle = time;
}


ISR(INT2_vect) {
  pulseWidthCalculator(&ch1);
}

ISR(INT3_vect) {
  pulseWidthCalculator(&ch2);
}

ISR(INT4_vect) {
  pulseWidthCalculator(&ch3);
}

ISR(INT5_vect) {
  pulseWidthCalculator(&ch4);
}




void externalInterrputInitialization() {
  EIFR = _BV(INTF2) | _BV(INTF3) | _BV(INTF4) | _BV(INTF5); 
  EICRA = 0; EICRB = 0;
  EICRA = B10100000;
  EICRB = B00001010;
  EIMSK = B00111100;
}

void setup() {
  Serial.begin(115200);

  pin_initialization();
  delayMicroseconds(10);

  externalInterrputInitialization();
  delayMicroseconds(10);

  timer3_initialization();
  delayMicroseconds(10);

}


void loop() {
  String a = String(15e6/ch1.get_width());
  a += " ";
  a += String(15e6/ch2.get_width());
  a += " ";
  a += String(15e6/ch3.get_width());
  a += " ";
  a += String(15e6/ch4.get_width());

  Serial.println(a);

}

The issue I am facing is , whenever I give a signal to INT2, INT3 is also getting triggered, same with INT4, INT5 also getting triggered without signal .

What I am I missing here, ?

Should I make my channels ch1, ch2 , ch3, ch4 to volatile or not.? like volatile Pulse ch1, ch2, ch3, ch4

  • Any thing wrong with OUTPUT_PULLUP
5
  • 1
    volatile is necessary to be sure changes made are observable between the ISR and non-ISR contexts. That said, it doesn't seem like it would completely account for what you're seeing. You should make them volatile an let us know what the behaviour in that case is though.
    – timemage
    Aug 9, 2021 at 15:09
  • 2
    why do you believe that it is a programming problem?
    – jsotola
    Aug 9, 2021 at 15:25
  • @timemage, changing to volatile is not helping.
    – Lawliet
    Aug 9, 2021 at 15:31
  • In that case, it's probably a good idea to just make the variables volatile in your code and remove the part where ask about doing that, to remove the distraction from the primary question.
    – timemage
    Aug 9, 2021 at 15:45
  • 1
    This has nothing to do with your question as such, but your Serial stream concatenates things for you as a matter of course. All of your assignments and appends to String a are an inefficient and bug-prone alternative to a series of print/println calls.
    – timemage
    Aug 9, 2021 at 15:53

1 Answer 1

1

You have the right idea to atomically obtain a copy of the data that is updated by the interrupt:

  unsigned char sreg;
  sreg = SREG;
  cli();
  uint16_t tcnt3 = TCNT3;
  SREG = sreg;
  uint32_t ovf_count = ovfCount;

...but the last two lines should be swapped to keep the copying operation within the non-interrupt section:

  unsigned char sreg;
  sreg = SREG;                    // Save interrupt state.
  cli();                          // Disable interrupts.
  uint16_t tcnt3 = TCNT3;         // Atomic operations.
  uint32_t ovf_count = ovfCount;
  SREG = sreg;                    // Restore interrupt state.

Though I notice you are calling that code from within an interrupt service routine so interrupts should already be disabled unless you are intending to use nested interrupts.

The false interrupt could be caused by crosstalk between INT2 and INT3. You could confirm this by using an oscilloscope. Keep the signal wires separate to avoid crosstalk.

You could also try stronger external pull-ups such as 10K or 1K. The Arduino internal pull-ups are weaker at about 20-50K Ohms.

2
  • Thanks Tim , from oscilloscope I understood its an issue of INPUT_PULLUP, I will do external PULLUPs.
    – Lawliet
    Aug 10, 2021 at 7:06
  • used 1K resistor and its working. Is there any issue with using external pull-up along with INPUT_PULLUP.?
    – Lawliet
    Aug 11, 2021 at 10:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.