Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Using analog pin for interrupts? (Feather M4)
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Using analog pin for interrupts? (Feather M4)

by Egholm on Sun Sep 08, 2019 4:40 pm

I've just acquired an Adafruit Feather M4 Express board, and looking at the pinouts page (https://learn.adafruit.com/adafruit-fea ... 51/pinouts) it says:

* "All pins can be interrupt inputs"
* "A2 thru A5 - These are each analog input as well as digital I/O pins."

("As well as digital I/O pins).

So, in my naive approach, I've tried hooking up A4 for digital interrupts using an Arduino sketch:

8< 8< 8<
pinMode(A4, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(A4), ISR, CHANGE);
8< 8< 8<

However I never get an interrupt (shorting the pin to either 3V3 or GND).
But I can read the pin status (digitalRead(A4)) and see that it indeed goes LOW and HIGH as expected.

Using e.g. pin 6 for the same exercise, and things goes exactly as expected.

Am I reading the information on the above page incorrectly?

Best regards,
Martin

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by adafruit_support_mike on Mon Sep 09, 2019 2:33 am

The pins can accept interrupts, but there might be a glitch in the digitalPinToInterrupt() macro.

Try using just the number '6' and see if that works.

adafruit_support_mike
 
Posts: 61422
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Mon Sep 09, 2019 2:55 am

Hi Mike,

adafruit_support_mike wrote:The pins can accept interrupts, but there might be a glitch in the digitalPinToInterrupt() macro.
Try using just the number '6' and see if that works.


Well, pin 6 is the one that works. It's using pin A4 (pin 18) that doesn't. But I've printed the return value of digitalPinToInterrupt(A4) and digitalPinToInterrupt(18) and both return 18, so there's no glitch in there.
That would have been a nice solution, though :)

Any other ideas?

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by adafruit_support_mike on Mon Sep 09, 2019 11:32 pm

Pin A4 connects to interrupt channel 6. Digital pin #6 has nothing to do with it.

The fact that digitalPinToInterrupt() returns 18 is the reason your interrupts aren't working.

Try using the raw interrupt channel number 6 in attachInterrupt() and see if that makes pin A4 accept interrupts.

adafruit_support_mike
 
Posts: 61422
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Tue Sep 10, 2019 6:01 am

Hi Mike,

adafruit_support_mike wrote:Pin A4 connects to interrupt channel 6. Digital pin #6 has nothing to do with it.
The fact that digitalPinToInterrupt() returns 18 is the reason your interrupts aren't working.
Try using the raw interrupt channel number 6 in attachInterrupt() and see if that makes pin A4 accept interrupts.


Doh, that must be it!
Thanks! Can't wait to verify this later...

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Tue Sep 10, 2019 4:02 pm

Hi Mike,

adafruit_support_mike wrote:Pin A4 connects to interrupt channel 6. Digital pin #6 has nothing to do with it.
The fact that digitalPinToInterrupt() returns 18 is the reason your interrupts aren't working.
Try using the raw interrupt channel number 6 in attachInterrupt() and see if that makes pin A4 accept interrupts.


Back in the garage. And things are strange and not behaving as (naively) expected.
Changing the code to:

#define A4_INTERRUPT_PIN 6
----
pinMode(A4, INPUT_PULLUP);
attachInterrupt(A4_INTERRUPT_PIN , ISR, CHANGE);

Does have some effect - but not as expected. (Explanation follows below...)

However, before I explain my potential silly/erroneous test-setup, how did you derive that A4 should be interrupt channel 6?
I can see nothing in the pinout (original post) that indicates this. I can only read: PA04, 18/A4, I4.
And I can't find a (simple) table inside the:
"SAM D5x/E5x Family Data Sheet" [http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf]
of any help to me either. Table 6-1 ("Multiplexed Peripheral Signals") is the closest I get, but finding PA18 it says "EIC/EXTINT[4]", but there my trail stops.


Well, back to the my test-setup:
Recall/note that I (for simplicity of testing) have wired digital output pin 5 (PA16) to A4 (PA04), so that a digitalWrite(5, LOW); or digitalWrite(5, HIGH); should give rise to an interrupt on A4.
At least that is what I'm thinking should happen (and it also works as expected when I wire pin 5 and 6 together and configure digital pin 6 as input and for interrupts).
(I reckon it should be safe to wire things like that, right. According to Table 54-14 in the above, the internal pull-up is 20kOhm, so I = 3V3/20kOhm = 0.165mA.)

However, when I enter my serial-console command for setting pin 5 high (initially low), I (sometimes) get two interrupts (sometimes none), and most times when I afterwards lower pin 5, I get no interrupts.
However, if I measure the input voltage level on A4 with my "old" digital multimeter, it reads 3V3 as expected when HIGH and zero when LOW.
Further, probing the A4 with the multimeter triggers some interrupts (but that is likely to be expected when messing with the levels).


Any ideas to help me understand what happens?

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by adafruit_support_mike on Tue Sep 10, 2019 8:43 pm

Egholm wrote:However, before I explain my potential silly/erroneous test-setup, how did you derive that A4 should be interrupt channel 6?

It's in the variant.cpp file:

https://github.com/adafruit/ArduinoCore ... nt.cpp#L65

Egholm wrote:However, when I enter my serial-console command for setting pin 5 high (initially low), I (sometimes) get two interrupts (sometimes none), and most times when I afterwards lower pin 5, I get no interrupts.

Post the code you're using for the test between CODE tags please.

adafruit_support_mike
 
Posts: 61422
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Wed Sep 11, 2019 2:19 am

adafruit_support_mike wrote:It's in the variant.cpp file:
https://github.com/adafruit/ArduinoCore ... nt.cpp#L65

Thanks!

adafruit_support_mike wrote:
Egholm wrote:However, when I enter my serial-console command for setting pin 5 high (initially low), I (sometimes) get two interrupts (sometimes none), and most times when I afterwards lower pin 5, I get no interrupts.

Post the code you're using for the test between CODE tags please.


Here goes:

Code: Select all | TOGGLE FULL SIZE
#define INT_TRIGGER_PIN 5   // The I/O pin externally wired to A4
#define A4_INTERRUPT_PIN 6  // A4's interrupt is on raw channel 6

// Our interrupt counter
volatile int gInterruptCount = 0;

/***************
 **** SETUP ****
 ***************/
void setup() {
  Serial.begin(115200);
 
  // Initially low - that shouldn't cause an interrupt
  digitalWrite(INT_TRIGGER_PIN, LOW);
  pinMode(INT_TRIGGER_PIN, OUTPUT);
 
  pinMode(A4, INPUT_PULLUP);
  // This approach is not recommended, but is necessary since there's a bug in digitalPinToInterrupt():
  attachInterrupt(A4_INTERRUPT_PIN, ISR, CHANGE);
}

/**************
 **** LOOP ****
 **************/
void loop() {
  int pinStatus = digitalRead(A4);
  Serial.printf("A4 status (compile time: %s): %s (int count: %d)\n", __TIME__, (pinStatus == LOW ? "LOW": "HIGH"), gInterruptCount);

  // Check if we need to handle a command:
  if (Serial.available())
  {
    String inputString = Serial.readString();
    if (inputString.charAt(inputString.length()-1) == '\n')
    { // Strip of line-ending
      inputString.remove(inputString.length()-1); 
    }

    // Command handler
    if (inputString.equalsIgnoreCase("low"))
    {
      Serial.printf("Setting \"low\"\n");
      digitalWrite(INT_TRIGGER_PIN, LOW);
    }
    else if (inputString.equalsIgnoreCase("high"))
    {
      Serial.printf("Setting \"high\"\n");
      digitalWrite(INT_TRIGGER_PIN, HIGH);
    }
  }
   
  delay(1000); // Wait for a second             
}

/*************
 **** ISR ****
 *************/
void ISR()
{
   gInterruptCount++;
}


And then I have a wire between pin 5 and A4.
Entering "low" or "high" into the serial console makes the output pin change accordingly - expecting one interrupt count on either change.

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Mon Sep 16, 2019 2:16 am

No ideas?

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by adafruit_support_mike on Tue Sep 17, 2019 1:00 am

Try putting a boolean flag that the ISR sets true, and the main code sets false. Then put a conditional in your code to print the counter value every time it sees the flag set to true.

That will give us a better idea of when the interrupts are actually happening.

adafruit_support_mike
 
Posts: 61422
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Tue Sep 17, 2019 5:05 pm

Hi Mike,
Good to hear from you :)

And here's the result of your suggestion:

Code: Select all | TOGGLE FULL SIZE
Interrupt test (Compile time: 22:39:26)!
high
Setting "high"
Interrupt @ 11126 ms, [entry, exit] = [11126, 11126] (count: 1) (lvl: 1)
Interrupt @ 11191 ms, [entry, exit] = [11126, 11126] (count: 2) (lvl: 1)
low
Setting "low"
high
Setting "high"
Interrupt @ 22411 ms, [entry, exit] = [22405, 22405] (count: 3) (lvl: 1)
Interrupt @ 22479 ms, [entry, exit] = [22405, 22405] (count: 4) (lvl: 1)
low
Setting "low"
high
Setting "high"
Interrupt @ 28471 ms, [entry, exit] = [28471, 28471] (count: 5) (lvl: 1)
Interrupt @ 28541 ms, [entry, exit] = [28471, 28471] (count: 6) (lvl: 1)
low
Setting "low"
high
Setting "high"
Interrupt @ 35071 ms, [entry, exit] = [35056, 35056] (count: 7) (lvl: 1)
Interrupt @ 35122 ms, [entry, exit] = [35056, 35056] (count: 8) (lvl: 1)


As can be seen, there are two interrupts as a response to the one digitalWrite(HIGH)-action fired at the recorded [entry, exit]-time, and none at the digitalWrite(LOW).
The second interrupt appears some 60 ms after the first one.

I really wish I had an oscilloscope I could attach...
Maybe I could use the/an ADC to capture the readings (haven't considered that until now...)

Nevertheless, below's the modified code - comments are very much appraciated:

Code: Select all | TOGGLE FULL SIZE
#define INT_TRIGGER_PIN 5   // The I/O pin externally wired to A4
#define A4_INTERRUPT_PIN 6  // A4's interrupt is on raw channel 6

// Our interrupt counter
volatile int gInterruptCount = 0;
// Bool set high in the ISR, lowered by the main-loop:
volatile bool gInterruptSeen = false;

// Recorded entry/exit values when changing our INT_TRIGGER_PIN:
uint32_t gWriteEntryMs = 0;
uint32_t gWriteExitMs = 0;

/***************
 **** SETUP ****
 ***************/
void setup() {
  while (!Serial) {}
  Serial.begin(115200);
  Serial.printf("Interrupt test (Compile time: %s)!\n", __TIME__);
 
  // Initially low - that shouldn't cause an interrupt
  digitalWrite(INT_TRIGGER_PIN, LOW);
  pinMode(INT_TRIGGER_PIN, OUTPUT);
 
  pinMode(A4, INPUT_PULLUP);
  // This approach is not recommended, but is necessary since there's a bug in digitalPinToInterrupt():
  attachInterrupt(A4_INTERRUPT_PIN, ISR, CHANGE);
}

/**************
 **** LOOP ****
 **************/
void loop() {
  if (gInterruptSeen)
  { // If we've seen an interrupt in the the ISR, we record the values "atomically" and print afterwards:
    noInterrupts();
   
    gInterruptSeen = false;
    uint32_t ackTimeMs = millis();
    int interruptCount = gInterruptCount;
    uint32_t currentLevel = digitalRead(A4);
   
    interrupts();
   
    Serial.printf("Interrupt @ %u ms, [entry, exit] = [%u, %u] (count: %u) (lvl: %u)\n",
      ackTimeMs, gWriteEntryMs, gWriteExitMs, interruptCount, currentLevel);
  }

  // Check if we need to handle a command:
  if (Serial.available())
  {
    String inputString = Serial.readString();
    if (inputString.charAt(inputString.length()-1) == '\n')
    { // Strip of line-ending
      inputString.remove(inputString.length()-1);
    }

    // Command handler
    if (inputString.equalsIgnoreCase("low"))
    {
      Serial.printf("Setting \"low\"\n");
      gWriteEntryMs = millis();
      digitalWrite(INT_TRIGGER_PIN, LOW);
      gWriteExitMs = millis();
    }
    else if (inputString.equalsIgnoreCase("high"))
    {
      Serial.printf("Setting \"high\"\n");
      gWriteEntryMs = millis();
      digitalWrite(INT_TRIGGER_PIN, HIGH);
      gWriteExitMs = millis();
    }
  }
}

/*************
 **** ISR ****
 *************/
void ISR()
{
  gInterruptCount++;
  gInterruptSeen = true;
}

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by adafruit_support_mike on Tue Sep 17, 2019 11:51 pm

Try configuring pin A4 as a simple INPUT, not INPUT_PULLUP. The pull-up resistor could be messing with the results.

adafruit_support_mike
 
Posts: 61422
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Wed Sep 18, 2019 2:29 am

Hi Mike,

adafruit_support_mike wrote:Try configuring pin A4 as a simple INPUT, not INPUT_PULLUP. The pull-up resistor could be messing with the results.


Tried it this morning - exactly the same.
I will try connect another analog input and make recordings of the behavior...

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Re: Using analog pin for interrupts? (Feather M4)

by vattiat on Thu Sep 19, 2019 11:54 am

I am having an almost identical issue with my Feather M0 attached to a flow meter. The flow meter reading is always 2x higher than it should be. I have connected a oscilloscope and verified that the signal at the interrupt pin is cleanly switching between 3.3V and 0V at a frequency that closely matches the actual flow rate.

It seems that the interrupt gets called at least twice for every actual rising edge of the flow meter signal.

I saw similar posts elsewhere which led to the PinChangeInterrupt library, but that is incompatible with Feather M0/M4.

What are we missing???

vattiat
 
Posts: 2
Joined: Wed Sep 18, 2019 9:22 pm

Re: Using analog pin for interrupts? (Feather M4)

by Egholm on Thu Sep 26, 2019 4:46 pm

vattiat wrote:It seems that the interrupt gets called at least twice for every actual rising edge of the flow meter signal.
I saw similar posts elsewhere which led to the PinChangeInterrupt library, but that is incompatible with Feather M0/M4.
What are we missing???

That's a really good question!

Without having an oscilloscope at hand, I just tried wiring my A4 (the one I try to get interrupts at) to A3 and then sampled it every millisecond using analogRead().
The result reveals nothing: The analog samples are rock steady (unless something happens above 65520 (being the upper level rock steady value - no fluctuations!):

result.png
The analogRead() samples (with 16 bits resolution) in blue, and the interrupts times marked with red,
result.png (25.13 KiB) Viewed 423 times


And there really are nothing to be seen at the times of the "fake" interrupts:

zoom.png
zoom.png (19.93 KiB) Viewed 423 times


It could be "funny" to have the ADC sample above 3V3, but that requires another reference; but there was some limitations in the Feather board there:

"On the Feather M4, at least for now, AREF is tied to 3.3V due to a silicon v0 bug that does not allow the DACs
to work unless AREF is connected to 3.3V. You cut the bottom jumper if you need a different AREF voltage
but note that this may change DAC range!
"
[https://cdn-learn.adafruit.com/downloads/pdf/adafruit-feather-m4-express-atsamd51.pdf]

All in all, still lost...

Martin

Egholm
 
Posts: 10
Joined: Sun Sep 08, 2019 4:28 pm

Please be positive and constructive with your questions and comments.