Interrupts - Pinout help needed

I need some help finding the pin mapping for interrupts on the Artemis ATP. It appears from the non-sequential pin labels on the Artemis boards (e.g not D0-D13 like a Mega) that these trace directly to the Apollo3 pads – true?

I looked at the summary pinout you provided here, but it does not indicate the interrupt locations. https://cdn.sparkfun.com/assets/8/2/3/3 … apping.pdf

I also searched through the full Apollo3 Blue data sheet, but could not decode interupt-t-pin/pad map from there.

https://ambiqmicro.com/static/mcu/files … 349yoT.pdf

I’d appreciate some help. Thanks!

Your intuition is good - indeed the numbers on the ATP correspond to Apollo3 pads. As for interrupt mapping… the Apollo3 is interrupt capable on all its GPIO. Are you trying to use interrupts in Arduino or in the AmbiqSuite SDK?

In Arduino it is as simple as

attachInterrupt(digitalPinToInterrupt( pin, isr, mode);
attachInterruptArg(digitalPinToInterrupt( pin, isrArg, arg, mode);

(isr is a function with signature void void, isrArg has a signature void void* and arg is a void* pointer that gets passed to isrArg when it is called)

In the SDK you will need to perform these steps:

  • ensure that the pin configuration has interrupts enabled

  • enable GPIO peripheral interrupts in the NVIC

  • enable master interrupts

I guess that’s all to say that there is no interrupt mapping like there may be on other microcontrollers - all GPIO interrupts get routed to ```
void am_gpio_isr(void)


uint64_t gpio_int_mask = 0x00;
am_hal_gpio_interrupt_status_get(true, &gpio_int_mask);

and clear flags once they are handled with ```
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(gpio_int_mask );

Does that help answer your question?

Great - thanks! That’s the answer I was hoping for.

In the past, there have boards (different vendor) that said “any GPIO can be an interrupt” but then under the hood several pins share the same underlying IRQ, many multiple pins trip the same interrupt… This took a long time to determine and in the meantime led to much insanity.

I’m just using vanilla Arduino to code this, BTW. Thanks for the code snippets.

Hmm… looking further at the full Apollo3 data sheet, I’m confused again.

It seems to indicate 32 interrupts (see snipped below). But you mentioned that all 48 GPIO pins can be used as interrupts. That doesn’t seem to agree. Or, perhaps I poorly worded what I want. I’ll try again: What pins on the Artemis ATP can I utilize to get 20 unique (independent) interrupts? I plan to use with 10 hall-effect encoders, each of which require 2 interrupt channels.

From the Apollo3 datasheet (https://cdn.sparkfun.com/assets/learn_t … v0_9_1.pdf):

"High-performance ARM Cortex-M4 Processor

  • 48 MHz nominal clock frequency, with 96 MHz high performance “TurboSPOT” Burst Mode

  • Floating point unit

  • Memory protection unit

  • Wake-up interrupt controller with 32 interrupts"

Ambiq has a real sense of humor when it comes to pin numbers. Starting pads at pad zero. Hardware people at Ambiq must be gritting their teeth.

I believe that all GPIO pins are available for interrupts. When a GPIO interrupt occurs on any of those pins, it will generate an IRQ13 (one of the 32 interrupt sources, per the data sheet). You would then have to read the GPIO interrupt status registers to determine the specific GPIO pin associated with the interrupt (see the data sheet, Sec 11.7.2). Then, you can execute the appropriate ISR handler for that pin. I assume that you need to check all necessary status register bits to service all outstanding interrupts (based on your design). I’ve left out some details, that’s just a very top level perspective based on my previous experience.

Thanks for the insights. Everything checks out. I was able to get 20 pins using interrupts without any cross-talk.

In case it helps someone else, I’m sharing my ugly brute-force sketch that creates an interrupt routine for each of 20 pins. I tested by using a jumper wire from ground to each of these pins one-by-one to ensure only the counter for the respective pin is incrementing. Previously (on a Metro M0 Express board), pins shared underlying ISR’s, causing PinA’s toggle to increment Pin B’s counter. That wasn’t fun – for the longest time I thought I had a hardware short or brownout issue from encoders.

/*
 Brute force check to ensure hardware interrupts aren't cross-talking.  Tested with a jumper from ground, then going one-by one down the pins.  
 
 Listed here in order they are phyisically on the board. Starting nearest the usb plug and moving down, but skipping pins w/o numbers.  Then a few on the left (I needed 20).
 Going down the list twice and watching the counts, I confirmed no Pin's count was being incremented by another pin (a problem I had with Metro M0 boards).
*/

int count_13=0;
int count_12=0;
int count_32=0;
int count_28=0;
int count_27=0;

int count_23=0;
int count_22=0;
int count_04=0;
int count_35=0;
int count_14=0;

int count_08=0;
int count_10=0;
int count_09=0;
int count_26=0;
int count_15=0;

int count_19=0;
int count_18=0;
int count_17=0;
int count_41=0;
int count_45=0;



// defines pin number on the board (not the pin's current value)
int Pin_13=13;
int Pin_12=12;
int Pin_32=32;
int Pin_28=28;
int Pin_27=27;
            
int Pin_23=23;
int Pin_22=22;
int Pin_04=4;
int Pin_35=35;
int Pin_14=14;
            
int Pin_08=8;
int Pin_10=10;
int Pin_09=9;
int Pin_26=26;
int Pin_15=15;
            
int Pin_19=19;
int Pin_18=18;
int Pin_17=17;
int Pin_41=41;
int Pin_45=45;




void setup() {
  //start serial connection
  Serial.begin(9600);
  //configure as an input and enable the internal pull-up resistor
  pinMode(13, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(32, INPUT_PULLUP);
  pinMode(28, INPUT_PULLUP);
  pinMode(27, INPUT_PULLUP);
          
  pinMode(23, INPUT_PULLUP);
  pinMode(22, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(35, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
          
  pinMode(8, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(26, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
          
  pinMode(19, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(41, INPUT_PULLUP);
  pinMode(45, INPUT_PULLUP);
  pinMode(5, OUTPUT);

attachInterrupt(digitalPinToInterrupt(Pin_13), myIntRoutine_13, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_12), myIntRoutine_12, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_32), myIntRoutine_32, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_28), myIntRoutine_28, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_27), myIntRoutine_27, RISING);
                                                             
attachInterrupt(digitalPinToInterrupt(Pin_23), myIntRoutine_23, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_22), myIntRoutine_22, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_04), myIntRoutine_04, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_35), myIntRoutine_35, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_14), myIntRoutine_14, RISING);
                                                             
attachInterrupt(digitalPinToInterrupt(Pin_08), myIntRoutine_08, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_10), myIntRoutine_10, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_09), myIntRoutine_09, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_26), myIntRoutine_26, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_15), myIntRoutine_15, RISING);
                                                             
attachInterrupt(digitalPinToInterrupt(Pin_19), myIntRoutine_19, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_18), myIntRoutine_18, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_17), myIntRoutine_17, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_41), myIntRoutine_41, RISING);
attachInterrupt(digitalPinToInterrupt(Pin_45), myIntRoutine_45, RISING);
}

void loop() {
 
Serial.println("I still exist...");
delay(2000);
}
////////////////////
// Create interrupt routine for each pin...

void   myIntRoutine_13(){
              count_13++;
      Serial.print("_13 Within the ISR; count value ->");
Serial.println(count_13);
}                    
                     
void   myIntRoutine_12(){
              count_12++;
      Serial.print("_12 Within the ISR; count value ->");
Serial.println(count_12);
}                    
                     
void   myIntRoutine_32(){
              count_32++;
      Serial.print("_32 Within the ISR; count value ->");
Serial.println(count_32);
}                    
                     
void   myIntRoutine_28(){
              count_28++;
      Serial.print("_28 Within the ISR; count value ->");
Serial.println(count_28);
}                    
                     
void   myIntRoutine_27(){
              count_27++;
      Serial.print("_27 Within the ISR; count value ->");
Serial.println(count_27);
}                      
                       
void   myIntRoutine_23(){
              count_23++;
      Serial.print("_23 Within the ISR; count value ->");
Serial.println(count_23);
}                    
                     
void   myIntRoutine_22(){
              count_22++;
      Serial.print("_22 Within the ISR; count value ->");
Serial.println(count_22);
}                    
                     
void   myIntRoutine_04(){
              count_04++;
      Serial.print("_04 Within the ISR; count value ->");
Serial.println(count_04);
}                    
                     
void   myIntRoutine_35(){
              count_35++;
      Serial.print("_35 Within the ISR; count value ->");
Serial.println(count_35);
}                    
                     
void   myIntRoutine_14(){
              count_14++;
      Serial.print("_14 Within the ISR; count value ->");
Serial.println(count_14);
}                    
                     
void   myIntRoutine_08(){
              count_08++;
      Serial.print("_08 Within the ISR; count value ->");
Serial.println(count_08);
}                    
                     
void   myIntRoutine_10(){
              count_10++;
      Serial.print("_10 Within the ISR; count value ->");
Serial.println(count_10);
}                    
                     
void   myIntRoutine_09(){
              count_09++;
      Serial.print("_09 Within the ISR; count value ->");
Serial.println(count_09);
}                    
                     
void   myIntRoutine_26(){
              count_26++;
      Serial.print("_26 Within the ISR; count value ->");
Serial.println(count_26);
}                    
                     
void   myIntRoutine_15(){
              count_15++;
      Serial.print("_15 Within the ISR; count value ->");
Serial.println(count_15);
}                    
                       
void   myIntRoutine_19(){
              count_19++;
      Serial.print("_19 Within the ISR; count value ->");
Serial.println(count_19);
}                    
                     
void   myIntRoutine_18(){
              count_18++;
      Serial.print("_18 Within the ISR; count value ->");
Serial.println(count_18);
}                    
                     
void   myIntRoutine_17(){
              count_17++;
      Serial.print("_17 Within the ISR; count value ->");
Serial.println(count_17);
}                    
                     
void   myIntRoutine_41(){
              count_41++;
      Serial.print("_41 Within the ISR; count value ->");
Serial.println(count_41);
}                    
                     
void   myIntRoutine_45(){
              count_45++;
      Serial.print("_45 Within the ISR; count value ->");
Serial.println(count_45);
}

Is there a way to clear the interrupts manually in the Arduino core? I’m running into (an apparently classic) error where the Artemis “Remembers” a falling edge occurring before I attached the interrupt to the pin but after I declared the pin as an INPUT or an INPUT_PULLUP (or maybe because if it, going from floating to input pullup?), and acts on that “original falling edge” before I provide the intended falling edge