Moteino keeps cycling through setup

Started by raenrfm, September 28, 2017, 11:10:24 PM

raenrfm

I have a moteino with flash chip and RFM69HCW transciever and an AM2315 humidity and temperature sensor and I'm also going to connect it to a rain bucket and wind vane and anemometer.  The AM2315 is I2C and the rain and anemometer are interrupt driven devices.  I have the rain bucket on pin 3 (int 1) and the anemometer on pin 4 with pinchangeint library running the show there.  What I have noticed is that my code keeps cycling through setup even though I have tried disabling all the sleep functions.   I've tried disabling the watchdog but I don't think it's working.  Can someone look at my code and tell me where I'm going wrong here?  I need to keep the moteino awake because wind and rain can happen at any time so I can't miss anything by waking it up on an interrupt only to miss the event.

#include <Adafruit_AM2315.h>
#include <SPIFlash.h>
#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
#include <RFM69_ATC.h>
#include <SPI.h>
#include <Arduino.h>            // assumes Arduino IDE v1.0 or greater
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <Wire.h>
#include <stdlib.h>
#include <PinChangeInt.h>

/* RFM69 library and code by Felix Rusu - [email protected]
// Get libraries at: https://github.com/LowPowerLab/
// Make sure you adjust the settings in the configuration section below !!!
// **********************************************************************************
// Copyright Felix Rusu, LowPowerLab.com
// Library and code by Felix Rusu - [email protected]
// **********************************************************************************
// License
// **********************************************************************************
// This program is free software; you can redistribute it 
// and/or modify it under the terms of the GNU General    
// Public License as published by the Free Software       
// Foundation; either version 3 of the License, or        
// (at your option) any later version.                    
*/

//watchdog interrupt

/*uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) \
  __attribute__((naked)) \
  __attribute__((section(".init3")));
void get_mcusr(void)
{
  mcusr_mirror = MCUSR;
  MCUSR = 0;
  wdt_disable();
}*/
ISR (WDT_vect) {
  wdt_disable();
}
//#include <LowPower.h> //get library from: https://github.com/lowpowerlab/lowpower
                      //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/

//*********************************************************************************************
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************
#define NETWORKID     100  // The same on all nodes that talk to each other
#define NODEID        2    // The unique identifier of this node
#define RECEIVER      1    // The recipient of packets

//Match frequency to the hardware version of the radio on your Feather
//#define FREQUENCY     RF69_433MHZ
//#define FREQUENCY     RF69_868MHZ
#define FREQUENCY     RF69_915MHZ
#define ENCRYPTKEY    "1ClouDRiveRfaRms" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HCW   true // set to 'true' if you are using an RFM69HCW module

//*********************************************************************************************
#define SERIAL_BAUD   115200

#define RFM69_CS      10
#define RFM69_IRQ     2
#define RFM69_IRQN    0  // Pin 2 is IRQ 0!
#define RFM69_RST     9
#define LED           13  // onboard blinky
#define now() millis()
#define RAIN_PIN      3
#define RAIN_IRQ      1
#define WSPEED_PIN    4
#define WDIR          A0

int16_t packetnum = 0;  // packet counter, we increment per xmission
char * outTemp = "";
char * outHumidity = "";
char * tempmqtt = "";
char * humidmqtt = "";
char * drainmqtt = "";
long lastSecond; //The millis counter to see when a second rolls by
byte seconds; //When it hits 60, increase the current minute
byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data
byte minutes; //Keeps track of where we are in various arrays of data
byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data
byte windspdavg[120]; //120 bytes to keep track of 2 minute average

long lastWindCheck = 0;
volatile long lastWindIRQ = 0;
volatile byte windClicks = 0;
volatile unsigned long raintime, rainlast, raininterval, rain;
volatile float dailyrainin = 0; // [rain inches so far today in local time]
volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain
float windSpeed, tempF, humidity, windgustmph, windspdmph_avg2m, windspeedmph;
int winddir, windgustdir;
int winddiravg[120]; //120 ints to keep track of 2 minute average
int winddir_avg2m; // [0-360 2 minute average wind direction]
float windgustmph_10m; // [mph past 10 minutes wind gust mph ]
int windgustdir_10m; // [0-360 past 10 minutes wind gust direction]
float windgust_10m[10]; //10 floats to keep track of 10 minute max
int windgustdirection_10m[10]; //10 ints to keep track of 10 minute max

void rainIRQ(void);

RFM69_ATC radio = RFM69_ATC(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN);
Adafruit_AM2315 am2315;

void setup() {
  wdt_disable();
  pinMode(RFM69_RST, INPUT);
  pinMode(RFM69_CS, OUTPUT);
  digitalWrite(RFM69_CS, LOW);
  pinMode(RAIN_PIN, INPUT_PULLUP);
  attachInterrupt(RAIN_IRQ, rainIRQ, FALLING);
  pinMode(WSPEED_PIN, INPUT_PULLUP);
  attachPinChangeInterrupt(WSPEED_PIN, wspeedIRQ, FALLING);
  

//  while (!Serial); // wait until serial console is open, remove if not tethered to computer
  Serial.begin(SERIAL_BAUD);
  //AM2315 Stuff
   
  // Give the user a bit of time to bring up the serial window.
  delay( 5000 );
     
  // Indicate whether the AM2315 sensor is present or not.
  if (! am2315.begin()) {
      Serial.println( "Sensor not found, check wiring & pullups!" );
      while (1);
  }
   
  Serial.println("Arduino RFM69 Transmitter");
  
  /*// Hard Reset the RFM module
  
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);
  */

  // Initialize radio
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  if (IS_RFM69HCW) {
    radio.setHighPower();    // Only for RFM69HCW & HW!
  }

    // https://lowpowerlab.com/forum/moteino/rfm69hw-bit-rate-settings/msg1979/#msg1979
  radio.writeReg(0x03,0x0D); //set bit rade to 9k6
  radio.writeReg(0x04,0x05);

  //radio.setPowerLevel(10); // power output ranges from 0 (5dBm) to 31 (20dBm)
  radio.enableAutoPower(-80);
  radio.encrypt(ENCRYPTKEY);

  //radio.sleep();


  pinMode(LED, OUTPUT);
  Serial.print("\nTransmitting at ");
  Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(" MHz");
  
  power_timer1_disable();
  power_timer2_disable();
  //power_twi_disable();

   // Indicate whether the AM2315 sensor is present or not.
  if (! am2315.begin()) {
      Serial.println( "Sensor not found, check wiring & pullups!" );
      while (1);
  }
  //Serial.print( "Exit Setup" );   
}

void loop() {
  //Serial.println("Start loop");
  //Serial.print("Hum: "); Serial.println(am2315.readHumidity());
  //Serial.print("Temp: "); Serial.println(am2315.readTemperature());
  delay(2000);  // Wait 1 second between transmits, could also 'sleep' here!
//---------------------------------------------------------
  // Get the sensor's humidity value.
  float humidity = am2315.readHumidity();
  
  // Get the sensor's temperature value in Celsius and Fahrenheit.
  float tempC = am2315.readTemperature();
  float tempF = ((tempC * 9)/5)+32;
  if(millis() - lastSecond >= 1000)
  {
    //getWeather();
    lastSecond += 1000;

    //Take a speed and direction reading every second for 2 minute average
    if(++seconds_2m > 119) seconds_2m = 0;

    //Calc the wind speed and direction every second for 120 second to get 2 minute average
    float currentSpeed = get_wind_speed();
    windspeedmph = currentSpeed;
    int currentDirection = get_wind_direction();
    windspdavg[seconds_2m] = (int)currentSpeed;
    winddiravg[seconds_2m] = currentDirection;

    //Check to see if this is a gust for the minute
    if(currentSpeed > windgust_10m[minutes_10m])
    {
      windgust_10m[minutes_10m] = currentSpeed;
      windgustdirection_10m[minutes_10m] = currentDirection;
    }

    //Check to see if this is a gust for the day
    if(currentSpeed > windgustmph)
    {
      windgustmph = currentSpeed;
      windgustdir = currentDirection;
    }

    if(++seconds > 59)
    {
      seconds = 0;

      if(++minutes > 59) minutes = 0;
      if(++minutes_10m > 9) minutes_10m = 0;

      rainHour[minutes] = 0; //Zero out this minute's rainfall amount
      windgust_10m[minutes_10m] = 0; //Zero out this minute's gust
    }
      
    //Get readings from all sensors
    getWeather();
    char tempmqtt[30] = "weather/outTemp:";
  char hummqtt[30] = ",outHumidity:";
  char drainmqtt[30] = ",rain:";
  char wspdmqtt[30] = ",windSpeed:";
  dtostrf(tempF, 5, 1, &tempmqtt[16]);
  dtostrf(humidity, 5, 1, &hummqtt[13]);
  dtostrf(dailyrainin, 5, 3, &drainmqtt[6]);
  dtostrf(windSpeed, 4, 1, &wspdmqtt[11]);
  Serial.println(windClicks);
  Serial.println(dailyrainin);
  Serial.println(drainmqtt);
  //Construct MQTT message
  Serial.println(tempmqtt);
  strcat(tempmqtt, hummqtt);
  Serial.println(tempmqtt);
  strcat(tempmqtt,drainmqtt);
  //strcat(tempmqtt,drainmqtt);
  Serial.println(tempmqtt);
  strcat(tempmqtt,wspdmqtt);
  Serial.println(tempmqtt);
  strcat(tempmqtt,"!");
  Serial.println(tempmqtt);
  Serial.print( "Transmit Level: " );
  Serial.println(radio._transmitLevel);
  //char radiopacket[50] = "weather/outTemp:56,outHumidity:56!";
  //radiopacket = tempmqtt;
  int radpk_len = strlen(tempmqtt) + 1;
  itoa(packetnum++, tempmqtt+radpk_len, 10);
  //Serial.print("Sending "); Serial.println(radiopacket);
  Serial.print("Sending "); Serial.println(tempmqtt);
  
  /*if (radio.sendWithRetry(RECEIVER, radiopacket, strlen(radiopacket))) { //target node Id, message as string or byte array, message length
    Serial.println("OK");
  }*/
  if (radio.sendWithRetry(RECEIVER, tempmqtt, strlen(tempmqtt))) { //target node Id, message as string or byte array, message length
    Serial.println("OK");
  }

  //send the message without retrying
  // radio.send(RECEIVER, radiopacket, strlen(radiopacket));//target node Id, message as string or byte array, message length
  //  Serial.println("OK, sent without retrying");  

  radio.receiveDone(); //put radio in RX mode

  Serial.println("Radio going to sleep");
  //radio.sleep();
  delay(1000);

  //Serial.println("Everything going to sleep");
  Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU
  //deepsleep();

}
}

TomWS

You don't say how far through setup() you get or how your mote is powered, both might be important.

The one thing I did notice is that your radio reset code should be treating the pin as a input most of the time (it reflects the radio's reset cycle state) with it being driven to a solid level for only a brief period of time to trigger reset.  I don't recall the level at the moment and you should read the RFM69's datasheet on this matter anyway...

Tom

raenrfm

Appreciate the reply Tom, the code functions (I had to omit some of the function calls because it exceeded the length for the forum), but after it finishes the loop it resets again and I can see it going through setup every cycle.  I have it powered off the FTDI right now, so maybe that is my issue?  I have an enormous 8000 mWh lipo I could power it off of instead, could it simply be that it's resetting after transmitting?  It transmits the information to my gateway successfully, but I know it's resetting because my accumulated rain variable resets to 0 after each cycle.  Can you comment if what I'm doing with the watchdog is appropriate?

Felix

Is this a LowPowerLab FTDI stock adapter?
Then that passes 5V from the USB, the Moteino LDO can supply up to 250mA and that should be plenty.
Otherwise if the VIN rail collapses below 2.7V, it will enter brown out and reset once voltage is back to normal, (stock Moteino fuses).
The new Moteino-8Mhz has 1.8v brown out.

raenrfm

Hey Felix, I got the ftdi from you but I'm also powering a voltage booster to supply the am2315 which it needs. Based on your comments I'll try powering the booster separately to test this out. It kind of makes sense because the last thing that happens in the loop is the transmit which taxes the supply the most. Stay tuned.

TomWS

Quote from: raenrfm on September 29, 2017, 10:58:33 PM
Hey Felix, I got the ftdi from you but I'm also powering a voltage booster to supply the am2315 which it needs. Based on your comments I'll try powering the booster separately to test this out. It kind of makes sense because the last thing that happens in the loop is the transmit which taxes the supply the most. Stay tuned.
Alternative quick test would be to reduce the transmit power and that will substantially reduce the load enough to keep the voltage from collapsing too far.

Tom

perky

Quote from: raenrfm on September 29, 2017, 10:58:33 PM
Hey Felix, I got the ftdi from you but I'm also powering a voltage booster to supply the am2315 which it needs. Based on your comments I'll try powering the booster separately to test this out. It kind of makes sense because the last thing that happens in the loop is the transmit which taxes the supply the most. Stay tuned.

You need to watch current pulses with boost regulators, they can somtimes take a lot of current during their startup phase. They often take many hundred milliamps by design. Best to use soft start regulators, but even these can be troublesome if the value is fixed in the chip as they're invariably too high. There is a technique using a slew rate controlled high side switch, and feedback via a capacitor from the output voltage of the regulator rather than the output from the high side switch itself. That works quite well, I got mine down from several hundred milliamps to less than 50.

Mark.

TomWS

Quote from: perky on September 30, 2017, 02:15:27 PM
There is a technique using a slew rate controlled high side switch, and feedback via a capacitor from the output voltage of the regulator rather than the output from the high side switch itself.
Good tip, Mark.  And if you use a series resistor into the gate node, your slew rate is very predictable and controllable to virtually any rise time.

Tom

perky

Quote from: TomWS on September 30, 2017, 03:12:54 PM
Good tip, Mark.  And if you use a series resistor into the gate node, your slew rate is very predictable and controllable to virtually any rise time.

Yes, this is how these slew rate controlled high side switches work, and they are characterized accordingly. The key with using them with boost regulators is to take the slew feedback from the regulator's output rather than the output of the switch (i.e. the input supply to the regulator). This is because the regulator won't start switching until it reaches a certain level, and when it does it tends to pull the input supply down and that messes with switch which is trying to slew rate control the rise of that supply. You can still get significant current pulses. Taking the feedback from the regulator's output eliminates that effect.

Mark.

raenrfm

Ok so I used an external supply for everything other than the moteino and it's still cycling through setup. Is it my code?

TomWS

Quote from: raenrfm on October 01, 2017, 11:15:13 AM
Ok so I used an external supply for everything other than the moteino and it's still cycling through setup. Is it my code?
I'll put good money on the series of:
strcat(tempmqtt,drainmqtt);

Overflowing the tempmqtt buffer and then the stack, and then the return from loop goes to somewhere where no man has been before...

Tom


raenrfm

I guess my code is too bloated.  I'll have to play around with the buffer sizes then to make it work.  I'll try a bit of polishing tonight to see if I can get it working.  Thanks for the tips.

TomWS

Quote from: raenrfm on October 02, 2017, 11:17:25 AM
I guess my code is too bloated.  I'll have to play around with the buffer sizes then to make it work.  I'll try a bit of polishing tonight to see if I can get it working.  Thanks for the tips.
The IDE should tell you how much RAM is being used.  I doubt that you've run out, but moving your buffers to static space will not only let you know what you're using, it will also reduce the risk of blowing out your stack.  Since you can't send more than 62 bytes in a packet, you shouldn't need more than 2X that for transfer buffers.

Tom

raenrfm

When you say "move your buffers to static space" what do you mean?  Sorry, I'm still a bit of a newbie.

Reducing the size of my buffers fixed the problem, so your analysis was correct there.  I was blowing it up obviously.  Now if only I could get my pinchange interrupt on pin 4 working...new thread?

TomWS

Quote from: raenrfm on October 02, 2017, 10:30:09 PM
When you say "move your buffers to static space" what do you mean?
Rather than declaring your variables inside loop() like:
  char tempmqtt[30] = "weather/outTemp:";
  char hummqtt[30] = ",outHumidity:";
  char drainmqtt[30] = ",rain:";
  char wspdmqtt[30] = ",windSpeed:";

which makes the variables 'automatic', placing them in the stack. 

Instead, do this:
  static char tempmqtt[30] = "weather/outTemp:";
  static char hummqtt[30] = ",outHumidity:";
  static char drainmqtt[30] = ",rain:";
  static char wspdmqtt[30] = ",windSpeed:";

which places them in normal RAM data area and will get measured in the IDE memory report.  Another benefit is that they only get initialized once, but that can be a double edged sword since you're appending all the other results into tempmqtt.  However, in your case, this problem goes away when you execute:
  dtostrf(tempF, 5, 1, &tempmqtt[16]);

since this will add the NULL termination to the end of the tempF value in the string, effectively erasing all the characters that follow it.
Quote
Sorry, I'm still a bit of a newbie.
No problem, we were all newbies at one point!
Quote
Reducing the size of my buffers fixed the problem, so your analysis was correct there.  I was blowing it up obviously.  Now if only I could get my pinchange interrupt on pin 4 working...new thread?
Yeah, that's probably best as you'll get more focused results.

Tom