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
timemage
  • 5,639
  • 1
  • 14
  • 25
Lawliet
  • 183
  • 7

1 Answers1

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.

tim
  • 699
  • 6
  • 15