This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Can't Get an Interrupt to Execute

Gentlemen:

I'm new to Nordic processors, but I have implemented projects with Silabs Gecko and ATTiny processors in the past.  I'm working on a project for a consumer product with an Arduino Nano 33 BLE that uses the Nordic RNF52840 processor (I picked this board because of its tiny footprint and unique peripherals).  Arduino, as yet, still hasn't offered their own software tools for timers and interrupts, so I'm largely using Nordic code.

I'm having a terrible time getting a simple hardware interrupt to work.  It's as if the interrupts are not properly enabled or something.  Here is my basic code.  I am using simple hex to set registers to be more understandable than the long variable names.  I'm a mechanical engineer by trade, so please excuse my poor coding technique.

#include <nrf.h>
#include "nrf_timer.h"
#include "nrf_gpio.h"

const int epin = 2;
int LED = LED_BUILTIN;
uint32_t last_ecount = 0;

void setup() {

    nrf_gpio_cfg_output(LED);                           //set built-in LED pin as output
    nrf_gpio_cfg_input(epin, NRF_GPIO_PIN_PULLUP);      //set pin 2 as pullup input

    NVIC_EnableIRQ(GPIOTE_IRQn);                        //enable interrupts
    NRF_GPIOTE->CONFIG[0] = 0x00010201;                 //low-to-high, pin2, event mode
    NRF_GPIOTE->INTENSET = 0x00000001;                  //enable IN[0]
    
    NRF_TIMER1->TASKS_STOP = 1;
    NRF_TIMER1->MODE = 0;
    NRF_TIMER1->BITMODE = 3;                            //timer1 32-bit mode
    NRF_TIMER1->PRESCALER = 0;                          //use full system clock for timer1: 16 MHz
    NRF_TIMER1->TASKS_CLEAR = 1;
    NRF_TIMER1->CC[0] = 0;                              //zero timer1
    NRF_TIMER1->TASKS_START = 1;                        //start timer1
...

}

void loop(){...}

void GPIOTE_IRQHandler(void){
    uint32_t count = 0;
    
    if(NRF_GPIOTE->EVENTS_IN[0] == 1){                  //filter interrupt for wave E
        NRF_GPIOTE->EVENTS_IN[0] = 0;                   //clear interrupt flag
        NRF_TIMER1->TASKS_CAPTURE[0] = 1;               //capture timer1 value in CC0
        count = NRF_TIMER1->CC[0] - last_ecount;        //time elaspsed for one wave (CC0)
        last_ecount = count;                            //reset for next count
    }
}

Pin2 gets a square wave and the object is to measure the period of the wave (which is then Bluetoothed to another processor). I have troubleshooted the input and know that I'm getting a signal on GPIO2 (I can light an LED using that input pin number).  But when I run the code I get no interrupt at all, ever.  I don't even get an interrupt flag NRF_GPIOTE->EVENTS_IN[0].

I feel like I've tried everything and I'm at wits end.  I'm hoping that there is something simple and stupid I'm doing/not doing. 

Does anyone see my error?  Thanks for your help.

Don

DG Devices

Parents
  • No errors?  Should I assume that the Nordic chip is faulty?

    Don

    DG Devices

  • How did you found that your interrupt handler is not called? Did you set a breakpoint?

    The hardware seems to be configured ok. What I can see - last_ecount and count are defined inside an interrupt handler and will be zeroed every time the handler is called, they're probably will be optimized out by the compiler as well. You need to define last_ecount as global variable outside your handler.

  • I cut the code down to the bare minimum and ran it.  This is literally the entire program now:

    #include <nrf.h>
    #include "nrf_timer.h"
    #include "nrf_gpio.h"
    
    volatile uint32_t last_ecount = 0;                //last count values
    const int epin = 2;                               //board pin D2, signal from E-wave
    int LED = LED_BUILTIN;                            //built-in orange LED for debug
    static void gpio_initialize(void);
    
    void setup() {  
    
      nrf_gpio_cfg_output(LED);                       //set built-in LED pin as output
      nrf_gpio_cfg_input(epin, NRF_GPIO_PIN_PULLUP);  //set pin 2 as pullup input
       
      NVIC_EnableIRQ(GPIOTE_IRQn);                    //enable interrupts
      NRF_GPIOTE->CONFIG[0] = 0x00010201;             //low-to-high, pin2, event mode
      NRF_GPIOTE->INTENSET = 0x00000001;              //enable IN[0]   
      
      NRF_TIMER1->TASKS_STOP = 1;
      NRF_TIMER1->MODE = 0;
      NRF_TIMER1->BITMODE = 3;                        //timer1 32-bit mode
      NRF_TIMER1->PRESCALER = 0;                      //use full system clock for timer1: 16 MHz
      NRF_TIMER1->TASKS_CLEAR = 1;
      NRF_TIMER1->CC[0] = 0;                          //zero timer1
      NRF_TIMER1->TASKS_START = 1;                    //start timer1
    }
    
    void loop() {
      
    }
       
    void GPIOTE_IRQHandler(void){                     //interrupts
      uint32_t count = 0;
      int avcount = 0;
      
      digitalWrite(LED, HIGH);
       
      if(NRF_GPIOTE->EVENTS_IN[0] == 1){              //filter interrupt for E-wave
        NRF_GPIOTE->EVENTS_IN[0] = 0;                 //clear interrupt flag
        NRF_TIMER1->TASKS_CAPTURE[0] = 1;             //capture timer1 value in CC0
        count = NRF_TIMER1->CC[0] - last_ecount;      //time elaspsed for one wave (CC0)
        last_ecount = count;                          //reset for next count
      }
    }

    When I connect pin2 (epin = 2) to ground or to 3.3V I get nothing on the LED. 

    However, when I move the LED output driver from the ISR to the loop() and control it directly with epin like this:

    #include <nrf.h>
    #include "nrf_timer.h"
    #include "nrf_gpio.h"
    
    volatile uint32_t last_ecount = 0;                //last count values
    const int epin = 2;                               //board pin D2, signal from E-wave
    int LED = LED_BUILTIN;                            //built-in orange LED for debug
    static void gpio_initialize(void);
    
    void setup() {  
      nrf_gpio_cfg_output(LED);                       //set built-in LED pin as output
      nrf_gpio_cfg_input(epin, NRF_GPIO_PIN_PULLUP);  //set pin 2 as pullup input
       
      NVIC_EnableIRQ(GPIOTE_IRQn);                    //enable interrupts
      NRF_GPIOTE->CONFIG[0] = 0x00010201;             //low-to-high, pin2, event mode
      NRF_GPIOTE->INTENSET = 0x00000001;              //enable IN[0]   
      
      NRF_TIMER1->TASKS_STOP = 1;
      NRF_TIMER1->MODE = 0;
      NRF_TIMER1->BITMODE = 3;                        //timer1 32-bit mode
      NRF_TIMER1->PRESCALER = 0;                      //use full system clock for timer1: 16 MHz
      NRF_TIMER1->TASKS_CLEAR = 1;
      NRF_TIMER1->CC[0] = 0;                          //zero timer1
      NRF_TIMER1->TASKS_START = 1;                    //start timer1
    }
    
    void loop() {
      int pin2 = 0;
      pin2 = digitalRead(epin);
      if(pin2)
        digitalWrite(LED, HIGH);
        else
          digitalWrite(LED, LOW);
    }
       
    void GPIOTE_IRQHandler(void){                     //string interrupts
      uint32_t count = 0;
      int avcount = 0;
       
      if(NRF_GPIOTE->EVENTS_IN[0] == 1){              //filter interrupt for E-string
        NRF_GPIOTE->EVENTS_IN[0] = 0;                 //clear interrupt flag
        NRF_TIMER1->TASKS_CAPTURE[0] = 1;             //capture timer1 value in CC0
        count = NRF_TIMER1->CC[0] - last_ecount;      //time elaspsed for one vibration (CC0)
        last_ecount = count;                          //reset for next count
      }
    }

    I get a lit LED, which I can turn off by connecting pin2 to ground.  No other input pin does this but pin2.

    I don't understand.

    Don

  • I had another Arduino Nano 33 BLE Nano, which also runs on a 52840.  I tried downloading the same two programs with the same results today.  So I don't think it is a faulty processor.

    Don

  • Do you use Arduino IDE? AFAIK its language is a sort of C++, maybe you just have to add extern "C" { ... } around your handler.

  • The Arduino compiler is based on C++, but I can't get extern "C" to work at all.  I am dead in the water and I need to get this product prototype running soon.  No other development board has a small enough profile to fit in my application.

    Apparently the handler isn't getting recognized (though I get no errors).  Isn't there any other way of making the compiler execute the ISR?

    Don

  • The handler for GPIOTE is defined in arduino core and used for attachInterrupt/detachInterrupt.  You cannot redefine it without changing core sources. I think you can use EGU peripheral to pass GPIOTE event to EGU interrupt handler that is not defined by core.

Reply Children
  • I had originally tried the Arduino interrupt method.  I tried it again today to verify.  I even tried explicitly using the numeral "2" for the pin.  You can't get any simpler than this...

    void setup(){
    Serial.begin(9600); //start display serial
    while (!Serial);
    
    attachInterrupt(2, estring_ISR, RISING);
    }
    
    void loop(){
    }
    
    void estring_ISR(void){
    Serial.println("interrupt occurred");
    }

    When run, this code refuses to interrupt when a signal is applied to pin 2 (literally jumping pin 2 to 3.3V and to ground).  I know the pin is not bad because I can use it elsewhere just fine.

    It's as if I'm using the wrong pin.  I looked over the Arduino core code that you posted and it looks like my code should work.  I can't figure it out.

    Don

  • "D2" is P1.11 on the nRF52840 on the Nano 33 BLE, yet "epin" is defined as "2" which is a different pin, P0.02 which happens to be used on the Nano for AIN0 and SCL.

    The red/green/blue LEDs are active-low, so this code turns those LEDs off, not on (Yellow is active high, edit):

      digitalWrite(LED, HIGH);

    This is the NANO33BLE_V2.0 schematic I referred to, in case I missed something in the posts above, hope this helps.

  • I still don't understand. If I run this code:

    int epin = 2;
    void setup() {
      nrf_gpio_cfg_output(LED_BUILTIN);                       //set built-in LED pin as output
      nrf_gpio_cfg_input(epin, NRF_GPIO_PIN_PULLUP);  //set pin 2 as pullup input
    }
    
    void loop() {
     int pin2 = 0;
      pin2 = digitalRead(epin);
      if(pin2)
        digitalWrite(LED_BUILTIN, HIGH);
        else
          digitalWrite(LED_BUILTIN, LOW);
    }

    The LED will be on.  If I connect pin D2 to ground, the LED turns off, if I disconnect it, it turns back on.  No other GPIO pin will affect the LED but D2.  Doesn't that mean that D2 is mapped to GPIO 2?  I don't understand.

    If D2 is mapped to P1.11, then what GPIO number do I use?  The GPIO number is an integer, not a P number.

    If I use the Arduino method I get the same result:

    int epin = 2;
    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);                       //set built-in LED pin as output
      pinMode(epin, INPUT);                                  //set pin 2 as pullup input
    }
    
    void loop() {
     int pin2 = 0;
      pin2 = digitalRead(epin);
      if(pin2)
        digitalWrite(LED_BUILTIN, HIGH);
        else
          digitalWrite(LED_BUILTIN, LOW);
    }

    I don't understand what you're telling me.  The wiring schematic you refer to shows D2 connected to GPIO39, but GPIO's only are supposed to go to 31. How can this be?

    All I need is to have six input pins that I can use for external interrupts.  If someone can tell me what pins to use and what GPIO numbers to use, that will get me by.

    Don

    DG Devices

  • Post the code for pinmode, digitalRead and digitalWrite, maybe there is some mapping there. The Nordic functions such as nrf_gpio_cfg_output deal with nRF52840 pin numbers P0.02 is pin 2 in that notation. GPIO39 is Nordic nRF52840 pin P1.11

  • But If D2 works when directly connected to the LED, then shouldn't it work when used to trigger an external interrupt? A pin is a pin, isn't it?  If the mapping were different, it would cause serious problems.  In my code above (two posts ago) I used D2 (GPIO2) as an interrupt and it doesn't work.

    I don't think there even is a "GPIO39".  I tried this:

    int epin = 39;
    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);                       //set built-in LED pin as output
      pinMode(epin, INPUT);                                  //set pin 39 as pullup input
    }
    
    void loop() {
     int pin39 = 0;
      pin39 = digitalRead(epin);
      if(pin39)
        digitalWrite(LED_BUILTIN, HIGH);
        else
          digitalWrite(LED_BUILTIN, LOW);
    }

    And nothing happens with any pin.  GPIO numbers are only supposed to be 0 to 31.

    Regardless of what is mapped to what, how can D2 operate the LED directly, but not generate an interrupt on the same GPIO?

    Don

    DG Devices

Related