Pro Mini + RFM95 and two ISR-watched buttons possible?



  • Hi everyone,

    as connecting a RFM95 radio uses Arduino digital pin 2, I am wondering if it is possible to use another pin besides pin 3 to get two ISR watched buttons connected to one node? I am looking into building general MySensor based remotes for controlling music, lights and other connected DIY hardware via MyController. In this scenario, only having a single button per battery powered node would be kind of inefficient.

    Thanks everyone for any clues,

    Joost

    Arduino ref regarding ISRs



  • Hi Joost,

    the Arduino Reference article you linked explains how to setup external interrupts, of which the Pro Mini has only two: INT0 on D2 and INT1 on D3. But there are many more interrupt vectors available - for a complete list see page 74 of the megaAVR datasheet - including pin change interrupts which enable you to use (almost) any pin as an interrupt.

    Keep in mind though that pin change interrupts are lower priority than external interrupts and they will always call an interrupt on both the rising and falling edge. Since a button press usually changes the signal twice (closing and opening, plus possibly bouncing), you'll get two interrupts per click and and have to handle that in your ISR.

    Here are two resources that should help you setting up pin change interrupts:

    There are also dedicated libraries available which make pin change interrupts easier to use, but unfortunately I can't recommend any of these, as I have never used one.

    Nick Gammons excellent interrupts introduction is also always worth reading:
    http://www.gammon.com.au/interrupts



  • Thanks very much for pointing me the way and linking all those docs/references!

    I'll try to make up a working example and leave it here as reference,
    bye,

    Joost



  • Look here for a working example with nrf24:

    https://github.com/rikki78/MySensors



  • Thanks very much! Will start looking into this now!



  • Hi everybody,
    thanks for you help, I got as far as this:

    #include <Arduino.h>
    #include <avr/interrupt.h>
    
    #define MY_RADIO_RFM95
    #include <MySensors.h>
    
    volatile int value = 1000;
    volatile char PinRegLast, ChangedPin, PinRegister;
    volatile unsigned long last_debounce_time=0;
    
    void setup()
    {
    noInterrupts();
    PCICR |= 0b00000011; // Enables Ports B and C Pin Change Interrupts
    PCMSK1 |= 0b00000110; //PCINT9 & PCINT10 = A1 & A2
    PCMSK1 |= 0b00001000; // PCINT11
    PCIFR  = B00000001; // Reset Interruptflag
    interrupts();
    pinMode(A1, INPUT_PULLUP); pinMode(A2, INPUT_PULLUP);
    Serial.begin(38400);
    }
    
    void presentation() {}
    
    void loop()
    {
      //_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
      Serial.print(value); Serial.print(" : ");Serial.println(PinRegister, BIN);
      sleep(160000);
    }
    
    ISR(PCINT1_vect)
    {
      if ( (long) millis() - last_debounce_time > 30)
      {
        //_wokeUpByInterrupt = 0xFE;
        PinRegister = PINC;
        ChangedPin = PinRegister ^ PinRegLast;
        PinRegLast = PinRegister;
        switch (ChangedPin){
        case (1 << PINC1):
          if (~PinRegister & (1 << PINC1)) value++;
          break;
        case (1 << PINC2):
          if (~PinRegister & (1 << PINC2)) value--;
          break;
        default:
          break;
        }
        last_debounce_time = millis();
    
      }
    }
    
    

    When I have this code without the MySensors parts (e.g. #inclue MySensors.h & sleep(..)) in it running, it kind of works plus/minus some debouncing issues. But when including MySensors and sleeping in loop(), there is rarely a reaction to pin changes and at no time a change of the variable "value", which is working without the MySensors bits in there.

    Is there something special to deal with when using sleep() together with PinChangeInterrupts?


  • Mod

    @Joost I think you need to use a custom sleep command, like at https://github.com/rikki78/MySensors/blob/master/WallRemote/WallRemote.ino#L142



  • @mfalkvidd Thanks, will try that.
    TBH I had seen that already in there, but hoped it would not be needed anymore (since that sketch is from 2016).
    Would I need to power down my RFM95 radio like it is done with the NRF24?
    Don't want to loose my 9microAmp sleeping current 🙂

    Will get back with results tomorrow,

    Joost


  • Mod

    @Joost yes you would need to power down the rfm95 to get low sleeping current. I think the radio will need to be reinitialized when it is powered on again but I have no experience working on this low level.



  • A good while ago I have experimented with a multi (touch) button node which used both external and pin change interrupts and did not need to use a custom sleep function. Here is the relevant excerpt of the latest sketch which I used. As far as I remember, it was working fine.

    Note that I was using a NRF24 radio. I'm not familiar with the RFM95, but I don't think that should be a problem. (Is the IRQ pin even needed for a regular sensor node?)

    #include <Arduino.h>
    #include <avr/interrupt.h>
    
    #define MY_RADIO_RF24
    [ other MySensors stuff ]
    #include <MySensors.h>
    
    void sense()
    {
        // Handle interrupt
    }
    
    ISR(PCINT2_vect)
    {
        // Handle interrupt
    }
    
    setup () 
    {
        pinMode(2, INPUT);
        pinMode(3, INPUT);
        pinMode(4, INPUT);
        cli();
        PCICR |= 0b00000100; // Port D
        PCMSK2 |= 0b00010000; // PCINT20 (D4)
        sei();
        attachInterrupt(0, sense, RISING); // (D2)
        attachInterrupt(1, sense, RISING); // (D3)
    }
    
    void loop()
    {
        // Do stuff, send messages
    	
        sleep(0);
    }
    


  • @mfalkvidd Will look into this tonight or tomorrow; just as a quick note for me and potentially others:
    Just found this thread with a very professional looking sketch by the author which seems a solid base to start upon:

    https://forum.mysensors.org/topic/5704/rfm95-sleep-mode/6

    Seemingly important parts from the sketch ( https://github.com/trlafleur/Soil_Moisture_Sensor_MS_R1.1-RFM95/blob/master/Soil_Moisture_Sensor_MS_R1.1-RFM95.ino ) :

    void systemSleep()
    {
        debug1(PSTR("\n*** Going to Sleep ***\n"));
        wait (100);
        // put led's, radio and flash to sleep
        // Turn off LED's
        pinMode (MY_DEFAULT_TX_LED_PIN, INPUT);
        pinMode (MY_DEFAULT_RX_LED_PIN, INPUT);
        pinMode (MY_DEFAULT_ERR_LED_PIN, INPUT);
        pinMode (OnBoardLed, INPUT); 
        
        // Put Flash to sleep
        
    
        // Put Radio and transport to Sleep
        transportPowerDown();               // Shut down radio and MySensor transport
        
        interrupts();                       // make sure interrupts are on...
        LowPower.standby();                 // SAMD sleep from LowPower systems
        
           //  .... we will wake up from sleeping here if triggered from an interrupt
        interrupts();                       // make sure interrupts are on...                                      
    }
    
    /* **************** System Wake-up from Sleep ******************* */
    void systemWakeUp() 
    {                                          
        
    //  re enable LED's if needed
    //    pinMode (MY_DEFAULT_TX_LED_PIN, OUTPUT);
    //    pinMode (MY_DEFAULT_RX_LED_PIN, OUTPUT);
    //    pinMode (MY_DEFAULT_ERR_LED_PIN, OUTPUT);
    //    pinMode (OnBoardLed, OUTPUT);  
    
        // wake up Flash if needed
    
        // wake up MySensor transport and Radio from Sleep
        //transportInit();
        hwSleep(1);                         // as MySensor had NO sleep or Watch Dog for SAMD, this will
                                            // wake us up so that we can send and receive messages
        while (!isTransportReady()) {       // Make sure transport is ready
        _process(); }
    
        interrupts();                       // make sure interrupts are on...
    }
    


  • @BearWithBeard Thanks; will look into this as well.
    Seems to me that the main difference is your sleep(0) vs. my sleep(16000), but who knows, perhaps that makes a difference. Btw, I believe Pin2 with the attached IRQ is obligatory for RFM95 radios (at least it's the default in MySensors, and I designed my PCB according to this).



  • Well, seems MySensors and the Low-Power lib in its latest revisions don't play nice together, bummer...

    Getting

    Compiling .pio/build/pro8MHzatmega328/src/main.cpp.o
    Linking .pio/build/pro8MHzatmega328/firmware.elf
    LowPower.cpp.o (symbol from plugin): In function `LowPowerClass::idle(period_t, adc_t, timer2_t, timer1_t, timer0_t, spi_t, usart0_t, twi_t)':
    (.text+0x0): multiple definition of `__vector_6'
    .pio/build/pro8MHzatmega328/src/main.cpp.o (symbol from plugin):(.text+0x0): first defined here
    collect2: error: ld returned 1 exit status
    *** [.pio/build/pro8MHzatmega328/firmware.elf] Error 1
    

    and it looks like I'm not the only one: 😕
    Github issue



  • @Joost I've used mysensors V2 I believe...



  • *** Edit: sorry, all below seems to be wrong / misuse of sleep(); see end of linked thread from 2017

    Some news: I found this comment https://forum.mysensors.org/post/56372 by @DavidZH who possibly described what I seem to be seeing as well (no wakeups via PinChangeInterrupt when using MySensors sleep() function as posted above) and who also posted a workaround (thanks David for posting this in 2017!!):

    sleep(0xff,0x00, 0xff, 0x00, 0); 
    

    Quote: "...As soon as I change any of the parameters, the node will not wake up anymore...."

    Now indeed my node can be woken via PinChangeInterrupts on Pin A1 and A2 and is down to some unbelievable 1microAmp in between (by means of a cheap Multimeter) with no radio/transport initialization so far.
    So, with just preliminary testing so far this might be the solution (did not check radio transmission after interrupts for now).
    Could someone shed some light on what these parameters do to the sleep function? Looked here of course https://www.mysensors.org/download/sensor_api_20#sleeping but couldn't make sense out of 0xFF, 0x00 .
    Thanks everyone,

    Joost

    ********************** End of edit



  • PS: one downside will probably be not being able to wake up programmatically and double the node as a e.g. temperature / climate sensor, as I had in mind.

    Sorry for the confusion above, too little sleep in the last days (at least I hope that explains it 🙂 )

    Perhaps @Yveaux can help here on how to combine pin change interrupts and timer wake into a successful sleep() command? So far it looks like that would be possible with Low-Power lib, but this is not compiling in conjunction with MySensors 2.3.2.


Log in to reply
 

Suggested Topics

  • 996
  • 15
  • 1
  • 6
  • 886
  • 3
  • 3
  • 2

220
Online

9.6k
Users

10.2k
Topics

106.2k
Posts