Adafruit Feather M0 RFM69HCW with MySensors?



  • Hi,

    I am fairly new to all that stuff and hope that you might help me out a bit.
    I have seen the Feather getting mentioned a couple of times but so far only lafleur's post about 8 or 32bit MCUs suggested that he successfully use one of these. (https://forum.mysensors.org/topic/6718/8bit-or-32bit-processors)

    I am using the Feather M0 @433MHz RFM69 (https://www.adafruit.com/product/3177)
    Arduino IDE 1.8.2 (portable)
    MySensors 2.1.1
    DallasTemperature 3.7.7
    OneWire 2.3.3

    I want to build a sensor-node with one wire sensors, which sends back temperature and battery level to a RaspberryPi.

    As far as I can tell the Feather is not explicitly supported by the MySensors-library. When I try to compile it returns:

    In file included from C:\Users\LaborK06\Documents\Arduino\libraries\MySensors/core/MyHwSAMD.cpp:20:0,
    
                     from C:\Users\LaborK06\Documents\Arduino\libraries\MySensors/MySensors.h:67,
    
                     from F:\arduino-1.8.2-windows\Sketches\M0_Adafruit_RFM69_v01\M0_Adafruit_RFM69_v01.ino:37:
    
    C:\Users\LaborK06\Documents\Arduino\libraries\MySensors/core/MyHwSAMD.cpp: In function 'void hwInit()':
    
    C:\Users\LaborK06\Documents\Arduino\libraries\MySensors/core/MyHwSAMD.h:55:25: error: 'SerialUSB' was not declared in this scope
    
     #define MY_SERIALDEVICE SerialUSB
    
                             ^
    
    C:\Users\LaborK06\Documents\Arduino\libraries\MySensors/core/MyHwSAMD.cpp:104:2: note: in expansion of macro 'MY_SERIALDEVICE'
    
      MY_SERIALDEVICE.begin(MY_BAUD_RATE);
    
      ^
    
    exit status 1
    Fehler beim Kompilieren für das Board Adafruit Feather M0.
    

    I saw that lafleur already contributed to the MyHwSAMD.h but even though I do have these changes in my file it does not work.

    With the Sensebender board selected it compiles (without the battery measurement) and I can even upload it, but I'd like to use the battery reading from A7, which does not work with Sensebender ("is not defined in this scope" error), I think because of the fact that sensebender only has two analog pins.

    Surely I am missing something fundamental. I hope you guys can help me.

    This is the code I am working with. Essentially the example for dallas temperature sensors with minor additions.

    /**
     * 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.
     *
     *******************************
     *
     * DESCRIPTION
     *
     * Example sketch showing how to send in DS1820B OneWire temperature readings back to the controller
     * http://www.mysensors.org/build/temp
     */
    
    
    // Enable debug prints to serial monitor
    //#define MY_DEBUG 
    
    // Enable and select radio type attached
    //#define MY_RADIO_NRF24
    #define MY_RADIO_RFM69
    
    #include <SPI.h>
    #include <MySensors.h>  
    #include <DallasTemperature.h>
    #include <OneWire.h>
    
    #define COMPARE_TEMP 0 // Send temperature only if changed? 1 = Yes 0 = No
    
    #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected 
    #define MAX_ATTACHED_DS18B20 16
    
    
    
    
    #define MY_RF69_SPI_CS 8
    #define MY_RF69_IRQ_PIN 7
    #define MY_RF69_IRQ_NUM 4
    #define VBATPIN A7  // select the input pin for the battery sense point
    int oldBatteryPcnt = 0;
    int batteryPcnt;
    
    unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. 
    float lastTemperature[MAX_ATTACHED_DS18B20];
    int numSensors=0;
    bool receivedConfig = false;
    bool metric = true;
    // Initialize temperature message
    MyMessage msg(0,V_TEMP);
    
    void before()
    {
      // Startup up the OneWire library
      sensors.begin();
    }
    
    void setup()  
    { 
      // requestTemperatures() will not block current thread
      sensors.setWaitForConversion(false);
    
       // use the 1.1 V internal reference
      #if defined(__AVR_ATmega2560__)
      analogReference(INTERNAL1V1);
      #else
      //analogReference(INTERNAL);
      #endif
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Temperature Sensor", "1.1");
    
      // Fetch the number of attached temperature sensors  
      numSensors = sensors.getDeviceCount();
    
      // Present all sensors to controller
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
         present(i, S_TEMP);
      }
      //sendSketchInfo("Battery Meter", "1.0");
    }
    
    void loop()     
    { 
        
      // get the battery Voltage
      // To make this easy we stuck a double-100K resistor divider on theBAT pin, and connected it to D9 (a.k.a analog #7 A7). You can read this pin's voltage, then double it, to get the battery voltage.
      float sensorValue = analogRead(VBATPIN);
      #ifdef MY_DEBUG
      Serial.println(sensorValue);
      #endif
      sensorValue *= 2; // we divided by 2, so multiply back
      sensorValue *= 3.3; // Multiply by 3.3V, our reference voltage
      sensorValue /= 1024; // convert to voltage
    
      #ifdef MY_DEBUG
    
      float batteryV  = sensorValue;
    
      int batteryPcnt = ((batteryV-2.7)/3.3)*100;
    
      Serial.print("Battery Voltage: ");
      Serial.print(batteryV);
      Serial.println(" V");
    
      Serial.print("Battery percent: ");
      Serial.print(batteryPcnt);
      Serial.println(" %");
      #endif
    
      if (oldBatteryPcnt != batteryPcnt) {
        // Power up radio after sleep
        sendBatteryLevel(batteryPcnt);
        oldBatteryPcnt = batteryPcnt;
        }
      sleep(SLEEP_TIME);
    
      // Fetch temperatures from Dallas sensors
      sensors.requestTemperatures();
    
      // query conversion time and sleep until conversion completed
      // auskommentiert, da private! Stattdessen sleep(750ms)
      //int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution());
      // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
      //sleep(conversionTime);
      sleep(750);
    
      // Read temperatures and send them to controller 
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
    
        // Fetch and round temperature to one decimal
        float temperature = static_cast<float>(static_cast<int>((getControllerConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
    
        // Only send data if temperature has changed and no error
        #if COMPARE_TEMP == 1
        if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
        #else
        if (temperature != -127.00 && temperature != 85.00) {
        #endif
    
          // Send in the new temperature
          send(msg.setSensor(i).set(temperature,1));
          // Save new temperatures for next compare
          lastTemperature[i]=temperature;
        }
      }
      sleep(SLEEP_TIME);
    }
    

  • Admin

    @Sweeman

    You probably need to tweak the hardware definition files for the feather, in order to match the configuration that is expected by the mysensors core.

    (Or patch the core so it matches the other way around..) pin definitions on the sensebender GW is modified heavily, and does not match any of the other boards. As an example, we use 3 distinct SPI ports. One for the rfm69 / nrf24, one for w5100, and one for the MysX connector.

    I did not look that much towards the arduino zero board, for pin assignments, when I did the board layout. As I moved things around to make routing the pcba as painless as possible. That means that in some cases I am using a secondary or tertiary function of a pin, in order to get the desired hardware routed.

    Cortex M0 processors are very flexible, and the sercom units (which can be configured for SPI/I2C/Serial) can be routed to a variety of different pins, so for example MOSI on sercom0, can be on 3-4 different pins, depending on how you configure it.



  • Thank you for the advice!

    To begin with I followed lafleurs advice from this thread: https://forum.mysensors.org/topic/6718/8bit-or-32bit-processors/4

    Unfortunately I wasn't able to establish communication by using the Zero-Board-definitions. I didn't really figure out what screwed up, since I was able to compile but it never really worked and I had no Serial-Monitor available.

    Even tweaking the hardware definiton files didn't really work out. So I had a look into the initial error again to make it work with original Adafruit-FeatherM0-definitions. And I don't know why I didn't see that earlier:

    Since SerialUSB wasn't declared I did a quick search for that error and I found this: https://forums.adafruit.com/viewtopic.php?f=22&t=88793

    Apparently they changed "SerialUSB" to only "Serial".
    I edited that in MyHwSAMD.h from

    #ifndef MY_SERIALDEVICE
    #define MY_SERIALDEVICE SerialUSB
    #endif
    

    to

    #ifndef MY_SERIALDEVICE
    #define MY_SERIALDEVICE Serial
    #endif
    

    and it seems to work now.
    I will have to check with a gateway tomorrow. I hope this helps anyone in the future.

    And btw. for the M0-Feather the PINs changed (I found that for the 32u4 and didn't notice the difference immediately).
    You now need to define this before including the MySensors.h

        #define MY_RF69_SPI_CS 8
        #define MY_RF69_IRQ_PIN 3
        #define MY_RF69_IRQ_NUM 3
    

    Thanks for the help and setting me on the right track! I will post if it works tomorrow.



  • It works.
    They communicate and I am able to send data from a onewire.
    The only thing which doesn't work right now is sleep. Even though I am using MySensors 2.1.0 (lafleur mentioned that sleep does not work for M0 in 2.1.1).
    Any thoughts how to fix this? It would be annoying to change batteries all the time :)


  • Admin

    If I remember right, then sleep is still on the todo list for m0.. The first m0 board (Sensebender Gateway), is meant to be a gateway, and as such, does not need sleep functionality.



  • Hi guys,
    I do have a working node now. And I think sleep is working as well. I am using Adafruit_SleepyDog for now.
    Powerconsumption has to be tested yet. To see if the node is still active I made it flash the LED everytime it wakes up for sending data. If you leave out that part it will behave a little odd, because the LED will light up for a whole cycle and go down in the next one. But I guess that's just cosmetics.

    So far it sends battery level and the temperature from one wire sensors.

    For anybody interested I will post the code. I hope it helps someone.

    
     /**
         * 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.
         *
         *******************************
         *
         * DESCRIPTION
         *
         * Example sketch showing how to send in DS1820B OneWire temperature readings back to the controller
         * http://www.mysensors.org/build/temp
         */
    
        #define MY_DEBUG                                  // used by MySensor (Print debug messages via serial)
        #define MY_RADIO_RFM69                            // Select Radio-Module RFM69
        #define MY_RFM69_FREQUENCY RF69_433MHZ            // Define our Frequency of 433 MHz
        #define MY_IS_RFM69HW                             // Module is high power (HW/HCW)
        //#define MY_RFM69_NETWORKID 100                  // leave out for gateway selection
        #define MY_RF69_SPI_CS 8                          // SPI CS PIN
        #define MY_RF69_IRQ_PIN 3                         // IRQ PIN
        #define MY_RF69_IRQ_NUM 3                         // IRQ PIN NUM (for M0 it is the same as IRQ PIN. Will be obsolete in upcoming MySensors.h) 
        #define MY_NODE_ID 162                            // Node ID
        #define MY_DEFAULT_TX_LED_PIN 13                  // LED Pin for "Blink while sending"
        
        #define CHILD_ID_BATTERY 1                        // Battery ID (standard 1) 
        
        #include <SPI.h>                                  // include SPI for communication with radio
        #include <MySensors.h>                            // include MySensors (it has to be done after the defines) 
        #include <DallasTemperature.h>                    // Lib for Dallas Temperature OneWires
        #include <OneWire.h>                              // Lib for OneWires
        #include <Adafruit_SleepyDog.h>
        
        #define COMPARE_TEMP 0                            // Send temperature only if changed? 1 = Yes 0 = No
        #define ONE_WIRE_BUS 12                           // Pin where dallase sensor is connected 
        #define MAX_ATTACHED_DS18B20 16                   // maximum number of sensors
    
        int VBATPIN = A7;                                 // select the input pin for the battery sense point
        int batteryPcnt;                                  // battery value in percent
        int SleepCycles = 1;                              // Number of sleep cycles (each 17 seconds)
        int n = 0;                                        // Sleepcounter
        
        OneWire oneWire(ONE_WIRE_BUS);                    // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
        DallasTemperature sensors(&oneWire);              // Pass the oneWire reference to Dallas Temperature. 
        float lastTemperature[MAX_ATTACHED_DS18B20];      // lastTemp variabels for every possible Sensor (0 - MAX_ATTACHED_DS18B20)
        int numSensors=0;                                 // Number of Sensors (automatically defined later)
        bool receivedConfig = false;                      
        bool metric = true;
       
        MyMessage msg(0,V_TEMP);                          // initialize temperature message
        MyMessage msgBatt(CHILD_ID_BATTERY,V_VOLTAGE);    // initialize battery reading
    
        
        
    /* ********************* Before *********************** */
        void before()
        {
          sensors.begin();                                // Startup up the OneWire library
        }
        
    
    /* ******************** Setup ************************ */
        void setup()  
        { 
          sensors.setWaitForConversion(false);            // requestTemperatures() will not block current thread
          pinMode(LED_BUILTIN, OUTPUT);
        }
    
    
    /* ********************** Presentation ********************** */
        void presentation() {
          sendSketchInfo("Temperature Sensor", "1.1");                    // Send the sketch version information to the gateway and Controller
          numSensors = sensors.getDeviceCount();                          // Fetch the number of attached temperature sensors
          for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
              present(i, S_TEMP);                                         // Present all sensors to controller
          }
          present(CHILD_ID_BATTERY, S_MULTIMETER);                        // Present battery to controller
        }
    
     
    /* ********************** Loop ********************** */    
        void loop()     
    { 
        n = 0;                                                            // reset sleep count
        if (n == 0)                                                       // Only send Data when sleep cycles completed
        {
         
          /* ***************** Get the battery Voltage ***************** */
          
          // To make this easy we stuck a double-100K resistor divider on the BAT pin, and connected it to D9 (a.k.a analog #7 A7). You can read this pin's voltage, then double it, to get the battery voltage.
          float sensorValue = analogRead(VBATPIN);
          #ifdef MY_DEBUG
          Serial.println(sensorValue);                                  // Debug msg
          #endif
          sensorValue *= 2;                                             // we divided by 2, so multiply back (because of double-100K resistor)
          sensorValue *= 3.3;                                           // Multiply by 3.3V, our reference voltage
          sensorValue /= 1024;                                          // convert to voltage
          float batteryV  = sensorValue;
          int batteryPcnt = ((batteryV-2.7)/3.3)*100;                   // for 6V batterypack (don't use 6V directly. It will fry your radio. 3.3 -5 V is OK) 
        
          #ifdef MY_DEBUG                                               // Battery Debug
          Serial.print("Battery Voltage: ");
          Serial.print(batteryV);
          Serial.println(" V");
    
          Serial.print("Battery percent: ");
          Serial.print(batteryPcnt);
          Serial.println(" %");
          #endif
    
          sendBatteryLevel(batteryPcnt);
          send(msgBatt.set(batteryV,2));
          
          /* ***************** Send Sensor Data ***************** */
    
          sensors.requestTemperatures();                                                                                                                                      // Fetch temperatures from Dallas sensors
          for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {                                                                                                        // Read temperatures and send them to controller 
            float temperature = static_cast<float>(static_cast<int>((getControllerConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;     //Fetch and round temperature to one decimal (v2.1.1 "getControllerConfig" instead of "getConfig")
            #if COMPARE_TEMP == 1                                                                                                                                             // Only send data if temperature has changed and no error
              if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
            #else
              if (temperature != -127.00 && temperature != 85.00) {                          // Only send Data if not -127 or 85 °C (indicates reading-error)
            #endif
                 send(msg.setSensor(i).set(temperature,1));                                  // Send the new temperature
            
                 lastTemperature[i]=temperature;                                             // Save new temperatures for next compare
              }
          }
         digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on to indicate transmission
         delay(500);                        // wait for a 500 ms
         digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
        }                                                                                    // end of "only send data if sleep cycles completed"-if 
     
      /* ***************** Sleep ***************** */
      
      while (n <= SleepCycles)
        {
        Watchdog.sleep(17000);              // Deepsleep with Watchdog interrupt !!Watchdog can't handle long sleep times, hence the cycles!! (n=1 -> 17 sec * 2 = 34 sec sleep)
        n++;
        }
    
    } // end of loop
    
    


  • @Sweeman Thank you for posting this. I will be attempting to put a mo into practice soon.


  • Hero Member

    @Sweeman
    I'm very interested to hear your power consumption measurements. I only just recently acquired an Adafruit Feather M0 RFM69HCW, and it's probably my #1 question, because if it's not good, then I'm going to shelve it until it is good. Ultra low current consumption is simpy a MUST.



  • I think that I will have some data on that by next tuesday, since that is also my #1 requirement. I will let you know!



  • My gear is a bit quick and dirty, because I am in a cheapo lab and would need to get a better suited resistor for my measurement to be absolutely certain. But what I get is aprox. 150mA while sending and 2mA during sleep (with 10 Ohms as measurement resistor).
    There is some room for improvement I guess. But it is already better than the old setup.
    I hope that helps a little and maybe you find a way to have even less power consumption.
    I will think a little about this and decide wheather I will get some better gear for that later. :)


  • Hero Member

    @Sweeman
    That sounds rather high. Was it the sketch above that you were running for the sleep cycle? I could try measuring with a uCurrent Gold. It's the sleep current that matters most. I'm around 1ua during sleep with an atmega328p and an RFM69.


  • Hardware Contributor

    from datasheet, atsamd is approx 2.8uA in deepest sleep mode without rtc, 4uA with rtc 1khz. wdt should consumes some uA too. it's not comparable with 328p, it's different, not same features, still low power vs features though.



  • @NeverDie
    Yes it was essentially the same sketch. I guess the 3.3 V regulator is consuming some power as well?
    I would love to see it consuming even less power. But as long as it holds for about 3 months on 4500 mAh it is kind of OK for my purposes.
    It would be great if you could measure it with your gear and maybe you have an idea how to get it even lower, since I also have to work on some peripheral stuff first. I am looking forward to hear from your tests.

    @scalz
    To be honest I am a little lost with all these abbreviations since I just started on working with MCUs, but I guess it is to make a point of "features need power"? But I will use these as hints as where to look for more saving potential. :)


  • Mod

    voltage regulators do consume power and are usually bad for sleeping nodes. ;)


  • Hero Member

    @Sweeman said in Adafruit Feather M0 RFM69HCW with MySensors?:

    I guess the 3.3 V regulator is consuming some power as well?

    It's a SPX3819 and the datasheet says "Low Quiescent Current: 90μA". Out of spec for any decent battery powered sensor IMHO :P


  • Hero Member

    @scalz said in Adafruit Feather M0 RFM69HCW with MySensors?:

    from datasheet, atsamd is approx 2.8uA in deepest sleep mode without rtc, 4uA with rtc 1khz.

    Thanks for posting this. I think that alone may kill it for me. For some reason I thought it was lower.



  • Hey guys aside from these power-consumption issues, I am now running the Feather as gateway and node.
    And I get a strange problem.
    The gateway is attached to a raspberry pi via usb (by-id), which runs fhem. And everything works great for about an hour to 1 1/2. Then somehow the gateway stops receiving/communicating. I already tried an active USB-Hub incase the power consumption was too high for too long. But that didn't help. I have to reset the gateway and node to make it work again.
    Did anybody else ever experience similar behaviour?



Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.