Arduino – They got it mostly right!

In classic Fast Show style – this week I have been mostly programming Arduino.

After the demise of my RaspberryPi/Gertduino weather station project I decided to go fully Arduino.   I’d bought 2 Uno clones from ebay and never did much with them, so time to put them to use!

Next I bought the ethernet shield.   About £10 has bought be an ‘internet of things’ building platform.   The plan was to have the weather station based in the garage reporting via IP to the Linux server in the house.   That way the outboard station was all flash based with no local storage.   I’ve used Atmel AVRs a LOT and know they are pretty robust.   No more worries about SD cards eating themselves!

All the code for the gerduino (which handled the time critical and analogue elements of the weather monitoring) was all written in vanilla C.   As I’m used to.   Lots of use of interrupts, printf (yes, I’m lazy) and some bit bashing too.

As I wanted to use the ethernet shield I could either convert to the Arduino build env or try and mate the Arduino libs with vanilla C.   A quick look around showed that using the C++ libs with vanilla C was like trying to drink the water of life.   Many have tried, few have come out of the experience with their sanity intact.

So time to get friendly with the way the Arduino IDE works.   The setup and loop is very neat, you can get something working in very few lines of code.   Even the ethernet libs were pretty simple.   Take up acres of flash, but pretty simple! 🙂

Stumbling blocks… I use the 1ms(ish) interrupt for things other than just counting milliseconds.   I don’t want to put time critical stuff in the loop section as the timing in there is uncertain.   I don’t want to use timers 1 or 2 as they are used to control the solar thermal experiment. (details later, it needs a new pump)   So cue a bit of core code hacking to add a function pointer to the end of the timer0 overflow.
static volatile voidFuncPtr intMsFunc = 0;

// volatile static voidFuncPtr twiIntFunc;

void attachMsInterrupt(void (*userFunc)(void)) {
intMsFunc = userFunc;
}
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;

m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}

timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;

if(intMsFunc)
intMsFunc();
}

So I’m pretty much on track.   Didn’t bother to use the library ADC functions as I oversample to get 12 bits.   The cheap chinese wind direction I’m using sensor is a bit crude and some of the direction values are too close together for accurate detection in 10 bits.

The onewire lib worked first time.   EEprom, serial, TCP sockets etc.. all seemed to fall into place.   They’ve  all done a good job.   TWI was a bit funky as the examples are a bit lacking.   Its also interrupt based which is something I’ve not done on the atmega.   And of course it takes the address shifted down by 1… they don’t really mention that bit 🙂

So what about gotchas… the serial writes!   Don’t use them in interrupts, they don’t work 🙂   To stop the serial writes from blocking they use a software buffer and interrupts.   Makes sense, anyone coming to this new won’t realise that sending strings at 9600 baud takes a really long time and it will mess up your carefully calculated delays.   But of course when in an ISR in atmel world all the interrupts are turned off!

Also, just like with printf you use up huge amounts of SRAM with the format strings.   Remember to put F() around your text!   Saves hundreds of bytes.   I always use rom_printf.   An inline that puts the format string in PROGMEM.

Just to make life complex I found arduino-netboot.   A small bootloader that uses BOOTP and tftp to update an ethernet equipped Arduino.   Luckily I have a JTAGIceMkII to hand so could re-program the bootloader.   That was the easy bit… turns out my 3com switch blocks BOOTP when spanning tree is turned on… that took me a while to figure out…

It needs a binary file for the tftp.   Not easy getting these from the Arduino IDE.   Simple way is to find the temp dir and avr-objcopy them yourself.   Yuk!   I wrote a bat file that creates the .hex and a .bin and copies it to the tftp dir.   Hacked platform.txt to make it call my bat file instead of avr-objcopy.   Would have been nice if they’d used makefiles… ho hum.

So now I have a fully Arduino based weather station based in the garage which boots off the network and reports back to WeeWx over TCP.   Lets see how reliable this incarnation of my ‘made from spare parts’ weather station is.