[SOLVED] A2 interrupt doesn't wake node from sleep



  • Hello first off here is my code (not all ofcourse):

    //**************//
    //* INTERRUPTS *//
    //**************//
    
    // Install Pin change interrupt for a pin, can be called multiple times
    void pciSetup(byte pin)
    {
      *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
      PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
      PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
    }
    
    // Use one Routine to handle each group
    ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
    {
      tripped = true;
      GetDigital();
    //  digitalWrite(13, digitalRead(8));
    }
    
    ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
    {
      //Only on fall interrupt of TSL2561
      if (!digitalRead(A2)) {
        lightInterrupt = true;
        Serial.println("falling trigger");
      }
    }
    
    ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
    {
      tripped = true;
      GetDigital();
     // digitalWrite(13, digitalRead(2) and digitalRead(3) and digitalRead(5) and digitalRead(6) and digitalRead(7));
    }
    
    void loop()
    {
    
      //*****************//
      //* BATTERY LEVEL *//
      //*****************//
    
      //processBattLevel();
    
      //********************//
      //* DHT: TEMPERATURE *//
      //********************//
    
       //processTemperature();
    
      //*****************//
      //* DHT: HUMIDITY *//
      //*****************//
    
      //processHumidity();
    
      //*******************//
      //* TSL: LIGHTLEVEL *//
      //*******************//
    
        //processLightLevel();
      if (lightInterrupt == true) {
        Serial.println("A2 low!!!!!!!!!!!!!!!!!");
        processLightLevel();
        light.clearInterrupt();
        lightInterrupt = false;
      }
    
      //*******************//
      //* DI: DOOR/WINDOW *//
      //*******************//
    
        //UpdateCurrentState();
    
    
      //*********//
      //* SLEEP *//
      //*********//
    
      // Sleep for a while to save energy
      sleep(PCINT1_vect, CHANGE, PCINT2_vect, CHANGE,  UPDATE_INTERVAL);
    }
    

    I have the problem that a change in PCINT1_vect doesn't wake up my node. The interrupt gets triggered but it doesn't seem to run all of the code in the ISR and doesn't exit the sleep. I get the following in the output:

    data0: 1343
     data1: 219
    TSL2561 interrupts thresholds set successfully
    lux: 34.25
    mlux: 36
    lastLux: 36
    gain: 1
    10764 TSF:MSG:SEND,59-59-0-0,s=3,c=1,t=0,pt=2,l=2,sg=0,ft=0,st=OK:34
    LightLevel: 34 lux
    10774 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=59,M2=1
    10780 MCO:SLP:TPD
    10782 MCO:SLP:WUP=-1
    10784 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=59,M2=1
    10790 MCO:SLP:TPD
    10792 MCO:SLP:WUP=-1
    10795 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=59,M2=1
    10801 MCO:SLP:TPD
    10803 MCO:SLP:WUP=-1
    10805 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=59,M2=1
    10811 MCO:SLP:TPD
    faโธฎ
    

    Last line is supposed to be "falling triggr". This Serial.println is located in the ISR PCINT0_vect, but it seems it doesn't get fully executed. after the node wakes up (on timer), it seems like 'lightInterrupt' has been set in the ISR since the lightlevel is processed and updated.

    A2 low!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    data0: 1440
     data1: 245
    TSL2561 interrupts thresholds set successfully
    lux: 36.30
    mlux: 35
    lastLux: 35
    gain: 1
    8491 TSF:MSG:SEND,59-59-0-0,s=3,c=1,t=0,pt=2,l=2,sg=0,ft=0,st=OK:36
    LightLevel: 36 lux
    8503 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=210,M2=1
    8507 MCO:SLP:TPD
    8509 MCO:SLP:WUP=-1
    8511 MCO:SLP:MS=30000,SMS=0,I1=186,M1=1,I2=210,M2=1
    8517 MCO:SLP:TPD
    

    Stranger even still, PCINT2_vect does work as expected. In this case the node does wake up on interrupt on D2-D7 (if these DI's are enabled in the code). If anyone can help it would be much appreciated. I really don't see the reason PCINT1_vect doesn't wake up the node. If more code is needed tell me, I will happely post the entire code if you want.


  • Mod

    Using Serial from within an ISR is not recommended. See TL;DR at http://gammon.com.au/interrupts

    What does GetDigital() do? ISRs need to be executed quickly, and a lot of things must be avoided (see above link).

    10782 MCO:SLP:WUP=-1
    

    shows that the wake up reason is -1 which is MY_WAKE_UP_BY_TIMER so the wake up reason was timer, not interrupt.

    What is PCINT1_vect and PCINT2_vect ? (they are not defined in the code you've posted).
    Maybe these variables are not what the MySensors sleep function expects? Documentation: https://www.mysensors.org/download/sensor_api_20#sleeping



  • @mfalkvidd Hi, first off thanks for taking a look at my problem.

    I know I'm not supposed to use Serial.print inside an ISR, this was just for debugging purposses to see if this part of the code even was run. I tried without the Serial.print but same result.

    GetDigital looks wich interruptpin was triggered

    boolean GetDigital(void) {
      noInterrupts();
    
      if (tripped) {
        for (char i = 0; i < NR_OF_SWITCH; i++) {
          currState[i] = digitalRead(intPin[i]);
          if (lastState[i] != currState[i]) {
            lastState[i] = currState[i];
            Serial.print("Pin "); Serial.print(intPin[i]); Serial.print(" triggered: "); Serial.println(currState[i]);
            switch (i) {
              case 0:
                send(msgSwitch1.set(currState[i]));
                break;
              case 1:
                send(msgSwitch2.set(currState[i]));
                break;
              case 2:
                send(msgSwitch3.set(currState[i]));
                break;
              case 3:
                send(msgSwitch4.set(currState[i]));
                break;
              case 4:
                send(msgSwitch5.set(currState[i]));
                break;
              case 5:
                send(msgSwitch6.set(currState[i]));
                break;
              default:
                Serial.println("Not an interrupt pin");
            }
          }
        }
        tripped = false; //Clear processed triggers
        interrupts();
        return true;
      }
      interrupts();
      return false;
    }
    

    Again Serial.print for debugging (but seems to run fine even with Serial.print, granted it takes the ISR alot longer)

    I know the node woke up because the timer expired, this is kind of the problem ๐Ÿ˜‰

    PCINT0_vect, PCINT1_vect and PCINT2_vect are interruptvectors used in pinchange interrupt on all pins (D8-D13, A1-A5 & D0-D7) see this link: https://playground.arduino.cc/Main/PinChangeInterrupt.

    These variables are probably not what the MySensors Sleep function expects, but it seems to work fine for PCINT0_vect and PCINT2_vect, where the digital pins are connected to. When any of the digital pins change the node wakes up immediatly and sends an update about the pin that changed. Should work the same for the interrupt on the analog pin, but something goes wrong ๐Ÿ˜ž

    I even tried using absolute pinnumbers for analog pins (A0=14,A1=15,A2=16,...) but still same result. see:
    http://forum.arduino.cc/index.php?topic=41238.0

    I will include the entire sketch in next post, so you can follow all of the code if needed. Its devided into several files and i cant upload a zip appearently so get ready for some serious code blocks ๐Ÿ˜

    I have these nodes on every door & window in my house for about a year now and they work great. Just wanted to add interrupt functionality to my light measurement now.



  • @jimmy-loyens

    This is the entire code:

    Setup & loop (.ino)

    /**
       The MySensors Arduino library handles the wireless radio link and protocol
       between your home built sensors/actuators and HA controller of choice.
       The sensors forms a self healing radio network with optional repeaters. Each
       repeater and gateway builds a routing tables in EEPROM which keeps track of the
       network topology allowing messages to be routed to nodes.
    
       Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       Copyright (C) 2013-2015 Sensnology AB
       Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    
       Documentation: http://www.mysensors.org
       Support Forum: http://forum.mysensors.org
    
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License
       version 2 as published by the Free Software Foundation.
    
     *******************************
    
       REVISION HISTORY
       Version 1.0: Henrik EKblad
       Version 1.1 - 2016-07-20: Converted to MySensors v2.0 and added various improvements - Torben Woltjen (mozzbozz)
    
       DESCRIPTION
       Mysensors battery node. With temperature, relative humidity, lightintensity and battery level measurements
    
       For more information, please visit:
       http://www.mysensors.org/build/
    
    */
    
    //** Includes
    #include "Defines.h"
    #include "Globals.h"
    #include <SPI.h>
    #include <Wire.h>
    
    //**************//
    //* INTERRUPTS *//
    //**************//
    
    // Install Pin change interrupt for a pin, can be called multiple times
    void pciSetup(byte pin)
    {
      *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
      PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
      PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
    }
    
    // Use one Routine to handle each group
    ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
    {
      tripped = true;
      GetDigital();
    }
    
    ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
    {
      //Only on fall interrupt of TSL2561
      if (!digitalRead(16)) {
        lightInterrupt = true;
        Serial.println("falling trigger");
      }
    }
    
    ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
    {
      tripped = true;
      GetDigital();
    }
    
    
    
    void setup()
    {
      Serial.begin(115200);
      //***********************//
      //* SETUP BATTERY LEVEL *//
      //***********************//
    
      setupBattery();
    
      //*************//
      //* SETUP DHT *//
      //*************//
    
      setupDHT();
    
      //*****************//
      //* SETUP TSL2561 *//
      //*****************//
    
      setupTSL();
    
      //**************//
      //* SETUP DI's *//
      //**************//
    
      setupDI();
    
    }
    
    void loop()
    {
    
      //*****************//
      //* BATTERY LEVEL *//
      //*****************//
    
      processBattLevel();
    
      //********************//
      //* DHT: TEMPERATURE *//
      //********************//
    
       processTemperature();
    
      //*****************//
      //* DHT: HUMIDITY *//
      //*****************//
    
      processHumidity();
    
      //*******************//
      //* TSL: LIGHTLEVEL *//
      //*******************//
    
      //  processLightLevel();
      if (lightInterrupt == true) {
        Serial.println("A2 low!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        processLightLevel();
        light.clearInterrupt();
        lightInterrupt = false;
      }
      //*******************//
      //* DI: DOOR/WINDOW *//
      //*******************//
    
    
        UpdateCurrentState();
    
    
      //*********//
      //* SLEEP *//
      //*********//
    
      // Sleep for a while to save energy
      sleep(PCINT1_vect, CHANGE, PCINT2_vect, CHANGE,  UPDATE_INTERVAL);
    }
    

    Battery (.ino)

    void setupBattery(void) {
      // Define internal reference for battry level measurement
    #if defined(__AVR_ATmega2560__)
      analogReference(INTERNAL1V1);
    #else
      analogReference(INTERNAL);
    #endif
    }
    
    void processBattLevel(void) {
      noInterrupts();
      int sensorValue = analogRead(batterySensePin);
      interrupts();
    #ifdef MY_DEBUG
      Serial.print("Battery sensorValue : ");Serial.println(sensorValue);
    #endif
    
      //1M, 470K divider across battery and using ADC ref of 1.1V
      //Sense point is bypassed with 0.1ยตF cap to reduce noise at that point
      //((1e6+470e3) / 470e3) * 1.1 = Vmax = 3.44V
      //3.44 / 1023 = Volt per bit = 0.003363075
      int batteryPcnt = sensorValue / 10;
    
    #ifdef MY_DEBUG
      float batteryV = sensorValue * 0.003363075;
      Serial.print("Battery Voltage: ");
      Serial.print(batteryV);
      Serial.println(" V");
    
      Serial.print("Battery Percent: ");
      Serial.print(batteryPcnt);
      Serial.println(" %");
    #endif
    
      if (oldBatteryPcnt != batteryPcnt || nNoUpdatesBatt == FORCE_UPDATE_N_READS_B) {  // Only send battery message when value has changed
        //Power up radio after sleep
        send(msgBatt.set(batteryPcnt));
        //sendBatteryLevel(batteryPcnt);
        oldBatteryPcnt = batteryPcnt;
        nNoUpdatesBatt = 0;
      }
      else {
        // Increase no update counter if the battery level stayed the same
        nNoUpdatesBatt++;
      }
    }
    

    DHT (.ino)

    void setupDHT(void){
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
    }
    
    void processTemperature(void){
      noInterrupts();
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
    
      // Get temperature from DHT library
      float temperature = dht.getTemperature();
      interrupts();
      Serial.print("temperature (float): ");Serial.println(temperature);
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT!");
      }
      else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS_T) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        temperature += SENSOR_TEMP_OFFSET;
        send(msgTemp.set(temperature, 1));
    
    #ifdef MY_DEBUG
        Serial.print("Temperature: ");
        Serial.print(temperature);
        Serial.println(" ยฐC");
    #endif
      }
      else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
    }
    
    void processHumidity(void){
      noInterrupts();
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      interrupts();
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      }
      else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS_H) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
    
    #ifdef MY_DEBUG
        Serial.print("Humidity: ");
        Serial.print(humidity);
        Serial.println(" %");
    #endif
      }
      else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    }
    

    Digital (.ino)

    void setupDI(void) {
    #ifdef PULL_UP_EN
      // set pullups, if necessary
      for (int i = 2; i <= 8; i++) {
        digitalWrite(i, HIGH);
      }
      Serial.println("pullup");
    #endif
    
      // enable interrupt for pin...
      for (int i = 0; i < NR_OF_SWITCH; i++) {
        pciSetup(intPin[i]);
    #ifdef MY_DEBUG
        Serial.print("Int pin ");
        Serial.print(i);
        Serial.print(": ");
        Serial.println(intPin[i]);
    #endif
      }
    }
    
    void UpdateCurrentState(void) {
      noInterrupts();
    
      for (char i = 0; i < NR_OF_SWITCH; i++) {
        currState[i] = digitalRead(intPin[i]);
    
        Serial.print("Pin "); Serial.print(intPin[i]); Serial.println(" updated: "); Serial.println(currState[i]);
        switch (i) {
          case 0:
            send(msgSwitch1.set(currState[i]));
            break;
          case 1:
            send(msgSwitch2.set(currState[i]));
            break;
          case 2:
            send(msgSwitch3.set(currState[i]));
            break;
          case 3:
            send(msgSwitch4.set(currState[i]));
            break;
          case 4:
            send(msgSwitch5.set(currState[i]));
            break;
          case 5:
            send(msgSwitch6.set(currState[i]));
            break;
          default:
            Serial.println("Not an interrupt pin");
        }
      }
      interrupts();
    }
    boolean GetDigital(void) {
      noInterrupts();
    
      if (tripped) {
        for (char i = 0; i < NR_OF_SWITCH; i++) {
          currState[i] = digitalRead(intPin[i]);
          if (lastState[i] != currState[i]) {
            lastState[i] = currState[i];
            Serial.print("Pin "); Serial.print(intPin[i]); Serial.print(" triggered: "); Serial.println(currState[i]);
            switch (i) {
              case 0:
                send(msgSwitch1.set(currState[i]));
                break;
              case 1:
                send(msgSwitch2.set(currState[i]));
                break;
              case 2:
                send(msgSwitch3.set(currState[i]));
                break;
              case 3:
                send(msgSwitch4.set(currState[i]));
                break;
              case 4:
                send(msgSwitch5.set(currState[i]));
                break;
              case 5:
                send(msgSwitch6.set(currState[i]));
                break;
              default:
                Serial.println("Not an interrupt pin");
            }
          }
        }
        tripped = false; //Clear processed triggers
        interrupts();
        return true;
      }
      interrupts();
      return false;
    }
    

    Presentation (.ino)

    void presentation()
    {
      noInterrupts();
      // Send the sketch version information to the gateway
      sendSketchInfo(SKETCH_NAME, Sketch_VERSION);
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_BATT, I_BATTERY_LEVEL);
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
      present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
      if (NR_OF_SWITCH >= 1) {
        present(CHILD_ID_SWITCH1, S_DOOR);
        if (NR_OF_SWITCH >= 2) {
          present(CHILD_ID_SWITCH2, S_DOOR);
          if (NR_OF_SWITCH >= 3) {
            present(CHILD_ID_SWITCH3, S_DOOR);
            if (NR_OF_SWITCH >= 4) {
              present(CHILD_ID_SWITCH4, S_DOOR);
              if (NR_OF_SWITCH >= 5) {
                present(CHILD_ID_SWITCH5, S_DOOR);
                if (NR_OF_SWITCH >= 6) {
                  present(CHILD_ID_SWITCH6, S_DOOR);
                }
              }
            }
          }
        }
      }
      metric = getControllerConfig().isMetric;
      interrupts();
    }
    

    TSL (.ino)

    void setupTSL(void) {
      
      pinMode(16,INPUT_PULLUP);//16 = A2
    
    pciSetup(16);
    
      // Initialize the SFE_TSL2561 library
    
      // You can pass nothing to light.begin() for the default I2C address (0x39),
      // or use one of the following presets if you have changed
      // the ADDR jumper on the board:
    
      // TSL2561_ADDR_0 address with '0' shorted on board (0x29)
      // TSL2561_ADDR   default address (0x39)
      // TSL2561_ADDR_1 address with '1' shorted on board (0x49)
    
      // For more information see the hookup guide at: https://learn.sparkfun.com/tutorials/getting-started-with-the-tsl2561-luminosity-sensor
    
      light.begin();
    
      // The light sensor has a default integration time of 402ms,
      // and a default gain of low (1X).
    
      // If you would like to change either of these, you can
      // do so using the setTiming() command.
    
      // If gain = false (0), device is set to low gain (1X)
      // If gain = high (1), device is set to high gain (16X)
    
      gain = 1;
    
      // If time = 0, integration will be 13.7ms
      // If time = 1, integration will be 101ms
      // If time = 2, integration will be 402ms
      // If time = 3, use manual start / stop to perform your own integration
    
      time = 2;
      // setTiming() will set the third parameter (ms) to the
      // requested integration time in ms (this will be useful later):
    
      light.setTiming(gain, time, ms);
      if (light.setInterruptControl(1,2)) {
        Serial.println("TSL2561 interrupts set successfully");
      }
      if (light.setInterruptThreshold(500, 1800)) {
        Serial.println("TSL2561 interrupts thresholds set successfully");
      }
    
      // To start taking measurements, power up the sensor:
      light.setPowerUp();
    
      // The sensor will now gather light during the integration time.
      // After the specified time, you can retrieve the result from the sensor.
      // Once a measurement occurs, another integration period will start.
    }
    
    void processLightLevel(void) {
      // Wait between measurements before retrieving the result
      // (You can also configure the sensor to issue an interrupt
      // when measurements are complete)
    
      // This sketch uses the TSL2561's built-in integration timer.
      // You can also perform your own manual integration timing
      // by setting "time" to 3 (manual) in setTiming(),
      // then performing a manualStart() and a manualStop() as in the below
      // commented statements:
    
      // ms = 1000;
      // light.manualStart();
      //delay(ms);
      // light.manualStop();
    
      // Once integration is complete, we'll retrieve the data.
    
      // There are two light sensors on the device, one for visible light
      // and one for infrared. Both sensors are needed for lux calculations.
    
      // Retrieve the data from the device:
    
      unsigned int data0, data1;
    
      if (light.getData(data0, data1))
      {
        // getData() returned true, communication was successful
    
    #ifdef MY_DEBUGX
        Serial.print("data0: ");
        Serial.println(data0);
        Serial.print(" data1: ");
        Serial.println(data1);
    #endif
    
    
    if(data0>65000){
      gain=0;
      light.setTiming(gain, time, ms);
    }
    if(data0<500){
      gain=1;
      light.setTiming(gain, time, ms);
    }
    
    if (light.setInterruptThreshold(data0-(data0/100*10),data0+(data0/100*10))) {       //light.setInterruptThreshold(data0-50,data0+50)
        Serial.println("TSL2561 interrupts thresholds set successfully");
      }
    
    
      
        double lux;    // Resulting lux value
        boolean good;  // True if neither sensor is saturated
    
        // Perform lux calculation:
        good = light.getLux(gain, ms, data0, data1, lux);
        if (good) {
    #ifdef MY_DEBUGX
          Serial.print("lux: ");
          Serial.println(lux);
          Serial.print("mlux: ");
          Serial.println(mlux);
          Serial.print("lastLux: ");
          Serial.println(lastLux);
          Serial.print("gain: ");
          Serial.println(gain);
    #endif
          mlux = int(lux);  // Lux value to be transmitted as integer
          if (isnan(mlux)) {
            Serial.println("Failed reading lightintensity from TSL2561!");
          } else if (mlux != lastLux || nNoUpdatesTemp == FORCE_UPDATE_N_READS_L) {
            send(msgLight.set(mlux));
            lastLux = mlux;
    #ifdef MY_DEBUG
            Serial.print("LightLevel: ");
            Serial.print(mlux);
            Serial.println(" lux");
    #endif
          }
          else {
            // Increase no update counter if the humidity stayed the same
            nNoUpdatesLight++;
          }
        }
      }
    }
    

    Defines (.h)

    //** Define scetch name and version
    #define SKETCH_NAME "ID59_Kitchen_1(2*window)"
    #define Sketch_VERSION "V1.1"
    
    //** Enable debug prints
    #define MY_DEBUG
    #define MY_DEBUGX
    //** Define node ID
    #define MY_NODE_ID 59
    
    //** Define child ID's
    #define CHILD_ID_BATT 0
    #define CHILD_ID_HUM 1
    #define CHILD_ID_TEMP 2
    #define CHILD_ID_LIGHT 3
    #define CHILD_ID_SWITCH1 4
    #define CHILD_ID_SWITCH2 5
    #define CHILD_ID_SWITCH3 6
    #define CHILD_ID_SWITCH4 7
    #define CHILD_ID_SWITCH5 8
    #define CHILD_ID_SWITCH6 9
    #define NR_OF_SWITCH 6  //Window_1+2
    
    //** Define interrupt pins (doors & windows)
    #define INT_PIN1  2
    #define INT_PIN2  3
    #define INT_PIN3  5
    #define INT_PIN4  6
    #define INT_PIN5  7
    #define INT_PIN6  8
    #define PULL_UP_EN true
    
    //** Enable and select radio type attached
    #define MY_RADIO_NRF24
    #define MY_RF24_CE_PIN  9
    #define MY_RF24_CS_PIN  10
    #define MY_RF24_PA_LEVEL RF24_PA_HIGH
    
    //** DHT defines
    // Set this to the pin you connected the DHT's data pin to
    #define DHT_DATA_PIN 4
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    

    Globals (.h)

    #include <DHT.h>
    #include <SparkFunTSL2561.h>
    #include <MySensors.h>
    
    enum {
      ON,
      OFF
    };
    
    //** Define sleep time
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 30000;
    
    //** Define force values
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS_T = 10; //Temperature force value
    static const uint8_t FORCE_UPDATE_N_READS_H = 10; //Humidity force value
    static const uint8_t FORCE_UPDATE_N_READS_L = 10; //LightLevel force value
    static const uint8_t FORCE_UPDATE_N_READS_B = 50; //Binairy force value
    
    // Vars for battery level measurement
    int batterySensePin = A0;
    int oldBatteryPcnt = 0;
    uint8_t nNoUpdatesBatt;
    
    // Vars for DHT sensor
    DHT dht;
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    //Vars for TSL2461
    SFE_TSL2561 light;
    int lastLux;
    double lux;    // Resulting lux value
    int mlux;
    boolean gain;     // Gain setting, 0 = X1, 1 = X16;
    unsigned char time;
    unsigned int ms;  // Integration ("shutter") time in milliseconds
    uint8_t nNoUpdatesLight;
    volatile boolean lightInterrupt=true;
    
    //Vars for DI's
    volatile byte tripped = 0;
    int intPin[] = {2, 3, 5, 6, 7, 8};
    boolean currState[] = {OFF, OFF, OFF, OFF, OFF, OFF};
    volatile boolean lastState[] = {OFF, OFF, OFF, OFF, OFF, OFF};
    
    // Prepare messages for gateway
    MyMessage msgBatt(CHILD_ID_BATT, I_BATTERY_LEVEL);  // Battery message
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);  // Humidity message
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); // Temperature message
    MyMessage msgLight(CHILD_ID_LIGHT, V_TEMP); // Lightlevel message
    MyMessage msgSwitch1(CHILD_ID_SWITCH1, V_TRIPPED);
    MyMessage msgSwitch2(CHILD_ID_SWITCH2, V_TRIPPED);
    MyMessage msgSwitch3(CHILD_ID_SWITCH3, V_TRIPPED);
    MyMessage msgSwitch4(CHILD_ID_SWITCH4, V_TRIPPED);
    MyMessage msgSwitch5(CHILD_ID_SWITCH5, V_TRIPPED);
    MyMessage msgSwitch6(CHILD_ID_SWITCH6, V_TRIPPED);
    

  • Mod

    @jimmy-loyens I haven't analyzed everyhing you posted, but calling send from within an ISR will not work. Send will need to communicate over SPI which will be problematic when clocks and interrupts are disabled.

    So you'll need to refactor the code. That doesn't explain why sleep isn't woken up by the interrupts though.



  • @jimmy-loyens Oh I see now, ....

    the node isn't waking up by any of my interrupt vectors. GetDigital does more then just getting the interrupt pin, it allso sends a message inside the ISR. Thats why status changes on digital pins are sent immediatly. the node never wakes up to send them its handeled by the interrupt!!!

    This is not possible for my lightsensor (evaluate & send mssg in ISR) because this uses functions (i think). Is the sleep function expecting interrupt pins on the 'interrupt1' & 'interrupt2' parameters? Does anyone have an idea for a workaround? I have about 50 of these pcb's so its a little late for a re-design ๐Ÿ˜ข ๐Ÿ˜ฉ



  • @mfalkvidd For the digital pins send seems to work just fine, as long as i don't use any functions inside the ISR



  • @jimmy-loyens

    These mssges where all sent from within ISR:

    Pin 2 triggered: 0
    8417 !TSF:MSG:SEND,59-59-0-0,s=4,c=1,t=16,pt=1,l=1,sg=0,ft=0,st=NACK:0
    Pin 2 triggered: 1
    8419 !TSF:MSG:SEND,59-59-0-0,s=4,c=1,t=16,pt=1,l=1,sg=0,ft=1,st=NACK:1
    Pin 3 triggered: 0
    8421 TSF:MSG:SEND,59-59-0-0,s=5,c=1,t=16,pt=1,l=1,sg=0,ft=2,st=OK:0
    Pin 3 triggered: 1
    8423 !TSF:MSG:SEND,59-59-0-0,s=5,c=1,t=16,pt=1,l=1,sg=0,ft=0,st=NACK:1
    8425 MCO:SLP:WUP=-1
    8427 MCO:SLP:MS=30000,SMS=0,I1=114,M1=2,I2=75,M2=1
    8433 MCO:SLP:TPD
    Pin 5 triggered: 0
    8435 !TSF:MSG:SEND,59-59-0-0,s=6,c=1,t=16,pt=1,l=1,sg=0,ft=1,st=NACK:0
    Pin 5 triggered: 1
    8437 !TSF:MSG:SEND,59-59-0-0,s=6,c=1,t=16,pt=1,l=1,sg=0,ft=2,st=NACK:1
    Pin 6 triggered: 0
    8439 !TSF:MSG:SEND,59-59-0-0,s=7,c=1,t=16,pt=1,l=1,sg=0,ft=3,st=NACK:0
    Pin 6 triggered: 1
    8441 !TSF:MSG:SEND,59-59-0-0,s=7,c=1,t=16,pt=1,l=1,sg=0,ft=4,st=NACK:1
    8443 MCO:SLP:WUP=-1
    8445 MCO:SLP:MS=30000,SMS=0,I1=114,M1=2,I2=75,M2=1
    8452 MCO:SLP:TPD
    Pin 7 triggered: 0
    8454 !TSF:MSG:SEND,59-59-0-0,s=8,c=1,t=16,pt=1,l=1,sg=0,ft=5,st=NACK:0
    Pin 7 triggered: 1
    8456 !TSF:MSG:SEND,59-59-0-0,s=8,c=1,t=16,pt=1,l=1,sg=0,ft=6,st=NACK:1
    8458 MCO:SLP:WUP=-1
    8460 !TSM:READY:UPL FAIL,SNP
    
    

    i think the NACK comes from triggering pins in fast tempo



  • The whole problem seems to originate from the node not waking up by the interruptvectors. If i can get the node to wake up by PCINT0_vect/PCINT1_vect/PCINT2_vect i can process data and send messages outside the ISR. I gues thats why i resorted to sending messages in ISR a year ago. Does anyone know how to wake the node by these interrupt vectors? maybe i can re-write the sleep function to do this?



  • I just found this post on the forum: https://forum.mysensors.org/topic/6352/pin-change-interrupt-on-any-pin/11

    It adds "_wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop" at the end of every ISR

    and

    "// Unset value from dirty hack to get out of sleep loop (set in interrupt)
    _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;" at the beginning of loop.

    I tried it, not knowing at all what i'm doing by adding these lines. But i do know it works!!! Even if it is a dirty hack, IT WORKS!!!! ๐Ÿ™Œ ๐Ÿ˜ ๐Ÿ‘ ๐Ÿ‘Œ ๐Ÿ‘

    Now i can rewrite my code to do the processing/messaging in loop outside of the ISR. If anyone can explane what these lines do exactly please let me know.

    It would be even nicer if somewhere in the future there could be a sleep function in the MySensors library that supports these pinchange interrupt vectors, but this hack makes it work for now.

    Thanks for all the help!


 

340
Online

8.2k
Users

9.0k
Topics

95.9k
Posts