Saturday, October 29, 2011

The 2560 Board is Not So Stupid Anymore

As I noted here, the Arduino 2560 has a couple of problems right out of the box. The bootloader will refuse to load any sketch(program) that has three exclamation points in row in it. Things like Serial.print("hello!!!"); will lock the loader up and it never completes. This is insidious since the three exclamation points can be in data. Even the compiler can create this. So, your sketch just won't load.

After complaining publicly about this a couple of folk stepped up and fixed it so that this problem has been solved. You have to burn a new boot loader, but that's not too hard.  The file I used is available here.  It's a hex file, so copy, paste and save it as a .hex file using notepad.

However, they didn't address the problem of the watchdog timer. I've been using timer three to work around the problem, but I didn't like that solution much. Timer three is a nice general purpose timer and messing with it can affect PWM operations, so I've been thinking about how to solve it. I got a clue today on the Arduino forum and put together some code that solves this problem for me with a side benefit. I can have watchdog timers that exceed the 8 second limit in the hardware as well.

Here is the code, have fun with it.


#include <avr/wdt.h>

unsigned long resetTime = 0;
#define TIMEOUTPERIOD 5000             // You can make this time as long as you want,
                                       // it's not limited to 8 seconds like the normal
                                       // watchdog
#define doggieTickle() resetTime = millis();  // This macro will reset the timer
void(* resetFunc) (void) = 0; //declare reset function @ address 0

void watchdogSetup()
{
cli();  // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF);  // because the data sheet said to
/*
WDTCSR configuration:
WDIE = 1 :Interrupt Enable
WDE = 1  :Reset Enable - I won't be using this on the 2560
WDP3 = 0 :For 1000ms Time-out
WDP2 = 1 :bit pattern is
WDP1 = 1 :0110  change this for a different
WDP0 = 0 :timeout period.
*/
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupte enable, 0110 for timer
WDTCSR = (1<<WDIE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0);
sei();
Serial.println("finished watchdog setup");  // just here for testing
}


ISR(WDT_vect) // Watchdog timer interrupt.
{
  if(millis() - resetTime > TIMEOUTPERIOD){
    Serial.println("This is where it would have rebooted");  // just here for testing
    doggieTickle();                                          // take these lines out
//  resetFunc();     // This will call location zero and cause a reboot.
  }
  else                                                       // these lines should
    Serial.println("Howdy");                                 // be removed also
}


void setup(){
  watchdogSetup();
  Serial.begin(57600);
  Serial.println("Hello, in setup");
}

int firstTime = true;
void loop() {
  if (firstTime){
    firstTime = false;
    Serial.println("In loop waiting for Watchdog");
  }
  if(millis() - resetTime > 2000){
    //doggieTickle();  // if you uncomment this line, it will keep resetting the timer.
  }
}



And yes, I know about the millisecond timer rolling over. That is left as an exercise for the student.

Update Feb 2, 2012:  I've gotten comments both here and in email that the routine above isn't truly a watchdog timer.  OK, facts are that it is as good a simulation as one can get in software.  Sure, the code could get overwritten and fail if one has a bad enough bug, but that's unlikely.  When it fires, it goes to location zero which is in ROM and can't be over written which will reload the RAM code and start all over. I've been using it for months now without a problem.  Just put it at the beginning of your code and it should be fine.  Eventually, someone will correct the bootloader and all will be well.

Update May 30, 2012: The bootloader problems have been solved and there is a new loader that can be put on the board to avoid these problems.  I post about the solution here.

Friday, October 28, 2011

Winter is coming

I've had the fancy thermostats for a year now and they have been updated as new capabilities were needed and work pretty darn well. I've had the house controller for several months and it is still growing and worked pretty well during the summer. Now, winter is coming and I have to think and experiment with the various controls a little differently.

For example when it is well over 90F outside, 70F is too cold inside for me. When it is 48F outside, will 70F still feel cold or will it be warm? Especially since I'll actually be wearing clothes and maybe even shoes. I don't know.

The current plan is to set the house for heating and the inside temp at 70F with recirculation and see what happens. I can test the heat and such to see what is the most comfortable and least costly. I like a cool room to sleep, so there may be different settings depending on the outside temperature.

So, maybe I'll turn the thermostats completely off if the outside temperature is between 70F and 80F and then adjust the inside temperature based on outside temp.

I just don't know and will have to research this over the coming winter. Wish me luck.

On another front, the house controller went through a major set of changes this last week and a half. I found a way to make the internet connection and response much, much better. The Arduino library will send one byte packets if you use certain facilities. This means each single byte of real data sent has about 50 bytes of overhead to get it to the destination. This is not a bug in the Arduino code, it's a pretty nice feature that allows new users a lot of flexibility. For me, it was something that was causing me a lot of trouble and had to go. It was simple to fix, just use client.write() instead of client.print(). This means I have to do my own formatting of data for display, but I was almost totally doing that already. So, I went through all the code and changed this. Now, the ethernet is very reliable and seems to work every single time.

I took the special code around Pachube out and modified it to allow for errors. Pachube has been incredibly reliable, but sometimes it takes more than 10 seconds to respond to a request. That would exceed my watchdog timer and cause the device to reset. So, I changed the ethernet library to allow me to set a time limit on connect() requests and time the Pachube connection out in 5 seconds. This is no big deal since I'll be back to that point in a minute anyway and Pachube seldom fails to respond in that amount of time. This is a nice solution because I can also time other interactions with the internet to prevent hanging up waiting for a connection to time out. The timeout for something like this seems to be around 30 seconds. For me, that's too long to wait.

The problem with this is that I now have a custom ethernet library. So, when the Arduino folks come out with a better IDE, I'll have to fit my changes into their stuff. That also means I have to keep careful track of my changes and make sure I have them all the time. I guess I'll have to look into cloud storage of my various code pieces for the devices and IDE. It's getting to the point now where I have a ton of time invested in these controlling devices and I'd hate to lose it all to a hard disk crash.

Also, the fixes to the internet interaction turned up another problem. The way I'm using the XBees allows for collisions. The more of them I have, the more likely collisions are to happen. Each collision causes a packet to get messed up and then my packet decoder will mess up. Yes, I know that each packet has a checksum, but what they don't tell you is that the XBee sending broadcasts will split a broadcast between two or more packets. That means each part of a packet has the correct checksum. Sigh, hard to find problem that was relatively easy to fix. Since I have packets constantly coming telling the status of the devices, I just have to check for the packet for consistency and dump it if it fails. There'll be another one in a minute or less. So, I check the incoming packets and discard the ones that have been fragmented. This works fine now and my little box has been running perfectly for a few days. The only reboot that has happened is the one I force at midnight every day to just clean it out.

The really, really cool thing about this is that I CAN do it. See, prior to starting this experiment, I couldn't control any of this, much less wonder what to do if the outside temperature went up or down. People just don't understand what is actually possible and are constantly frustrated by high bills or uncomfortable environments. My frustrations are related to how I want to control it, not whether I can or not.

Nice.

Friday, October 14, 2011

Playing with Graphs part 2

I did it. With a heck of a lot of help from the support staff at Pachube, I can now read the data for whatever period I want and graph it. I don't have an illustration on the web yet because it takes time to gather the data and people get tired of waiting and just click off somewhere else.

However, this is so cool. I can sample data at one minute intervals for, say an hour, any hour, any day, for the last year (or however long I have had the sensor running) and look at it in detail. Ever wonder what happens when the clouds block the sun from your solar heater sensor? What happens to the pump power demand when the sun comes back. I know all about this now.

Saturday, October 8, 2011

Playing with Graphs

I'm just testing the Google visualization library.  The chart below should show the last few hours of power usage and temperature changes.  This is something I want to do with the data I collect around the house and this is my first javascript code to try it.  I currently can't get more than 5 hours of data back from Pachube without it paging on me.  This will take some thought.