1

I come from a .Net background, typically I would 'lock' operations on an integer when I have thread-safe requirements. I'm not sure that applies to my sketch here? Could I potentially bypass an increment from one of my interrupt pins?

In summary, I have 2 interrupt pins - I want to increment a count which (every 5 seconds) writes via serial and resets.

I'm doing this to, kind of, avoid writing serial from within an interrupt - since I've read it's strongly discouraged.

#include <Controllino.h>

const byte interruptPin0 = CONTROLLINO_IN0;
const byte interruptPin1 = CONTROLLINO_IN1;
int counter1 = 0;
int counter2 = 0;
unsigned long previousMillis = 0;
unsigned long interval = 5000;
int a = 60;
char buffer[256];

void setup()
{
  pinMode(interruptPin0, INPUT_PULLUP);
  pinMode(interruptPin1, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin0), pin1Fired, RISING);
  attachInterrupt(digitalPinToInterrupt(interruptPin1), pin2Fired, RISING);
  Serial.begin(9600);
}

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    sprintf(buffer,"A%d",counter1);
    Serial.println(buffer);
    sprintf(buffer,"D%d",counter2);
    Serial.println(buffer);
    counter1 = counter2 = 0;
  }
}

void pin1Fired()
{
  counter1++;
}

void pin2Fired()
{
  counter2++;
}
5

There is indeed a race condition in your code: if an interrupt fires while you are reading one of the counters, you might read garbage. If it fires between reading and resetting the counter, you loose one count.

The way to prevent the race is to block interrupts while the main thread (everything that does not run in interrupt context) accesses the counters. BTW, do not forget to make the counters volatile.

The portions of the code that run with interrupts disabled are called “critical sections”, and you should keep them as short as possible in order to limit the interrupt latency they introduce. Typically, within those critical sections you do nothing more than access the shared variables. Example:

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    noInterrupts();  // start of critical section
    int counter1Copy = counter1;
    counter1 = 0;
    interrupts();  // end of critical section
    Serial.print("A");
    Serial.println(counter1Copy);
    noInterrupts();  // start of critical section
    int counter2Copy = counter2;
    counter2 = 0;
    interrupts();  // end of critical section
    Serial.print("D");
    Serial.println(counter2Copy);
  }
}
  • Excellent! Thanks very much for this, probably saved me a lot of hassle when it came to missing counts! Just one question - during the time in which the interrupts are disabled(?) - are we not vulnerable to missing the interrupt handlers? i.e. still missing counts? – JᴀʏMᴇᴇ May 31 '20 at 11:32
  • 1
    When an interrupt occurs in that time, it will be executed after you turned on the interrupts again.you only loose counts, when 2 or more interrupzs occur in that time. To prevent that you need to keep the disabled time lower than the time between 2 interrupts – chrisl May 31 '20 at 11:48
  • 1
    @chrisl is right. To be more specific, you loose a count if 2 or more instances of the same interrupt fire during that window. If you get one INT0 and one INT1 you are fine. – Edgar Bonet May 31 '20 at 12:25
  • Got you, brilliantly explained. Thanks Edgar. – JᴀʏMᴇᴇ May 31 '20 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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