arduino / Arduino

Arduino IDE 1.x
https://www.arduino.cc/en/software
Other
14.13k stars 7k forks source link

Interrupts problem on Arduino Due #5897

Closed mvladic closed 7 years ago

mvladic commented 7 years ago

Here is relatively small sketch that I extracted from my much larger project.

In this sketch there are 2 interrupt handlers:

For the purpose of debugging, I'm counting, for both FAN and ADC, the number of interrupts occurred and print this counters to serial port every 1 second when I also reset them back to zero.

Here is what I get on serial port output when I run my sketch:

In the first 5 seconds, there is no FAN interrupts (as expected) and there are 20 ADC interrupts per second (also, as expected):

FAN interrupt counter = 0, ADC interrupt counter = 3
FAN interrupt counter = 0, ADC interrupt counter = 20
FAN interrupt counter = 0, ADC interrupt counter = 20
FAN interrupt counter = 0, ADC interrupt counter = 20

At this moment FAN interrupts are enabled for the brief period of time, and as expected now there are some FAN interrupts to process:

FAN interrupt counter = 1, ADC interrupt counter = 20

Now, FAN speed is measured (and printed on serial port) and FAN interrupts are again disabled:

RPM=4452

But now, suddenly, we started to receive 20 FAN interrupts per second all the time, when we should receive no FAN interrupt because they should be disabled!?

FAN interrupt counter = 22, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 21, ADC interrupt counter = 20
RPM=4419
FAN interrupt counter = 23, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 21, ADC interrupt counter = 20
RPM=4388
FAN interrupt counter = 23, ADC interrupt counter = 20
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 19, ADC interrupt counter = 19
FAN interrupt counter = 20, ADC interrupt counter = 20
FAN interrupt counter = 21, ADC interrupt counter = 20
...

I checked the implementation of the functions attachInterrupt and detachInterrupt inside file WInterrupts.c from the Arduino library for the SEM boards. I have two observations/questions I think are interesting:

1) At the beginning of the file WInterrupts.c, there is initialization of the callbacksPioB (interrupt PIN's inside my sketch belongs to port B) for every pin (32 of them) to NULL:

int i;
for (i=0; i<32; i++) {
    callbacksPioA[i] = NULL;
    callbacksPioB[i] = NULL;
    callbacksPioC[i] = NULL;
    callbacksPioD[i] = NULL;
}

When attachInterrupt is called, callbacksPioB is set to given callback:

// Set callback function
if (pio == PIOA)
    callbacksPioA[pos] = callback;
if (pio == PIOB)
    callbacksPioB[pos] = callback;
if (pio == PIOC)
    callbacksPioC[pos] = callback;
if (pio == PIOD)
    callbacksPioD[pos] = callback;

I was expecting, that in detachInterrupt, callbacksPioB will again be set to NULL, but there is no such code!?

void detachInterrupt(uint32_t pin)
{
    // Retrieve pin information
    Pio *pio = g_APinDescription[pin].pPort;
    uint32_t mask = g_APinDescription[pin].ulPin;

    // Disable interrupt
    pio->PIO_IDR = mask;
}

2) Interrupt handler for the port B looks like this:

void PIOB_Handler(void) {
  uint32_t isr = PIOB->PIO_ISR;
  uint8_t leading_zeros;
  while((leading_zeros=__CLZ(isr))<32)
  {
    uint8_t pin=32-leading_zeros-1;
    if(callbacksPioB[pin]) callbacksPioB[pin]();
    isr=isr&(~(1<<pin));
  }
}

So, depending of PIO_ISR, multiple callbacks (given with attachInterrupt) could be called during single port B interrupt handler.

And indeed, in my case, after first 5 seconds, every time when ADC interrupt has been triggered, both ADC bit and FAN bit of PIO_ISR are set to 1 (I repeat, at this point FAN interrupts should be disabled).

Consequently, both (FAN and ADC) interrupt handlers that are set with attachIntterupt are called.

If detachInterrupt had reset callback to NULL (see point 1) FAN interrupt handler wouldn't be called. But still, the question is why ISR bit for the FAN pin is marked when FAN interrupts should be disabled?

agdl commented 7 years ago

This issue was moved to arduino/ArduinoCore-sam#13