Computing stuff tied to the physical world

Archive for the ‘AVR’ Category

Wrapping up

In AVR, Hardware, News, Software, Musings on Oct 6, 2013 at 00:01

I’m writing this post while one of the test JeeNode Micro’s here at JeeLabs is nearing its eighth month of operation on a single coin cell:

DSC_4507

It’s running the radioBlip2 sketch, sending out packets with an incrementing long integer packet count, roughly once every minute:

Screen Shot 2013-10-04 at 15.44.58

The battery voltage is also tracked, using a nice little trick which lets the ATtiny measure its own supply voltage. As you can see, the battery is getting weaker, dropping in voltage after each 25 mA transmission pulse, but still recovering very nicely before the next transmission:

Screen Shot 2013-10-04 at 15.45.45

Fascinating stuff. A bit like my energy levels, I think :)

But this post is not just about reporting ultra low-power consumption. It’s also my way of announcing that I’ve decided to wrap up this daily weblog and call it quits. There will be no new posts after this one. But this weblog will remain online, and so will the forum & shop.

I know from the many emails I’ve received over the years that many of you have been enjoying this weblog – some of you even from the very beginning, almost 5 years ago. Thank you. Unfortunately, I really need to find a new way to push myself forward.

This is post # 1400, with over 6000 comments to date. Your encouragement, thank-you’s, insightful comments, corrections and additions – I’m deeply grateful for each one of them. I hope that the passion which has always driven me to explore this computing stuff tied to the physical world technology and to write about these adventures, have helped you appreciate the creativity that comes with engineering and invention, and have maybe even tempted you to take steps to explore and learn beyond the things you already knew.

In fact, I sincerely hope that these pages will continue to encourage and inspire new visitors who stumble upon this weblog in the future. For those visitors, here’s a quick summary of the recent flashback posts, to help you find your way around on this weblog:

Please don’t ever stop exploring and pushing the boundaries of imagination and creativity – be it your own or that of others. There is infinite potential in each of us, and I’m certain that if we can tap even just a tiny fraction of it, the world will be a better place.

I’d like to think that I’ve played my part in this and wish you a lot of happy tinkering.

Take care,
Jean-Claude Wippler

PS. For a glimpse of of what I’m considering doing next, see this page. I can assure you that my interests and passions have not changed, and that I’ll remain as active as ever w.r.t. research and product development. The whole point of this change is to allow me to invest more focus and time, and to take the JeeLabs projects and products further, in fact.

PPS. Following the advice of some friends I highly respect, I’m making this last weblog post open-ended: it’ll be the last post for now. Maybe the new plans don’t work out as expected after all, or maybe I’ll want to reconsider after a while, knowing how much joy and energy this weblog has given me over the years. So let’s just call this a break, until further notice :)

Update Dec 2013 – Check out the forum at jeelabs.net for the latest news about JeeLabs.

Flashback – Dive Into JeeNodes

In AVR, Hardware, Software, Linux on Oct 4, 2013 at 00:01

Dive Into JeeNodes (DIJN) is a twelve-part series, describing how to turn one or more remote JeeNodes, a central JeeLink, and a Raspberry Pi into a complete home monitoring setup. Well, ok, not quite: only a first remote setup is described with an LDR as light sensor, but all the steps to make the pieces work together are described.

More visually, DIJN describes how to get from here:

dijn01-essence.png   dijn01-diagram

.. to here:

Screen-Shot-2013-02-09-at-12.22.13

This covers a huge range of technologies, from embedded Arduino stuff on an ATmega-based JeeNode, to setting up Node.js and the HouseMon software on a Raspberry Pi embedded Linux board. The total cost of a complete but minimal setup should be around €100. Less than an Xbox and far, far more educational and entertaining, if you ask me!

It’s all about two things really: 1) describing the whole range of technologies and getting things working, and 2) setting up a context which you can explore, learn, and hack on tinker with in numerous ways.

If you’re an experienced Linux developer but want to learn about embedded hardware, wireless sensors, physical computing and such, then this offers a way to hook up all sorts of things on the JeeNode / Arduino side of things.

If you’re familiar with hardware development or have some experience with the Arduino world, then this same setup lets you get familiar with setting up a self-contained low-power Linux server and try out the command line, and many shell commands and programming languages available on Linux.

If you’ve set up a home automation system for yourself in the past, with PHP as web server and MySQL as back end, then this same setup will give you an opportunity to try out rich client-side internet application development based on AngularJS and Node.js – or perhaps simply hook things together so you can take advantage of both approaches.

With the Dive Into JeeNode series, I wanted to single out a specific range of technologies as an example of what can be accomplished today with open source hardware and software, while still covering a huge range of the technology spectrum – from C/C++ running on a chip to fairly advanced client / server programming using JavaScript, HTML, and CSS (or actually: dialects of these, called CoffeeScript, Jade, and Stylus, respectively).

Note that this is all meant to be altered and ripped apart – it’s only a starting point!

Flashback – Ports and I2C in JeeLib

In AVR, Software on Oct 2, 2013 at 00:01

One of the small innovations in the JeeNode is the use of “Ports”:

ports

Most µC boards, including the Arduino, brought out all the I/O pins on one or more large headers, meaning that you had to pick and route individual pins for each case where some component or sensor was being connected. While flexible, it prevented adding stuff in a plug-an-play manner: hook up some sensors, use matching bits of C/C++ code, and done.

I also always kept running out of VCC and GND connection pins while experimenting. So instead of bundling all I/O pins, a decision was made in 2009 to bring out a couple of (nearly) identical “ports”, to any of which the same sensor could be attached. That meant you could connect up to at least four sensors independent of each other.

As it turns out, there are enough spare I/O pins on an ATmega to provide one digital and one analog pin to each port. Add GND, VCC (+3.3V) and PWR (the input voltage, could be up to about 13V), and you end up with a fairly general-purpose setup. One extra spare pin was provided as “IRQ” to allow connected sensors to draw attention to themselves via an interrupt, although this feature has admittedly so far not been used much on JeeNodes.

But the real improvement is the fact that the two I/O pins can be used as I2C bus. All of a sudden, each port is no longer limited to a single sensor. The I2C bus is so useful because many types of low-cost chips include an I2C interface in hardware, and it lets multiple chips operate on a single bus.

One of the first extensions added was the Expander Plug, an 8-bit general-purpose digital I/O interface. So now, with just two pins consumed on the ATmega, you could have up to 32 input/output pins (by daisy chaining 4 of these plugs and setting them each to a different I2C address). The Dimmer Plug takes this even further: up to 8 of them on one bus, each driving up to 16 LED’s – for a total of 128 dimmable LEDs on 2 I/O pins!

Officially, the I2C bus requires dedicated hardware with “slew control” to increase the accuracy of signals on the bus. And while the ATmega has such an interface, there is just one per ATmega. Fortunately, you can also “bit-bang” I2C in plain software, i.e. simulate the relatively slow pin changes with nothing but software on any 2 I/O pins. The speed is not quite as high, and the supported bus length is also limited to a few dozen centimeters, but for direct connection of a few plugs that still works out quite well.

And so the JeeNode has ended up having 4 “ports”, each of them individually capable of supporting either I2C, or one analog (AIO) and one digital (DIO) pin – or alternately 2 digital I/O’s, since each analog pin on the ATmega can also be used in digital mode.

Since then, lots of different types of “JeePlugs” have been created, some I2C, some not. Most of the plugs have a corresponding class and a demo sketch in the JeeLib library, making it very easy to hook them up and interface to them in software. With most plugs, you just have to define which port they are connected to – and in the case of I2C plugs, which bus address they have been set to.

The placement of these ports and the choice of very low-cost standard 6-pin headers took some experimentation, but I think it all turned out ok. Lots of expandability and flexibility.

Flashback – The first JeeNode PCB

In AVR, Hardware on Oct 1, 2013 at 00:01

The first JeeNode circuit board was very exciting to make, back in January 2009:

pd-d1

Initially, I just wanted to get the connections right and didn’t care for silkscreen labelling, so there was none. It was created with CadSoft’s EAGLE, a commercial package with a freeware version for small boards. The “JeeNode” name came a month later, by the way.

The learning curve of the EAGLE package is steep, but then again, drawing this sort of stuff is going to be complicated whatever you do, because it’s not about drawing a nice picture where only aesthetics matter, but a meticulously designed diagram of which all the paths and connections have to follow certain rules, such as wires not crossing (doh!) and wires all having a minimum width and separation.

Here’s the JeeNode v6 PCB in comparison, of which many thousands have been produced:

DSC_4499

It’s still surprisingly similar in design to the first iteration, although the production details and fabrication process have greatly improved over the years. One aesthetic detail I’ve always been pleased with is the blue-with-gold color choice. The gold plating is easier to solder than the HASL process I used initially, and is much more resistant to corrosion. Don’t think too much of this gold layer, by the way: it’s chemically deposited (fairly nasty stuff, from what I understand) and only a few atoms thick. Still… enough to do its work, and visually attractive (all in the eye of the beholder, evidently).

The purpose of a PCB is three-fold: a physically strong base for all the components, a reliable interconnect between all the pins to implement the actual circuit design, and silkscreen labelling to ease assembly and use afterwards.

The result: a tangible product. Quite an exciting change for a software developer used to work with bits and bytes, and who could never before point to the “real” result of it all!

Flashback – Batteries came later

In AVR, Hardware, Software on Sep 30, 2013 at 00:01

During all this early experimentation in 2008 and 2009, I quickly zoomed in on the little ATmega + RFM12B combo as a way to collect data around the house. But I completely ignored the power issue…

The necessity to run on battery power was something I had completely missed in the beginning. Everyone was running Arduino’s off either a 5V USB adapter or – occasionally – off a battery pack, and never much more than a few days. Being “untethered” in many projects at that time, meant being able to do something for a few hours or a day, and swapping or recharging batteries at night was easy, right?

It took me a full year to realise that a wireless “node” tied to a wire to run for an extended period of time made no sense. Untethered operation also implies being self-powered:

DSC_0496

Evidently, having lots of nodes around the house would not work if batteries had to be swapped every few weeks. So far, I just worked off the premise that these nodes needed to be plugged into a power adapter – but there are plenty of cases where that is extremely cumbersome. Not only do you need a power outlet nearby, you need fat power adapters, and you have to claim all those power outlets for permanent use. It really didn’t add up, in terms of cost, and especially since the data was already being exchanged wirelessly!

Thus started the long and fascinating journey of trying to run a JeeNode on as little power as possible – something most people probably know this weblog best for. Over the years, it led to some new (for me) insights, such as: transmission draws a “huge” 25 mA, but it’s still negligible because the duration is only a few milliseconds. By far the most important parameter to optimise for is sleep-mode power consumption of the entire circuit.

In September 2010, i.e. one year after starting on this low-power journey, the Sleepy class was added to JeeLib, as a way to make it easy to enter low-power mode:

class Sleepy {
public:
    /// start the watchdog timer (or disable it if mode < 0)
    /// @param mode Enable watchdog trigger after "16 << mode" milliseconds 
    ///             (mode 0..9), or disable it (mode < 0).
    static void watchdogInterrupts (char mode);
    
    /// enter low-power mode, wake up with watchdog, INT0/1, or pin-change
    static void powerDown ();
    
    /// Spend some time in low-power mode, the timing is only approximate.
    /// @param msecs Number of milliseconds to sleep, in range 0..65535.
    /// @returns 1 if all went normally, or 0 if some other interrupt occurred
    static byte loseSomeTime (word msecs);

    /// This must be called from your watchdog interrupt code.
    static void watchdogEvent();
};

The main call was named loseSomeTime() to reflect the fact that the watchdog timer is not very accurate. Calling Sleepy::loseSomeTime(60000) gives you approximately one minute of ultra low-power sleep time, but it could be a few seconds more or less. To wait longer, you can call this code a few times, since 65,535 ms is the maximum value supported by the Sleepy class.

As a result of this little class, you can do things like put the RFM12B into sleep mode (and any other power-hungry peripherals you might have connected), go to sleep for a bit, and restore all the peripherals to their normal state. The effects can be quite dramatic, with a few orders of magnitude less power consumption. This extends a node’s battery lifetime from a few days to a few years – although you have to get all the details right to get there.

One important design decision in the JeeNode was to use a voltage regulator with a very low idle current (the MCP1700 draws 2 µA idle). As a result, when a JeeNode goes to sleep, it can be made to draw well under 10 µA.

Most nodes here at JeeLabs now keep on running for well over a year on a single battery charge. Everything has become more-or-less install and forget – very convenient!

Flashback – RFM12B wireless

In AVR, Hardware, Software on Sep 29, 2013 at 00:01

After the ATmega µC, the second fascinating discovery in 2008 was the availability of very low-cost wireless modules, powerful enough to get some information across the house:

wireless-modules

It would take another few months until I settled on the RFM12B wireless module by HopeRF, but the uses were quickly falling into place – I had always wanted to track the energy consumption in the house, to try and identify the main energy consumers. That knowledge might then help reduce our yearly energy consumption – either by making changes to the house, or – as it turned out – by simply adjusting our behaviour a bit.

Here is the mouse trap which collected energy metering data at JeeLabs for several years:

mousetrap

This is also when I found Modern Devices’s Real Bare Bone Board Arduino clone by Paul Badger – all the good stuff of an Arduino, without the per-board FTDI interface, and with a much smaller form factor.

Yet another month would pass to get a decent interrupt-driven driver working, and some more tweaks to make transmission interrupt-based as well. The advantage of such as design is that you get the benefits of a multi-tasking setup without all the overhead: the RF12 driver does all its time-critical work in the background, while the main loop() can continue to use delay() calls and blocking I/O (including serial port transmission).

In February 2009, I started installing the RF12demo code on each ATmega, as a quick way to test and try out wireless. As it turned out, that sketch has become quite useful as central receiving node, even “in production” – and I still use it as interface for HouseMon.

In April 2009, a small but important change was made to the packet format, allowing more robust use of multiple netgroups. Without this change, a bit error in the netgroup byte will alter the packet in a way which is not caught by the CRC checksum, making it a valid packet in another netgroup. This is no big deal if you only use a single netgroup, but will make a difference when multiple netgroups are in use in the same area.

Apart from this change, the RF12 driver and the RFM12B modules have been remarkably reliable, with many nodes here communicating for years on end without a single hick-up.

I still find it pretty amazing that simple low-power wireless networking is available at such a low cost, with very limited software involvement, and suitable for so many low-speed data collection and signalling uses in and around the house. To me, wireless continues to feel like magic after all these years: things happening instantly and invisibly across a distance, using physical properties which we cannot sense or detect…

Flashback – Discovering the Arduino

In AVR, Hardware on Sep 28, 2013 at 00:01

It’s now just about 5 years ago when I started with JeeLabs, so I thought it might be a good idea to bring back some notes from the past. Get ready for a couple of flashback posts…

One of the first posts on this weblog was about the Arduino, or rather Atmel’s AVR ATmega chip I had just discovered (it was the ATmega168 back then):

atmega328p

It was the Arduino IDE which made it trivial to play with this chip, an open source multi-platform software package combining an editor, the avr-gcc compiler, and the avrdude uploader. And despite the use of very Arduino-ish names such as “sketches” (firmware) and “shields” (add-on hardware), it was all nearly-standard C and C++, with a couple of convenient libraries to easily access I/O pins, the ADC, the serial port, timers, and more.

Five years ago, a fascinating brand new world opened up for me. I knew all about C and C++ as well as digital I/O and boot loaders, but a lot of really interesting and powerful new technologies were new to me: I2C, SPI, embedded timer hardware, and above all: sleep mode. These chips were not only able to run at an amazing 16 MHz clock rate, they could actually go to sleep and use a watchdog timer to wake up again later, saving 3 orders of magnitude on energy consumption.

A small universe, controlled by standard software and able to interface to the real world.

Physical Computing. Low cost. Accessible to anyone.

Wow.

3 years on one set of batteries

In AVR, Hardware on Sep 8, 2013 at 00:01

Ok, so maybe it’s getting a bit boring to report these results, but one of the JeeNodes I installed long ago has just reached a milestone:

Screen Shot 2013-09-06 at 23.30.55

That “buro JC” node has been running on a single battery charge for 3 years now:

And it’s not even close to empty: this is a JeeNode USB with a 1300 mAh LiPo battery tied to its back, and (as I just measured) it’s still running at 3.74 V, go figure.

Let’s do the math on what’s going on here:

  • the battery is specified as 1300 mAh, i.e. 1300 mA for one hour and then it’s empty
  • in this case, it has been running for some 1096 x 24 = 26,304 hours total
  • so the average current consumption must have been under 1300 / 26304 = 50 µA
  • well… in that case, the battery should be empty by now, but it isn’t
  • in fact, I suspect that the average power consumption is more like 10..25 µA

Two things to note: 1) LiPo batteries pack a lot of energy, and 2) they have a really low self-discharge rate, so they are able to store that energy for a long time.

The other statistic worth working out, is the amount of energy consumed by a single packet transmission. Again, first assuming that the battery would be dead by now, and that the microcontroller and the rest of the circuit are not drawing any current:

  • 1,479,643 packets have been sent out, i.e. ≈ 1300 / 1500000 = under 1 µAh per packet
  • since 60 packets are sent out per hour: about 60 µAh per hour, i.e. 60 µA continuous
  • energy can also be expressed in coulombs, i.e. 60 µC gets used per packet transmission (3,600 seconds to the hour, but there were 60 packets sent out during that period)
  • so despite the fact that the RFM12B draws a substantial 25 mA of current during transmission, it does it so briefly that overall it’s still extremely low-power (a few ms every 1s, so that’s a truly minute duty cycle)

The conclusion here is: for these types of uses, with occasional brief wireless sensor data transmissions, the power consumption of the wireless module is not the main issue. It’s far more important to keep the idle (i.e. sleep mode) of the entire circuit under control.

The 2nd result is also a record, a JeeNode Micro, running over 6 months on a coin cell:

This one is running the newer radioBlip2 sketch, which also measures and reports the battery voltage before and after packet transmission. As you can see, the coin cell is struggling a bit, but its voltage level is still fine: it drops to 2.74 V right after sending out a packet (drawing 25 mA), and then recovers the rest of the time to a fairly high 2.94 V. This battery sure isn’t empty yet. Let’s see how many more months it can keep this up.

The 3rd result (penlight test), is this setup, based on the latest JNµ v3:

The timing values are way off though: it has also been running for over 6 months, but I accidentally caused it to reset when moving things around earlier this summer. This one is running with a switching boost regulator. The Eneloop battery started out at 1.3 V and has now dropped slightly to 1.28 V – it should be fine for quite some time, as these batteries tend to run down gradually to 1.2V before they start getting depleted. This is a rechargeable battery, but Eneloop is known to hold on to its charge for a surprisingly long time (losing 20% over 2 years due to self-discharge, if I remember correctly).

You can see the boost regulator doing its thing, as the output voltage sent to the ATtiny is the same 3.04 V as it was on startup. That’s the whole idea: it regulates to a fixed level, while sucking the battery dry along the way…

Note that all these nodes are not sensing anything. They’re just bleeping once a minute.

Anyway… so much for the progress report on a pretty long-running experiment :)

What’s inside that chip?

In AVR, Hardware on Jun 9, 2013 at 00:01

Came across an interesting post the other day, from a Russian site which looks “under the hood” of some sophisticated chips – some well-known in the West, some less so.

First, the technique of using sulfuric and nitric acid is described and illustrated:

SONY DSC

But the really bit interesting bit is what comes out. Here’s the ATmega8:

atmega8

(both pictures were copied from that site, i.e. zeptobars.ru – I hope that’s ok)

The size of this chip is 2855 x 2795 µm, i.e less than 3 x 3 mm.

Fascinating! I wonder what all the different bits and pieces are…

A thousand days!

In AVR, Hardware on Jun 6, 2013 at 00:01

It’s getting a bit repetitive, but I just noticed this:

Screen Shot 2013-06-05 at 17.27.15

That’s over 1000 days of sending out one packet a minute on this thing:

dsc_1822

… and over 100 days on the recent JeeNode Micro v3:

DSC_2858.jpg

The battery boost version runs off a single Eneloop AA battery, and is doing fine too:

DSC_4401

Onwards!

Idling in low-power mode

In AVR, Software on May 28, 2013 at 00:01

With a real-time operating system, going into low-power mode is easy. Continuing the recent ChibiOS example, here is a powerUse.ino sketch which illustrates the mechanism:

#include <ChibiOS_AVR.h>
#include <JeeLib.h>

const bool LOWPOWER = true; // set to true to enable low-power sleeping

// must be defined in case we're using the watchdog for low-power waiting
ISR(WDT_vect) { Sleepy::watchdogEvent(); }

static WORKING_AREA(waThread1, 50);

void Thread1 () {
  while (true)
    chThdSleepMilliseconds(1000);
}

void setup () {
  rf12_initialize(1, RF12_868MHZ);
  rf12_sleep(RF12_SLEEP);

  chBegin(mainThread);
}

void mainThread () {
  chThdCreateStatic(waThread1, sizeof (waThread1),
                    NORMALPRIO + 2, (tfunc_t) Thread1, 0);

  while (true)
    loop();
}

void loop () {
  if (LOWPOWER)
    Sleepy::loseSomeTime(16); // minimum watchdog granularity is 16 ms
  else
    delay(16);
}

There’s a separate thread which runs at slightly higher priority than the main thread (NORMALPRIO + 2), but is idle most of the time, and there’s the main thread, which in this case takes the role of the idling thread.

When LOWPOWER is set to false, this sketch runs at full power all the time, drawing about 9 mA. With LOWPOWER set to true, the power consumption drops dramatically, with just an occasional short blip – as seen in this current-consumption scope capture:

SCR35

Once every 16..17 ms, the watchdog wakes the ATmega out of its power-down mode, and a brief amount of activity takes place. As you can see, most of these “blips” take just 18 µs, with a few excursions to 24 and 30 µs. I’ve left the setup running for over 15 minutes with the scope background persistence turned on, and there are no other glitches – ever. Those 6 µs extensions are probably the milliseconds clock timer.

For real-world uses, the idea is that you put all your own code in threads, such as Thread1() above, and call chThdSleepMilliseconds() to wait and re-schedule as needed. There can be a number of these threads, each with their own timing. The lowest-priority thread (the main thread in the example above) then goes into a low-power sleep mode – briefly and repeatedly, thus “soaking” up all unused µC processor cycles in the most energy-efficient manner, yet able to re-activate pending threads quickly.

What I don’t quite understand yet in the above scope capture is the repetition frequency of these pulses. Many pulses are 17 µs apart, i.e. the time Sleepy::loseSomeTime() goes to sleep, but there are also more frequent pulses, spread only 4..9 ms apart at times. I can only guess that this has something to do with the ChibiOS scheduler. That’s the thing with an RTOS: reasoning about the repetitive behavior of such code becomes a lot trickier.

Still… not bad: just a little code on idle and we get low-power behaviour almost for free!

ChibiOS for the Arduino IDE

In AVR, Software on May 25, 2013 at 00:01

A real-time operating system is a fairly tricky piece of software, even with a small RTOS – because of the way it messes with several low-level details of the running code, such as stacks and interrupts. It’s therefore no small feat when everything can be done as a standard add-on library for the Arduino IDE.

But that’s exactly what has been done by Bill Greiman with ChibiOS, in the form of a library called “ChibiOS_AVR” (there’s also an ARM version for the Due & Teensy).

So let’s continue where I left off yesterday and install this thing for use with JeeNodes, eh?

  • download a copy of ChibiOS20130208.zip from this page on Google Code
  • unpack it and inside you’ll find a folder called ChibiOS_AVR
  • move it inside the libraries folder in your IDE sketches folder (next to JeeLib, etc)
  • you might also want to move ChibiOS_ARM and SdFat next to it, for use later
  • other things in that ZIP file are a README file and the HTML documentation
  • that’s it, now re-launch the Arduino IDE to make it recognise the new libraries

That’s really all there is to it. The ChibiOS_AVR folder also contains a dozen examples, each of which is worth looking into and trying out. Keep in mind that there is no LED on a standard JeeNode, and that the blue LED on the JeeNode SMD and JeeNode USB is on pin 9 and has a reverse polarity (“0” will turn it on, “1” will turn it off).

Note: I’m using this with Arduino IDE 1.5.2, but it should also work with IDE 1.0.x

Simple things are still relatively simple with a RTOS, but be prepared to face a whole slew of new concepts and techniques when you really start to dive in. Lots of ways to make tasks and interrupts work together – mutexes, semaphores, events, queues, mailboxes…

Luckily, ChibiOS comes with a lot of documentation, including some general guides and how-to’s. The AVR-specific documentation can be found here (as well as in that ZIP file you just downloaded).

Not sure this is the best place for it, but I’ve put yesterday’s example in JeeLib for now.

I’d like to go into RTOS’s and ChibiOS some more in the weeks ahead, if only to see how wireless communication and low-power sleep modes can be fitted in there.

Just one statistic for now: the context switch latency of ChibiOS on an ATmega328 @ 16 MHz appears to be around 15 µs. Or to put it differently: you can switch between multiple tasks over sixty thousand times a second. Gulp.

Blinking in real-time

In AVR, Software on May 24, 2013 at 00:01

As promised yesterday, here’s an example sketch which uses the ChibiOS RTOS to create a separate task for keeping an LED blinking at 2 Hz, no matter what else the code is doing:

#include <ChibiOS_AVR.h>

static WORKING_AREA(waThread1, 50);

void Thread1 () {
  const uint8_t LED_PIN = 9;
  pinMode(LED_PIN, OUTPUT);
  
  while (1) {
    digitalWrite(LED_PIN, LOW);
    chThdSleepMilliseconds(100);
    digitalWrite(LED_PIN, HIGH);
    chThdSleepMilliseconds(400);
  }
}

void setup () {
  chBegin(mainThread);
}

void mainThread () {
  chThdCreateStatic(waThread1, sizeof (waThread1),
                    NORMALPRIO + 2, (tfunc_t) Thread1, 0);
  while (true)
    loop();
}

void loop () {
  delay(1000);
}

There are several things to note about this approach:

  • there’s now a “Thread1” task, which does all the LED blinking, even the LED pin setup
  • each task needs a working area for its stack, this will consume a bit of memory
  • calls to delay() are forbidden inside threads, they need to play nice and go to sleep
  • only a few changes are needed, compared to the original setup() and loop() code
  • chBegin() is what starts the RTOS going, and mainThread() takes over control
  • to keep things similar to what Arduino does, I decided to call loop() when idling

Note that inside loop() there is a call to delay(), but that’s ok: at some point, the RTOS runs out of other things to do, so we might as well make the main thread similar to what the Arduino does. There is also an idle task – it runs (but does nothing) whenever no other tasks are asking for processor time.

Note that despite the delay call, the LED still blinks in the proper rate. You’re looking at a real multitasking “kernel” running inside the ATmega328 here, and it’s preemptive, which simply means that the RTOS can (and will) decide to break off any current activity, if there is something more important that needs to be done first. This includes suddenly disrupting that delay() call, and letting Thread1 run to keep the LEDs blinking.

In case you’re wondering: this compiles to 3,120 bytes of code – ChibiOS is really tiny.

Stay tuned for details on how to get this working in your projects… it’s very easy!

Maxing out the Hameg scope

In AVR, Hardware on May 10, 2013 at 00:01

Yesterday’s post was about how test equipment can differ not only in terms of hardware, but also the software/firmware that comes with it (anyone hacking on the Owons or Rigols yet to make the software more feature-full?).

Here’s another example, where I’m using just about all the bells and whistles of the Hameg HMO series scopes – not for the heck of it, but because it really can help gain more insight about the circuit being examined.

This is my second attempt at understanding what sort of start up currents need to be available for the new JeeNode Micro v3 to properly power up:

SCR12

I’m applying a 0..2V power up ramp (yellow line) as power supply, using a 1 Hz sawtooth signal. This again simulates an energy harvesting setup where the power supply slowly ramps up (the real thing would actually rise far more slowly, i.e. when using a solar cell + supercap, for example). The current consumed by the JNµ v3 (blue line) is measured by measuring the voltage drop across a 10 Ω resistor – as usual.

The current consumption starts at about 0.85V and rises until the power supply reaches about 1.4V. At that point, the current consumption is about 77 µA. Then the ATtiny84A comes out of reset, enters a very brief high-current mode (much higher than the peak shown, but this is averaged out), and then goes into ultra low-power sleep mode. The sketch running on the JNµ is the latest power_down.ino, here in simplified form:

#include <JeeLib.h>

void setup () {
    cli();
    Sleepy::powerDown();
}

void loop () {}

Note that since this is the new JNµ v3, the RFM12B module never even gets powered up, so there’s no need to initialise the radio and then put it in sleep mode.

The red line uses the Hameg’s advanced math features to perform digital filtering on top of the averaging already performed during acquisition: the averaging keeps the power-up spike visible (albeit distorted), at the cost of leaving some residual noise in the blue trace, while the IIR digital low-pass filter applied to that result then makes it possible to estimate the 77 µA current draw just before the ATtiny84A starts running.

Here’s the zoomed-in view, showing the interesting segment in even more detail:

SCR14

The IIR filtering seen here is slightly different, with a little spike due to the following power-up spike, so the 86 µA reported here is slightly on the high side.

Note how the Hameg’s storage, high sensitivity, averaging, adjustable units display, variable vertical scale, math functions, on-screen measurements, on-screen cursors, and zooming all come together to produce a pretty informative screen shot of what is going on. Frankly, I wouldn’t know how to obtain this level of info in any other way.

So what’s all this fuss about measuring that 77 µA level?

Well, this is how much current the JNµ draws before it starts running its code. There’s nothing we can do to reduce this power consumption further until it reaches this point. In the case of energy harvesting, the supply – no matter how it’s generated – will have to be able to briefly deliver at least 77 µA to overcome the startup requirements. If it doesn’t, then the supply voltage (presumably a supercap or rechargeable battery) will never rise further, even though a JNµ can easily draw less than a tenth of that current once it has started up and goes into ultra-low power with brief occasional wake-ups to do the real work.

What I’m taking away from this, is that a solar energy setup will need to provide at least 0.1 mA somewhere during the day to get a JNµ started up. Once that happens, and as long as there is enough power to supply the average current needed, the node can then run at lower power levels. But whenever the supercap or battery runs out, another period with enough light is needed to generate that 0.1 mA again.

It all sounds ridiculously low, and in a way it is: 0.1 mA could be supplied for over two years by 3 AA batteries. The reason for going through all this trouble, is that I’d really like to find a way to run off indoor solar energy light levels. Even if it only works near a window, it would completely remove the need for batteries. It would allow me to just sprinkle such nodes where needed and collect data … forever.

What if the supply is under 3.3V?

In AVR, Hardware on May 1, 2013 at 00:01

Welcome to the weekly What-If series, also available via the Café wiki.

To follow up on a great suggestion from Martyn, here’s a post about the different trade-offs and implications of running an ATmega at lower voltages.

The standard Arduino Uno, and all models before it, have always operated the ATmega at 5.0V – which used to be the standard TTL levels used in the 7400 series of chips used in the 1960’s and 1970’s. The key benefit of a single standardised voltage level being that it made it possible to combine different chips from different vendors.

To this day, even though most semiconductor logic has evolved from bipolar junction transistor to CMOS, the voltage level has often been kept at 5V, with slightly adjusted – but compatible – voltage levels for “0” and “1”, respectively.

Nowadays, chips operate at lower voltages because it leads to lower power consumption and because it is a better fit for batteries and LiPo cells. In fact, lots of new chips operate at 3.3V and will not even tolerate 5.0V.

The ATmega328p is specified to run at a very wide range, from 1.8V all the way up to 5.5V. Which is great for ultra low-power use, supporting different battery options, and even for energy harvesting scenario’ such as a solar panel charging a supercap, for example.

But there are still many trade-offs to be aware of!

The first one is the system clock rate, which is limited (see also this older post):

Screen Shot 2013-04-30 at 21.59.07

If you look closely, you’ll see that 16 MHz is out of spec for 3.3V, the way the JeeNode is running, that is. In practice, this has never caused any known problems, but lowering the voltage further might just be too much.

The good news is that it’s not really the crystal oscillator which is causing problems, but the main circuitry of the ATmega, and that there’s a very easy fix for it: when running at voltages below 3.3V, you should set the ATmega’s pre-scaler to 2, causing the system clock to run at 8 MHz. When running even lower, perhaps under 2.4 V or so, set the pre-scaler to 4, i.e. run the system clock at 4 MHz. This also explains the presence of the divide-by-8 fuse bit: when you need to start up at low voltages, you can force the ATmega to always power up with a clock pre-scaler of 8, and then adjust the pre-scaler under software control after power-up, once the voltage has been verified to be sufficient. Without this setting, an ATmega would not be able to reliably start up at 1.8V, even if it’s meant to run much faster most of the time.

Note that the RF12 driver will still work at 4 MHz, but not less: the interrupt service time will be too slow for proper operation at any slower rate.

Another important issue to be aware of when running a JeeNode at voltages under 3.3V, is that the MCP1702 voltage regulator will no longer be able to regulate the incoming voltage. It can only reduce the input voltage for regulation, so when there is no “headroom” left, the regulator will just pass whatever is left, minus a small “dropout” voltage difference. Hence its name LDO: Low-DropOut.

The problem is that all LDO regulators start consuming (i.e. wasting) more idle current in this situation. See this weblog post for the measured values – which can be substantial!

To avoid this, you should really disconnect the LDO altogether, or at least its ground pin.

A third aspect of running at lower voltages, is that you need to verify that all the parts of the circuit continue to work. This applies to sensors as well as to the RFM12B radio – which should only be operated between 2.2V and 3.8V.

Actually, some experiments a while back showed that the radio could work down to 1.85V, but I suspect that things like transmit power will be greatly reduced at such supply levels.

Lastly, when the supply voltage is lowered, you need to keep some secondary effects in mind: the ADC will operate against a lower reference voltage as well, so its scale will change. One ADC step will be just under 3.3 mV when the supply is 3.3V, but this drops to under 2.0 mV per step with a 2.0V supply.

To summarise: yes, an ATmega/ATtiny can run at voltages below 3.3V, and even an entire JeeNode can, but you need to reduce the system clock by switching the pre-scaler to 2 or 4, and you need to make sure that all parts of your setup can handle these lower voltages.

(9)50 days and counting

In AVR, Hardware, Software on Apr 18, 2013 at 00:01

The new JeeNode Micro has joined the ranks of the test nodes running here to determine battery life in real time. The oldest one has been running over 2 and a half years now:

dsc_1822

That LiPo battery has a capacity of 1300 mAh, and since it’s still running, this implies that the average current draw must be under 1300/24/950 = 57 µA, including self-discharge.

The other two battery tests now running here are based on the new JeeNode Micro v3, i.e. this one – using a boost converter:

DSC_4401

… and another one using a coin cell. Here’s a picture of a slightly older version:

DSC_2858.jpg

The boost version is running off a rechargeable AA battery, of type Eneloop, which I use all over the house now. These batteries hold 1900 mAh, but there’s a substantial penalty for running off one AA cell with a boost converter:

  • energy is not free, i.e. drawing 10 µA at 3.3V means we will need to draw 30 µA at 1.1V, even if we could use a 100% efficient boost converter
  • real-world efficiency is more like 70..80% at these levels, so make that 40..45 µA
  • the boost converter has some idle current consumption, probably 10..20 µA, so this means we’ll draw 50..65 µA even if the JeeNode Micro only uses up 10 µA at 3.3V (actually, it’s 3.0V in the latest JNµ)

This would translate to 1900/.065/24/365, i.e. ≈ 3-year life. Or perhaps 2, if we account for the Eneloop’s 85% per year self-discharge.

The coin cell option runs off a CR2032 battery, which is rated at about 225 mAh, i.e. considerably less than the above options. Still, since there are no boost converter losses, this translates to 225/0.010/24/365, i.e. ≈ 2.5 years of life if the JNµ draws only 10 µA.

These figures look excellent, but keep in mind that 10 µA average power consumption is a very very optimistic value, particularly when there are sensors hooked up and packets are being sent out. I’d be quite happy with a 6-month battery life for a single AA or a coin cell.

For reference, here is an earlier post about all these power calculations.

Here are the current reports I’m getting via HouseMon:

Screen Shot 2013-04-17 at 11.12.08

That’s just about 50 days off a coin cell. Let’s see how it holds up. The nice bit in these tests is that the new nodes now report several different voltage level measurements as well (this also consumes some energy!). They haven’t dropped much yet, but when they do, I hope that we’ll be able to use the drop as a predictor.

Onwards!

JeeNode Micro start-up power

In AVR, Hardware on Mar 29, 2013 at 00:01

The JeeNode Micro v3 includes a P-channel MOSFET to control power to the RFM12B radio. This isn’t just a new gimmick – the goal was to “fix” the RFM12B wireless radio’s startup power consumption, which can prevent an ultra-low power source from ever building up a high enough supply voltage for a JeeNode to start up.

Now that the JNµ is in production, it’s time to measure how well such an approach works. Get ready for a bunch of scope screenshots, all based on the same circuit as before:

JC's Grid, page 51

… except that now the entire JeeNode Micro is in there, and I’m using a 10 Ω resistor.

I’ll be applying a 1 Hz ramp signal going from 0.0 to 3.0V using the power booster behind a signal generator, to see exactly what amount of current is being drawn. In all the images below, the yellow trace is the input voltage (i.e. a simulated power supply), and the blue trace is the voltage over the 10 Ω resistor – that means 1 vertical division on the blue trace corresponds to 0.5 mA when the display shows 5 mV/div:

SCR88

The above image is just a baseline: a simple blink sketch which never enables the radio, and which then toggles some I/O pins every 500 ms. As you can see, the ATtiny84 comes out of power-on reset at about 1.4V and ends up drawing about 3.5 mA at 3.0V.

Fuses are set to low=C2 high=D7 ext=FF, i.e. BOD disabled, startup asap on RC @ 8Mhz.

Now let’s look at the same setup with the JNµ running radioBlip2.ino:

SCR89

This time, the sketch enables the MOSFET to power up the radio, measures the battery voltage, tries to send out a packet (this will fail at 1.4V), and goes into deep sleep. A short but very quick (and high!) blip before power consumption drops to almost zero.

The third measurement is with a sketch doing nothing but powering down right away:

#include <JeeLib.h>

void setup () {
    cli(); // disable all interrupts
    Sleepy::powerDown();
}

void loop () {}

Which produces this result:

SCR90

I’ve bumped the scope sensitivity up to its maximum of 1 mV/div (i.e. 100 µA/div) and am now adding a lot of averaging to try and keep the displayed noise levels low. The “blip” is the ATtiny getting out of reset and powering down completely.

As last test, I repeated the above, but now using a sweep of 10 s (0.1 Hz), and filtering the signal through the lowest low-pass setting available, i.e. 5 Hz. This loses the important spike at 1.4V, which is of course still there, but improves the readout of the baseline:

SCR92

As you can see, the power consumption now never rises above ≈ 60 µA – that’s a ten-fold improvement over what we get with the RFM12B connected to power in the standard way.

The shape of this curve is quite interesting: it’s essentially resistive (since it’s more or less linear), but the current starts at 1.2V, i.e. after overcoming two extra diode drops.

This is the power-up “hump” which any ultra-low power supply based on solar cells or other energy harvesting techniques will need to overcome, so that the ATtiny can switch itself into power down mode and let the supply voltage rise further.

I think that’s an excellent result, and am looking forward to trying a few things out!

Avrdude in CoffeeScript

In AVR, Software on Mar 27, 2013 at 00:01

Here’s a fun project – rewriting avrdude in CoffeesCript, as I did a while back with Tcl:

{SerialPort} = require 'serialport'

pageBytes = 128

avrUploader = (bytes, tty, cb) ->
  serial = new SerialPort tty, baudrate: 115200

  done = (err) ->
    serial.close ->
      cb err

  timer = null
  state = offset = 0
  reply = ''

  states = [ # Finite State Machine, one function per state
    -> 
      ['0 ']
    -> 
      buf = new Buffer(20)
      buf.fill 0
      buf.writeInt16BE pageBytes, 12
      ['B', buf, ' ']
    -> 
      ['P ']
    ->
      state += 1  if offset >= bytes.length
      buf = new Buffer(2)
      buf.writeInt16LE offset >> 1, 0
      ['U', buf, ' ']
    ->
      state -= 2
      count = Math.min bytes.length - offset, pageBytes
      buf = new Buffer(2)
      buf.writeInt16BE count, 0
      pos = offset
      offset += count
      ['d', buf, 'F', bytes.slice(pos, offset), ' ']
    -> 
      ['Q ']
  ]

  next = ->
    if state < states.length
      serial.write x  for x in states[state++]()
      serial.flush()
      reply = ''
      timer = setTimeout (-> done state), 300
    else
      done()

  serial.on 'open', next

  serial.on 'error', done

  serial.on 'data', (data) ->
    reply += data
    if reply.slice(-2) is '\x14\x10'
      clearTimeout timer
      next()

And here’s a little test which uploads the RF12demo sketch into a JeeNode over serial:

fs = require 'fs'
hex = fs.readFileSync '/Users/jcw/Desktop/RF12demo.cpp.hex', 'ascii'

hexToBin = (code) ->
  data = ''
  for line in code.split '\n'
    count = parseInt line.slice(1, 3), 16
    if count and line.slice(7, 9) is '00'
      data += line.slice 9, 9 + 2 * count
  new Buffer(data, 'hex')

avrUploader hexToBin(hex), '/dev/tty.usbserial-AH01A0GD', (err) ->
  console.error 'err', err  if err
  console.log hexToBin(hex).length

Just copy it all into a file upload.coffee and run it as: coffee upload.coffee

It’s fairly dense code, but as you can see, the stk500v1 protocol requires very little logic!

It’s a software goose (again)

In AVR, Software on Mar 26, 2013 at 00:01

Yesterday’s weblog post documented my attempts to debug a problem while programming the JeeNode Micro with a Flash Board. I really thought it was a hardware bug.

Given that the results where slightly changing as I tried different things, but nevertheless seemed really consistent and repeatable when retrying exactly the same steps over and over again should have caused an alarm bell to ring, but alas it took me quite some time to figure it out: repeatable is a hint that the problem might be a software issue, not hardware.

So the next step was to use the data dump feature from the scope to collect the data written and well as the data being read back. These can be saved as CSV files, and with a bit of scripting, I ended up with this comparison:

Screen Shot 2013-03-19 at 10.47.35

This shows three editor windows super-imposed and lined up with, from left to right:

  • the data read back
  • the data written
  • the hex file with the compiled sketch

As you can see, the writes are exactly what they should be – it’s the read which gives junk. And it’s not even that far off – just a few bits!

Looking closer, it is clear that some bits are “0” where they should have been “1”.

Uh, oh – I think I know what’s going on…

It looks like the chip hasn’t gone through an erase cycle! Flash programming works as follows: you “erase” the memory to set all the bits to “1”, and then you “program” it to set some of them to “0”. Programming can only flip bits from “1” to “0”!

And indeed… that was the problem. The Arduino boot loaders are set up to auto-erase on request, so avrdude is called from the IDE with “bulk erase” disabled. That way, the IDE just sends the pages it wants to program, and the boot loader will make sure the erase is performed just before writing the page.

In this case, however, there is no boot loader: we are using the normal ISP conventions, whereby erasing and programming must be explicitly requested.

It was a matter of dropping the “-d” “-D” flag from the avrdude command in platform.txt:

DSC_4425

And now it works, flawlessly! Doh – this “bug” sure has kept me busy for a while…

Wild goose chase

In AVR, Hardware, Software on Mar 25, 2013 at 00:01

Sometimes, when messing with stuff, you end up in a blind alley which makes no sense…

This happened to me a few days ago, as I was trying to get a good setup going for programming the new JeeNode Micro v3.

The code in the IDE was working, I was able to program the JNµ via avrdude on the command line, but for some crazy reason, the same thing just kept failing when launched through the new 1.5.2 Arduino IDE. Getting that to work would make all the difference in the world, since it means you don’t need to install anything other than the IDE (on any platform) and then simply drop in the ide-hardware folder.

Very odd: a Flash Board which works on one Mac with avrdude, but fails with the IDE, which also uses avrdude. Time to set up the scope in Logic Analyser mode! Lots of wires, lots of configuration to identity all the signals, and then the fun starts: locating the spot in the data stream which would allow me to see what was going on.

Here is a peek at the SPI bus, decoded where it is reporting the ATtiny84 signature bytes:

SCR77

Looks ok. Next, instead of looking at the SPI bus, I looked at the 9600 baud serial data:

SCR83

It’s a slower time scale, since the bit stream is not as fast, thus allowing to capture more information (2 M samples are not that much when sampling at fixed time intervals, since you have to sample often enough to reliably decode the data stream).

I even suspected the power supply lines, and had a look at VCC as an analog trace:

SCR85

And although it’s not very clean, this wasn’t the problem either. Drat…

Since the verification was failing, I decided to capture the data read-back in the second half of the programming process. The way to do this, is to set the trigger on the RESET line going low at the start, and then delaying the capture by about 4 seconds. As you can see in that last screenshot, this is the point where avrdude switches from writing data into flash memory to reading the data back.

And sure enough, the data read back was wrong. Not much, but just some bits flipped – consistently, and reproducably!

It wasn’t a hardware problem after all! A wild good chase: final episode tomorrow…

JeeNode Micro breakout

In AVR, Hardware on Mar 24, 2013 at 00:01

While messing around with a bunch of JeeNode Micro’s here, I decided to create a little convenience breakout board for it:

DSC_4399

Sooo many ways to mess up – it definitely helps to avoid silly mistakes! This particular board doesn’t do that much, but it’s still a nice convenience when you’re drowning in cables and trying to debug some of the nastier bits, such as the Flash Board ISP programmer:

DSC_4406

The above setup was the result of what turned out to be a wild goose chase – stay tuned…

JN Micro v3 reference

In AVR on Mar 23, 2013 at 00:01

As promised, here is the reference card for the JeeNode Micro v3:

qrc-jm-v3-part

(Click on the image to see the full-size version)

Note: the definitions in Ports.h were incorrect for the JeeNode Micro. Please make sure you update to the latest version of JeeLib if you intend to use the Port or PortI2C classes with the ATtiny84 on the JeeNode Micro!

The thing with diagrams such as these, is that they are hampered by file format wars, with all full-featured drawing apps going out of their way to lock people in. In this case, the diagrams where created by Marco Bakker in Visio on Windows – which I don’t have – so I imported it into OmniGraffle for Mac – which is in turn useless on other platforms.

Luckily, PNG and PDF have become de-facto standards which every browser knows how to display – so rendering the diagrams at least produces results everyone can use.

Maybe one day, we’ll all be using SVG editors. There’s a web-based one called SVG-edit, but it doesn’t seem to be quite there yet w.r.t. importing the SVG from OmniGraffle. There is also the multi-platform Inkscape, which does import the SVG very nicely (just one minor font size issue, as far as I can tell). But the UI is a bit quirky on the Mac, since it has to conform to the XQuartz conventions of the X.Org X Window System (aka X11).

I’ve updated the Pinouts page on the Hardware wiki to include these new Quick Reference Cards, and have attached the design and output files in different formats.

JeeNode v6 reference

In AVR on Mar 22, 2013 at 00:01

What started out as a great initiative on the forum has now become a complete “Quick Reference Card” for the JeeNode v6. With many many thanks to @mars for working out all the details and tweaks and for sharing his design files:

qrc-jn-v6-part

(Click on the image to see the full-size version)

Here is the legend and the Creative Commons attribution:

legend   attribution

Tomorrow, I’ll post the other reference card for the JeeNode Micro (after a bit more checking), along with links to the final version in several formats on the wiki.

Programming the JNµ – at last!

In AVR, Hardware, Software on Mar 21, 2013 at 00:01

Yesterday’s post shows that it the JNµ can be easily be programmed using the standard Arduino IDE, if you get all the pieces right (isn’t that always the case?):

Screen Shot 2013-03-19 at 14.34.08

The easiest way to get the connections right, is to assemble a custom cable (more):

DSC_4429

What about the software setup? Well, that too is now very simple:

  • download and install a copy of the Arduino IDE 1.5.2
  • create a folder called “hardware” inside your IDE’s “sketchbook” folder
  • download or – preferably – clone the new ide-hardware package from GitHub
  • rename it to “jeelabs” (!) and move it inside the “hardware” folder

The new jcw/ide-hardware project on GitHub was adapted from the arduino-tiny project on Google Code. I didn’t want to wait for that project (it hasn’t been updated for over 6 months), and decided to create a fork on GitHub instead. I did find two other such forks – rambo/arduino-tiny and james147/arduino-tiny, but neither of them appears to offer a major advantage – and since I had to rearrange things to make it work with the IDE 1.5.x structure, there does not seem to be much point in basing things off those forks.

The result of all these steps is that you now have the following new options:

  • use the Tools -> Programmer menu to select “Arduino as ISP”
  • select “JeeNode Micro” from the Tools -> Boards menu to build for that setup
  • use the Tools -> Burn Bootloader menu to set up the fuses
  • use the standard “Upload” button to upload a sketch using this ISP-based setup:

    Screen Shot 2013-03-20 at 16.42.05

Those two warnings are harmless, and can be ignored (I don’t know how to avoid them).

That’s it!

Update – Fixed a problem with setting fuses, make sure you use latest code from github.

Programming the JNµ – again

In AVR, Hardware on Mar 20, 2013 at 00:01

Given that the JeeNode Micro is based on an ATtiny84 and not the standard ATmega used in Arduino’s and clones, it has always been quite tricky to make things work on the JNµ.

No more:

Screen Shot 2013-03-19 at 14.34.08

The new (and still somewhat experimental) Arduino IDE 1.5.2 adds much better support for other process cores, making it possible to set up things as shown above, and then you can just use the “Upload” button to get things loaded into a JeeNode Micro.

It’s all based on setting up a JeeNode (or other 3.3V-level Arduino clone) to run as ISP programmer, and then a few wires to hook it up to a “target” JeeNode Micro. The IDE now includes an ISP programmer setup, but I tend to use the Flash Board for this – in combination with the isp_flash.ino sketch, which was recently updated to run at 9600 baud i.s.o. 19200, to make it compatible with what the IDE expects by default:

DSC_1400_large

For more information about ISP programming, see this post and tag on this daily weblog.

Tomorrow, I’ll describe the steps needed to set things up. Stay tuned…

Programming the JNµ v3 – part 2

In AVR, Software on Mar 7, 2013 at 00:01

It’s a long and winding road, that path to finding an easy way to program the JeeNode Micro v3, as mentioned two days ago. With emphasis on the “easy” adjective…

Let me at least describe the process details of what I’ve been using so far:

  1. A custom cable to connect the JNµ to an ISP programmer
  2. Installed copy of the “arduino-tiny” project from Google Code
  3. A trick to get the Arduino IDE compile the sketch into a HEX file
  4. Setting up the JeeNode + Flash Board as an ISP programmer
  5. Using avrdude directly, to set the fuses and upload the sketch into the JNµ

It works, in fact it works fine once you’ve set it all up – but easy? Hm…

Let’s go through each of these in turn.

1. Custom cable

This was described a few days ago. Let me just add that it’s very easy to take apart the connectors on the Extension Cable, once you know the trick:

DSC_4409

It’s all a matter of gently lifting the plastic tabs, then the wires come sliding out. Note that this is the wrong end of the cable for our case – but the other end works the same.

2. Arduino-tiny

These files on Google Code contain all the necessary code to trick the Arduino IDE into compiling for ATtiny processors, including the ATtiny84 used in the JNµ.

It works with IDE 1.0.x as is, if you follow the instructions, but I’ve been reorganising it to meet the requirements of the new multi-architecture IDE 1.5.x series, which would support this as a straight drop-in. I’m still working on it, but it means you can then just press the “Upload” button – a lot simpler than the process being described in this post!

3. Hex files

Normally, the Arduino IDE takes care of everything: compilation as well as uploading. However, for this setup, we need to get hold of the raw HEX file that gets generated before uploading. There’s a preference in the IDE for that:

Screen Shot 2013-03-06 at 10.22.12

Now the nasty bit: you have to compile (“run” in Arduino IDE terms, go figure!) the sketch to see the output that gets generated, and then copy the full path from the output window:

Screen Shot 2013-03-06 at 10.23.36

In this case, it’s that “/var/folders/…/radioBlip2.cpp.hex” thing.

4. ISP programmer

To turn the JeeNode + Flash Board combo into an ISP programmer, upload the isp_flash.ino to it. Make sure you get the very latest version, which uses 9600 Baud for communication, as that makes it compatible with the “Arduino as ISP” programmer:

Screen Shot 2013-03-06 at 15.36.07

As mentioned before, you don’t really need the Flash Board at this stage – a couple of wires will also work fine (see these posts about all the ways this can be done).

5. Avrdude

The last step is to call the “avrdude” uploader from the command line, specifying all the arguments needed, and pasting in that full file name. In my case, it was something like:

avrdude -v -v -pattiny84 -cstk500v1 -P/dev/tty.usbserial-A600K04C \
  -b9600 -D -Uflash:w:/var/folders/.../radioBlip2.cpp.hex:i

Oh, and if this is the first time you’re programming this ATtiny84 chip, then you also have to first set the fuses properly, as follows:

avrdude -v -v -pattiny84 -cstk500v1 -P/dev/tty.usbserial-A600K04C \
  -b9600 -e -U lfuse:w:0xC2:m -U hfuse:w:0xDF:m -U efuse:w:0xFF:m

That’s the internal RC oscillator with fastest startup, and the brown-out level set to 1.8V.

As I said, this is the messy way to do things. I’ll try to have something simpler soon!

Programming the JNµ v3 – part 1.5

In AVR, Hardware on Mar 5, 2013 at 00:01

After having created the cable, I was going to set up the AVRISP MkII programmer…

AVRISPmkII

Things didn’t work out as planned, alas. When having some problems (unrelated, and due to a wrong part choice, as it turned out), I wanted to make sure that the AVRISP was really set up properly, and decided to install AVR Studio 6.0 …

Hm. Since I don’t have any computers running Windows, this had to be done in a virtual machine (running under Parallels in my case). Easy, right? Yeah, well, I do keep an image around for cases like these, so I downloaded the installer from Atmel, and a little later it was indeed running. Lost some 4 GB of disk space (nuts), and it installed all sorts of stuff as part of the deal (nuts), but hey, that’s how software should be… apparently (nuts!).

Plugging in the AVRISP, I got a message from AVR Studio that I had to upgrade its firmware (it worked fine with avrdude, but hey, who am I to argue). This was not an option, but a requirement (nuts).

So I proceded with the upgrade… piece of cake, right?

Whoops! As part of the upgrade, the device drops off the USB bus, at which point Parallels ceased to recognise it. Unrecognised devices can’t be attached to a Windows VM.

So the end result is: a “bricked” AVRISP programmer, which can probably only be restored on a non-VM install of Windows. Nuts!

I’m going to switch to the Flash Board, which works and has a normal upgrade process:

DSC_1400_large

Note that I’m not using the on-board EPROM or button. A few wires could also be used.

It’s easy to use as a programmer, when you’re used to the Arduino IDE and avr-gcc way of doing things: install the flash.ino sketch on a JeeNode, insert this thing on top, and you end up with an ISP programmer which is recognised by avrdude by using the parameters “-p stk500v1” and “-B 19200”, and the serial port as “-P …”.

So much for closed source & lock-in – stuff I can’t control. ISP mode resumes tomorrow!

JNµ battery tests

In AVR, Hardware on Mar 4, 2013 at 00:01

With the LiPo battery “blipping” along happily for years now, I’ve started two new tests, based on the JeeNode Micro v3. Here’s the boost unit, running an updated radioBlip2.ino:

DSC_4401

This one converts the incoming 1.2 .. 1.4 V from a single-cell Eneloop AA battery to roughly 3.0 V, as you can see in this overview in HouseMon (using an updated “radioBlip” driver):

Screen Shot 2013-03-04 at 00.59.28

The other new node runs off a CR2032 coin cell, which is struggling a bit to maintain a stable voltage each time a packet gets sent out, as indicated by the 3.20 -> 3.08 V drop. In case you’re wondering how a node can report its battery voltage after already having sent the data, simple: measure the voltage and send it out in the next packet.

The technique used to measure one’s own battery voltage was described in a post last year. Measuring the battery voltage in this way does not consume very much power in itself, since the ATtiny is placed in a special low-power “ADC-only” sleep mode while doing so:

SCR72

The energy used for the measurement is the area under those last four little “blips” after the main packet transmission: there’s almost no penalty in performing this measurement before and after each packet transmission. Over time, hopefully the trend of the before + after voltages can be used as predictor for the amount of life left in them little coin cells…

PS – The main change in the radioBlip2 sketch, apart from adapting it to work on the ATtiny, is that the packet now includes a “sender ID” byte. This way all the battery test nodes can re-use the same node ID here at JeeLabs – since the number of ID’s used is starting to become a concern (there are 30 unique ID’s in each net group). For nodes like these, which only send, it’s no problem at all to “re-use” node ID’s this way.

Update – I’ve added a “BOOST” option to report the battery input voltage, which is much more useful. It’s measured with a jumper from PWR to the AIO pin (PA0, analog 0).

Programming the JNµ v3 – part 1

In AVR, Hardware on Mar 3, 2013 at 00:01

The new JeeNode Micro v3 announced yesterday does some very subtle things w.r.t. how it deals with the SPI bus during ISP programming (don’t you love those silly acronyms?). I’ll have a lot more to tell about this in a future weblog post, but for now let’s just focus on getting a new sketch into the ATtiny84 chip!

As mentioned yesterday, there is no longer a standard 2×3 ISP header on this board. It’s just a 4-pin header, with GND and VCC obtained from the 8-pin header on the side of the board. For reference, here is the ISP header pinout as most ISP programmers expect it:

ISP 6 way pinout

In my case, I wanted to use the modified AVRISP mkII programmer, so I’ve set up a little cable + breadboard hack, as follows:

DSC_4396

The 2×3 to 6-pin (actually 5-pin) header was constructed from an Extension Cable. Here is the hookup, using 2×3 long header pins to connect the 2 female ends together:

DSC_4397

And here’s the breadboard side of things, in close-up:

DSC_4398

Note the sixth wire (providing or sensing VCC power), which goes to either +3V or PWR on the main header. This flexibility will in fact turn out to be quite convenient when dealing with direct-power vs boost-power versions of the JeeNode Micro.

So much for the hardware side of things. The software side turned out to be a lot trickier, and I’d like to take a little more time to work out the best way to do things. After a short intermezzo tomorrow, will come part 2 – stay tuned!

Meet the JeeNode Micro v3

In AVR, Hardware on Mar 2, 2013 at 00:01

There’s a new kid in town, the JeeNode Micro v3 with ATtiny84 + optional boost converter:

DSC_4392

(Can you spot the differences? That’s without and with buck/boost converter…)

It’s even shorter than the v2, and has all the components on one side again:

DSC_4385

The main reason for the reduced size is the reduced number of header pins. One of the biggest changes in that regard, is that v3 no longer has a full 2×3 ISP header – just the 4 data pins. The idea is that GND and +3V can be connected to the 8-pin “port+” header.

As it so happens, there’s a fifth pad on the bottom side of the PCB which connects to GND. This can be put to good use for experimentation, by connecting some headers as follows:

DSC_4393

Note that the 6th pin was removed from the female header – this is very easy to do: just pull on the pin from the bottom with some pliers and it’ll slide out.

That leaves just power to be connected up for SPI programming. More details tomorrow…

Taking the JNµ to 3.0 V

In AVR, Hardware on Mar 1, 2013 at 00:01

As mentioned in yesterday’s post, lower supply voltages lead to lower power consumption.

There’s a new JeeNode Micro v3 revision coming which applies this logic to try and get the power consumption as low as possible. It also has changed slightly in its pinout:

Screen Shot 2013-02-26 at 09.30.47

The main physical changes are: it’s now 16 x 43 mm, and the ISP pins are no longer 2×3.

Let’s just focus on the power side of things for now, though. The JNµ v3 can be operated from several power sources:

  • Direct power: this runs without regulation, and requires a 2.2V .. 3.8V power source
  • Boost power: using the same circuit as the AA Power Board, runs from 0.9V .. 5.0V

The boost power circuit is very flexible as you can see, but it adds a certain amount of quiescent power consumption of its own, making the whole setup draw more idle current than when it is directly powered. What you do get with the boost power hookup, is that it’ll try to stay running as long as possible, down to a 0.5 V input under ideal conditions, so this thing will squeeze the last drop of energy out of its power source. Great for “empty” AA’s!

Boost power supplies are very clever and useful circuits, but they can’t break the laws of physics: a 100% efficient boost supply will draw 15 mA when asked to generate a 3.3 V @ 5 mA output from a 1.1 V input source. The current it draws will be triple that which it produces (more like four times, in fact, since the real circuit is far from 100% efficient).

Note that – in the light of yesterday’s story – it would really make no sense to pump up the voltage to say 5V, only to end up with a more wasteful circuit. That’s not just a quadratic increase, those losses would in fact be proportional to the third power of the voltage!

With a boost circuit, it really pays to work with as low an output voltage as possible. Which is why the JeeNode Micro v3 now comes with a 3.0V version of the boost chip, not 3.3V.

Let’s do the math, assuming a 100% efficient boost supply:

  • a 3.0 V booster draws 3.0 / 3.3 ≈ 91% of the current in comparison to a 3.3 V one
  • running at 3.0 V instead of 3.3 V consumes ≈ 83% of the power (with a resistive load)
  • combined, that means we’ll be using 3.0 ^ 3 / 3.3 ^ 3 ≈ 75% of the power at 3.0 V
  • so the total power consumed is 25% less at 3.0 V compared to what it’d take at 3.3V

That translates to 3 more months on a battery lifetime of 1 year – quite a bit!

This doesn’t just apply to the boost regulator: coin cells often have a 3.0V rating, and so do 2 alkaline AA batteries in series. Note also that 2 rechargable AA batteries will still work fine, as these will supply 2.4..2.6 V, well within the direct power range of the JNµ v3.

Note that for all the standard JeeNodes, nothing changes: these will continue to be populated with 3.3V regulators. One key reason for this is that they are already operating slightly beyond their specs (“overclocked”) with the clock running at 16 MHz. We shouldn’t push our luck with these settings, which are standard in the Arduino world. So the JN, JN SMD, and JN USB will all continue to be operated at 3.3V – no changes!

As for the many different JeePlugs: these all run at 3.3V, and the chips used on these plugs are normally qualified to run at either 3.0 .. 3.6V or 2.7 .. 3.3V, so we’re still fully in range.

Is it all win, then? Well, yes, but note that the noise margins are slightly reduced at 3.0V, which can slightly affect the accuracy of analog pin measurements and the cable lengths at which I2C chips still operate reliably. These effects are going to be minimal, I expect, but it’s something to watch out for.

Update – As pointed out in the comments, the above calculations are not correct. There is a small effect on booster circuit efficiency in all this, but the power savings are closer to 20% than 25% – not quite 3 months per year, as I claimed.

Dropping below 3.3 V

In AVR, Hardware on Feb 28, 2013 at 00:01

One of the departures from the Arduino world has always been that JeeNodes operate at 3.3 V, whereas the standard Arduino’s all ran at 5 V. Things are changing, with the ARM-based “Arduino Due”, for example, which also runs at 3.3 V. There’s not really a choice: ARM chips all run at 3.3V or less (3.6V max actually, which leaves a nice safety margin).

So what’s this trend towards lower voltages all about, eh?

Well… you may have seen an older post in the Easy Electrons series (whoa, over two years ago.. time flies!). If you think about it for a moment, all the electric energy pumped into a circuits will end up being converted into some other form of energy: a teeny tiny bit of radiated RF energy in the case of a JeeNode, but mostly heat, really.

Odd as it may seem, all that electronic stuff is just a way to turn current into heat. There is a purpose for this, since we’re usually interested in the side effects: some physical sensing and some computation, leading to the information we’re interested in. But the electricity consumption is just an (unavoidable) side-effect.

Whenever we can lower the voltage and/or current consumption, we’ll end up consuming less power as a result (W = I x V). Lowering the voltage on a circuit often leads to a dramatic reduction in power, since part of a circuit is always resistive. Ohm’s law says that voltage = resistance x current, or to put it differently: current = voltage / resistance. So halving the voltage (V) over a resistor also halves the current (I) it draws. The effect: half the voltage leads to a quarter of the power consumption, in purely resistive circuits:

JC's Grid, page 65

Unfortunately, you can’t just use 0.1 V to power a circuit: bipolar semiconductors such as diodes and transistors have a 0.6V threshold voltage, anything below that renders them useless. In the real world, running digital circuits at under 1.0 V is rarely done. Even that 1.8 V level down to which an ATmega and ATtiny can be operated is pushing some limits.

Another reason is that lower voltages make capacitive effects more dominant. The lower you go, the longer it takes to charge or discharge a capacitor. Which explains why the ATmega’s maximum clock speed must drop to 4 MHz with a supply voltage of 1.8 V.

But lowering the clock speed is somewhat self-defeating, as this means that the ATmega and ATtiny have to remain powered-up longer before going back into deep-sleep mode! Lots of trade-offs. Still: a low supply voltage is often a good idea – generally speaking.

Tomorrow, I’ll describe the choices made for the next revision of the JeeNode Micro…

HouseMon resources

In AVR, Hardware, Software, Musings, Linux on Feb 6, 2013 at 00:01

As promised, a long list of resources I’ve found useful while starting off with HouseMon:

JavaScript – The core of what I’m building now is centered entirely around “JS”, the language behind many sites on the web nowadays. There’s no way around it: you have to get to grips with JS first. I spent several hours watching most of the videos on Douglas Crockford’s site. The big drawback is the time it takes…

Best book on the subject, IMO, if you know the basics of JavaScript, is “JavaScript: The Good Parts” by the same author, ISBN 0596517742. Understanding what the essence of a language is, is the fastest way to mastery, and his book does exactly that.

CoffeeScript – It’s just a dialect of JS, really – and the way HouseMon uses it, “CS” automatically gets compiled (more like “expanded”, if you ask me) to JS on the server, by SocketStream.

The most obvious resource, http://coffeescript.org/, is also one of the best ways to understand it. Make sure you are comfortable with JS, even if not in practice, before reading that home page top to bottom. For an intruiging glimpse of how CS code can be documented, see this example from the CS compiler itself (pretty advanced stuff!).

But the impact of CS goes considerably deeper. To understand how Scheme-like functional programming plays a role in CS, there is an entertaining (but fairly advanced) book called CoffeeScript Ristretto by Reginald Braithwaite. I’ve read it front-to-back, and intend to re-read it in its entirety in the coming days. IMO, this is the book that cuts to the core of how functions and objects work together, and how CS lets you write on a high conceptual level. It’s a delightful read, but be prepared to scratch your head at times…

For a much simpler introduction, see The Little Book on CoffeeScript by Alex MacCaw, ISBN 1449321046. Also available on GitHub.

Node.js – I found the Node.js in Action book by Mike Cantelon, TJ Holowaychuk and Nathan Rajlich to be immensely useful, because of how it puts everything in context and introduces all the main concepts and libraries one tends to use in combination with “Node”. It doesn’t hurt that one of the most prolific Node programmers also happens to be one of the authors…

Another useful resource is the API documentation of Node itself.

SocketStream – This is what takes care of client-server communication, deployment, and it comes with many development conveniences and conventions. It’s also the least mature of the bunch, although I’ve not really encountered any problems with it. I expect “SS” to evolve a bit more than the rest, over time.

There’s a “what it is and what it does” type of demo tour, and there is a collection on what I’d call tech notes, describing a wide range of design docs. As with the code, these pages are bound to change and get extended further over time.

Redis – This a little database package which handles a few tasks for HouseMon. I haven’t had to do much to get it going, so the README plus Command Summary were all I’ve needed, for now.

AngularJS – This is the most framework-like component used in HouseMon, by far. It does a lot, but the challenge is to understand how it wants you to do things, and altough “NG” is not really an opinionated piece of software, there is simply no other way to get to grips with it, than to take the dive and learn, learn, learn… Let me just add that I really think it’s worth it – NG can be magic on the client side, and once you get the hang of it, it’s in fact an extremely expressive way to create a responsive app in the browser, IMO.

There’s an elaborate tutorial on the NG site. It covers a lot of ground, and left me a bit overwhelmed – probably because I was trying to learn too much as quickly as possible…

There’s also a video, which gives a very clear idea of NG, what it is, how it is used, etc. Only downside is that it’s over an hour long. Oh, and BTW, the NG FAQ is excellent.

For a broader background on this sort of JS frameworks, see Rich JavaScript Applications by Steven Sanderson. An eye opener, if you’ve not looked into RIA’s before.

Arduino – Does this need any introduction on this weblog? Let me just link to the Reference and the Tutorial here.

JeeNode – Again, not really much point in listing much here, given that this entire weblog is more or less dedicated to that topic. Here’s a big picture and the link to the hardware page, just for completeness.

RF12 – This is the driver used for HopeRF’s wireless radio modules, I’ll just mention the internals weblog posts, and the reference documentation page.

Vim – My editor of choice, lately. After many years of using TextMate (which I still use as code browser), I’ve decided to go back to MacVim, because of the way it can be off-loaded to your spine, so to speak.

There’s a lot of personal preference involved in this type of choice, and there are dozens of blog posts and debates on the web about the pro’s and con’s. This one by Steve Losh sort of matches the process I am going through, in case you’re interested.

Best way to get into vim? Install it, and type “vimtutor“. Best way to learn more? Type “:h<CR>” in vim. Seriously. And don’t try to learn it all at once – the goal is to gradually migrate vim knowledge into your muscle memory. Just learn the base concepts, and if you’re serious about it: learn a few new commands each week. See what sticks.

To get an idea of what’s possible, watch some videos – such as the vim entries on the DAS site by Gary Bernhardt (paid subscription). And while you’re at it: take the opportunity to see what Behaviour Driven Design is like, he has many fascinating videos on the subject.

For a book, I very much recommend Practical Vim by Drew Neil. He covers a wide range of topics, and suggests reading up on them in whatever order is most useful to you.

While learning, this cheatsheet and wallpaper may come in handy.

Raspberry Pi – The little “RPi” Linux board is getting a lot of attention lately. It makes a nice setup for HouseMon. Here are some links for the hardware and the software.

Linux – Getting around on the command line in Linux is also something I get asked about from time to time. This is important when running Linux as a server – the RPi, for example.

I found the linuxcommand.org resource which appears to do a good job of explaining all the basic and intermediate concepts. It’s also available as a book, called “The Linux Command Line” by William E. Shotts, Jr. (PDF).

There… the above list ought to get you a long way with all the technologies I’m currently messing around with. Please feel free to add pointers and tips in the comments, if you think of other resource which can be of use to fellow readers in this context.

Dive Into JeeNodes

In AVR, Hardware, Software, Linux on Feb 1, 2013 at 00:01

Welcome to a new series of limited-edition posts from JeeLabs! Read ’em while they last!

Heh… just kidding. They’ll last forever of course, as does everything on this thing called internet. But what I’m going to describe in probably a dozen posts or so is the following:

dijn-essence

Hm, that doesn’t quite explain it, I guess. Let me try again:

JC's Grid, page 63

So this is to announce a new “DIJN” series of weblog posts, describing how to set up your own Wireless Sensor Network with JeeNodes, as well as the infrastructure to report a measured light-level somewhere in your house, in real time. The end result will be fully automated and autonomous – you could take your mobile phone, point it to your web server via WiFi, and see the light level as it is that very moment, adjusting as it changes.

This is a far cry from a full-fledged home monitoring or home automation system, clearly – but on the other hand, it’ll have all the key pieces in place to explore whatever direction interests you: ready-made sensors, DIY sensors, your own firmware on the remote nodes, your own web pages and automation logic on the central server… it’s up to you!

Everything is open source, which in this context matters a lot, because that also means that you can really dive into any aspect of this to learn and explore the truly magical world of Physical Computing, Wireless Sensor Networks, environmental sensing and control, as well as state-of-the art web technologies.

The focus will be on describing every step needed to implement this from scratch. I’ll cover setting up all the necessary software and hardware, in such a way that if you know next to nothing about any of the domains involved, you can still follow along and try it out – whether your background is in software, electronics, wireless, or none of these.

If technology interests you, and if I can bring across even a small fraction of the fun there is in tinkering with this stuff and making new things up as you g(r)o(w) along, then that would be a very nice reward for everyone involved, as far as I’m concerned.

PS. “Dijn” is also old-Dutch for “your” (thy, to be precise). Quite a fitting name in my opinion, as this sort of knowledge is really yours for the taking – if you want it…

PPS. For reference: here is the first post in the series, and here is the overview.

Arduino sketches on RPi

In AVR, Software, Linux on Jan 17, 2013 at 00:01

There’s an arduino-mk package which makes it simple to build and upload sketches on a Raspberry Pi. Here’s how to set it up and use it with a JeeLink, for example:

Install the package:

  sudo apt-get install arduino-mk

That gets all the required software and files, but it needs a tiny bit of setup.

First, create the library area with a demo sketch in it:

  mkdir ~/sketchbook
  cd ~/sketchbook
  ln -s /usr/share/arduino/Arduino.mk
  mkdir blink
  cd blink

Then create two files – the blink.ino sketch for a JeeLink or JeeNode SMD / USB:

// Blink - adapted for a JeeNode / JeeLink

void setup() {
  pinMode(9, OUTPUT);
}

void loop() {
  digitalWrite(9, LOW);
  delay(1000);
  digitalWrite(9, HIGH);
  delay(1000);
}

… and a Makefile which ties it all together:

BOARD_TAG    = uno
ARDUINO_PORT = /dev/ttyUSB0
ARDUINO_LIBS =
ARDUINO_DIR  = /usr/share/arduino

include ../Arduino.mk

(that Arduino.mk file in the sketchbook/ dir is well-commented and worth a read)

That’s it. You now have the following commands to perform various tasks:

  make             - no upload
  make upload      - compile and upload
  make clean       - remove all our dependencies
  make depends     - update dependencies
  make reset       - reset the Arduino by tickling DTR on the serial port
  make raw_upload  - upload without first resetting
  make show_boards - list all the boards defined in boards.txt

The first build is going to take a few minutes, because it compiles the entire runtime code. After that, compilation should be fairly snappy. Be sure to do a make clean whenever you change the board type, to re-compile for a different board. The make depends command should be used when you change any #include lines in your code or add / remove source files to the project.

This setup makes things run smoothly, without requiring the Arduino IDE + Java runtime.

Assembling the LED Node v2

In AVR, Hardware on Dec 28, 2012 at 00:01

After yesterday’s little mistake, here’s a walk-through of assembling the LED Node v2:

DSC_4332

Note that the LED Node comes with pre-soldered SMD MOSFETs so you don’t have to fiddle with ’em.

The LED Node is really just a JeeNode with a different layout and 3 high-power MOSFET drivers, to control up to 72W of RGB LED strips through the ATmega’s hardware PWM. Since there’s an RFM12B wireless module on board, as well as two free JeePorts, you can do all sorts of funky things with it.

As usual, the build progresses from the flattest to the highest components, so that you can easily flip the PCB over and press it down while soldering each wire and pin.

Let’s get started! So we begin with 7 resistors and 1 diode (careful, the diode is polarised):

DSC_4333

Be sure to get the values right: 3x 1 kΩ, 3x 1 MΩ, and 1x 10 kΩ (next to the ATmega).

(note: I used three 100 kΩ resistors i.s.o. of 1 MΩ, as that’s what I had lying around)

Next, add the 4x 0.1 µF capacitors and the IC socket – lots of soldering to do on that one:

DSC_4334

Then the MCP1702 regulator and the electrolytic capacitor (both are polarised, so here too, make sure you put them in the right way around), as well as the male 6-pin FTDI header:

DSC_4335

Soldering the RFM12B wireless radio module takes a bit of care. It’s easiest if you start off by adding a small solder dot and hold the radio while making the solder melt again:

DSC_4336

Then solder the remaining pins (I tend to get lazy and skip those which aren’t used, hence not all of them have solder). I also added the 3-pin orange 16 MHz ceramic resonator, the antenna wire, the two port headers, and the big screw terminal for connecting power:

DSC_4337

Celebration time – we’ve completed the assembly of the LED Node v2!

Here’s a side view, with the ATmega328 added – as you can see it’s much flatter than v1:

DSC_4338

And here’s a top view of the completed LED Node v2, in all its glory:

DSC_4339

You can now connect the FTDI header via a USB BUB, and you should see the greeting of the RF12demo sketch, which has been pre-loaded onto the ATmega328.

To get some really fancy effects, check out the Color-shifting LED Node post from a while back on this weblog. You can adjust it as needed and then upload it through FTDI.

Next step is to attach your RGB strip (it should match the 4-pin connector on the far left). Be sure to use fairly sturdy wires as there are up to 2 amps going through each color pin and a maximum of 6 amps total through the “+” connector pin!

Lastly, connect a 12V DC power supply (making absolutely sure to get the polarity right!) and you will have a remote-controllable LED strip. Enjoy!

The difference between 2 and 3

In AVR, Software on Nov 13, 2012 at 00:01

One. Ok, next post :)

I was curious about the difference between Power-down and Standby in the ATmega328p. Power-down turns off the main clock (a 16 MHz resonator in the case of JeeNodes), whereas standy keeps it on. And quite surprised by the outcome… read on.

There’s an easy way to measure this, as far as software goes, because the rf12_sendWait() function has an argument to choose between the two (careful: 2 = Standby, 3 = Power-down – unrelated to the values in the SMCR register!).

I tweaked radioBlip.ino a bit, and came up with this simple test sketch:

Screen Shot 2012 11 05 at 18 13 23

With this code, it’s just a matter of hooking up the oscilloscope again in current measurement mode (a 10 Ω resistor in the power line), and comparing the two.

Here’s the standby version (arg 2):

SCR76

… and here’s the power-down version (arg 3), keeping the display the same:

SCR73

I’ve zoomed in on the second byte transmission, and have dropped the baseline by 21 mA to properly zoom in, so what you’re seeing is the ATmega waking up to grab store a single byte out of into the RFM12B’s reception FIFO, and then going back to sleep again.

The thing to watch is the baseline level of these two scope captures. In the first case, it’s at about 0.5 mA above the first division, and the processor quickly wakes up, does it’s thing, and goes into power-save again.

In the second case, there’s a 40 to 50 µs delay and “stutter” as the system starts its clock (the 16 MHz resonator), does its thing, and then goes back to that ultra-low power level.

There are bytes coming in going out once every 200 µs, so fast wakeup is essential. The difference is keeping the processor drawing 0.5 mA more, versus a more sophisticated clock startup and then dropping back to total shutdown.

What can also be gleaned from these pictures, is that the RF12 transmit interrupt code takes under 40 µs @ 16 MHz. This explains why the RF12 driver can work with a clock frequency down to 4 MHz.

The thing about power-down mode (arg 3), is that it requires a fuse setting different from what the standard Arduino uses. We have to select fast low-power crystal startup, in 258 cycles, otherwise the ATmega will require too much time to start up. This is about 16 µs, and looks very much like that second little hump in the last screen shot.

Does all this matter, in terms of power savings? Keep in mind that this is running while the RFM12B transmitter is on, drawing 21 mA. This case was about the ATmega powering down between each byte transmission. Using my scope’s math integral function, I measured 52.8 µC for standby vs 60.0 µC for power-down – so we’re talking about a 12 % increase in power consumption during transmit!

The explanation for this seemingly contradictory result is that the power-down version adds a delay before it actually sends out the first byte to transmit. In itself that wouldn’t really make a difference, but because of the delay, the transmitter stays on noticeably longer – wiping out the gains of shutting down the main clock. Check this out:

SCR77

Standby is the saved white reference trace, power-down is yellow.

See? Ya’ can’t always predict this stuff – better measure before jumping to conclusions!

PS. While I’m at it – enabling the RF12’s “OPTIMIZE_SPI” mode lowers charge usage only a little: from 52.8 to 51.6 µC, i.e. using fast SPI @ 8 MHz i.s.o. 2 MHz for sending to the RFM12B. Hardly worth the trouble.

Using watchdog resets

In AVR, Hardware, Software on Nov 9, 2012 at 00:01

The Bluetooth readout node running the “smaRelay” code is ready to go:

DSC 4237

As mentioned yesterday, I’ve decided to take the easy way out and completely power down the Bluetooth module and go through a full powerup/connect/readout cycle about once every 5 minutes.

The advantage for me of a battery-powered unit, is that I don’t have to locate this thing near a power outlet – it can be placed out of sight, unobtrusively doing its work.

I seem to have developed an allergy for power cables and wall warts all over the place…

The power on/off logic held a little surprise, about which I’ll report tomorrow.

Here’s is the new part of the updated smaRelay.ino sketch:

Screen Shot 2012 11 07 at 14 27 33

Quite a different use of the watchdog here:

  • on powerup, go into low-power mode and wait for 5 minutes
  • prepare the watchdog to perform a reset in 8 seconds
  • power up Bluetooth, connect to the SMA, and read out some values
  • then power down Bluetooth and power up the RFM12 radio
  • send out a data packet over RF12
  • lastly, turn the radio off and power down
  • let the watchdog do the reset and make this sketch start over

This approach has as “benefit” that it’ll fail gracefully: even if anything goes wrong and things hang, the hardware watchdog will pull the ATmega out of that hole and restart it, which then starts off again by entering an ultra-low power mode for 5 minutes. So even if the SMA is turned off, this sketch won’t be on more than about 1% of the time.

Here’s the energy consumption measurement of an actual readout cycle:

SCR80

The readings are a bit noisy – perhaps because I had to use 1 mV/div over a 1 Ω resistor (the 10 Ω used before interfered too much with this new power-switching code).

As you can see, the whole operation takes about 4 seconds. IOW, this node is consuming 153 milli-Coulombs every 300 seconds. That’s 0.5 mC/sec, or 0.5 mA on average. So the estimated lifetime on 3x AA 1900 mAh Eneloops is 3800 hours – some 5 months.

Update – The first set of batteries lasted until March 18th, 2013 – i.e. over 4 months.

Good enough for now. Deploy and forget. Onwards!

Verifying synchronisation over time

In AVR, Software on Nov 5, 2012 at 00:01

(Perhaps this post should be called “Debugging with a scope, revisited” …)

The syncRecv.ino sketch developed over the last few days is shaping up nicely. I’ve been testing it with the homePower transmitter, which periodically sends out electricity measurements over wireless.

Packets are sent out every 3 seconds, except when there have been no new pulses from any of the three 2000 pulse/kWh counters I’m using. So normally, a packet is expected once every second, but at night when power consumption drops to around 100 Watt, only every third or fourth measurement will actually lead to a transmission.

The logic I’m using was specifically chosen to deal with this particular case, and the result is a pretty simple sketch (under 200 LOC) which seems to work out surprisingly well.

How well? Time to fire up that oscilloscope again:

SCR68

This is a current measurement, collected over about half an hour, i.e. over 500 reception attempts. The screen was set in 10s trace persistence mode (with “false colors” and “background” enabled to highlight the most recent traces and keep showing each one, so all the triggers are superimposed on one another.

These samples were taken with about 300 W consumption (i.e. 600 pulses per hour, one per 6s on average), so the transmitter was indeed skipping packets fairly regularly.

Here’s a typical single trigger, giving a bit more detail for one reception:

SCR58

Lots of things one can deduce from these images:

  • the mid-level current consumption is ≈ 8 mA, that’s the ATmega running
  • the high-level current increases by another 11 mA for the RFM12B radio
  • almost all receptions are within 8..12 ms
  • most missing packets cause the receiver to stay on for up to some 18 ms
  • on a few occasions, the reception window is doubled
  • when that happens, the receiver can be on, but still no more than 40 ms
  • the 5 ms after proper reception are used to send out info over serial
  • the ATmega is on for less than 20 ms most of the time (and never over 50 ms)
  • it looks like the longer receptions happened no more than 5 times

If you ignore the outliers, you can see that the receiver stays on well under 15 ms on average, and the ATmega well under 20 ms.

This translates to a 0.5% duty cycle with 3s transmissions, or a 200-fold reduction in power over leaving the ATmega and RFM12B on all the time. To put that in perspective: on average, this setup will draw about 0.1 mA (instead of 20 mA), while still receiving those packets coming in every 3 seconds or so. Not bad, eh?

There’s always room for improvement: the ATmega could be put to sleep while the radio is receiving (it’s going to be idling most of that time anyway). And of course the serial port debugging output should be turned off for real use. Such optimisations might halve the remaining power consumption – diminishing returns, clearly!

But hey, enough is enough. I’m going to integrate this mechanism into the homeGraph.ino sketch – and expect to achieve at least 3 months of run time on 3x AA (i.e. an average current consumption of under 1 mA total, including the GLCD).

Plenty for me – better than both my wireless keyboard and mouse, in fact.

Predicting the next packet time

In AVR, Software on Nov 4, 2012 at 00:01

The problem described in the last post was caused by the receiver losing track of what the transmitter is doing when packets are missing.

Here are the key parts of an improved syncRecv.ino, with several refinements:

  • on powerup, an estimate is chosen as before, using a few iterations
  • we save the best estimate in EEPROM and reuse it after a restart
  • the loop then switches to predicting the next arrivals each time
  • failure to capture within 20 packets restarts a full estimation run
  • every 4, 8, 12, etc lost packets, the window size is doubled (up to a maximum)
  • on each successful capture, the window size is halved (down to a minimum)
  • the cycle time estimate is averaged with a 6-fold smoothing filter

The estimation logic is roughly the same as before:

Screen Shot 2012 10 31 at 15 15 10

And here’s the main loop, with the rest of the logic described above:

Screen Shot 2012 10 31 at 15 15 25

The code will lock onto packets even when some of them are missing. It does so by simply ignoring the last miss, and predicting another packet again exactly one cycle later.

Here are some first results, illustrating synchronisation loss:

Screen Shot 2012 10 31 at 15 20 55

Still some rough spots, but this algorithm should receive properly with a < 1% on/off cycle.

Losing sync is bad

In AVR, Software on Nov 3, 2012 at 00:01

Yesterday’s code has a nasty side-effect of getting into a corner out of which it almost can’t recover at times. Here’s a somewhat longer run, edited for brevity (note the indented lines):

Screen Shot 2012 10 30 at 23 52 35

On one occasion, it took 238 retries (12 minutes) to get back into sync!

Note how the code is sailing slightly too close to the edge, by always being at 0 or 1 ms from the expected time, just because this watchdog timer “happens” to run at a particular rate.

One fix is to gradually widen the window again when too many receptions in a row fail:

Screen Shot 2012 10 30 at 23 56 44

The other step is to always leave a bit more time when calculating a new estimate – it’s better to err on the side of receiving too early than to miss the start of the packet:

Screen Shot 2012 10 30 at 23 55 53

Whoops, looks like this doesn’t get it right – but it illustrates the widening:

Screen Shot 2012 10 31 at 00 02 29

This change works a lot better (i.e. plus 2, instead of minus 2):

Screen Shot 2012 10 31 at 00 07 05

Here’s the sample output:

Screen Shot 2012 10 31 at 00 05 35

The syncRecv code on GitHub has been updated with this tweak. More to come!

Synchronised reception

In AVR, Software on Nov 2, 2012 at 00:01

That homeGraph setup brought out the need to somehow synchronise a receiver to the transmitter, as illustrated in a recent post. See also this forum discussion, which made me dive in a little deeper.

Let’s take a step back and summarise what this is this all about…

The basic idea is that if the transmitter is transmitting in a fixed cycle, then the receiver need not be active more than a small time window before and after the expected transmission. This might make it possible to reduce power consumption by two orders of magnitude, or more.

Here’s the initial syncRecv.ino sketch I came up with, now also added to JeeLib:

Screen Shot 2012 10 30 at 22 55 17

The idea is to turn the radio off for T – W milliseconds after a packet comes in, where T is the current cycle time estimate, and W the current +/- window size, and then wait for a packet to come in, but no later than T + W.

Each time we succeed, we get a better estimate, and can reduce the window size. Down to the minimum 16 ms, which is the granularity of the watchdog timer. For that same reason, time T is truncated to multiples of 16 ms as well. We simply cannot deal with time more accurately if all we have is the watchdog.

Here are some results from three different JeeNodes:

Screen Shot 2012 10 30 at 22 48 04

Screen Shot 2012 10 30 at 22 42 44

Screen Shot 2012 10 30 at 22 39 44

Screen Shot 2012 10 30 at 22 37 04

(whoops – the offset sign is the wrong way around, because I messed up the subtraction)

Note that for timing purposes, this sketch first waits indefinitely for a packet to come in. Since the transmitter doesn’t always send out a sketch, some of these measurement attempts fail – as indicated by multiple R’s.

That last example is a bit surprising: it was modified to run without powering down the radio in between reception attempts. What it seems to indicate is that reception works better when the radio is not put to sleep – not sure why. Or maybe the change in current consumption affects things?

As you can see, those watchdog timers vary quite a lot across different ATmega chips. These tests were done in about 15 minutes, with the sending sketch (and home power consumption levels) about the same during the entire period.

Still, these results look promising. Seems like we could get the estimates down to a few milliseconds and run the watchdog at its full 16 ms resolution. With the radio on less than 10 ms per 3000 ms, we’d get a 300-fold reduction in power consumption. Battery powered reception may be feasible after all!

Decoding Bencode data

In AVR, Software on Oct 3, 2012 at 00:01

After the encoding and collection of Bencoded data, all the pieces are finally in place to actually process that incoming data again.

I’ve extended the EmBencode library and the serialReceive demo sketch to illustrate the process:

Screen Shot 2012 09 30 at 15 15 53

Let’s try it with the same test data, i.e. the following text (all on one line):

    5:abcde3:123i12345eli987eli654eei321ee
    i999999999ed3:onei11e3:twoi22ee4:bye!

Here is the output:

Screen Shot 2012 09 30 at 15 18 03

You can see the pieces being separated, and all the different parts of the message being decoded properly. One convenient feature is that the asString() and asNumber() calls can be mixed at will. So strings that come in but are actually numeric can be decoded as numbers, and numbers can be extracted as strings. For binary data, you can get at the exact string length, even when there are 0-bytes in the data.

The library takes care of all string length manipulations, zero-byte termination (which is not in the encoded data!), and buffer management. The incoming data is in fact not copied literally to the buffer, but stored in a convenient way for subsequenct use. This is done in such a way that the amount of buffer space needed never exceeds the size of the incoming data.

The general usage guideline for this decoder is:

  • while data comes in, pass it to the decoder
  • when the decoder says it’s ready, switch to getting the data out:
    • call nextToken() to find out the type of the next data item
    • if it’s a string or a number, pull out that value as needed
  • the last token in the buffer will always be T_END
  • reset the decoder to prepare for the next incoming data

Note that dict and list nesting is decoded, but there is no processing of these lists – you merely get told where a dict or list starts, and where it ends, and this can happen in a nested fashion.

Is it primitive? Yes, quite… but it works!

But the RAM overhead is just the buffer and a few extra bytes (8 right now). And the code is also no more than 2..3 KB. So this should still fit fairly comfortably in an 8-bit ATmega (or perhaps even ATtiny).

Note that the maximum buffer size (hence packet size) is about 250 bytes. But that’s just this implementation – Bencoded data has no limitations on string length, or even numeric accuracy. That’s right: none, you could use Bencode for terabytes if you wanted to.

PS – It’s worth pointing out that this decoder is driven as a push process, but that actual extraction of the different items is a pull mechanism: once a packet has been received, you can call nextToken() as needed without blocking. Hence the for loop.

Collecting Bencode data

In AVR, Software on Oct 1, 2012 at 00:01

After having constructed some Bencode-formatted data, let’s try and read this stuff back.

This is considerably more involved. We’re not just collecting incoming bytes, we’re trying to make sense of it, figuring out where the different strings, ints, lists, and dicts begin and end, and – not obvious either perhaps – we’re trying to manage the memory involved in a maximally frugal way. RAM is a scarce resource on a little embedded µC, so pointers and malloc’s have to be avoided where possible.

Let’s start with the essential parsing task of figuring out when an incoming byte stream contains a complete Bencoded data structure. IOW, I want to keep on reading bytes until I have a complete “packet”.

The following serialReceive sketch does just that:

Screen Shot 2012 09 30 at 11 46 31

All of the heavy-lifting is done in the EmBencode library. What we’re doing here is giving incoming bytes to the decoder, until it tells us that we have a complete packet. Here’s the output, using the test data created yesterday:

Screen Shot 2012 09 30 at 11 46 07

Looks obvious, but this thing has fully “understood” the incoming bytes to the point that it knows when the end of each chunk has been reached. Note that in the case of a nested list, all the nesting is included as part of one chunk.

There’s more to this than meets the eye.

First of all, this is a “push” scanner (aka “lexer”). Think about how you’d decode such a data stream. By far the simplest would be something like this (in pseudo code):

  • look at the next character
  • if it’s a digit:
    • get the length, the “:”, and then grab the actual string data
  • if it’s an “i”:
    • convert the following chars to a signed long and drop the final “e”
  • if it’s a “d” or an “l”:
    • recursively grab entries, until we reach an “e” at the end of this dict / list

But that assumes you’re in control – you’re asking for more data, IOW you’re waiting until that data comes in.

What we want though, is to treat this processing as a background task. We don’t know when data comes in and maybe we’d like to do other stuff or go into low-power mode in the meantime. So instead of the scanner “pulling” in data, we need to turn its processing loop inside out, giving it data when there is some, and having it tell us when it’s done.

The code for this is in EmBencode.cpp:

Screen Shot 2012 09 30 at 12 01 52

It’s written in (dense) C++ and implemented as a finite state machine (FSM). This means that we switch between a bunch of “states” as scanning progresses. That state is saved between calls, so that we’ll know what to do with the next character when it comes in.

There’s a fair amount of logic in the above code, but it’s a useful technique to have in your programming toolset, so I’d recommend going through this if FSM’s are new to you. It’s mostly C really, if you keep in mind that all the variables not declared locally in this code are part of a C++ object and will be saved from call to call. The “EMB_*” names are just arbitrary (and unique) constants. See if you can follow how this code flows as each character comes in.

The above code needs 7 bytes of RAM, plus the buffer used to store the incoming bytes.

There are tools such as re2c which can generate similar code for you, given a “token grammar”, but in simple cases such as this one, being able to wrap your mind around such logic is useful. Especially for embedded software on limited 8-bit microcontrollers, where we often don’t have the luxury of an RTOS with multiple “tasks” operating in parallel.

Halfway there: we’ve identified the pieces, but we’re not yet doing anything with ’em!

PS – The new JeeLabs Café website is now alive and kicking.

Sending Bencode data

In AVR, Software on Sep 30, 2012 at 00:01

As mentioned a while back, I’m adopting ZeroMQ and Bencode on Win/Mac/Linux for future software development. The idea is to focus on moving structured data around, as foundation for what’s going on at JeeLabs.

So let’s start on the JeeNode side, with the simplest aspect of it all: generating Bencoded data. I’ve set up a new library on GitHub and am mirroring it on Redmine. It’s called “EmBencode” (embedded, ok?). You can “git clone” a copy directly into your Arduino’s “libraries” folder if you want to try it out, or grab a ZIP archive.

This serialSend sketch sends some data from a JeeNode/Arduino/etc. via its serial port:

Screen Shot 2012 09 29 at 20 20 32

Note that we have to define the connection between this library and the Arduino’s “Serial” class by defining the “PushChar” function declared in the EmBencode library.

One thing to point out, is that this code uses the C++ “function overloading” mechanism: depending on the type of data given as argument to push(), the appropriate member function for that type of value gets called. The C++ compiler automagically does the right thing when pushing strings and numbers.

Apart from that, this is simply an example which sends out a bit of data – i.e. some raw values as well as some structured data, each one right after the other.

Here’s what you’ll see on the IDE’s serial console monitor:

    5:abcde3:123i12345eli987eli654eei321ee
    i999999999ed3:onei11e3:twoi22ee4:bye!

(the output has been broken up to make it fit on this page)

It looks like gobbledygook, but when read slowly from left to right, you can see each of the calls and what they generate. I’ve indented the code to match the structures being sent.

You can check out the EmBencode.h header file to see how the encoder is implemented. It’s all fairly straight-forward. More interestingly perhaps, is that this code requires no RAM (other than the run-time stack). There is no state we need to track for encoding arbitrarily complex data structures.

(Try figuring out how to decode this stuff – it’s quite tricky to do in an elegant way!)

Tomorrow, I’ll process this odd-looking Bencoded data on the other side of the serial line.

Timing troubles with upload

In AVR, Hardware on Sep 22, 2012 at 00:01

Since the Raspberry Pi can now reset a JeeNode, I assumed that uploading would be a piece of cake. Hmmm… maybe not quite.

The trouble is timing, and I’m currently I was pulling my hair out on this one:

  • the plan is to reset the JeeNode and then have avrdude upload new code to it
  • this works automagically when opening a serial port causes DTR to go low
  • but here, we don’t have DTR or RTS, this is a basic serial port on GPIO pins
  • what we do have, is a GPIO pin 18 which can be pulled low to force a reset

At the moment, there seems to be a major problem with timing:

SCR31

Here’s how to decode this screen shot:

  • the YELLOW line is serial from RPi to JeeNode
  • the BLUE line is serial from JeeNode to RPi
  • the MAGENTA line is the reset pulse on the GPIO pin

The way I test this, is via a shell script which first toggles reset using /sys/class/gpio/…, and then launches avrdude to perform the upload, using these commands:

echo 18 >/sys/class/gpio/export
echo out >/sys/class/gpio/gpio18/direction
echo 1 >/sys/class/gpio/gpio18/value
sleep 0.1
echo 0 >/sys/class/gpio/gpio18/value
avrdude -pm328p -carduino -P/dev/ttyAMA0 -D -Uflash:w:test.hex:i
echo 18 >/sys/class/gpio/unexport

Here’s what actually happens, I think:

  • the GPIO pin is correctly pulsed high and then dropped low after 0.1 s
  • the scope triggers on that falling edge, presumably same time as the ATmega resetting
  • after 323 ms, I see a 30 µs blip on the outgoing serial pin
  • after 674 ms, it looks like avrdude sends out it’s “0” wakeup character
  • after about 750 ms, the JeeNode starts sending the RFM12demo greeting
  • after 946 ms, the second “0” wakeup goes out
  • after 1197 ms, the third and final “0” goes out

In other words: it looks like avrdude is starting to send the 0’s too late! – and as a result, the JeeNode’s boot loader passes control to the sketch and never enters the upload cycle. After a few seconds, avrdude then gives up:

avrdude: ser_recv(): programmer is not responding

Note that reset and serial communication both work properly, as verified several times.

Trouble is, apart from redoing all in a single app, I see no way to reduce the startup time of avrdude. The SD card is perhaps not the fastest, but it’s no slouch either:

# hdparm -tT /dev/mmcblk0

/dev/mmcblk0:
 Timing cached reads:   248 MB in  2.00 seconds = 123.77 MB/sec
 Timing buffered disk reads:  50 MB in  3.05 seconds =  16.40 MB/sec
#

Is a reset + upload via GPIO not possible? I’m not giving up, but it sure ain’t workin’ yet!

Update – Problem solved, stay tuned for the explanation tomorrow…

One million packets

In AVR, Hardware, Software on Sep 15, 2012 at 00:01

Minutes after this weblog post goes live will be a new milestone for one of the JeeNodes.

This thing has been running for over two years, sending out nearly one million test packets:

Here are the entries from the data logged to file on my central server, minutes ago:

1:40   RF12-868.5.3 radioBlip age       740
1:40   RF12-868.5.3 radioBlip ping      999970

The counter is about to reach 1,000,000 – just after midnight today, in fact.

These log entries come from a JeeNode with a radioBlip sketch which just sends out a counter, roughly every 64 seconds, and goes into maximum low-power mode in between each transmission. That’s the whole trick to achieving very long battery lifetimes: do what ya’ gotta do as quickly as possible, then go go bck to ultra-low power as deeply as possible.

The battery is a 1300 mAh LiPo battery, made for some Fujitsu camera. I picked it because of the nice match with the JeeNode footprint.

Bit the big news is that this battery has not been recharged since August 21st, 2010!

Which goes to show that:

  • lithium batteries can hold a lot of charge, for a long time
  • JeeNodes can survive a long time, when programmed in the right way
  • sending out a quick packet does not really take much energy – on average!
  • all of this can easily be replicated, the design and the code are fully open source

And it also clearly shows that this sort of lifetime testing is really not very practical – you have to wait over two years before being sure that the design is as ultra-low power as it wast intended to be!

If we (somewhat arbitrarily) assume that the battery is nearly empty now, then running for 740 days (i.e. 17,760 hours) means that the average current draw is about 73 µA, including the battery’s self-discharge. Which – come to think of it – isn’t even that low. I suspect that with today’s knowledge, I could probably set up a node which runs at least 5 years on this kind of battery. Oh well, there’s not much point trying to actually prove it in real time…

One of the omissions in the original radioBlip code was that only a counter is being sent out, but no indication at all of the remaining battery charge. So right now I have no idea how much longer this setup will last.

As you may recall, I implemented a more elaborate radioBlip2 sketch a while ago. It reports two additional values: the voltage just before and after sending out a packet over wireless. This gives an indication of the remaining charge and also gives some idea how much effect all those brief transmission power blips have on the battery voltage. This matters, because in the end a node is very likely to die during a packet transmission, while the radio module drains the battery to such a point that the circuit ceases to work properly.

Next time, as a more practical way of testing, I’ll probably increase the packet rate to once every second – reducing the test period by a factor of 60 over real-world use.

Waiting a couple of years for the outcome is a bit silly, after all…

Delayed power-up

In AVR, Hardware on Sep 9, 2012 at 00:01

To recall yesterday’s reasoning, I’m looking for a way to keep the RFM12B from starting up too soon and drawing 0.6 mA before the microcontroller gets a chance to enable it’s ultra-low power sleep mode.

The solutions so far require an extra I/O pin, allowing the microntroller to turn power on and off as needed, with the extra detail that power stays off until told otherwise.

But all I’m really interested in, is to keep that RFM12B from powering up too soon. After that, I never need to power it down again (and lose its settings) – at 0.3 µA, the RFM12B’s sleep mode will be just fine.

One solution is to use a dedicated chip for this, which can reliably send out a trigger when a fixed voltage threshold has been exceeded. That would still need a MOSFET, though, so this increases the cost (and footprint) of such a solution.

The other way would be to create a low-speed RC network, gradually charging a cap until a threshold is reached and turns on the MOSFET switch. Lower cost, no doubt, but in fact not flexible enough in case of a very slow power-on voltage ramp, as in the case of a solar cell charging a supercap or small battery. There is just no way to determine how long the delay needs to be – it might take days for the power rail to reach a usable level!

Yet another option is this little gem (thanks for the initial suggestion, Martyn!):

JC s Grid page 32

No I/O pin, no pull-up, nothing!

This trick takes advantage of what was originally considered a drawback of MOSFET switching: the fact that the gate voltage has to reach a certain level before the MOSFET will switch. Assuming that voltage is say 1.5V, then the MOSFET will be turned off as long as the power rail has not yet reached 1.5V, and once it rises above that value, it’ll automatically switch on. Magic!

Does it work? Well, I’m still waiting for some P-MOSFETs to arrive, but I’ve done a little test with an N-MOSFET, connected the other way around and using a 1 kΩ resistor as load. We can look at that combination as a component which has only two pins: a power rail and ground.

If the circuit works as expected, then when applying an increasing voltage, no current will flow until the threshold has been reached, and then it’ll switch on and start drawing current.

As it turns out, this is very easily observable using a Component Tester – like the one built into my scope:

SCR06

The horizontal scale is the applied voltage (from about -5V to +5V), the vertical scale is the current through that component (from about -5 mA to +5 mA). The straight slanted line is characteristic of a 1 kΩ resistor.

But the interesting bit is that little dent: from under 0V to about 1.5V, the circuit draws no current at all. Once 1.5V or more are applied, the circuit starts conducting, and behaving like a plain 1 kΩ resistor again.

Woohoo, this might actually work: just a single P-MOSFET would be all that’s needed!

Switching with a P-MOSFET

In AVR, Hardware on Sep 8, 2012 at 00:01

One reason for yesterday’s exploration, is to figure out a way around a flaw of the RFM12B wireless radio module.

Let me explain – the RFM12B module has a clock output, which can be used to drive a microcontroller. The idea being that you can save a crystal that way. Trouble is that this clock signal has to be present on power-up, even though it can be configured over SPI in software, because otherwise the microcontroller would never start running and hence never get a chance to re-configure the radio. A nasty case of Catch 22 (or a design error?).

In short: the radio always powers up with the crystal oscillator enabled. Even when not using that clock signal!

The problem is that an RFM12B draws about 0.6 mA in this mode, even though it can be put to sleep to draw only 0.3 µA (once running and listening to SPI commands). In the case of energy harvesting, where you normally get very tiny amounts of energy to run off, this startup hurdle can be a major stumbling block.

See my low-power supply weblog post about how hard that can be, and may need extra hardware to get fixed.

So I’m trying to find a way to keep that radio powered down until the microcontroller is running, allowing it to be put to sleep right away.

For ultra-low power use, yesterday’s PNP transistor approach is not really good enough.

This is where an interesting aspect of MOSFETs comes in: they make great power switches, because all they need is a gate voltage to turn them on or off. When on, their resistance (and hence voltage drop) is near zero, and the voltage on the gate doesn’t draw any current. Just like a water faucet doesn’t consume energy to keep water running or blocked, only to change the state – so do MOSFETs.

But many MOSFETs typically require several volts to turn them on, which we may or may not have when running at the lower limit of 1.8V of an ATmega or ATtiny. So the choice of MOSFET matters.

Just like yesterday, we’ll need a P-channel MOSFET to let us switch the power supply rail:

JC s Grid page 32

Note the subtly different placement of the resistor. With a PNP transistor, it was needed to limit the current through the base (which then got wasted, but that current is needed to make the transistor switch). With a MOSFET there is no current, but now we need to make sure that the MOSFET stays off until a low voltage is applied.

Except that now R can be very large. It’s basically a pull-up, and can be extremely weak, say 10 MΩ. That means that when pulled low, the leakage current will be only 0.3 µA.

The trick is to find a P-MOSFET type which can switch using a very low gate voltage, so that it can still be fully switched on. I’ve ordered a couple of types to test this out, and will report once they arrive and measurements can be made.

All in all, this is a very nice solution, though – just 2 very simple components. The main drawback is that we still need to reserve an I/O pin for this.

Tomorrow, I’ll explore a refinement which does not even need an extra I/O pin.

Edge interrupts

In AVR, Hardware, Software on Jun 27, 2012 at 00:01

To continue yesterday’s discussion about level interrupts, the other variant is “edge-triggered” interrupts:

JC s Grid page 22

In this case, each change of the input signal will trigger an interrupt.

One problem with this is that it’s possible to miss input signal changes. Imagine applying a 1 MHz signal, for example: there is no way for an ATmega to keep up with such a rate of interrupts – each one will take several µs.

The underlying problem is a different one: with level interrupts, there is sort of a handshake taking place: the external device generates an interrupt and “latches” that state. The ISR then “somehow” informs the device that it has seen the interrupt, at which point the device releases the interrupt signal. The effect of this is that things always happen in lock step, even if it takes a lot longer before the ISR gets called (as with interrupts disabled), or if the ISR itself takes some time to process the information.

With edge-triggered interrupts, there’s no handshake. All we know is that at least one edge triggered an interrupt.

With “pin-change interrupts” in microcontrollers such as the ATmega and the ATtiny, things get even more complicated, because several pins can all generate the same interrupt (any of the PD0..PD7 pins, for example). And we also don’t get told whether the pin changed from 0 -> 1 or from 1 -> 0.

The ATmega328 datasheet has this to say about interrupt handling (page 14):

Screen Shot 2012 06 26 at 23 08 46

(note that the “Global Interrupt Enable” is what’s being controlled by the cli() and sei() instructions)

Here are some details about pin-change interrupts (from page 74 of the datasheet):

Screen Shot 2012 06 26 at 23 13 01

The way I read all the above, is that a pin change interrupt gets cleared the moment its associated ISR is called.

What is not clear, however, is what happens when another pin change occurs before the ISR returns. Does this get latched and generate a second interrupt later on, or is the whole thing lost? (that would seem to be a design flaw)

For the RF12 driver, to be able to use pin-change interrupts instead of the standard “INT0” interrupt (used as level interrupt), the following is needed:

  • every 1 -> 0 pin change needs to generate an interrupt so the RFM12B can be serviced
  • every 0 -> 1 pin change can be ignored

The current code in the RF12 library is as follows:

Screen Shot 2012 06 26 at 23 19 59

I made that change from an “if” to a “while” recently, but I’m not convinced it is correct (or that it even matters here). The reasoning is that servicing the RFM12B will clear the interrupt, and hence immediately cause the pin to go back high. This happens even before rf12_interrupt() returns, so the while loop will not run a second time.

The above code is definitely flawed in the general case when more I/O pins could generate the same pin change interrupt, but for now I’ve ruled that out (I think), by initializing the pin change interrupts as follows:

Screen Shot 2012 06 26 at 23 23 28

In prose:

  • make the RFM12B interrupt pin an input
  • enable the pull-up resistor
  • allow only that pin to trigger pin-change interrupts
  • as last step, enable that pin change interrupt

Anyway – I haven’t yet figured out why the RF12 driver doesn’t work reliably with pin-change interrupts. It’s a bit odd, because things do seem to work most of the time, at least in the setup I tried here. But that’s the whole thing with interrupts: they may well work exactly as intended 99.999% of the time. Until the interrupt happens in some particular spot where the code cannot safely be interrupted and things get messed up … very tricky stuff!

Low power – µA’s in perspective

In AVR, Hardware on Jun 23, 2012 at 00:01

Ultra-low power computing is a recurring topic on this weblog. Hey – it’s useful, it’s non-trivial, and it’s fun!

So far all the experiments, projects, and products have been with the ATmega from Atmel. It all started with the ATmega168, but since some time it’s now all centered around the ATmega328P, where “P” stands for pico power.

There’s a good reason to use the ATmega, of course: it’s compatible with the Arduino and with the Arduino IDE.

With an ATmega328 powered by 3.3V, the lowest practical current consumption is about 4 µA – that’s with the watchdog enabled to get us back out of sleep mode. Without the internal watchdog, i.e. if we were to rely on the RFM12B’s wake-up timer, that power-down current consumption would drop considerably – to about 0.1 µA:

Screen Shot 2012 06 22 at 22 03 30

Whoa, that’s a factor 40 less! Looks like a major battery-life improvement could be achieved that way!

Ahem… not so fast, please.

As always, the answer is a resounding “that depends” – because there are other power consumers involved, and you have to look at the whole picture to understand the impact of all these specs and behaviors.

First of all, let’s assume that this is a transmit-only sensor node, and that it needs to transmit once a minute. Let’s also assume that sending a packet takes at most 6 ms. The transmitter power consumption is 25 mA, so we have a 10,000:1 sleep/send ratio, meaning that the average current consumption of the transmitter will be 2.5 µA.

Then there’s the voltage regulator. In some scenarios, it could be omitted – but the MCP1702 and MCP1703 used on JeeNodes were selected specifically for their extremely low quiescent current draw of 2 µA.

The RFM12B wireless radio module itself will draw between 0.3 µA and 2.3 µA when powered down, depending on whether the wake-up timer and/or the low-battery detector are enabled.

That’s about 5 to 7 µA so far. So you can see that a 0.1 µA vs 4 µA difference does matter, but not dramatically.

I’ve been looking at some other chips, such as ATXmega, PIC, MSP430, and Energy Micro’s ARM. It’s undeniable that those ATmega328’s are really not the lowest power option out there. The 8-bit PIC18LF25K22 can keep its watchdog running with only 0.3 µA, and the 16-bit MSP430G2453 can do the same at 0.5 µA. Even the 32-bit ARM EFM32TG110 only needs 1 µA to keep an RTC going. And they add lots of other really neat extra features.

In terms of low power there are at two more considerations: other peripherals and battery size / self-discharge.

In a Room Node, there’s normally a PIR sensor to detect and report motion. By its very nature, such a sensor cannot be shut off. It cannot even be pulsed, because a PIR needs a substantial amount of time to stabilize (half a minute or more). So there’s really no other option than to keep it powered on at all times. Well, perhaps you could turn it off at night, but only if you really don’t care what happens then :)

Trouble is: most PIR sensors draw a “lot” of current. Some over 1 mA, but the most common ones draw more like 150..200 µA. The PIR sensor I’ve found for JeeLabs is particularly economical, but it still draws 50..60 µA.

This means that the power consumption of the ATmega really becomes almost irrelevant. Even in watchdog mode.

The other variable in the equation is battery self-discharge. A modern rechargeable Eneloop cell is quoted as retaining 85% of its charge over 2 years. Let’s assume its full charge is 2000 mAh, then that’s 300 mAh loss over 2 years, which is equivalent to about 17 µA of continuous self-discharge.

Again, the 0.1 µA vs 4 µA won’t really make such a dramatic difference, given this figure. Definitely not 40-fold!

As you can see, every microamp saved will make a difference, but in the grand scheme of things, it won’t double a battery’s lifetime. There’s no silver bullet, and that Atmel ATmega328 remains a neat Arduino-compatible option.

That doesn’t mean I’m not peeking at other processors – even those that don’t have a multi-platform IDE :)

Low-power waiting – interrupts

In AVR, Hardware on Jun 17, 2012 at 00:01

Following yesterday’s trial, here is the code which uses the pin-change interrupt to run in a continuous cycle:

Screen Shot 2012 06 15 at 17 57 02

The main loop is empty, since everything now runs on interrupts. The output signal is the same, so it’s working.

Could we somehow increase the cycle frequency, to get a higher time resolution? Sure we can!

The above code discharges the cap to 0V, but if we were to discharge it a bit less, it’d reach that 1.66V “1” level more quickly. And sure enough, changing the “50” loop constant to “10” increase the rate to 500 Hz, a 2 ms cycle:

SCR24

As you can see, the cap is no longer being discharged all the way to 0V. A shorter discharge cycle than this is not practical however, since the voltage does need to drop to a definite “0” level for this whole “cap trick” to work.

So how do we make this consume less power? Piece of cake: turn the radio off and go to sleep in the main loop!

Screen Shot 2012 06 15 at 19 50 10

The reason this works, is that the whole setup continuously generates (and processes) pin-change interrupts. As a result, this JeeNode SMD now draws about 0.23 mA and wakes up every 2 ms using nothing more than a single 0.1 µF cap tied to an I/O pin. Mission accomplished – let’s declare (a small) victory!

PS. Exercise for the reader: you could also use this trick to create a simple capacitance meter :)

Low-power waiting

In AVR, Hardware on Jun 16, 2012 at 00:01

This continues where yesterday left off, trying to wait less than 16 milliseconds using as little power as possible.

First off, I’m seeing a lot of variation, which I can’t explain yet. I decided to use a standard JeeNode SMD, including regulator and RFM12B radio, since that will be closer to the most common configuration anyway.

Strangely enough, this sketch now generates a 704 µS toggle time instead of 224 µs, i.e. 44 processor cycles per loop() iteration. I don’t know what changed since yesterday, and that alone is a bit worrying…

The other surprise is that power consumption varies quite a bit between different units. On one JN SMD, I see 1.35 mA, on another it’s only 0.86 mA. Again: I have no idea (yet) what causes this fairly substantial variation.

How do we reduce power consumption further? The watchdog timer is not an option for sleep times under 16 ms.

The key point is to find some suitable interrupt source, and then go into a low-power mode with all the clock/timing circuitry turned off (in CMOS chips, most of the energy is consumed during signal transitions!).

Couple of options:

  1. run the ATmega off its internal 8 MHz RC clock and add a 32 KHz crystal
  2. add extra circuitry to generate a low-frequency pulse and use pin-change interrupts
  3. connect the RFM12B’s clock pin to the IRQ pin and use Timer 2 as divider
  4. add a simple RC to an I/O pins and interrupt on it’s charge cycle
  5. use the RFM12B’s built-in wake-up timer – to be explored in a separate weblog post

Option 1) has as drawback that you can’t run with standard fuse settings anymore: the clock will have to be the not-so-accurate 8 MHz RC clock and the crystal oscillator needs to be set appropriately. It does seem like this would allow short-duration low-power waiting with a granularity of ≈ 30 µs.

Option 2) needs some external components, such as perhaps a low-power 7555 CMOS timer. This would probably still consume about 0.1 mA – pretty low, but not super-low. Or maybe a 74HC4060, for perhaps 0.01 mA (10 µA) power consumption.

Option 3) may sound like a good idea, since Timer 2 can run while the rest of the ATmega’s clock circuits are switch off. But now you have to keep the RFM12B’s 10 MHz crystal running, which draws 0.6 mA … not a great improvement.

Option 4) seems like an option worth trying. The idea is to connect these components to a spare I/O pin:

JC s Grid page 17

By pulling the I/O pin low as an output, the capacitor gets discharged. When turning the pin into a high-impedance input, the cap starts charging until it triggers a transition from a “0” to a “1” input, which could be used as pin-change interrupts. The resistor value R needs to be chosen such that the charge time is near to what we’re after for our sleep time, say 1 millisecond. Longer times can then be achieved by repeating the process.

It might seem odd to do all this for what is just one thousandths of a second, but keep in mind that during this time the ATmega can be placed in deep-sleep mode, consuming only a few µA’s. It will wake up quickly, and can then either restart another sleep cycle or resume its work. This is basically the same as a watchdog interrupt.

Let’s first try this using the internal pull-up resistor instead, and find out what sort of time delays we get:

Screen Shot 2012 06 15 at 17 22 53

(several typo’s: the “80 µs” comment in the above screen shot should be “15 µs” – see explanation below)

This code continuously discharges the 0.1 µF capacitor connected to DIO1, then waits until it charges up again:

SCR23

With the internal pull-up we get a 3.4 ms cycle time. By adding an extra external resistor, this could be shortened. The benefit of using only the internal pull-up, is that it also allows us to completely switch off this circuit.

We can see that this ATmega switches to “1” when the voltage rises to 1.66V, and that its internal pull-up resistor turns out to be about 49 kΩ (I determined this the lazy way, by tweaking values on this RC calculator page).

Note that discharge also takes a certain amount of time, i.e. when the output pin is set to “0”, we have to keep it there a bit. Looks like discharge takes about 15 µs, so I adjusted the asm volatile (“nop”) loop to cycle 50 times:

SCR22

In other words, this sketch is pulling the IO pin low for ≈ 15 µs, then releases it and waits until the internal pull-up resistor charges the 0.1 µF capacitor back to a “1” level. Then this cycle starts all over again. Easy Peasy!

So there you have it: a single 0.1 µF capacitor is all it takes to measure time in 3.4 µs ms increments, roughly. Current consumption should be somewhat under 67 µA, i.e. the current flowing through a 49 kΩ resistor @ 3.3V.

Tomorrow, I’ll rewrite the sketch to use pin-change interrupts and go into low-power mode… stay tuned!

Waiting without the watchdog

In AVR, Hardware on Jun 15, 2012 at 00:01

The watchdog timer in the ATmega has as shortest interval about 16..18 milliseconds. Using the watchdog is one of the best ways to “wait” without consuming much power: a fully powered ATmega running at 16 MHz (and 3.3V) draws about 7 mA, whereas it drops thousandfold when put to sleep, waiting for the watchdog to wake it up again.

The trouble is: you can’t wait less than that minimum watchdog timer cycle.

What if we wanted to wait say 3 ms between transmitting a packet and turning on the receiver to pick up an ACK?

Short time delays may also be needed when doing time-controlled transmissions. If low power consumption is essential, then it becomes important to turn the transmitter and receiver on at exactly the right time, since these are the major power consumers. And to wait with minimal power consumption in between…

One approach is to slow down the clock by enabling the built-in pre-scaler, but this has only a limited effect:

Screen Shot 2012 06 14 at 16 39 58

The loop toggles an I/O bit to allow verification of the reduced clock rate. The above code draws about 1.6 mA, whereas the same code running at full speed (16 MHz) draws about 8.8 mA. Note that these measurements ended up a bit lower, but that was as 3.3V – I’m running from a battery pack in these tests, i.e. at about 4.0V.

The I/O pin toggles at 2.23 KHz in slow mode, vs 573 KHz at full speed, which indicates that the system clock was indeed running 256 times slower. A 2.23 KHz rate is equivalent to a 224 µs toggle cycle, which means the system needs 14 processor cycles (16 µs each) to run through this loop() code. Most of it is the call/return stack overhead.

So basically, we could now wait a multiple of 16 µs while consuming about 1.6 mA – that’s still a “lot” of current!

Tomorrow, I’ll explore ways to reduce this power consumption further…

Code vs. power consumption

In AVR, Hardware on Jun 13, 2012 at 00:01

I’ve been wondering for some time whether the power consumption of an ATmega varies depending on the code it is running. Obviously, sleep modes and clock rate changes have a major impact – but how about plain loops?

To test this, I uploaded the following sketch into a JeeNode:

Screen Shot 2012 06 12 at 21 34 50

Interrupts were turned off to prevent the normal 1024 µs timer tick from firing and running in between. And I’m using “volatile” variables to make sure the compiler doesn’t optimize these calculations away (as they’re not used).

The result is that the code pattern does indeed show up in the chip’s total current consumption:

SCR20

The value displayed is the voltage measured over a 10 Ω resistor in series with VCC (the JeeNode I used had no regulator, and was running directly off a 3x AA battery pack @ 3.95V).

What you can see is that the power consumption cycles between about 8.4 mA and 8.8 mA, just by being in different parts of the code. Surprising perhaps, but it’s clearly visible!

The shifts in the second loop are very slow – due to the fact that the ATmega has no barrel shifter. It has to use a little loop to shift by N bits. To get a nice picture, those shifts are performed only 5,000 times instead of 50,000.

The high power consumption is during the multiplication loop, the low consumption is during the shift loop.

In the end, I had to use a lot of tricks to create the above oscilloscope capture, because there was a substantial amount of 50 Hz hum on the measured input signal. Since the repetition rate of the signal I was interested in was not locked to that 50 Hz AC mains signal, most of the “noise” went away by averaging the signal over 128 triggers.

The other trick was to use the scope’s “DC offset” facility to lower the signal by 80 mV. This allows bumping the input sensitivity all the way up to 2 mV/div without the trace running off the screen. An alternative would be to use AC coupling on the input, but then I’d lose the information about the actual DC levels being measured.

What else can we deduce from the above screen shot?

  • loop 1 takes 93.48 ms for 50,000 iterations, so one cycle runs in ≈ 1.8 µs
  • loop 2 takes 108.52 ms for 5,000 iterations, so one cycle runs in ≈ 21.8 µs

As you can see, shifts by a variable number of bits do take quite a lot of time on an ATmega, relatively speaking!

Update – As noted in the comments, a shift by “321” ends up being done modulo 256, i.e. 65 times. If I change the shift to 3, the run times drop to being comparable to a multiply. The power consumption effect remains.

It’s about survival

In AVR, Hardware, Software on May 29, 2012 at 00:01

When running off solar power, ya’ gotta deal with lack of (sun-) light…

As shown in a recent post, a 0.47F supercap appears to have enough energy storage to get through the night, at least when assuming that the day before was sunny and that the nights are not too long.

There are still a couple of issues to solve. One which I won’t go into yet, is that the current approach won’t start up properly when there is only a marginal power budget to begin with. That’s a hard problem – some other time!

But another tactic to alleviate this problem, is to try and sail through a low-power situation by reducing power consumption until (hopefully) more energy becomes available again, later on.

Here’s my first cut at implementing a “survival strategy”, using the radioBlip2 sketch:

Screen Shot 2012 05 15 at 14 00 12

It’s all in the comments, really: when power is low, try to avoid sending packets, since turning on the transmitter is by far the biggest power “hog”. And when power is really low, don’t even measure VCC – just slow down even more in maximally efficient sleep mode – I’ve set the times to 5 and 60 minutes. The 1-hour sleep being a last effort to get through a really rough night…

But I’ve also added some kamikaze logic: when running low, you don’t just want the sketch to go into sleep mode more and more and finally give up without having given any sign of life. So instead, when the sketch is about to decide whether it should send a packet again, it checks whether the voltage is really way too low after what was supposedly a long deep-sleep period. If so, and before power runs out completely, it will try to send out a packet anyway, in the knowledge that this might well be its last good deed. That way, the central node might have a chance to hear this final swan song…

The thresholds are just a first guess. Maybe there are better values, and maybe there is a better way to deal with the final just-about-to-die situation. But for now, I’ll just try this and see how it goes.

One last point worth mentioning: all the nodes running this sketch can use the same group and node ID, because they are transmit-only. There is never a need to address packets sent towards them. So the BLIP_ID inside the payload is a way to still disambiguate incoming packets and understand which exact node each one came from.

Re-using the same node ID is useful in larger setups, since the total number of IDs in a group is limited to 30.

I’ll do some tests with the above logic. Let’s hope this will keep nodes alive in long and dark winter days nights.

Re-thinking solar options

In AVR, Hardware, Musings on May 28, 2012 at 00:01

So will it ever be possible to run a JeeNode or JeeNode Micro off solar power?

Well, that depends on many things, really. First of all, it’s good to keep in mind that all the low-power techniques being refined right now also apply to battery consumption. If a 3x AA pack ends up running 5 or even 10 years without replacement, then one could ask whether far more elaborate schemes to try and get that supercap or mini-lithium cell to work are really worth the effort.

One fairly practical option would be a single rechargeable EneLoop AA battery, plus a really low-power boost circuit (perhaps I need to revisit this one again). The idea would be to just focus on ultra-low power consumption, and move the task of charging to a more central place. After all, once the solar panels on the roof of JeeLabs get installed (probably this summer), I might as well plug the charger into AC mains here and recharge those EneLoop batteries that way!

Another consideration is durability: if supercaps only last a few months before their capacity starts to drop, then what’s the point? Likewise, the 3.4 mAh Lithium cell I’ve been playing with is rated at “1000 cycles, draining no more than 10% of the capacity”. With luck, that would be about three years before the unit needs to be replaced. But again – if some sort of periodic replacement is involved anyway, then why even bother generating energy at the remote node?

I’m not giving up yet. My KS300 weather station (868 MHz OOK, FS20’ish protocol) has been running for over 3 years now, I’ve never replaced the 3x AA batteries it came with – here’s the last readout, a few hours ago:

     :41   KS300 ookRelay2 humi             77
     :41   KS300 ookRelay2 rain             469
     :41   KS300 ookRelay2 rnow             0
     :41   KS300 ookRelay2 temp             18.2
     :41   KS300 ookRelay2 wind             0

And the original radioBlip node is also running just fine after 631 days:

    1:32   RF12-868.5.3 radioBlip age       631
    1:32   RF12-868.5.3 radioBlip ping      852330

Even the JeeNode Micro running on a CR2023 coin cell is still going strong after 4 months:

    1:42   RF12-868.5.18 radioBlip age      139
    1:42   RF12-868.5.18 radioBlip ping     188449

So ultra-low power is definitely doable, even with an Arduino-compatible design.

No worries – I’ll keep pushing this in various directions, even if just for the heck of it…

First solar results

In AVR, Hardware on May 16, 2012 at 00:01

Some first results from trying to run a JeeNode off a 24 x 32 mm indoor solar cell…

In each of the cases described below, I’m using a JeeNode without regulator and with 100 µF cap hooked up, with fuses and settings as described in this post. The cap should have enough energy to cushion the dip from a small packet transmission. I’m using the latest radioBlip2 sketch, which now sends out the following 7-byte payload:

Screen Shot 2012 05 14 at 13 33 17

The benefit of this version, is that the sketch reports not just the battery level but also how far the battery level drops after sending out a packet once a minute. That value is sent out in the next packet, so it always lags.

To get started, I connect the JeeNode to a BUB, which charges the 100 µF cap to 5V (and runs the RFM12B slightly above spec). Then I disconnect and hook it up to the solar setup. This way I don’t have to deal with startup problems yet – which is an entirely different (and tricky) problem.

Yesterday’s elaborate setup didn’t get very far, unfortunately. Two different runs gave me just a few packets:

    L 09:16:01.571 usb-A600dVPp OK 17 1 0 0 0 1 209 0
    L 09:18:07.445 usb-A600dVPp OK 17 3 0 0 0 1 86 51
    L 09:19:10.308 usb-A600dVPp OK 17 4 0 0 0 1 86 50

    L 09:24:12.477 usb-A600dVPp OK 17 1 0 0 0 1 206 0
    L 09:25:15.707 usb-A600dVPp OK 17 2 0 0 0 1 86 210

Values are 20 mV steps, offset by 1V – the actual battery voltage is: 1 + 0.02 * X (where X is the reported value).

In the above runs, the battery is 86 (2.72V) before sending, and 50 (2.00V) after. That’s pretty close to the edge, I’m not sure why the drop is so large.

Another test with a 0.47 Farad supercap, charged for about 3 days to get the charge “deep” into the supercap, seems to fare a little better:

    L 09:43:06.943 usb-A600dVPp OK 17 19 0 0 0 1 210 52
    L 09:44:10.771 usb-A600dVPp OK 17 20 0 0 0 1 175 210
    L 09:45:14.549 usb-A600dVPp OK 17 21 0 0 0 1 175 146
    L 09:46:18.339 usb-A600dVPp OK 17 22 0 0 0 1 175 147
    L 09:47:22.100 usb-A600dVPp OK 17 23 0 0 0 1 175 147
    ...

That’s 4.50V and 3.94V before and after transmission, respectively. But a 0.47F supercap has a lot less energy in it than that 3.4 mAh Lithium cell used in the first tests above, so it’ll probably run down a lot faster.

After one hour, voltages drop to 4.28V and 3.72V. Two hours: 4.14V and 3.60V. Five hours: 3.92V and 3.36V. I’m not sure this will work, unless the node sends less at night perhaps or always restarts reliably the next day.

To be continued…

Watching it go down

In AVR, Hardware, Software on May 13, 2012 at 00:01

Now that there’s low-power vccRead() code to measure the current power supply voltage, we can finally get a bit more valuable info from the radioBlip sketch, which sends out one packet per minute.

So here’s a new radioBlip2 sketch which combines both functions. To support more test nodes, I’m adding a byte to the payload for a unique node ID, as well as a byte with the measured voltage level:

Screen Shot 2012 05 09 at 18 28 02

As a quick test I used a JeeNode without regulator, running off an electrolytic 1000 µF cap, charged to 5V via a USB BUB, and then disconnected (this is running the RFM12B module beyond its 3.8V max specs, BTW):

DSC 3127

Here’s a dump of the received packets:

    L 16:56:32.032 usb-A600dVPp OK 17 1 0 0 0 1 209
    L 16:57:35.859 usb-A600dVPp OK 17 2 0 0 0 1 181
    L 16:58:39.543 usb-A600dVPp OK 17 3 0 0 0 1 155
    L 16:59:43.029 usb-A600dVPp OK 17 4 0 0 0 1 134
    L 17:00:46.323 usb-A600dVPp OK 17 5 0 0 0 1 115
    L 17:01:49.431 usb-A600dVPp OK 17 6 0 0 0 1 98
    L 17:02:52.314 usb-A600dVPp OK 17 7 0 0 0 1 82
    L 17:03:55.016 usb-A600dVPp OK 17 8 0 0 0 1 66
    L 17:04:57.526 usb-A600dVPp OK 17 9 0 0 0 1 50

Or, more graphically, as voltage – showing 8 minutes before the sketch runs out of juice:

Screen Shot 2012 05 09 at 19 06 19

This consumes only marginally more power than without the VCC measurements: the original radioBlip sketch lasted 1 minute longer under similar conditions, i.e. one extra packet transmission.

Improved VCC measurement

In AVR, Software on May 12, 2012 at 00:01

As shown in this post, it is possible to read out the approximate level of VCC by comparing the internal 1.1 V bandgap with the current VCC level.

But since this is about tracking battery voltage on an ultra-low power node, I wanted to tinker with it a bit further, to use as little energy as possible when making that actual supply voltage measurement. Here’s an improved bandgap sketch which adds a couple of low-power techniques:

Screen Shot 2012 05 09 at 15 42 39

First thing to note is that the ADC is now run in noise-canceling-reducing mode, i.e. a special sleep mode which turns off part of the chip to let the ADC work more accurately. With as nice side-effect that it also saves power.

The other change was to drop the 250 µs busy waiting, and use 4 ADC measurements to get a stable result.

The main delay was replaced by a call to loseSomeTime() of course – the JeeLib way of powering down.

Lastly, I changed the sketch to send out the measurement results over wireless, to get rid of the serial port activity which would skew the power consumption measurements.

Speaking of which, here is the power consumption during the call to vccRead() – my favorite graph :)

SCR41

As usual, the red line is the integral of the current, i.e. the cumulative energy consumption (about 2300 nC).

And as you can see, it takes about 550 µs @ 3.5 mA current draw to perform this battery level measurement. The first ADC measurement takes a bit longer (25 cycles i.s.o. 13), just like the ATmega datasheet says.

The total of 2300 nC corresponds to a mere 2.3 µA average current draw when performed once a second, so it looks like calling vccRead() could easily be done once a minute without draining the power source very much.

The final result is pretty accurate: 201 for 5V and 147 for a 4V battery. I’ve tried a few units, and they all are within a few counts of the expected value – the 4-fold ADC readout w/ noise reduction appears to be effective!

Update – The latest version of the bandgap sketch adds support for an adjustable number of ADC readouts.

How low can it go?

In AVR, Hardware on May 7, 2012 at 00:01

While experimenting with various alternate power sources for a JeeNode, I was curious as to just how low it could go in terms of voltage and still function as a simple wireless transmit node.

Made the following mods to push things a bit more than usual:

  • adjusted the fuses to set the brownout level to 1.8V iso 2.7V (efuse: 0x06)
  • changed the RFM12B’s low-battery level to 2.2V iso 3.1V (rf12_control: 0xC040)
  • removed the voltage regulator from a JeeNode, and keep just the electrolytic cap
  • changed the radioBlip sketch to run at 8 MHz, i.e. 16 MHz clock % 2

This is the same setup as with the Tiny Lithium discharge setup described a few days ago, BTW.

Here’s the JeeNode-under-test (JUT?) – the cap I used here is again 100 µF:

DSC 3070

One pair of wires is from the power supply, the other from the multimeter.

And then it’s just a matter of hooking it up to a power supply and gradually lowering the supply voltage.

And the result is … 3.0, 2.9, 2.8, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1, 2.0, 1.9, 1.85 Volt still works!

Anything lower than that and the sketch stops sending out packets once a minute – but then again, that’s probably just the brownout detector of the ATmega kicking in!

To get it back up, I re-connected the power supply at 2.1 V and the node started its blips again… lower didn’t work, my hunch is that the RFM12B’s clock circuit needs that slightly higher voltage level to start oscillating.

Measuring VCC via the bandgap

In AVR, Hardware, Software on May 4, 2012 at 00:01

The ATmega’s (and ATtiny’s for that matter) all have a 10-bit ADC which can be used measure analog voltages. These ADC’s are ratiometric, meaning they measure relative to the analog reference voltage (usually VCC).

On a 5V Arduino, that means you can measure 0..5V as 0..1023, or roughly 5 mV per step.

On a 3.3V JeeNode, the measurements are from 0 to 3.3V, or roughly 3.3 mV per step.

There’s no point connecting VCC to an analog input and trying to measure it that way, because no matter what you do, the ADC readout will be 1023.

So can we figure out what voltage we’re running at? This would be very useful when running off batteries.

Well, there is also a “bandgap reference” in each ATmega/ATtiny, which is essentially a 1.1V voltage reference. If we read out that value relative to our VCC, then a little math will do the trick:

  • suppose we read out an ADC value “x” which represents 1.1V
  • with 5V as VCC, that value would be around 1100 / 5000 * 1023 = 225
  • whereas with 3.3V as VCC, we’d expect a reading of 1100 / 3300 * 1023 = 341
  • more generally, 1100 / VCC * 1023 = x
  • solving for VCC, we get VCC = 1100 / x * 1023

So all we have to do is measure that 1.1V bandgap reference voltage and we can deduce what VCC was!

Unfortunately, the Arduino’s analogRead() doesn’t support this, so I’ve set up this bandgap demo sketch:

Screen Shot 2012 04 22 at 21 44 43

Sample output, when run on a JeeNode SMD in this case:

Screen Shot 2012 04 22 at 21 47 20

There’s a delay in the vccRead() code, which helps stabilize the measurement. Here’s what happens with vccRead(10) – i.e. 10 µs delay instead of the default 250 µs:

Screen Shot 2012 04 22 at 21 51 15

Quite different values as you can see…

And here’s the result on an RBBB with older ATmega168 chip, running at 5V:

Screen Shot 2012 04 22 at 21 53 44

I don’t know whether the 168’s bandgap accuracy is lower, but as you can see these figures are about 10% off (the supply voltage was measured to be 5.12 V on my VC170 multimeter). IOW, the bandgap accuracy is not great – as stated in the datasheet, which specifies 1.0 .. 1.2V @ 25°C when VCC is 2.7V. Note also that the bandgap reference needs 70 µs to start up, so it may not immediately be usable when coming out of a power-down state.

Still, this could be an excellent way to predict low-battery conditions before an ATmega or ATtiny starts to run out of steam.

Tiny Lithium – packet test

In AVR, Hardware on May 2, 2012 at 00:01

This post continues where the Tiny Lithium discharge post left off…

To summarize: a tiny ML614 rechargable Lithium cell of a mere 3.4 mAh is used to power a JeeNode running the radioBlip sketch, which is going to send out one small packet per minute (the period is actually slightly longer).

I charged the battery overnight from a 3.0V power supply and through a 1 kΩ resistor, as described in the datasheet. As expected, the battery voltage without load is now indeed 2.97V

The test is really simple, but it’s going to take a little while: connect, see packets come in, with a counter being increased for each packet, and then just wait for the whole thing to stop sending. Here we go:

DSC 3072

The range will need to be good, since packets have to cross a reinforced concrete floor to reach my receiver.

Here’s the log of packets I got (the first packet seems to have been missed):

L 12:08:51.628 usb-A600dVPp OK 17 2 0 0 0
L 12:09:54.592 usb-A600dVPp OK 17 3 0 0 0
L 12:10:57.556 usb-A600dVPp OK 17 4 0 0 0
...
L 23:58:57.898 usb-A600dVPp OK 17 167 2 0 0
L 00:00:00.777 usb-A600dVPp OK 17 168 2 0 0
...
L 23:59:32.169 usb-A600dVPp OK 17 6 8 0 0
L 00:00:34.988 usb-A600dVPp OK 17 7 8 0 0
...
L 23:58:57.821 usb-A600dVPp OK 17 101 13 0 0
L 00:00:00.609 usb-A600dVPp OK 17 102 13 0 0
...
L 23:59:01.058 usb-A600dVPp OK 17 197 18 0 0
L 00:00:03.818 usb-A600dVPp OK 17 198 18 0 0
...
L 23:58:45.821 usb-A600dVPp OK 17 37 24 0 0
L 00:00:51.318 usb-A600dVPp OK 17 39 24 0 0
...
L 13:18:55.865 usb-A600dVPp OK 17 34 27 0 0
L 13:19:58.670 usb-A600dVPp OK 17 35 27 0 0
L 13:21:01.474 usb-A600dVPp OK 17 36 27 0 0
L 13:33:35.035 usb-A600dVPp OK 17 48 27 0 0
L 13:37:46.210 usb-A600dVPp OK 17 52 27 0 0
L 13:43:00.171 usb-A600dVPp OK 17 57 27 0 0
L 13:56:36.450 usb-A600dVPp OK 17 70 27 0 0
L 13:57:39.232 usb-A600dVPp OK 17 71 27 0 0
L 14:06:01.520 usb-A600dVPp OK 17 79 27 0 0
L 14:20:40.504 usb-A600dVPp OK 17 93 27 0 0
…silence…

As you can see, this “battery” packs enough energy to send out 27 x 256 + 93 = 7005 packets – of which 398 were not properly received (mostly in the last days). IOW, it was still sending after 5 days!

The node kept going even though several of the last packets were not received – so transmit power probably dropped off quite a bit, but the sketch was still running properly until the very end.

Note: once moved to measure the supply voltage (still about 2.5V), packets started coming in again – perhaps because of improved reception from the new location, or a slight warm-up of the battery.

This little cell just doesn’t want to give up!

Watchdog tweaking

In AVR, Software on Apr 1, 2012 at 00:01

The other day, I mentioned a way to keep approximate track of time via the watchdog timer, by running it as often as possible, i.e. in a 16 ms cycle.

This brought out some loose ends which I’d like to clean up here.

First of all, the loseSomeTime() code now runs 60 times per second, so optimizing it might be useful. I ended up moving some logic out of the loop, to keep the time between power-down states as short as possible:

Screen Shot 2012 03 27 at 11 00 51

The result is this power consumption profile, every ≈ 16 ms:

SCR78

That’s still about 22 µs @ 6.5 mA. But is it, really?

The above current measurement was done between the battery and the power supply of a JeeNode SMD. Let’s redo this without regulator, i.e. using a “modded” JeeNode with the regulator replaced by a jumper:

SCR77

Couple of observations:

  • different ATmega, different watchdog accuracy: 17.2 vs 16.3 ms
  • the rise and fall times of the pulse is sharper, i.e. not dampened by a 10 µF buffer cap
  • new behavior: there’s now a 0.4 mA current during 80 µs (probably the clock starting up?)
  • that startup phase adds another 75 nC to the total charge consumed
  • note that there is a negative current flow, causing the charge integral to decrease

The worrying bit is that these two ways of measuring the current pulses differ so much – I can’t quite explain it. One thing is clear though: an adjusted fuse setting with faster clock startup should also make a substantial difference, since this now needs to happen 60 times per second.

A second improvement is to assume that when a watchdog cycle gets interrupts, half the time has passed – on average that’ll be as best as we can guess, assuming the interrupt source is independent:

Screen Shot 2012 03 27 at 13 17 55

The last issue I wanted to bring up here, is that small code optimizations can sometimes make a noticeable difference. When running the test sketch (same as in this post) with a 8192 millisecond argument to loseSomeTime(), the above code produces the following profile:

SCR79

The reason the pulse is twice as wide is that the “while” in there now loops a few times, making the run time almost 50 µs between power-down phases. As Jörg Becker pointed out in a comment, the ATmega has no “barrel shifter” hardware, meaning that “shift-by-N” is not a hardware instruction which can run in one machine cycle. Instead, the C runtime library needs to emulate this with repeated shift-by-1 steps.

By changing the while loop from this:

Screen Shot 2012 03 27 at 12 18 20

… to this:

Screen Shot 2012 03 27 at 13 06 49

… we get this new power consumption profile (the horizontal scale is now 20 µs/div):

SCR80

IOW, this takes 20 µs less time. Does it matter? Well, that might depend on who you ask:

  • Marketing guy: “50 µs is 67% more than 30 µs – wow, that means your sketch might last 5 years i.s.o. 3 years on the same battery!”

  • Realist: “50 µs i.s.o. 30 µs every 8 seconds – nah, those extra 120 nC or so will merely add 15 nA to the average current consumption.”

The moral of this story: 1) careful how you measure things, and 2) optimize where it matters.

Anyway, I’ve added all three changes to JeeLib. It won’t hurt, and besides: it leads to smaller code.

75 days and counting

In AVR, Hardware on Mar 30, 2012 at 00:01

The JeeNode Micro based on the ATtiny84 is getting more and more use around here. One of the ways it can be powered is via a CR2032 coin cell on its back:

I’ve got one with the radioBlip sketch running here, to see how long it will last on a single coin cell.

Well… today it passed the 75-day mark – celebration time!

Onwards!

Tracking time via the watchdog

In AVR, Software on Mar 27, 2012 at 00:01

The JeeLib library has a convenient loseSomeTime() function which puts the ATmega in low power mode for 16 to 60,000 ms of time. This is only 10% accurate, because it uses the hardware watchdog which is based on an internally RC-generated 128 KHz frequency.

But the worst bit is that when you use this in combination with interrupts to wake up the ATmega, then you can’t tell how much time has elapsed, because the clock is not running. All you know when waking up, is that no more than the watchdog timeout has passed. The best you can assume is that half of it has passed – but with loseSomeTime() accepting values up to 1 minute that’s horribly imprecise.

Can we do better? Yes we can…

Internally, loseSomeTime() works by cutting up the request time into smaller slices which the watchdog can handle. So for a 10000 ms request, for example, loseSomeTime() would wait 8192 + 1024 + 512 + 256 + 16 ms to reach the requested delay, approximately. Convenient, except for those long waits.

Here’s a test sketch which simply keeps waiting 8192 ms at a time:

Screen Shot 2012 03 21 at 13 14 16

The corresponding current consumption, measured via oscilloscope, shows this:

SCR58

First of all, note how 8192 ms ends up being 8255 ms, due to the watchdog timer inaccuracy.

But the main result is that to perform this sketch, the ATmega will draw 5 mA during about 50 µs. The rest of the time it’ll be a few µA, i.e. powered down. These wake-ups draw virtually no current, when averaged.

The downside is that under these conditions, interrupts can cause us to lose track of time, up to 8192 ms.

So let’s try something else. Let’s instead run the watchdog as briefly as possible:

Screen Shot 2012 03 21 at 13 04 43

Current consumption now changes to this:

SCR57

I don’t really understand why Because of a loop in the loseSomeTime() code which runs faster, the running time drops by half in this case (and hence total nanocoulomb charge halves too). But note that we’re now waking up about 60 times per second.

This means that interrupts can now only mess with our sense of time by at most 16 ms. Without interruptions (i.e. most of the time), the watchdog just completes and loseSomeTime() adds 16 ms to the millis() clock.

Let’s try and estimate the power consumption added by these very frequent wake-ups:

  • each wake-up pulse draw 5.5 mA for about 25 µs
  • the charge consumed by each pulse is 122 nC
  • there are (roughly) 60 wake-up pulses per second
  • so per second, these pulses consume 60 x 122 nC ≈ 7.3 µC in total
  • that comes down to an average current consumption of 7.3 µA

That’s not bad at all! By waking up 60 times per second (and going back to sleep as quickly as possible), we add only 7.3 µA current consumption to the total. The reason this works, is that wake-ups only take 25 µs, which – even at 60 times per second – hardly adds up to anything.

So this technique might be a very nice way to keep approximate track of time while mostly in sleep mode, with the ability to wake up whenever some significant event (i.e. interrupt) happens!

PS. In case you’re wondering about the shape of these signals, keep in mind that I’m measuring current draw before the regulator and 10 µF capacitor on the JeeNode.

Serial Port on JeeNode Micro

In AVR, Software on Mar 9, 2012 at 00:01

The JeeNode Micro is based on an ATtiny84, which has quite a bit less hardware functionality built-in than an ATmega. There is some rudimentary byte-shifting hardware for sending or receiving a serial bit stream, but that’s already assigned to the SPI-style RFM12B interface.

So how about a serial port, for debugging? Even just serial out would be a big help, after all.

Luckily, the developers of the Arduino-Tiny library have thought of this, and have implemented a software solution. Better still, it’s done in an almost completely compatible way.

Here’s an example test sketch:

Screen Shot 2012 03 08 at 07 52 04

Look familiar? Of course it does: it’s exactly the same code as for a standard ATmega sketch!

The one thing you have to keep in mind, is that only a few baud rates are supported:

  • 9600, 38400, and 115200 baud

The latter is unlikely to work when running on the internal 8 MHz clock, though. It’s all done in software. For an ATtiny84 running at 8 MHz, the serial output appears on PB0. This is pin 2 on the chip and pin 10 on the 10-pin header of the JNµ, marked “IOX”.

The code for this software-based serial port is fairly tricky, using embedded assembly code and C++ templates to create just the right timing loops and toggle just the right pin.

Note also that since this is all done in software, interrupts cannot occur while sending out each byte, and sending eats up all the time – the code will resume after the print() and println() calls after all data has been sent.

But apart from these details, you get an excellent debugging facility – even on an ATtiny!

Which boot loader do I have?

In AVR, Software on Mar 7, 2012 at 00:01

Denisj asked on the forum recently whether it’s easy to find out which boot loader is stored in the ATmega. That would indeed be very useful, now that we have a few different versions floating around.

Here’s a new “bootCheck.ino” sketch which tries to identify the boot loader and reports it on the serial port:

Screen Shot 2012 03 06 at 12 23 06

Here’s some sample output when uploaded to the current JeeNodes and RBBBs:

    [bootCheck.2]
      CRC 2048b @ 0x7800 = CD70
      CRC 512b @ 0x7E00 = FD70
    Boot loader: OptiBoot 4.4

The current version only knows about a few boot loaders so far, but it’s table-driven and can quickly be extended.

So now that it exists, let’s use the power of crowdsourcing and make it really useful, eh?

If you’ve got an ATmega328-based board with a bootloader on it, upload this sketch to find out what it reports. If it says “UNKNOWN” and you happen to know exactly what boot loader is present, please let me know what output you get (i.e. the two CRC values) and the name/type of the boot loader, and I’ll add it to the table.

I’ll update the code for each new boot loader. The sketch is maintained as gist on GitHub, so please be sure to get the latest version before you try this. Your boot loader might already be in there!

Note that this is not limited to JeeNodes or RBBBs. Anything with an ATmega328 that will run this Arduino sketch can be included.

Meet the RBBB Pro

In AVR, Hardware on Mar 5, 2012 at 00:01

The Real Bare Bones Board by Modern Device is a neat little Arduino clone (it was my inspiration for the JeeNode, in fact). The RBBB is easy to build, very small, and very popular, at JeeLabs as well.

Now, there’s also a ready-made “pre-assembled” 5V model, based on the SMD version of the ATmega328 which has two additional analog-in pins (note that they are not general purpose I/O pins!):

DSC 2936

Well labeled for use either way, and very convenient for breadboard use. Here’s the bottom view:

DSC 2937

The headers and DC power connector are included, but not soldered on – for maximum flexibility:

DSC 2938

Fully compatible with the RBBB, but considerably flatter if you omit the DC connector.

I’ve added it to the JeeLabs shop and it’s available now. It’ll probably be used in future projects here as well.

The PWR vs the +3V pin

In AVR, Hardware on Jan 25, 2012 at 00:01

JeeNodes and plugs use 6-pin headers with the following pin assignment:

Port

(there’s usually a big printed dot near the PWR pin for orientation)

There has been some confusion about what PWR is w.r.t. +3V and how to use it, so let me elaborate a bit.

First: “+3V” is the main regulated power reference for most chips and circuits. And to make it more complicated: it’s actually 3.3V, not 3.0V. The “+3V” label merely identifies the pin (VCC would be too confusing).

The ATmega on the JeeNode, as well as most (but not all) chips on attached plugs run on this 3.3V voltage level. It is also the reference level for all digital I/O (0 = 0V, 1 = 3.3V), as well as for the ADC when used for analog inputs (1023 steps of 3.22580645161 millivolt each).

As for the other supply pin: “PWR” is usually a higher voltage from which +3V is derived.

There’s a voltage regulator on the JeeNode which can take any input voltage on “PWR” up to about 13V as input and which produces the 3.3V regulated voltage on the “+3V” pin.

The JeeNode regulator has some limits: it’s can’t supply more than 250 mA and it can’t dissipate more than about 600 mW. It’ll shutdown if either of these are exceeded (and it’ll get damaged if you feed it more than 13V). These figures are fairly limiting: if you run a JeeNode off 12V on the PWR pin, then it actually won’t be able to supply more than 70 mA. With 5V on the PWR pin, the limit will be current, not power dissipation, i.e. 250 mA max.

That’s for a JeeNode with through-hole components, i.e. an MCP1702 regulator in a TO-92 package. With the JeeNode SMD and JeeNode USB, you get even less power from the regulator: at most about 250 mW of heat dissipation. That’s 150 mA @ 5V, and only 28 mA @ 12V. In short: the JN SMD and JN USB are not really meant to be powered from more than 5V – or at least not without an extra external regulator (on the plus side: the MCP1703 supports up to 16V on the PWR pin). Note also that the JeeNode USB doesn’t support more than 7V on the PWR pin, due to limitations of the on-board LiPo charger – but that should not be an issue since it’s really only meant to be powered from 5V via USB.

As you can see, there are several limiting factors as to what voltage is supported on the PWR pin. Keep in mind that JeeNodes were designed for ultra-low power consumption, and the regulator was selected for its extremely low idle current draw, not its “high-end” characteristics.

But that’s not all…

One trap for the unwary is with the JeeNode USB: it doesn’t actually feed 5V to the PWR pin when connected to USB but only 4.2V. This is due to the LiPo charger circuit, which allows a LiPo battery to be connected between PWR and GND. With a LiPo battery, the JeeNode USB becomes a very convenient stand-alone unit: low-power untethered operation while not connected to USB, and automatic LiPo charging while connected to USB. It even has a voltage divider on board to monitor the LiPo battery voltage (tied to PC6, i.e. analog 6 in Arduino-speak).

The trouble here is that when you connect plugs to the JeeNode USB, you won’t get the full 5V you might expect. This affects all those plugs which don’t run entirely off +3V but expect some higher voltage on PWR.

And here’s another tricky situation…

With the AA Power Board, you can run JeeNodes off a single AA cell. In this case, there isn’t a voltage higher than 3.3V anywhere in the circuit – so what to do with the PWR line? Well, there’s a solder jumper on the AA board to let you decide: it’s normally open, but you can connect it to either +3V or to the battery “+” (i.e. 1.2..1.5V). Obviously, this setup will be even less suited for plugs which expect a higher voltage than 3.3V to operate.

As you see, the +3V pin is solidly specified as always being 3.3V, but the PWR pin level can be all over the map.

The following plugs are especially affected:

  • the LCD Plug will work, when used with a 3.3V display (as shipped by JeeLabs), but will only be suitable with 5V displays if PWR carries 5V

  • the Graphics Board assumes that PWR is 5V, because the display needs it (it’ll probably still work with 4.2V, but PWR should not be above 5V)

Most plugs will be fine, though, since they only use the +3V supply. The only issue here is to make sure that the total current consumption off +3V is not too high.

Using a JeeNode with an unregulated power supply

The maximum allowed voltage on the PWR pin is about 13V. Unfortunately, many 12V power bricks are fairly badly calibrated, and often deliver substantially more than 12V under no-load conditions. You could easily damage the JeeNode’s on-board regulator with a cheap 12V power brick – better use a 5V or 9V brick.

If you do want to power a JeeNode off 12V (perhaps you need 12V on the rest of the circuit for LEDs, relays, or motor power), then the best approach is to insert a 5V regulator and feed that 5V level to PWR. This can easily be done with a “7805” regulator chip, which is available from many electronics parts sources.

Putting the JNµ to sleep

In AVR, Hardware, Software on Jan 18, 2012 at 00:01

The Sleepy::loseSomeTime() code in the Ports library was never tested on a JeeNode Micro. Turns out that only a minor library difference kept it from working (the arduino-tiny library has its own version of millis(), etc):

Screen Shot 2012 01 14 at 23 55 34

So now, the JNµ can be put to sleep as well. Here’s the jouleTest sketch I used, tweaked to run on the JNµ as well:

Screen Shot 2012 01 14 at 23 55 09

And sure enough, about once every 10 seconds it shows that familiar packet-transmit current consumption:

SCR88

The blue line is the AC-coupled supply voltage, a 3x AA Eneloop battery pack in this case. It supplies about 3.8V, but when running off a 1000 µF cap, it looks like this continues to work down to 1.8V (well below the RFM12B’s minimum 2.2V specs) – although with only about half the transmit power by then.

This current use fingerprint is almost identical to the ATmega328 running this same code. Not surprising really, since it’s the RFM12B which determines most of the power consumption, not the ATmega vs ATtiny difference.

Onwards!

Browsing the Arduino run-time code

In AVR, Software on Jan 10, 2012 at 00:01

The Arduino IDE is a thin wrapper around the avr-gcc compiler and the avr-libc run-time library. It also includes a fairly basic IDE, i.e. a text editor and conventions for managing projects, in the form of “sketches” and libraries.

I prefer to use my own programmer’s editor, because it supports multiple programming languages and has a lot more features for software development (such as Git integration, code folding, and save-on-lose-focus). The Arduino IDE supports external editors by disabling its own one – which is an option in the preferences:

External edit

Now I can simply use my own editor and switch to the Arduino IDE for compiling and uploading.

One advantage of using an external editor, is that you can look at other source code than just your own sketches. In the rest of this post, I’m going to describe how to look at one of the most interesting parts of the Arduino IDE: its run-time library, i.e. the Wiring code which adds supports for everything which makes an Arduino different from the ATmega’s on which it is based.

Note: what follows is specific for Mac OSX, but apart from the location of these files and the editor used, you should be able to transpose all of this to your own beloved computer environment.

The first task, is to figure out where the Arduino IDE’s run-time code is located. In Mac OSX, this code is located inside the Arduino application. To view this area, you can right-click on the Arduino app:

Screen Shot 2012 01 09 at 19 29 48

This leads to the following directory structure:

Screen Shot 2012 01 09 at 19 28 16

The interesting bits are inside the “hardware” folder:

Screen Shot 2012 01 09 at 19 48 09

Here are the first few lines of “Arduino.h”, for example (this used to be “WProgram.h”):

Screen Shot 2012 01 09 at 19 55 09

These source files are where everything specific to the Arduino IDE’s runtime happens. The “Serial” object, and the “millis()” code, for example. If you want to really understand what the Arduino is about, then it’s well worth going through some of these files. As you’ll find out, there’s no magic once you start looking in the right places.

Try it!

Getting ready for OptiBoot 4.4

In AVR, Hardware, Software on Jan 7, 2012 at 00:01

Ok, it’s official – starting this week, all new ATmega’s here will be flashed with the OptiBoot 4.4 boot loader.

It’s going to take a while for all current inventory units to “flush through the system” so to speak (both DIPs and SMDs), but at some point this month all ATmega’s will be running the same boot loader as the Arduino Uno. Faster, smaller, and – hopefully – no more troubles with Windows being unable to upload sketches through FTDI.

One of the things I’ve done is to turn one of the new JeeNode Blocks into a dedicated Portable ISP Programmer for DIP-28’s. It’s the same isp_repair2 sketch as before (modified for the Block’s minor pin allocation diff’s):

DSC 2847

Note the 16 MHz resonator behind the ZIF socket. Here’s the wiring:

DSC 2848

There’s no 10 kΩ pull-up resistor for RESET, because ATmega’s have a (weak) built-in pull-up.

To avoid the delay-on-hardware-reset, I’ve added a push-button which briefly shorts +3V and GND together through a 10 µF electrolytic cap. Enough to force the JeeNode Block into a hardware reset. There’s a 10 kΩ resistor across the cap to discharge it afterwards. This is really quick because the reset occurs on button press i.s.o. release.

The savings are minimal – just 1..2 seconds more for the standard bootstrap – but for production, it matters. Total flash time, including boot loader, RF12demo sketch, and setting all the fuses is now just a few seconds:

  • insert DIP chip
  • close ZIF socket
  • press button
  • wait for two LED blinks
  • open ZIP socket
  • remove programmed chip
  • rinse and repeat…

When a serial port is connected via FTDI, you can see the progress of it all:

Screen Shot 2012 01 04 at 20 01 42

Now let’s just hope that this version of OptiBoot doesn’t lead to the same mess as the previous one.

If you have older JeeNodes or other ATmega328 boards running previous bootstrap loaders, I suggest looking at the recent ISP programmer post and the older summary. You might consider bringing all units up to date, because with a mix of boot loaders you end up constantly using the wrong one in the IDE and having to adjust board types each time.

Just be careful when messing with boot loaders. If the process goes wrong and you pick the wrong fuse settings, then you can end up with a “bricked” unit (only a high-voltage programmer can recover from such a state).

But apart from that: enjoy the doubled 115.2 Kbaud upload speed and the 1.5 Kb extra space for sketches!

ISP Programmers – part 2

In AVR, Hardware on Jan 5, 2012 at 00:01

In yesterday’s post, I presented my latest ISP programmers, based on the isp_repair2 sketch.

I made a few small improvements to that sketch:

  1. the RFM12B is powered down at the end, so that the unit only consumes a few µA’s once done
  2. the programming rate has been improved by getting rid of those horribly slow digitalWrite() calls, etc.
  3. updated RF12demo and OptiBoot to the latest version (v8 and v4.4, respectively)

Furthermore, I switched from the funky switches to plain jumpers, with the following layout:

Isp pins

Another change is that the default with no jumpers is now to burn RF12demo w/ OptiBoot for use with a 16 MHz resonator – this is a good default for JeeNodes, JeeNode USB’s, and JeeNode SMD’s. To select the other options, just hook this up to USB, change the jumpers, and watch the serial output report on reset.

This is the output with no jumpers and no target board attached:

Screen Shot 2011 12 28 at 11 49 57

This is the output after a normal programming cycle (again, the default case, no jumpers installed):

Screen Shot 2011 12 28 at 11 50 15

Programming takes only a few seconds. Note that this programmer is fully self-contained and includes its own LiPo battery, so all you need to do is press the 6 pins on the ISP header pads. The neat thing is that due to the normally-discharged cap on the target board, the brief power dip caused by touching the ISP pads will generate a hardware power-on reset in the programmer, which then immediately starts its programming cycle.

So the the whole workflow is now as follows:

  • grab this thing – and let’s call it a “Portable ISP Programmer” (PIP!)
  • press the pins against the ISP header of the unit to be re-flashed
  • watch the initial LED blink on the programmer as it comes out of reset
  • wait 2..3 seconds
  • watch the second LED blink, indicating that it has successfully completed programming

There is no power switch, since the programmer enters total power down when done. To re-charge, plug the programmer into a USB port and wait for the “charge” LED to turn off. Note that pressing the reset button also works, but that it adds a small boot loader delay before the isp_repair2 sketch gets started.

This has become so convenient, that I can now take any old JeeNode lying around here, and reset it to a well-known state in just a few seconds, before re-using it for some project or experiment.

ISP programmers

In AVR, Hardware on Jan 4, 2012 at 00:01

ISP (re-)programming is going to become more important in the future, so I’ve built a few more of these:

DSC 2844

The problem was to come up with a robust way to connect to the target board, but I think I’ve found a solution:

DSC 2843

Take a 4-pin header, slightly enlarge the holes in the plastic, and then gently-but-forcefully press a couple of Pogo pins in there. I’m using the type with a large head with sharp edges. Here’s the whole assembly:

DSC 2839

After that, it’s a matter of attaching all the wires and tying / glueing things together:

DSC 2841

These units are all refurbished ones with a defective radio, since that’s not needed here.

DSC 2840

The ZIP straps hold the battery and wires in place. The hot glue does the rest:

DSC 2842

These programmers are considerably more effective than you might think – tomorrow, I’ll explain why…

Tempus fugit …

In AVR, Hardware, Software on Dec 31, 2011 at 00:01

Another year is about to end, and the next one is already anxiously waiting to carry us along into the future…

A fitting moment to get that Dutchtronix clock working (a lot easier than this geek version):

DSC 2832

I bought this little kit long ago, not realizing that a low-end USB scope front-end can’t deal with it. Besides, it turns out that it didn’t work back then because of some bad solder joints (ground planes and 15W soldering irons don’t go well together – even my current soldering iron has trouble heating up some of those pads!).

Anyway, this is as far as the Hameg HMO2024 will go:

SCR60

Recognizable, but a far cry from what analog scopes can do. That’s what you get when digital sampling, waveform refresh rates, and vector drawing clash (bumping up the sampling rate causes a fuller, but flickering, image).

This design was from 2007, I think – which goes to show that fun stuff (especially clocks) can be time-less!

I wish you a healthy, safe, and happy 2012 – with lots of opportunities to tinker, learn, and create.

Update – for another example of how such X-Y displays differ between analog and high-end vs low-end DSO’s, see this video on Dave Jones’ EEVblog.

Out with the old – in with the new!

In AVR, Software on Dec 29, 2011 at 00:01

Le roi est mort …

It’s time to move on. I’m dropping all support and maintenance of the Ports and RF12 libs, as well as some others. Well, as far as subversion is concerned. All files are kept read-only at svn.jeelabs.org – for reference.

… vive le roi!

But the good news is that all this software has now been moved and updated on GitHub … and is fully supported.

All libraries on GitHub have been adjusted to work with Arduino IDE 1.0 (they may or may not still work on 0022 or 0023, but that will be supported only to the point of accepting patches to increase backward compatibility).

There is one change which I’ve been meaning to get to for a long time: the Ports and RF12 libraries have been combined into a new library called JeeLib. This means that you no longer have to include “Ports.h” and “RF12.h” at the start of your sketches (although those still continue to work). Instead, insert this one line instead:

    #include <JeeLib.h>

All the examples from both libraries have been retained, but make sure that the old Ports and RF12 are gone.

There are three other libraries for the JeeNodes which you may be using: EtherCard, GLCDlib, and RTClib. These too are now on GitHib and have all been adapted for use with Arduino IDE 1.0.

So how does one start using any of these libraries? Ah, glad you asked :)

  • go to GitHub, and pick the library you’re interested in to get to its home page
  • at the bottom of each home page is a README section with the latest info – always worth a check
  • one of the links at the top is marked “ZIP” – you could click it to download everything as ZIP archive
  • … but you shouldn’t !

The reason for this is Git. If you download a ZIP archive, unpack it, and install it in the right place (which is in the “libraries” folder where all your sketches are), then you’ll get a copy of the code your after, but no way to stay up to date. That might sound like a minor detail, but with open source, there are usually many changes over time. Bug fixes as well as new features. If you grabbed a ZIP file, then you’ll be forced to re-install the next version over the previous one every time there is an update. This quickly gets very boring, and can lead to all sorts of awful mistakes, such as overwriting a file you had fixed in some way (after a lengthy debug session, long ago).

I can’t stress it enough: don’t grab open source software and install it on your disk by just downloading and unpacking it. Not just the stuff from JeeLabs – any open source software distributed in source code form. It’s a nuisance, a ticking time bomb, a mine field, a disaster waiting to happen – get the message?

There is only one sane / long-term approach to working with source code, and that’s through a Version Control System. In this case Git – in combination with GitHub, which is the web site where all source code is stored.

So instead of downloading a ZIP or TAR archive, you need to create a “clone” of the original code on GitHub. The difference with the ZIP archive is that a clone knows where it came from, and gives you the ability to find out what changed, to instantly update your clone, or to revert to any older version, since GitHub keeps track of all versions of the code – past, present, and future.

The trick is to get started with Git and GitHub without drowning in the capabilities they offer. How depends on the environment you’re in:

  • On Windows, you can install TortoiseGit – then you need to get that clone onto your machine. For JeeLib, you’ll probably need to enter this path to it somewhere: git://git.jeelabs.org/jeelib.git

  • On Mac OSX, you need to install the Xcode developer tools, which includes Git (it’s a free install from the App Store). If you have an account at GitHub (or don’t mind getting one, it’s free), then I highly recommend getting the GitHub for Mac application. If not, you can always use the command line, like so:

        cd ~/Documents/Arduino/libraries
        git clone git://git.jeelabs.org/jeelib.git
    
  • On Linux, you need to install git through whatever package manager you’re using. On Debian / Ubuntu, this command line will probably do it:

        sudo apt-get install git-core
    

    After that, it’s the same as the Mac OSX command-line version, i.e. “cd …” and “git clone …” (see above).

So far, this is only a little more involved than grabbing that ZIP file. The gains start when you want to update your copy to the latest version. In git-speak, this is called “pulling” the latest changes (to your local disk). I encourage you to search around on the web, it’s usually as simple as doing “git pull” from inside the cloned area (from the command-line, some GUI, whatever). The difference with re-installing is absolute security – “git pull” will never overwrite or lose any changes you made, if they conflict with the original.

If all you do is track changes from time to time, then this is all you need to benefit from Git and GitHub.

If you actually make changes, then you’ll need to dig a little deeper when a “conflict” occurs, meaning you’ve made a change which interferes with changes made in the original on GitHub. But on the plus side, you’ll also be able to easily submit your changes (GitHub calls this “making a pull request”, i.e. pulling your changes back into the original). Why bother? Because contributions, no matter how small, are what make open source software fly!

Welcome to the world of open source software collaboration – where code lives, evolves, and grows.

The JeeNode, as seen from 15.24 km

In AVR, Hardware on Dec 19, 2011 at 00:01

(that’s 50,000 feet, or 9.47 miles – if those units mean more to you)

This post was prompted by a message on the forum, about what this whole “JeeNode” thing is, really.

Here are a JeeNode v6 and an Arduino Duemilanove, side by side:

DSC 2826

Let me start by saying, tongue-in-cheek: it’s all Arduino’s fault!

Because – let’s face it – the core of each Arduino and each JeeNode is really 95% the same: an Atmel AVR ATmega328P chip, surrounded by a teeny little bit of support circuitry and placed on a printed circuit board. So part of the confusion comes from the fact that the Arduino introduced its own conventions, moving it further away from the underlying common ATmega technology.

The differences between an Arduino Duemilanove and a JeeNode v6 – which resemble each other most – are:

  • the JeeNode has a “skinnier” shape, incompatible with Arduino “shields”
  • the Arduino runs at 5V, whereas the JeeNode runs at 3.3V (this carries through to all I/O pins)
  • the JeeNode includes a wireless radio module, called the RFM12B by HopeRF
  • the Arduino includes an FTDI <-> USB interface, while the JeeNode relies on an external one

There are many other differences, of course – so let’s continue this list a bit:

  • the Arduino’s “eco-system” is far, far bigger than the JeeNode’s (translation: everyone who finds out about JeeNodes probably already knows about the Arduino platform, and usually already has one or more of ’em)
  • this carries through to articles, websites, books, and discussion forums – Arduino is everywhere
  • you can do lots of stuff with an Arduino without ever touching a soldering iron, whereas the JeeNode is really not usable without some soldering (even if just to solder on a few pin headers)
  • different pinouts… it’s one big conspiracy to confuse everyone, of course! (just kidding: see below)

My reasons for coming up with the JeeNode have been documented in the past on this weblog, and can be summarized as: 1) running at 3.3V for lower power consumption and to better match modern sensors and chips, and 2) supporting a simpler form of expandability through the use of “plugs” – little boards which can be mixed and matched in many different combinations.

On the software side, JeeNodes remain fully compatible with the Arduino IDE, a convenient software environment for Windows, Mac, and Linux to develop “sketches” and upload them to the board(s).

The biggest stumbling block seems to be the way pins are identified. There are 4 conventions, all different:

  • Atmel’s hardware documentation talks about pins on its internal hardware ports, in a logical manner: so for example, there is a port “D” with 8 I/O pins numbered 0..7 – the sixth one would be called PD5.
  • Then there is the pin on the chip, this depends on which chip and which package is being referred to. On the 28-pin DIP package used for an ATmega328P, that same PD5 pin would be identified as pin 11. That’s the 11th pin, counting from the left side of the chip with pin 1 at the top.
  • The Arduino run-time library has software to control these pins. For a digital output pin, you can set it to “1” for example, by writing digitalWrite(5,1). This resembles PD5, but it fails for other pins (PB0 is “8” in Arduino-land, and PC1 is “1” if used as an analog input, or “15” if used otherwise – go figure…).
  • The JeeNode organizes several pins as part of 6-pin “Ports” (no relation to Atmels terminology!), each of them having 1 digital and 1 analog-or-digital pin.

The thing about JeeNode Ports is that there are 4 of them, and they can all be used for plugs in the same way. To support this, there’s a Ports library which lets you define port objects. This is an abstraction layer on top of the Arduino runtime. The reason is that it lets you associate a port object with a header on the JeeNode:

    Port myport (2);

Then you can connect your hardware / sensor / plug / whatever to the header marked “P2” on the JeeNode, and access it as follows:

    myport.digiWrite(1);

This happens to be the same pin as in the examples above, i.e. PD5 of an ATmega, pin 11 of the 28-pin DIP chip, and digitalWrite(5,1) on an Arduino. This also means that there are numerous ways to perform the same action of setting pin 11 of the chip to a logical “1” (i.e. 3.3V or 5V):

  • the “raw” C-level access, using Atmel’s register conventions and definitions (fastest, by far):

        PORTD |= 1 << 5;  // or ...
        PORTD |= _BV(5);  // same thing
        bitSet(PORTD, 5); // same thing, using an Arduino macro
    
  • the Arduino way of doing things:

        digitalWrite(5, 1);
    
  • the JeeNode Ports library way of doing things, as shown above:

        Port myport (2);
        myport.digiWrite(1);
    
  • … let’s throw in an extra bullet item, since every other list in this post appears to come in fours ;)

The one (minor) benefit you get from using the Ports approach on a JeeNode, is that if you attach your hardware to a different port, say port 3, then you only need to change a single line of code (to “Port myport (3);” in this case). The rest of the code, i.e. everywhere where its pins are being read or written, can then remain the same.

For an overview of all pinout differences, see also this weblog post. For full details, see the JeeNode PDF docs.

Developing a low-power sketch

In AVR, Software on Dec 13, 2011 at 00:01

As you’ll know if you’ve been reading this weblog for more than a few nanoseconds, I put a lot of time and effort into making the ATmega-based JeeNode use as little power as possible – microwatts, usually.

In the world of ultra-low power, the weakest link in the chain will determine whether your sketch runs days, weeks, months, or years… low power can be a surprisingly elusive goal. The last microoulombs are the hardest!

But it’s actually quite easy to get some real savings with only a little effort. Here are some things to avoid:

  • Don’t optimize in the wrong place – it’s tempting to start coding in a way which seems like a good idea in terms of power consumption, although more often than not the actual gains will be disappointing.

  • Don’t leave the lights on – the ATmega is amazingly easy to power down, which instantly reduces its consumption by several orders of magnitude. Make sure you do the same for every major power consumer.

  • Don’t just sit there, waiting – the worst thing you can do in terms of power consumption is wait. Unfortunately, that’s precisely what the Arduino runtime’s delay() and delayMicroseconds() calls do.

Ok, with this out of the way, I’ll describe a very simple way to get power consumption down – and hence battery lifetimes up (waaay up in fact, usually).

The trick is to use a convenience function from JeeLib (a.k.a. the Ports library). It’s in the “Sleepy” class, and it’s called loseSomeTime(). So if you have this in your code:

    delay(100);

… then you should replace it with this:

    Sleepy::loseSomeTime(100);

You also need to include the following code at the top of your sketch to avoid compilation and run-time errors:

    #include <JeeLib.h>

    ISR(WDT_vect) { Sleepy::watchdogEvent(); }

As the name indicates, the timing is not exact. That’s because the ATmega is put into a power down mode, and then later gets woken up by the watchdog timer (this is hardware, part of the ATmega). This timer can be several percent off, and although the milliseconds timer will automatically be adjusted by loseSomeTime(), it won’t be as accurate as when updated by the crystal or the ceramic resonator often used as system clock.

The second issue with the watchdog is that it can only delay in multiples of ≈ 16 ms. Any call to loseSomeTime() with an argument less than 16 will cause it to return immediately.

Furthermore, loseSomeTime() can only work with argument values up to 60,000 (60 seconds). If you need longer delays, you can simply create a loop, i.e. to wait 120 minutes in ultra-low power mode, use this:

    for (byte i = 0; i < 120; ++i)
      Sleepy::loseSomeTime(60000);

One last aspect of loseSomeTime() to be aware of, is that it will abort if an interrupt occurs. This doesn’t normally happen, since the ATmega is shut down, and with it most interrupt sources. But not all – so if loseSomeTime() returns prematurely, it will return 0. Normally, it returns 1.

The trade-off of loseSomeTime() is power consumption (system clock and timers are shut down) versus accuracy.

But the gains can be huge. Even this simple LED blink demo will use about 10 mA less (the ATmega’s power consumption while running at 16 MHz) than a version based on delay() calls:

    void loop () {
      digitalWrite(4, 1);
      Sleepy::loseSomeTime(250);
      digitalWrite(4, 0);
      Sleepy::loseSomeTime(250);
    }

To reduce this even further, you could shorten the blink ON time as follows:

    void loop () {
      digitalWrite(4, 1);
      Sleepy::loseSomeTime(50);
      digitalWrite(4, 0);
      Sleepy::loseSomeTime(450);
    }

The LED may be somewhat dimmer, but the battery will last 10x longer vs. the original delay() version.

Battery-powered operation isn’t hard, you just have to think a bit more about where the energy is going!

RFM12B low-power startup

In AVR, Hardware on Dec 8, 2011 at 00:01

The startup saga continues. Too many inter-related issues, I need to simplify…

Before tackling the power-ramp startup scenario, i.e. starting up a JeeNode (or JeeNode Micro) on a slowly-charging capacitor, I wanted to make absolutely certain that the sketch is set up to get the best low power mode as quickly as possible after a hardware power-on reset.

Time to create a test setup:

DSC 2816

This is a JeeNode running off 3.6 .. 3.9 V battery power, driving a MOSFET plug using this sketch:

Screen Shot 2011 11 30 at 17 08 54

In other words: power up for 2.5 seconds, power down for 0.5, then rinse and repeat. The JeeNode sitting upright at the bottom right is the Device Under Test (DUT). It’s a JeeNode without regulator, with a little test board to pass the ground connection through a 10 Ω resistor. This lets me measure current (or rather: voltage drop) as well as the voltage of the power supply.

Here is the behavior of a standard ATmega, with standard fuses and a sketch to init & power down the RFM12B:

SCR36

There’s a 1.5s startup delay as the boot loader listens for incoming commands, before it passes control to the current sketch. The lower half of this screen shot shows that point, i.e. right when the sketch is given control. Within about 250 µs, the RFM12B is put to sleep. The vertical scale is 2 mA/div (Ohm’s law, 10 Ω resistor).

Note the time scale: the lower portion is zoomed in 1000x w.r.t. the top.

After lots of experimentation, with the boot loader disabled, I managed to get startup a lot quicker, using a lot less energy. The code used was as follows (with these fuse settings: EXT = 0x06, HIGH = 0xDB, LOW = 0xC2):

Screen Shot 2011 11 30 at 18 22 47

Here is a screenshot with all the traces properly labeled and with measurement units added:

SCR50

Note again the horizontal time scale (top left). Here’s how to identify the different portions of these graphs:

  • the first blip is when the ATnega comes out of power-on reset
  • the second blip is for the rf12_initialize() and rf12_sleep() calls
  • the third blip is the first time loop() is run, which then quickly goes to sleep again

The big surprise (and disappointment) here, is the time between blips 1 and 2, where the average current consumption is about 0.75 mA (between the white cursor lines). This is caused by the RFM12B starting up (a bit irregularly) with the crystal oscillator enabled, instead of in power down.

The problem is that the RFM12B can’t be accessed in the first 30 ms or so after power up (probably because it’s still busy getting out of its own hardware reset). That’s a shame, since the ATmega can go to sleep in ≈ 250 µs.

The point of this all, is to make a JeeNode (or JNµ) start up with a capacitor powered from AC mains, using as low a current trickle as possible. But unless I can find a way to shut that RFM12B down very early on, it looks like a 1 mA or so trickle will be needed to overcome this initial power “hogging” behavior.

I’m not (yet?) willing to throw more hardware at the problem, but that would be one way to work around it: use an I/O pin and a MOSFET to power the RFM12B, after the voltage is high enough to be able to overcome this dip.

In the previous post, I managed to get a JeeNode started with what I though was a 10 µA trickle, but it now looks like I was off by two orders of magnitude in those tests. It’s easy to lose track of details while making changes!

Conclusion: an AC mains power supply with 1 mA trickle is an option, but I’m not ready to give up … yet!

Types of memory for an ATmega

In AVR, Hardware on Dec 5, 2011 at 00:01

There are a number of types of memory in (and for) the ATmega.

Flash memory is the place where compiled sketches end up. This memory has an important property: it retains its contents even when power is off, yet it’s modifiable (even by the ATmega itself – that’s how the boot loader works). An ATmega328 has 32 KByte of flash memory, enough to store fairly substantial sketches. When an ATmega is powered up, it starts executing the code stored in its flash memory.

RAM memory is the work memory where variables, buffers, strings, and other bits of data reside which get used and changed by the running sketch. The contents of RAM memory is lost when power is turned off, but access to the data kept here is extremely efficient. RAM is limited to 2 Kbyte on an ATmega328, and often a scarce resource, especially since all strings also need to stored there (these get copied from flash on startup).

EEPROM memory is the “configurable” memory available to a sketch. It’s very similar to flash, but not used for code – only data can be stored in EEPROM, and you need to call specific routine to read and write data (i.e. copy them to/from RAM). EEPROM memory retains its contents, which makes it very suitable for configuration settings, encryption keys, i.e. data which needs to be retained. There are 2 KByte of EEPROM in an ATmega328.

That’s it as far as built-in memory goes. The are many other types of memory (some far larger than the above), but they all have to be connected to the ATmega as “external memory” through its I/O pins. External memory is slower (sometimes dramatically so), and requires more code to work with.

There are three common ways to use external memory: I2C, SPI, and parallel (links / images from Wikipedia).

I2C memory uses the “I2C bus” protocol to talk to external hardware. The I2C bus is also known as the “Two Wire” bus, because it requires only 2 I/O lines (plus ground and power, i.e. 4 wires). The I2C bus is several orders of magnitude slower than the above three types of memory, but one advantage is that it is very low cost, and that I2C-capable chips are small and available in many shapes and sizes. The main types of I2C memory chips are SRAM (static RAM, same as in the ATmega) and EEPROM (also same as in the ATmega). The most common sizes are in the order of kilobytes, or dozens of kilobytes. Adding I2C memory such as the Memory Plug for JeeNodes, is cheap and simple. It’s also relatively slow – requiring in the order of a few milliseconds to write out a page of 32 bytes.

350px I2C svg

SPI memory uses the “SPI bus”, which needs 3 I/O pins shared among all SPI devices, plus 1 I/O “chip select” pin per device. It can be one or two orders of magnitude faster than I2C. The choice of SPI memory chips is more limited than I2C, but the memory chips are usually larger (such as the 2 Mbyte chip used in a JeeLink). The advantage of SPI over I2C is speed, but it’s still a serially-connected solution, and therefore still an order of magnitude slower than the ATmega’s built-in memory.

350px SPI single slave svg

Parallel memory uses many I/O pins together to get address and data information exchanged at a higher speed. This option is not really practical with an ATmega328, which has a limited number of I/O pins. It’s the way “real CPU’s” work, connecting the processor with external memory using over a hundred I/O pins.

One more memory type is worth mentioning here, because it’s easy to interface with an ATmega:

SD and µSD cards are a form of external flash memory, used widely in digital camera’s, for example. They offer by far the largest memory sizes (2 GByte and up) for a very low cost. The reason these cards can be used, is that the SD standard supports an SPI fallback mode, which means that they can be connected in the same way as other SPI memory chip solutions. Two caveats: 1) some initial handshaking will be needed to put an SD card into SPI mode, and 2) SD and µSD cards tend to be slow in SPI mode, i.e. nothing like SPI-capable memory chips.

In case you think that cheap and ample memory storage has always been so convenient: here are some flashes from the past of funky technologies used decades ago – check out mercury, drums, tubes, cores, and bubbles!

Update – see also this weblog post about RAM usage.

Generating sine waves with DDS

In AVR, Hardware on Dec 4, 2011 at 00:01

This is a topic I’ve covered before, in a post of about a year ago, but given the recent post about a sine wave generator, and yet another opportunity to learn and show the new scope in action, here goes…

The first step towards Direct Digital Synthesis (DDS), is to generate a rapidly-adjusted analog signal through a Digital-to-Analog Converter (DAC). One way to do so is to use a resistor ladder network, tied to a number of digital output pins. The idea is that all these pins are either 0 or 1 using fixed voltage levels, so with the proper resistors, you get a signal where bit N has the proper weight in the final signal to represent the voltage 2^N.

With 8 output bits, you get an 8-bit DAC which can output voltages 0 .. 3.3V in 256 steps, i.e. ≈ 13 mV each.

The next step is to approximate a sine wave by rapidly adjusting the output bits to the values of a sine wave. This toneGen sketch from the 2010 weblog post does precisely that:

This lets us generate an decent sine wave by stepping voltages in the proper sequence, looping forever:

SCR31

The trouble is the “glitching” and the step-wise behavior of the signal:

SCR32

This last image shows a small portion of the signal near zero, greatly magnified – and it’s quite a mess!

Fortunately, this is usually very easy to fix with a low-pass filter (even just a single R-C filter), since these artifacts are at a much higher frequency than the generated sine wave itself. But let’s not go into such details for now.

The AD9851 chip used in the Sine Wave Generator works the same way, but it has one more clever trick up its sleeve, which lets it generate arbitrary frequencies using a single fixed crystal-based master clock.

Let’s start from a 1 MHz clock, and use a 1000-element lookup table for the sine wave. Then every microsecond, a new value is looked up, and after 1000 lookups we can start over. The result would be a 1000Hz sine wave.

Now suppose we want a 500 Hz sine wave, driven by the same 1 MHz clock source: we can simply re-use the same table entry twice, before moving on to the next. Likewise, for a 1 Hz sine wave, we’d re-use the same table entries 1000 times, before moving on to the next table entry.

How about 300 Hz? Ah, yes, that’s a bit tricky. We’d need to re-use the same table entry 3 1/3rd times, which is not really meaningful. But what we can do, is represent the step time as a fractional value, i.e. 0.3. The 1st “step” is 0.3, the 2nd 0.6, the 3rd 0.9, the 4th 1.2, etc. The fractional part is called the “phase”, BTW.

And now the big trick: ignore the fractional part while deciding which table entry to use!

This causes the table entries to be used in sequence, but possibly with a slight jitter as the stepping progresses in such a way that the full table will be cycled through exactly fast enough to produce the desired frequency.

So 1 Hz output is produced with a 0.001 step, and 500 Hz is a 0.500 step. I.e. frequency = 1000 x step.

The same mechanism can also be used to generate frequencies higher than the 1 KHz you get when stepping through each of the 1000 table entries with a 1 µs step rate. All you need to do is allow the fractional step rate to be larger than 1. Stepping through the table with rate 100.000 (i.e. skipping the next 99 entries each time) will generate a 100 KHz sine wave, albeit with only 10 data points per wave. So its amplitude changes will not be as fine-grained, but its frequency will be exact. Again, same formula: frequency = 1000 x step – easy!

This is the basis on which a DDS chip such as the AD9851 can adjust its frequency output. It’s based on very fast hardware with a very fast DAC: the input clock can be up to 30 MHz, and it even has a built-in 6x clock multiplier, so the “sine wave table stepping” can be based on a 180 MHz clock, which is equivalent to a 5.56 ns step time!

For completeness: an Arbitrary Waveform Generator (AWG) works similar to a DDS in that it also synthesizes a wave by running samples through an DAC from a table, but now the table may contain anything, not just a pure sine wave. The entries in the table describe one full wave. In this case, stepping is not possible (neither fractional nor skipping) because then you’d no longer be creating the proper waveform. Instead, an AWG really has to accurately control its step time from table entry to table entry to produce the desired frequency. This is more complicated – also because the wave table is RAM, not just a fixed ROM with sine wave coefficients.

So much for DDS and AWG … onwards!

RF12 power optimization

In AVR, Hardware, Software on Dec 1, 2011 at 00:01

Here’s a small evolutionary change to the RF12 driver, to squeeze one more drop of power consumption out of it.

This is the code for which I’m trying to optimize power consumption:

Screen Shot 2011 11 19 at 11 31 16

The Sleepy::loseSomeTime() call is the big power saver. It puts the ATmega into a total power down mode, except for the watchdog timer, which is used to get it back out of this comatose state. So we’re sleeping for 10 seconds.

Around it are the rf_sleep() calls needed to put the RFM12B into low-power mode as well.

And lastly, the rf12_sendWait(3) call does something pretty nifty: it puts the ATmega into full power down mode between each byte sent to the RFM12B while transmitting. This requires a non-standard fuse setting in the ATmega – it only works with a ceramic resonator or the internal clock oscillator, not with a crystal: wake up out of power down within a few clock cycles.

The most efficient mode turns out to be with the ATmega running at 8 MHz off the internal RC oscillator (which starts up really fast). With default Arduino’ish settings, you have to use mode 2, i.e. a less extreme power down mode so it can wake up fast enough.

Here’s one complete transmission of a 8-byte payload (scope details to follow tomorrow):

SCR33

Each vertical division is 5 mA current draw (the voltage drop across a 10 Ω series resistor). You can see the ATmega turn on, drawing 5 .. 9 mA, and the RFM12B in transmit mode consuming about 23 mA.

The red line is pretty advanced stuff: it integrates the current over time – which is equivalent to the amount of charge consumed. At the end of the trace, this leads to a result of 7.22 microcoulombs per packet sent. One way to interpret this (thanks, Jörg – see comments), is that you could send one packet per second on an average current of less than 8 µA (hm, I think that should be 80 µA).

The “blips” are when the ATmega wakes up and feeds another byte to the RFM12B. In detail (edited image):

SCR16

These blips take about 32 µS @ 5 mA, which is what it takes to communicate with the RFM12B on the SPI bus at 2 MHz. The reason is that the RFM12B supports a 2.5 MHz maximum SPI rate (it turns out that this limitation only applies for data read from the RFM12B module).

The blips repeat 18 times, every 162 µS. Why 18? Well, an RF12 data transmission looks as follows:

RF12 packets

That’s 9 bytes of overhead, plus the 8 payload bytes, plus a trailing interrupt to shut down the RFM12B once the transmission is over.

For completeness – in case you think I can’t count blips: there’s one more activity peak at the start. That’s the call to rf12_canSend(), to check that the RFM12B is ready to start a transmission (which then takes 250 µs to start).

This is probably the limit of what you can push out of power savings with an ATmega (or ATtiny) and an RFM12B. Well, apart from: 1) sending less data, 2) increasing the transmit data rate, or 3) decreasing transmitter power.

When re-using the same code with “rf12_sendWait(2)” and running with normal fuse settings at 16 MHz using a ceramic resonator, it uses only slightly more charge – 7.70 µC, i.e. 7% more. So while this was a nice exercise, it’s not really a major improvement.

All in the name of nanowatt yak power s(h)aving…

All power-up puzzles solved?

In AVR, Hardware on Nov 30, 2011 at 00:01

As reported in a recent post, there were startup problems when powered from a 0.4 mA trickle-fed capacitor.

In short: it didn’t work…

The problem with a trickle-feed supply is not that the voltage level will ramp up very slowly (the brown-out detector and power-on reset circuitry should be able to handle that). The problem is that the circuit needs to draw less current than the trickle at all times – because otherwise the capacitor won’t ever reach its full charge level.

One problem was the MCP1702 voltage regulator, which has a large current draw before the input voltage reaches 3.3V where it can start regulating. So I removed the regulator, and created a setup which limits the capacitor charge to around 3.8V – thinking that without the regulator, the ATmega would at some point start up and immediately put itself and the RFM12B into sleep mode, letting the supply voltage rise a bit further.

Strangely enough, it didn’t work at all. I kept seeing a start-up spike of several milliamps. Here’s the current consumption on power-up (the scope shows the voltage over a 10 Ω resistor in series with the power supply):

DSC 2796

That’s over 10 milliamps, for well over a second – Huh?

And then it finally dawned on me: the boot loader! The ATmega is set to look for an upload right after power-up or reset, which is what the boot loader is all about. Guess what it does: look for incoming commands on the serial port for roughly one second, before passing control to the main sketch stored in the ATmega.

Clearly, the boot loader is running at full power. Whoops!

So the first conclusion is that in this context, we can’t use a boot loader. The solution is to change the high fuse from 0xDA to 0xDB with an ISP programmer. It’ll make it harder to upload code, but there’s no other way.

Great. I thought that would solve the problem. But that’s not all. The default fuse settings also cause the ATmega to wait for 65 milliseconds on power-up. This is for crystals to get up to a stable oscillation. Unfortunately, that means the ATmega is spending 65 ms in a higher-power mode on startup.

So I changed the fuses to use the 1K / 14 CK startup mode (power-up / reset). The way I read this, it means that the ATmega will power-up after 1024 + 14 clock cycles once it comes out of hardware reset, and after 1024 clock cycles when coming out of sleep mode.

Furthermore, the divide-by-8 prescaler fuse bit needs to be set, because the ATmega will power up with a 2.7 V supply voltage (the BOD level). At that level, running at 16 MHz is way out of spec, and no doubt very unreliable.

So all in all, the following fuse settings are required:

  • BOD level = 2.7V, i.e. don’t power up before the supply has reached 2.7V
  • enable ÷ 8 pre-scaler on startup (can be disabled in software later)
  • make the clock start up in low-power 1K / 14 CK mode
  • disable the boot loader, jump immediately to the main sketch

Here is the power consumption with these changes (note the 40x X scale and 5x Y scale differences):

DSC 2798

There’s still a 0.65 mA current draw during start-up. Unfortunately, this one is nasty: it’s caused by the RFM12B module, which powers up in this mode. Best thing I can do is put the RFM12B to sleep as soon as possible, but that can’t happen before the ATmega has started up fully. So basically, there’s a 0.65 mA current draw which we can’t get rid of (other than adding extra circuitry to control the RFM12B’s power – but see also below).

What this means, is that I’ll have to settle for a 1 mA trickle feed supply for now. It’s enough to keep charging the buffer cap, and this way things ought to finally get past that power-up hurdle.

And guess what? It works!

DSC 2801

The cap charges until the supply reaches 2.7V, then the ATmega snaps out of reset and puts the RFM12B to sleep.

The interesting thing now, is to check whether that MCP1702 current anomaly on startup really was a problem. So I switched back to a standard JeeNode, and tried it with the above fuse settings.

Hey, it still works! So we could go back to a 12V zener charging a 100 µF cap. This puzzle has come full circle!

More good news – it looks like there is a sneaky way to avoid the 0.65 mA power-up current draw of the RFM12B: make the ATmega start up at 1.8V instead of 2.7V – the RFM12B isn’t pulling much current at that level. So if we turn it off right away then the RFM12B will be put to sleep before it gets a chance to draw too much current.

Does this work? You bet. Here is by far the craziest low-power setup I’ve ever been able to get going:

DSC 2803

That’s a 100 µF cap charged using a 10 µA trickle. You can see the 1.8V bump where the ATmega kicks in, inits the RFM12B, puts it to sleep, and later on sends 2 packets. This is a standard JeeNode, but with special fuse settings:

  • internal 8 MHz RC oscillator, fastest startup
  • don’t enter the boot loader
  • brown-out level is set to 1.8V

The fuse settings are: extended = 0x06, high = 0xDB, low = 0xC2.

Fascinating how everything affects everything, eh?

UpdateI’m having some doubts about this last result. Will need to triple-check my calculations on this one. That last report is most definitely incorrect, there’s no way to get the RFM12B to start up with a 10 µA trickle – it starts up with the crystal oscillator active, which means that it’ll draw at least 0.6 mA until put to sleep.

Meet the Slave Plug

In AVR, Hardware on Nov 12, 2011 at 00:01

While fooling around with the ATtiny85 for the first AC current measurement tests, I found that ATtiny85 to be a pretty neat little chip in and by itself.

So why not create a plug for it, eh? Here’s the new Slave Plug:

DSC 2707

It’s all through-hole, so that it’s easy to assemble and easy to replace the ATtiny85 (or other compatible unit).

There are just enough pins to act as a (daisy-chainable) I2C slave and to drive a 6-pin header with 3..4 I/O pins:

Screen Shot 2011 11 08 at 23 14 11

With some care, that header can be made compatible with JeeNode ports, which means that this plug could even be used to act as host for another plug. Sort of an offloaded task for the “main” JeeNode. Or perhaps stand-alone, just to drive that single plug. Note also that the ATtiny85 supports differential ADC and an optional 20x gain stage, so that full scale voltages down to ≈ 55 mV can be measured (using the internal 1.1V bandgap as reference).

Here’s the schematic:

Screen Shot 2011 11 08 at 23 12 50

Pin 1 of the side header can be tied to either PWR (to create a port) or to the ATtiny’s RESET (SJ1).

And the port’s IRQ pin can optionally be connected to the ATtiny’s RESET pin via a solder jumper (SJ2).

Using a fuse setting, the ATtiny’s RESET pin can be turned into an I/O pin, but this means you’ll need a high-voltage programmer to re-flash the chip and lose the normal ISP programmability.

I’ll add it to the shop shortly, along with the other new boards.

It’s called v2, because there has been an (SMD) Slave Plug before, but that never made it into the real world.

Pins, damned pins, and JeeNodes

In AVR, Hardware, Software on Nov 10, 2011 at 00:01

(to rephrase Mark Twain …)

There is confusion in the ATmega / Arduino / JeeNode world, as brought to my attention again in the forum.

It all depends on your perspective, really:

  • if you want to connect to pins on the ATmega chip, then you’re after “pin 6”, “pin 17”, and “pin 26”
  • if you want to understand the ATmega data sheet, then you’re after names like “PD4”, “MOSI”, and “PC3”
  • if you want to follow Arduino sketches, then you want “digital 4”, “digital 12 11″, and “analog 3”
  • if you want to plug into JeeNode ports, then you’d prefer “DIO1”, “MOSI on SPI/ISP”, and “AIO4”

They are all the same thing.

Well, sort of. If you’re looking at an SMD chip, the pin numbers change, and if you’re using an Arduino Mega board, some names differ as well. They might also be different if you were to look at older versions of the JeeNode. In short: it’s messy because people come from different perspectives, and it’s unavoidable. There is no relation between “pin 4”, “PD4”, “digital 4”, and “DIO4” – other than that they all mention the digit 4 …

For that same reason, diagrams are not always obvious. For example, this one is nicely informative:

Arduino To Atmega8 Pins

But it doesn’t help one bit when hooking up a JeeNode.

Likewise, this one doesn’t really help if you’re after the pins on the ATmega328 chip or Arduino pin #’s:

Screen Shot 2011 11 08 at 13 02 04

Then there’s this overview, but it’s incomplete – only the DIO and AIO pins are mapped to the rest, in a table:

JN colors

This one from TankSlappa uses the DIP chip as starting point (and creates new abbreviations for DIO1, etc, alas):

Affectation GPIO JeeNode

Each of these diagrams conveys useful information. But none of them seem to be sufficient on their own.

Can we do better? I’ll be happy to take suggestions and make a new – c o n v e n i e n t – one-pager.

Fixing the Arduino’s PWM #2

In AVR, Software on Nov 9, 2011 at 00:01

Yesterday’s post identified a problem in the way different PWM pulses are generated in the ATmega.

It’s all a matter of configuration, since evidently the timers used to generate the PWM signals all run off the same clock signal, and can therefore be made to cycle at exactly the same rate (they don’t have to roll over at the same time for our purposes, but they do have to count equally fast).

The problem is caused by the fact than PWM pins D.5 and D.6 are based on timer 0, which is also used as millisecond timer, whereas PWM pin D.9 is based on timer 1. It’s not a good idea to mess with timer 0, because that would affect the delay() and millis() code and affect all parts of a sketch which are timing-dependent.

Timer 0 is set in “Fast PWM” mode, which is not perfect. So the Wiring / Arduino team decided to use “Phase Correct PWM” mode for timers 1 and 2.

In Fast PWM mode, the timer just counts from 0 to 255, and the PWM output turns high when the counter is in a specific range. So far so good.

In Phase Correct PWM mode, the timer counts from 0 to 255 and then back to 0. Again, the PWM output turns high when the counter is in a specific range.

The phase correct mode counts up and down, and takes twice as long, so that explains why the green LED output runs at half the speed of the others.

Except that… it’s not exactly twice!

Timer 0 wraps every 256 counts, and that should be kept as is to keep the millisecond code happy.

But timers 1 and 2 wrap every 0 -> 255 -> 0 = 511 counts (I think – or is it 510?). Hence the out-of-sync effect which is causing so much trouble for the LED Node.

See also Ken Shirriff informative page titled Secrets of Arduino PWM, for the ins and outs of PWM.

The solution turns out to be ridiculously simple:

    bitSet(TCCR1B, WGM12);

Just adding that single-bit change to setup() will force timer 1 into Fast PWM mode as well. The result:

DSC 2730

This picture was taken with the scope running. The signals are in lock-step and rock solid. More importantly, the result is a perfectly smooth LED light – yippie!

Fixing the Arduino’s PWM

In AVR, Hardware on Nov 8, 2011 at 00:01

The LED Node presented a few days ago, with the software to drive it, has exposed a nasty little problem…

The light has a slight periodic flicker.

Not good, in fact this gets pretty irritating fairly quickly. But how can this be? Each of the RGB colors is dimmed using the ATmega’s hardware PWM, after all – and well above the 50 Hz rate which our eyes could detect!

Luckily, I recently borrowed a oscilloscope from a friend which allowed me investigate this further. This is a Rigol DS5062CA, a predecessor of the popular DS1052E.

So let’s dive in, shall we?

DSC 2727

Channel 1 is tied to the PWM output driving the MOSFET for the green LEDs, and likewise channel 2 is for blue. There is little point in connecting to the PWM for the red LEDs, because these were driven 100%, i.e. not pulsed. The output color is sort-of-warm-white for the PWM ratios used for this test.

The first surprise was the PWM cycle frequency, which turns out to differ for these two PWM channels. The blue LED’s PWM pulse cycles at twice the rate of the green LED’s PWM (shown as yellow trace).

Ah, but wait… it’s not an exact multiple!

This is very easy to see while the scope is auto-triggering, because no matter how I set it up, I can only get one of the channels to stabilize. The other one always keeps moving, meaning that its phase is constantly changing.

The scope has some measurement options, and as you can see the PWM frequencies are not exact multiples (actually, this readout was a bit erratic – sometimes the frequency did get reported as exact multiple).

So what’s happening, is that there is sort of a Moiré effect between the different LED colors, and the difference is small enough that it manifests itself as a slight but very annoying flickering of 1 or 2 Hz, roughly.

I’ve been using analogWrite() to set these PWM values, but it now looks like I’ll have to change the setup and configure the timers and PWM outputs myself. Surely there’s a way to make all the timers count at the same rate?

Here’s another check I did:

DSC 2729

In this snapshot, channel 1 is the same as before, i.e. the PWM output for the green LEDs, while channel 2 is the power supply voltage (AC-coupled, i.e. only showing the fluctuations). You can see how the green LEDs pull the 12V down when turned on, with the blue LEDs presumably pulling it down further twice as often.

Again, the scope’s measurement capabilities come in handy to see the scale of these variations. Nothing extreme really, although I might add a fat capacitor to try and dampen them. I suspect that the combination of the out-of-sync PWMs and these slight power level fluctuations are what’s causing the visible flicker.

As you can see, a Digital Storage Oscilloscope (DSO) – even a basic one! – can be a fantastic diagnostic tool.

There is one more issue with these RGB LED strips:

DSC 2728

If you look closely, you can see that the left side is slightly more yellow and the right side slightly more red. Which is odd, because both strips are driven from the same LED Node, for a total of 5 meter. My explanation for this is that the ≈ 1000 Hz PWM rate, especially the short blue pulses, are being dampened by the strip’s inductance while traveling from the LED Node’s MOSFETs through the left strip to the right strip.

I haven’t tried it, but one way to verify this would be to compare the power signal of the blue LED at the start and at the end of the LED strip. If my theory is correct, then the pulses should look different.

It’s a small effect, but it shows, and I don’t like it at all. I’ve got two ways to solve it, I think: 1) feed the PWM power signals separately to both LED strips, or 2) use two LED Nodes, each directly feeding their own LEDs.

Maybe it’s just the +12V supply line, in which case it’d be enough to connect +12V to the end as well. We’ll see.

Finicky things, them RGB LED strips!

Update – I’ve placed the LED Node between both strips. Color differences are now almost gone, but there’s still a shift-to-red towards the ends, i.e. the high PWM frequency is hampered by signal propagation.

A color-shifting LED Node

In AVR, Software on Nov 5, 2011 at 00:01

Yesterday’s post described the logic which should be implemented in the LED node. It is fairly elaborate because I want to support subtle gradual color changes to simulate the natural sunrise and sunset colors.

Here’s the ledNode sketch – with a few parts omitted for brevity:

Screen Shot 2011 10 27 at 04 56 36

It’s pretty long, but I wanted to include it anyway to show how yesterday’s specifications can be implemented with not too much trouble.

The main trick is the use of fractional integers in the useRamps() routine. The point is that to get from brightness level X to Y in N steps, you can’t just use integers: say red needs to change from 100 to 200 in 100 steps, then that would simply be a delta of 1 for each step, but if blue needs to change from 10 to 20 in exactly the same amount of time, then the blue value really should be incremented only once every 10 steps, i.e. an increment of 0.1 if it were implemented with floating point.

And although the gcc compiler fully supports floating point on an ATmega, this really has a major impact on code size and execution performance, because the entire floating point system is done in software, i.e. emulated. An ATmega does not have hardware floating point.

It’s not hard to avoid using floating point. In this case, I used 32-bit (long) ints, with a fixed decimal point of 23 bits. IOW, the integer value 99 is represented as “99 << 23” in this context. It’s a bit like saying, let’s drop the decimal point and write down all our currency amounts in cents – i.e. 2 implied decimals (€10 = 1000, €1 = 100, €0.50 = 50, etc).

To make this work for this sketch, all we need to do is shift right or left by 23 bits in the right places. It turns out that is only affects the setLeds() and useRamp() code. As a result, RGB values will change in whatever small increments are needed to reach their final value in the desired number of 0.01s steps.

The sketch compiles to just slightly over 5 Kb by the way, so all this fractional trickery could have been avoided. But for me, writing mean and lean code has become second nature, and sort of an automatic challenge and puzzle I like to solve. Feel free to change as you see fit, of course – it’s all open source as usual.

So there you go: a color-shifting LED strip driver. Now I gotta figure out nice ramp presets for sunrise & sunset!

A sketch for the LED Node

In AVR, Software on Nov 4, 2011 at 00:01

The LED Node presented yesterday needs some software to make it do things, of course. Before writing that sketch, I first wrote a small test sketch to verify that all RGB colors worked:

Screen Shot 2011 10 26 at 20 59 17

That’s the entire sketch, it’ll cycle through all the 7 main colors (3 RGB, and 4 combinations) as well as black. There’s some bit trickery going on here, so let me describe how it works:

  • a counter gets incremented each time through the loop
  • the loop runs 200 times per second, due to the “delay(5)” at the end
  • the counter is a 16-bit int, but only the lower 11 bits are used
  • bits 0..7 are used as brightness level, by passing that to the analogWrite() calls
  • when bit 8 is set, the blue LED’s brightness is adjusted (pin 5)
  • when bit 9 is set, the red LED’s brightness is adjusted (pin 6)
  • when bit 10 is set, the green LED’s brightness is adjusted (pin 9)

Another way to look at this, is as a 3-bit counter (bits 8..10) cycling through all the RGB combinations, and for each combination, a level gets incremented from 0..255 – so there are 11 bits in use, i.e. 2048 combinations, and with 200 steps per second, the entire color pattern repeats about once every 10 seconds.

Anyway, the next step is to write a real LED Node driver. It should support the following tasks:

  • listen to incoming packets to change the lights
  • allow gradually changing the current RGB color setting to a new RGB mix
  • support adjustable durations for color changes, in steps of 1 second

So the idea is: at any point in time, the RGB LEDs are lit with a certain PWM-controlled intensity (0..255 for each, i.e. a 24-bit color setting). The 0,0,0 value is fully off, while 255,255,255 is fully on (which is a fairly ugly blueish tint). From there, the unit must figure out how to gradually change the RGB values towards another target RGB value, and deal with all the work and timing to get there.

I don’t really want to have to think about these RGB values all the time though, so the LED Node sketch must also support “presets”. After pondering a bit about it, I came up with the following model:

  • setting presets are called “ramps”, and there can be up to 100 of them
  • each ramp has a target RGB value it wants to reach, and the time it should take to get there
  • ramps can be chained, i.e. when a ramp has reached its final value, it can automatically start another ramp
  • ramps can be sent to the unit via wireless (of course!), and stored in any of the presets 1..99
  • preset 0 is special, it is always the “immediate all off” setting and can’t be changed
  • to start a ramp, just send a 1-byte packet with the 0..99 ramp number
  • to save a ramp as a preset, send a 6-byte packet (preset#, R, G, B, duration, and chain)
  • preset 0 is special: when “saving” to preset #0 it gets started immediately (instead of being saved)
  • presets 0..9 contain standard fixed ramps on power-up (presets 1..9 can be changed afterwards)
  • the maximum duration of a single ramp is 255 seconds, i.e. over 4 minutes

Quite an elaborate design after all, but this way I can figure out a nice set of color transitions and store them in each unit once and for all. After that, sending a “command” in the form of a 1-byte packet is all that’s needed to start a ramp (or a series of ramps) which will vary the lighting according to the stored presets.

Hm, this “ledNode” sketch has become a bit longer than expected – I’ll present that tomorrow.

Meet the LED Node

In AVR, Software on Nov 3, 2011 at 00:01

More than a year has passed, and I still haven’t finished the RGB LED project. The goal was to have lots of RGB LED strips around the house, high up near the ceiling to provide indirect lighting.

The reason is perhaps a bit unusual, but that has never stopped me: I want to simulate sunrise & sunset (both brightness and colors) – not at the actual time of the real sunset and sunrise however, but when waking up and and when it’s time to go to bed. Also in the bedroom, as a gentle signal before the alarm goes off.

Now that winter time is approaching and mornings are getting darker, this project really needs to be completed. The problem with the previous attempt was that it’s pretty difficult to achieve a really even control of brightness and colors with software interrupts. The main reason is that there are more interrupt sources (the clock and the RFM12B wireless module), which affect the timing in subtle, but visibly irregular, ways.

So I created a dedicated solution, called the LED Node:

Screen Shot 2011 10 26 at 11 48 54

It’s basically the combination of a JeeNode, one-and-a-half MOSFET Plugs, and a Room Board, with the difference that all MOSFETs are tied to I/O pins which support hardware PWM. The Room Board option was added, because if I’m going to put 12V power all over the house anyway for these LEDs, and if I want to monitor temperature, humidity, light, and motion in most of the rooms, then it makes good sense to combine it all in one.

Here is my first build (note that all the components are through-hole), connected to a small test strip:

DSC 2706

The pinouts are pre-arranged to connect to a standard common cathode anode RGB strip, and the SHT11 temp / humidity sensor is positioned as far away from the LEDs as possible, since every source of heat will affect its readings. For the same reason, the LDR is placed at the end so it can be aimed away from the light-producing LED strip. I haven’t thought much about the PIR mounting so far, but at least the 3-pin header is there.

The LED Node is 18 by 132 mm, so that it fits inside a U-shaped PVC profile I intend to use for these strips. There can be some issues with color fringing which require care in orienting the strips to avoid problems.

Apart from some I/O pin allocations required to access the hardware PWM, the LED Node is fully compatible with a JeeNode. It’s also fully compatible with Arduino boards of course, since it has the same ATmega328. There’s an FTDI header to attach to a USB BUB for uploading sketches and debugging.

The MOSFETS easily support 5 m of LED strips with 30 RGB LEDs per meter without getting warm. Probably much more – I haven’t tried it with heavier loads yet.

Here’s what I used as basic prototype of the whole thing, as presented last year:

DSC 2710

Tomorrow, I’ll describe a sketch for this unit which supports gradual color changes.

CC-RT: Pin assignments

In AVR, Hardware on Oct 29, 2011 at 00:01

Part 4 of the Crafted Circuits – Reflow Timer series.

Now that all the pieces of the circuit are known, more or less (I’ll assume that the MAX31855 can be used), it’s time to figure out whether everything will fit together. One issue I’d like to get out of the way early on, is pin assignments on the ATmega. There are 20 I/O pins: 14 digital, of which 6 PWM, and 6 digital-or-analog.

The best thing would be to make this as compatible with existing products as possible, because that simplifies the re-use of libraries. For this reason, I’ll hook up the RFM12B wireless module in the same way as on a JeeNode:

  • D.2 = INT0 = RFM12B INT
  • D.10 = SS = RFM12B CS
  • D.11 = MOSI = RFM12B SI
  • D.12 = MISO = RFM12B SO
  • D.13 = SCK = RFM12B SCK

5 I/O pins used up – let’s see how many the rest needs:

  • 2 LED’s = 2 pins
  • 2 buttons = 2 pins
  • buzzer = 1 pin
  • LCD + backlight = 7 pins
  • thermocouple = 3 pins
  • SSR output = 1 pin

Total 5 + 16 = 21 pins. Whoa, we’re running out of pins!

Unfortunately, we’re not there yet: the thermocouple chip consumes about 1 mA, so we need a way to power it down if we want a serious auto power-off option. That’s one extra pin.

Also, it would be very nice if this thing can be programmed like a regular Arduino or JeeNode, i.e. using D0 and D1 as serial I/O. That also would help a lot during debugging and in case we decide to use the serial port for configuration. Hm, another 2 pins.

And lastly, I’d like to be able to measure the current battery voltage. Drat, yet another (analog) pin.

All in all we seem to need 5 more pins than are available on an ATmega168/328 28-DIP chip!

The good news is that there are usually a few ways to play tricks and share pins for multiple purposes. One easy way out would be to just use an I/O expander (like the LCD-plug) and gain 5 I/O pins right away. But that’s cheating by throwing more hardware at the problem. Let’s look at some other options:

  • the SSR output can be combined with one of the LEDs, since a red LED will probably be used to indicate “heater on” anyway
  • the thermocouple chip is a (read-only) SPI chip, which means that its SCK and SO pins can be shared with those of the RFM12B
  • one way to free the button pins is to put the buttons on data lines used by the LCD – with extra resistors to let the LCD output work even while pressed
  • the buttons and LEDs could be combined, as on the Blink Plug (this is mildly confusing, since pressing a button always lights its LED as well), but this would prevent sharing the SSR output with the red LED
  • multiple buttons could be tied to a single analog input pin by adding some extra resistors, but this rules out the use of pin-change interrupts
  • yet another trick is to combine a high-impedance analog input (for measuring battery voltage) with a pin which is usually used as output, such as one of the LCD data pins

I’m inclined to adopt the first three tricks. That frees five pins – one can be used to power the thermocouple chip and two would be D0 and D1 to support standard serial I/O. We could have up to 5 push buttons this way.

So all in all, the 28-pin ATmega seems to be just right for the Reflow Timer. Depending on the complexity of the sketch, either an ATmega168 or an ATmega328 could be used. My current reflow sketch fits in either one.

With luck, the Reflow Timer can remain compatible with Arduino, RBBB, JeeNode, etc. and it will support sketch uploads in exactly the same way as with JeeNodes and RBBB’s, i.e. through an FTDI 6-pin header with a USB-to-FTDI interface such as the USB-BUB.

Let’s try and come up with a tentative pin allocation:

  • D.0 and D.1 = serial I/O via FTDI pins
  • D.2 and D.10 .. D.13 = RFM12B, as above
  • D.3 = LCD backlight (supports hardware PWM)
  • D.4 = buzzer
  • D.5 and D.6 = LED outputs (both support PWM)
  • D.8 and D.9 = thermocouple power and chip select
  • A.0 = battery voltage readout
  • A.1 .. A.5 and D7 = LCD (4 data + 2 control)
  • A.1 .. A.5 = shared with up to 5 push buttons

Several pins could be changed if this will simplify the board layout later – but hey, ya gotta start somewhere!

Note that I’m using D.X as shorthand for digital pins, and A.Y for analog pins, matching Arduino terminology (where A.Y can also be used as digital pin => D.(Y+14)).

The next step will be to work out more electrical details, i.e. figure out how to add some new features.

AC current node prototype

In AVR, Hardware on Oct 27, 2011 at 00:01

Time for some pictures. Here’s the “AC current node” prototype I’ve been working on:

DSC 2680

And in case you’re wondering: that’s a simple plastic enclosure I found a while back, which looks pretty much like (and probably was intended as) … a game catridge!

Here’s the completed unit with a test hookup:

DSC 2690

You can see the transformer-less power supply, and an ATtiny84-with-RFM12B board, which I’m tentatively calling the “JeeNode Micro” (“JNµ”) – 16 x 48 x 4 mm:

Screen Shot 2011 10 17 at 21 18 07

Please note that I’m using this for internal projects for now. I haven’t figured out whether it’s suitable for the shop, since the JNµ is different from a JeeNode in several ways, not in the least in that it requires quite a bit more hand-holding to develop “sketches” for and to load them into the unit. This isn’t even the first JNµ board – I’ve tried several different layouts in the past.

For this particular project though, it’s quite a good fit, both in size and due to the ATtiny’s differential ADC plus 20 x gain stage. I’ve yet to hook up the analog input to the sense resistor, BTW. It’s all work-in-progress…

Running on charge

In AVR, Hardware, Software on Oct 26, 2011 at 00:01

Now that the supercap charger works, and now that I’ve switched to the ATtiny84 as processor, everything is ready to create a self-contained AC current sensing node.

The one missing piece is the software for it all. It’s going to take a while to get it tweaked, tuned, and optimized, but a basic check is actually quite easy to do.

Here is the main loop if my first test, reusing most of the code already in the tiny50hz sketch:

Screen Shot 2011 10 17 at 20 03 56

My main goal was to quickly get power consumption down, so that the ATtiny would use less than what’s available through the low-power supply, i.e. roughly 1 mA. Without extra steps, it’ll draw over 4 mA @ 8 MHz.

What I did was to reduce the clock rate to 1 MHz (except while processing RF12 packets), and to turn off subsystems while not needed (timer 1 is never used, and the ADC and USI h/w is now enabled only while used).

These two lines at the top of loop() are special:

  set_sleep_mode(SLEEP_MODE_IDLE);
  sleep_mode();

They will reduce power consumption by halting the processor until the next interrupt. Since time is being tracked via the millis() call, and since that operates through a timer interrupt, there is no reason to check for a new millisecond transition until the next interrupt. This is a quick way to cut power consumption in half.

But keep in mind that the processor is still running most of the time, and running at 1 MHz. That explains why the current consumption remains at a relatively high 440 µA in the above code (with a brief “power blip” every 16 s). For comparison: in power-down mode, current draw could be cut to 4 µA (with the watchdog timer running).

Still, this should be enough for a first test. Sure enough, it works fine – powered by the ISP programmer:

    OK 17 84 2 0 0
    OK 17 67 2 84 2
    OK 17 103 2 67 2

Every ≈ 16 seconds, a 4-byte packet comes in with the latest reading and the previous reading (as 2-byte ints).

The interesting bit is what happens when the ISP programmer gets disconnected. While connected, it charged the supercap to about 4.9V – so with a bit of luck, this node should keep running for a while, right?

Guess what… it does. My test node just sent out 197 packets before running out of steam!

This includes the ≈ 500 x ADC samples and 16-second waits in each cycle. IOW, a 0.47 F capacitor charged to 4.9V clearly has more than enough energy for this application. In fact, it makes me wonder whether even a normal electrolytic capacitor might be sufficient. The benefit of a smaller capacitor would be that the node can be up and running much faster than the 1 hour or so needed to charge up a supercap.

Here’s my very very sketchy estimate:

  • let’s assume the unit operates down to 2.5 V
  • with 4.9 V charge, it can run for about 200 cycles
  • so with 3.7 V charge (on AC mains), it ought to run for 100 cycles
  • using a capacitor 1/100th the size, we ought to have enough charge for one cycle
  • with more power-saving logic, energy use can no doubt be lowered further

Given that the node is permanently powered, a 4,700 µF cap ought to be sufficient. I’ve ordered a 6,800 µF @ 6.3V electrolytic cap – with a bit of luck, that should also work. And if it does indeed, startup times will go down drastically, to hopefully just a few seconds.

Progress!

Picking an ATtiny

In AVR, Hardware on Oct 25, 2011 at 00:01

The reason I’m using an ATtiny for the AC current measurement setup, is their differential ADC + gain, and because it is fairly easy to develop for them using the same Arduino IDE as used by, eh, well, Arduino’s and JeeNodes. There are good installers for Windows, Mac OSX, and Linux.

There are several very interesting alternatives other than ATmega and ATtiny, such as the Microchip Technologies PIC and the Texas Instruments MSP430 series. But while they each are attractive for a number of reasons, they either have only a development environment for Windows, or they don’t support standard gcc, or they just don’t offer enough of an advantage over the Atmel AVR series to justify switching. So for something like the AC current node, which doesn’t even need to run off a battery, I’d rather stick to the Arduino IDE and carry over much of what is already available for it. In terms of cost, the differences are minimal.

The trouble with the ATtiny85 I’ve been using for the AC current sensor is that it only has at most 6 I/O pins, while the RFM12B needs 5 to operate (with polling instead of interrupts, this could be reduced to 4).

I’ve tried hard to find tricks to re-use pins, so that the differential ADC pins can be used during measurements while still supporting the RFM12B somehow. I even considered using a 1-pin OOK transmitter instead of the RFM12B. But in the end I gave up – the hassle of finding a solution, figuring out how to support this in software, and still have a decent way of debugging this (read: ISP) … it didn’t add up.

It’s much easier to pick a chip which is slightly less I/O-pin limited, such as the 14-pin ATtiny84:

Screen Shot 2011 10 17 at 14 10 11

One drawback w.r.t. to the ATtiny85, is that it has no 2.56V bandgap reference, only 1.1V – but it does have differential ADC inputs with optional 20x gain stage, which is what made AC current measurements possible.

It turns out that the ATtiny84 has enough I/O pins (a whopping 11!) to support an SPI interface to the RFM12B as well as 2 complete JeeNode-like ports. There is in fact enough I/O capability here to hook up a Room Board.

The 8 Kb flash rom size is sufficient for the RF12 driver plus a bit of application-specific functionality. The 512-byte RAM is not huge, but should also be sufficient for many purposes (two full RF12 buffers will use up less than a third of what’s available). And lastly, there are 512 bytes of EEPROM – more than enough.

To be honest, I’ve been fooling around with this chip for some time, since it could be used to create even smaller PCB’s than the JeeNode. But it has taken me quite a while to get the SPI working (both hardware- and software-based), which was essential to support the RFM12B wireless module. The good news is that it now does, so this is what I’m going to use for the rest of the AC current sensor experiments – wireless is on the way!

Stay tuned …

No, wait. One more factoid: this weblog was started exactly 3 years ago. Celebration time – cheers!

Voltage levels

In AVR, Hardware on Oct 17, 2011 at 00:01

In yesterday’s post, I described the idea of powering the AC current detector via a transformer-less power supply, using a very large capacitor or a supercap.

That means the whole circuit ends up being connected to 220V AC mains. You might think that nothing changed, since the circuit was already connected to mains via the 0.1 Ω shunt, but there’s more to it – as always!

If the power supply is tied to AC mains, then that means the circuit’s GND and VCC are also tied to these wires. The problem is that these two things interfere with each other:

JC s Doodles page 19

Because now we have a signal coming from the voltage drop generated by the shunt which is referenced to the same voltage level as the GND of the circuit. In other words, that signal we’re trying to measure now swings around zero! And while the ATtiny has a differential input, which in principle only cares about the voltage differential between two pins, it’s not designed to deal with negative voltages.

Uh, oh – we’re in trouble!

I could use a capacitor to “AC-couple” the 50 Hz frequency into a voltage divider, but that effectively creates a high-pass filter which attenuates the 50 Hz and lets more of the noise through. Not a very nice outlook, and it’s also going to require a few additional passive components. I’m still aiming for a truly minimal component count.

But we’re in luck this time. The differential ADC appears to be perfectly happy with tying one side to ground. It might not be able to measure the negative swings, but it does the positive ones just fine. When I tried it on my existing setup, I still got more or less the same readings.

Still, we do have to be careful. A negative voltage on any input pin is going to seek its way through the ESD protection diodes present on each ATtiny I/O pin. Keep in mind that we’re dealing with a very low-impedance shunt, and large currents. So it’s important to limit the effect of negative swings to avoid damage to the chip. The easiest way to do so is to include a 1 kΩ resistor in series, i.e. between signal and ADC input pin. That way, even a 1 V negative voltage excursion will drive less than 1 mA current through the ESR diode, a value which is still well within specs. Even better, that 1 kΩ resistor can be combined with a 0.1 µF cap to ground, as low-pass for the ADC.

Good, so if that weak-supply-feeding-a-big-cap idea works, then the rest of the circuit ought to continue working as intended, even though we’re operating at the limit of the ATtiny’s ADC voltage range.

All that’s left to do then, is get that power supply right. Oh, wait: and figure out a way to get a wireless setup going. Oh, and also figure out a good enclosure to keep this dangerous hookup safely tucked away and isolated.

Oh well. Not there yet, but progress nonetheless!

CC-RT: Initial requirements

In AVR, Hardware, Software on Oct 14, 2011 at 00:01

Let’s get going with the CC-RT series and try to define the Reflow Timer in a bit more detail. In fact, let me collect a wish list of things I’d like to see in there:

The Reflow Timer should…

  • support a wide range of ovens, grills, toasters, and skillets
  • be self-contained and safe to build and operate
  • include some buttons and some sort of indicator or display
  • be created with through-hole parts as much as possible
  • (re-) use the same technologies as other JeeLabs products
  • be built on a custom-designed printed circuit board
  • use a convenient and robust mechanical construction
  • be very low-cost and simple to build

To start with that last point: the aim is to stay under € 100 as end-user price, including a simple toaster and whatever else is needed to control it. That’s a fairly limiting goal, BTW.

I’m sticking to “the same technologies” to make my life easy, both in terms of design and to simplify inventory issues later, once the Reflow Timer is in the shop. That translates to: an Arduino-like design with an ATmega328, and (for reasons to be explained next) an RFM12B wireless module.

Safety is a major concern, since controlling a heater tied to 220 V definitely has its risks. My solution to controlling an oven of up to 2000 W is the same as what I’ve been doing so far: use a commercially available and tested power switch, controlled via an RF signal. KAKU or FS20 come to mind, since there is already code to send out the proper signals through an RFM12B module. Range will not be an issue, since presumably everything will be within a meter or so from each other.

With wireless control, we avoid all contact with the mains power line. I’ll take it one step further and make the unit battery-operated as well. There are two reasons for this: if we’re going to uses a thermocouple, then leakage currents and transients can play nasty games with sensors. These issues are gone if there is no galvanic connection to anything else. The second reason is that having the AC mains cable of a power supply running near a very hot object is not a great idea. Besides, I don’t like clutter.

Having said this, I do not want to rule out a couple of alternatives, just in case someone prefers those: controlling the heater via a relay (mechanical or solid-state), and powering the unit from a DC wall wart. So these should be included as options if it’s not too much trouble.

To guard against heat & fire problems, a standard heater will be used with a built-in thermostat. The idea being that you set the built-in thermostat to its maximum value, and then switch the entire unit on and off via the remote switch. Even in the worst scenario where the switch fails to turn off, the thermostat will prevent the heater from exceeding its tested and guaranteed power & heat levels. One consequence of this is that the entire reflow process needs to unfold quickly enough, so that the thermostat doesn’t kick in during normal use. But this is an issue anyway, since reflow profiles need to be quick to avoid damaging sensitive components on the target board.

On the software side, we’ll need some sort of configuration setup, to adjust temperature profiles to leaded / unleaded solder for example, but also to calibrate the unit for a specific heater, since there are big differences.

I don’t think a few LEDs will be enough to handle all these cases, so some sort of display will be required. Since we’ve got the RFM12B on board anyway, one option would be to use a remote setup, but that violates the self-contained requirement (besides, it’d be a lot less convenient). So what remains is a small LCD unit, either character-based or graphics-based. A graphic LCD would be nice because it could display a temperature graph – but I’m not sure it’ll fit in the budget, and to be honest, I think the novelty of it will wear off quickly.

On the input side, 2 or 3 push buttons are probably enough to adjust everything. In day-to-day operation, all you really need is start/stop.

So this is the basic idea for the Reflow Timer so far:

JC s Doodles page 18

Ok, what else. Ah, yes, an enclosure – the eternal Achilles’ heel of every electronics project. I don’t want anything fancy, just something that is robust, making it easy to pick up and operate the unit. I’ve also got a somewhat unusual requirement, which applies to everything in the JeeLabs shop: it has to fit inside a padded envelope.

Enclosures are not something you get to slap on at the end of a project. Well, you could, but then you lose the opportunity of fitting its PCB nicely and getting all the mounting holes in the best position. So let’s try and get that resolved as quickly as possible, right?

Unfortunately, it’s not that easy. We can’t decide on mechanical factors before figuring out exactly what has to be in the box. Every decision is inter-dependent with everything else.

Welcome to the world of agonizing trade-offs, eh, I mean… product design!

AC measurement status

In AVR, Software on Oct 12, 2011 at 00:01

Before messing further with this AC current measurement stuff, let me summarize what my current setup is:

JC s Doodles page 17

Oh, and a debug LED and 3x AA battery pack, which provides 3.3 .. 3.9 V with rechargeable EneLoop batteries.

I don’t expect this to be the definitive circuit, but at least it’s now documented. The code I used on the ATtiny85 is now included as tiny50hz example sketch in the Ports library, eh, I mean JeeLib. Here are the main pieces:

Screen Shot 2011 10 07 at 00 32 58

Nothing fancy, though it took a fair bit of datasheet reading to get all the ADC details set up. This sketch compiles to 3158 bytes of code – lots of room left.

This project isn’t anywhere near finished:

  • I need to add a simple RC low-pass filter for the analog signal
  • readout on an LCD is nice, but a wireless link would be much more useful
  • haven’t thought about how to power this unit (nor added any power-saving code)
  • the ever-recurring question: what (safe!) enclosure to use for such a setup
  • and most important of all: do I really want a direct connection to AC mains?

To follow up on that last note: I think the exact same setup could be used with a current transformer w/ burden resistor. I ought to try that, to compare signal levels and to see how well it handles low-power sensing. The ATtiny’s differential inputs, the 20x programmable gain, and the different AREF options clearly add a lot of flexibility.

Onwards!

AC current detection works!

In AVR, Software on Oct 10, 2011 at 00:01

As promised, the results for the ATtiny85 as AC current detector, i.e. measuring current over a 0.1 Ω shunt.

Yesterday’s setup showed the following values in the display:

    30 71-101 68.

From right to left, that translates to:

  • it took 68 ms to capture 500 samples, i.e. about 7 KHz
  • the measured values were in the range 71 .. 101
  • the spread was therefore 30

With a 75 W lamp connected, drawing about 100 mA, I get this:

DSC 2677

With the 25 W lamp, the readout becomes:

DSC 2673

And finally, with a 1 kΩ resistor drawing 20 mA, this is the result:

DSC 2679

As soon as the load is removed, readings drop back to the first values listed above.

Now it seems to me that these readings will be fine for detection. Even a low 20 mA (i.e. 4.4 W @ 220V) load produces a reading with is 30 times higher than zero-load (with about 10% variation over time).

I’m measuring with 2.56V as reference voltage to remain independent of VCC (which is 3.8V on batteries). So each step is 2.5 mV with the built-in 10-bit ADC. With the 20x amplification, that becomes 0.125 mV per ADC step. Now let’s see… a 20 mA DC current across a 0.1 Ω shunt would generate a 2 mV differential. I’m using an order 31 moving average, but I didn’t divide the final result by 31, so that 1099 result is actually 35 on the ADC. Given that one ADC step is 0.125 mV, that’s about 4.4 mV peak-to-peak. Hey, that looks more or less right!

There is still a problem, though. Because half of the time I get this:

DSC 2675

Total breakdown, completely ridiculous values. The other thing that doesn’t look right, is that none of the readings are negative. With a differential amplifier fed with AC, one expects the values and signs to constantly alternate. Maybe I damaged the ATtiny – I’ll get another one for comparison. And maybe I didn’t get the sign-extensions right for the ADC’s “bipolar differential” mode. There’s a lot of bit-fiddling to set all the right register bits.

But still… this looks promising!

Update – Problem solved: it was a signed / unsigned issue. The values are now completely stable with under 1 % variation between measurements. I’m not even filtering out high frequencies, although I know I should.

JeeNode with a 32 KHz crystal

In AVR, Hardware on Jun 28, 2011 at 00:01

Another experiment: running a JeeNode on its internal 8 MHz RC clock while using the crystal input to run timer 2 as an RTC. This would allow going into a very low-power mode while still maintaining a much more accurate sense of time.

To this end, I modified a JeeNode SMD, by replacing the 16 MHz resonator with a 32 KHz crystal:

Dsc 2599

I didn’t even bother adding capacitors, these are probably not needed with this crystal (same as on the RTC Plug) since there is probably enough parasitic capacitance already.

The tricky part is the code, since the ATmega is now running in a not-so-Arduino-like mode. Could almost have used OptiBoot with this setup, but the only internal RC clock build for it is the LilyPad, which has an ATmega168.

I ended up using the ISP programmer. IOW, I now compile for “LilyPad w/ 328” and then bypass the bootstrap and serial-upload. Less convenient, but it works.

Here’s a quick test sketch which writes a dot on the serial line exactly once a second:

Screen Shot 2011 06 24 at 15.51.49

So this setup is working. It draws 4.10 ma, consistent with the recent current measurements: slightly less than with the 16 MHz resonator pre-scaled by two.

In idle mode, current use drops to 1.71 mA, not bad!

Now let’s power down with just the timer running as real time clock. There’s a special “power save” mode which does just that. The difference is that timer 0 will now be off, so there won’t be interrupts waking up the ATmega every 1024 µs (as side-effect, the millis() function will start to lose track of time):

Screen Shot 2011 06 24 at 16.15.04

A small adjustment is needed to make sure the serial port is finished before we go into low-power mode, hence the call to delay(3).

Hm, power consumption is still 0.67 mA – quite a bit, given that we’re really powering down most of the time.

Ah, wait. I forgot to turn off the radio. Doing that brings the reading down to 0.15 mA – and I forgot to turn off the ADC and other sub-systems. Now we’re down to … 0.05 mA, while still printing dots:

Screen Shot 2011 06 24 at 16.39.15

Note that these 1 second interrupts are very accurately timed, more so even than with the standard 16 MHz resonator. This could be used to perform time-domain tricks on the wireless side, i.e. waking up just in time whenever a “scheduled” packet is expected to come in – as described in yesterday’s post.

There’s probably more left to try. The delay is running on full power, waiting for the serial output to clear the USART. It could be done while in idle mode, for example. Anyway… that entire delay becomes superfluous when we stop sending out debugging output over the serial port.

So there you have it – a JeeNode running at ≈ 8 MHz, with a precise 32,768 Hz pulse feeding timer 2, in a way which supports low-power sketches while maintaining an accurate sense of time.

Wanna make a clock?

Current measurements

In AVR, Hardware on Jun 26, 2011 at 00:01

Wanted to check a few things w.r.t. current consumption of a JeeNode. The old way of doing this was a bit inconvenient, so I made a new test setup:

Dsc 2597

(old one on the left, new one on the right)

Sturdier, no need to disconnect the multimeter to short it out, and most importantly: high-side current sensing! That’s quite important, because multimeters can add a small voltage drop when used in current measurement mode, and that voltage drop will affect the serial I/O on the FTDI pins when placed in the GND line. Silly me, should have been on the PWR line all along!

The back side of the new connector is trivial:

Dsc 2598

The multimeter attaches to the top pins, bent apart for easy connection. The jumper shorts it out so this contraption can still be used when the multimeter is turned off.

Ok, time for some simple measurements:

  • ATmega full speed, doing nothing: 6.84 mA
  • ATmega full speed, with the RFM12B receiver on: 18.42 mA
  • ATmega powered down, only the RFM12B receiver on: 11.53 mA
  • ATmega full speed, with the RFM12B tranmitter on: 29.92 mA

Idle mode is a simple way to reduce power consumption without changing the logic of the code. It turns the MPU off until an interrupt occurs. Basically, you’re telling it “I’ve got nothing to do until something new happens”. It’s a pretty safe change, and well worth doing in any idle loop which isn’t directly polling I/O pins. The ATmega’s current consumption is slashed by more than half:

  • ATmega in idle mode, doing nothing: 2.80 mA

Another way to reduce power consumption, is to slow down the clock at which everything takes place, by setting the “clock pre-scaler”:

  • ATmega @ 16 MHz, doing nothing: 6.84 mA (as before)
  • ATmega @ 8 MHz, doing nothing: 4.35 mA
  • ATmega @ 4 MHz, doing nothing: 2.96 mA
  • ATmega @ 2 MHz, doing nothing: 2.02 mA
  • ATmega @ 1 MHz, doing nothing: 1.55 mA
  • ATmega @ 500 KHz, doing nothing: 1.28 mA
  • ATmega @ 250 KHz, doing nothing: 1.16 mA
  • ATmega @ 125 KHz, doing nothing: 1.09 mA
  • ATmega @ 62.5 KHz, doing nothing: 1.06 mA

Diminishing returns, clearly. Note that lowering the system clock in this way is not necessarily the best choice – getting something done N times faster and then powering down completely might be more efficient (see below).

One thing to watch out for: don’t go below 4 Mhz if you want to be able to use the RFM12B, or the processor will be too slow to process each byte.

When combining this, we get:

  • ATmega @ 4 MHz in idle mode, doing nothing: 1.48 mA
  • ATmega @ 62.5 KHz in idle mode, doing nothing: 1.03 mA

The advantage of this approach is that the clock is still running on the 16 MHz resonator (which probably draws most of that remaining current), so you’re still able to keep track of time – just more slowly.

A different approach is to go into real low power mode, and use the watchdog to get back out of this comatose state. The watch dog timer is less accurate, but depending on your application that may not be an issue.

Here’s the current consumption with the ATmega alternately in full speed and in power down mode:

  • ATmega 16 ms @ 16 MHz / 16 ms powered down, doing nothing: 3.49 mA
  • ATmega 8 ms @ 16 MHz / 16 ms powered down, doing nothing: 2.31 mA
  • ATmega 4 ms @ 16 MHz / 16 ms powered down, doing nothing: 1.39 mA
  • ATmega 2 ms @ 16 MHz / 16 ms powered down, doing nothing: 0.80 mA
  • ATmega 1 ms @ 16 MHz / 16 ms powered down, doing nothing: 0.46 mA

That last one does about the same amount of work as when running constantly @ 1 MHz, but with a third of the power consumption. Here is the corresponding sketch:

Screen Shot 2011 06 24 at 13.45.56

And it will continues to scale downward:

  • ATmega 100 µs @ 16 MHz / 16 ms powered down, doing nothing: 90.4 µA

Which still represents 100,000 active processor cycles per second…

And lastly, let’s take it into power down and run for just 1 ms per second, i.e. 0.1% of the time. I can’t measure this with the multimeter, because the power use jumps up every second, but the comatose period draws a mere 6.8 µA, which is consistent with what has been reported several times before (the watchdog is still active, and so is the brown-out detector).

Ping example

In AVR, Software on Jun 18, 2011 at 00:01

Another example of how to use the EtherCard library:

Screen Shot 2011 06 15 at 09.08.33

This example illustrates doing DHCP, DNS, and then periodically pinging a remote server to see if it’s alive.

Sample output:

Screen Shot 2011 06 15 at 09.10.11

As you can see, it not only pings others, but also reports when it’s being pinged by others.

Add a LED and you could make a trivial server status display. Or add a web page fetch to verify that the web server is also still alive. Or add a graphics display to show a graph of the ping times. Or add a relay and power-cycle the server when it’s not responding … endless possibilities, and very simple to implement!

Complete web client demo

In AVR, Software on Jun 17, 2011 at 00:01

After yesterday’s addition of DHCP to the EtherCard library, it’s only a small step to create a sketch which does everything needed for convenient stand-alone use on a local LAN.

Here’s a webClient.pde demo sketch which sets itself up via DHCP, then does a DNS lookup to find a server by name, then does a web request every 5 seconds and displays the first part of the result:

Screen Shot 2011 06 15 at 09.04.57

Sample output:

Screen Shot 2011 06 15 at 09.05.51

The total sketch is under 10 Kb, so there’s still lots of room to add the RF12 wireless driver, as well as a fair amount of application logic.

Who says a little 8-bit processor can’t be part of today’s internet revolution, eh?

DHCP support

In AVR, Software on Jun 16, 2011 at 00:01

Not long ago, Andrew Lindsay added support for DHCP to his EtherShield library, which is derived from the same “Guido Socher & Pascal Stang” code base as the EtherCard library. Fantastic work, hats off!

I’ve reworked the code to simplify things, and more importantly: reduce its code size. Many of these changes made it into Andy’s Github code base, but I’ve decided to take it quite a bit further and completely redo the way DHCP gets called in sketches.

It’s now based on just one call: dhcpSetup(). For completeness, I must mention that lease expiry and re-lease have been swept under the rug for now. Here’s the new testDHCP.pde demo I’ve come up with:

Screen Shot 2011 06 16 at 00.10.07

Sample output:

Screen Shot 2011 06 08 at 13.43.27

The entire demo sketch is currently 7732 bytes (6420 without the serial I/O). The DHCP part appears to require about 1200 bytes in all this. Note that the actual code to perform or serve web requests will add several more Kb to the total size, this merely illustrates the minimal code for doing DHCP.

There’s a “#define SELECT_BIT” in the enc28j60.cpp source which can be changed for boards which don’t use B0 (i.e. arduino digital I/O pin 8) as chip select. There’s also a “#define FULL_SPEED” setting which switches the SPI bus to 8 MHz during block transfers – it’s enabled by default and has a noticeable impact on performance.

So now any ENC28J60-based EtherCard with an ATmega328 can be connected to a local LAN and become usable as web server and/or client without having to configure an IP address, DNS server, or gateway!

How the JeeNode evolved

In AVR, Hardware on Jun 8, 2011 at 00:01

Thought it might be interesting to put the six JeeNode versions / designs next to each other. It nicely illustrates my progress in learning PCB design, and making some trade-offs and pinout choices over the past 2.5 years:

JeeNode v1:

Jlpcb 002

JeeNode v2:

Jlpcb 003

JeeNode v3:

Jlpcb 018

JeeNode v4:

Jlpcb 044

JeeNode v5:

Jlpcb 105

JeeNode v6:

Jlpcb 128

We’ve come a long way. And I think it’s now time to call this final v6 design… it!

Summary of ISP options

In AVR, Hardware, Software on May 29, 2011 at 00:01

First of all, see this weblog post for an overview of what ISP is, why you’d want to know, and when you need it.

There have been quite a few posts about ISP on this weblog over time – all tagged, so they can be reached via this link: https://jeelabs.org/tag/isp/.

I’ll summarize here, since particularly the different sketches floating around by now might be a bit confusing.

The ZIF socket is a way to connect to chips before they have been soldered into a circuit. There’s one for through-hole DIP chips, and one for 32-TQFP SMD chips:

Once soldered into a circuit, you can use an I(C)SP programmer, which not everyone has. So I created a couple of different options based on a JeeNode (can also be an RBBB or Arduino) to perform the same function.

My first trial was a hack with the isp_flash.pde sketch, which then led to the Flash Board (info). The nice thing about this board is that it has 128 Kbyte of EEPROM on board – enough to hold the complete programming instructions for an ATmega168 or ATmega328.

One way to use the Flash Board is as capturing ISP programmer: you send a sketch to it as if it were an ISP programmer, and then you can disconnect it and use it repeatedly to upload that sketch to other boards via ISP:

I used this to build a 4-fold Multi-ISP programmer to program all those gazillion ATmega’s needed for JeeNodes:

Took a few attempts to get all the bugs worked out, but now it works perfectly.

But there’s a much simpler way to do this, if all you want is to fix a JeeNode, occasionally:

… or use an Arduino:

These two ISP setups use an isp_repair.pde sketch, which has as novelty that it includes the sketch and bootstrap its needs for programming – as data array in flash memory. So all that’s needed is: connect the two boards and power up the master. No need to use the Arduino IDE’s “Burn Bootloader” command or anything.

Then came OptiBoot, which is compatible with the Arduino Uno, and smaller/faster. This is a relatively new boot loader so you might want to update your current JeeNodes – even though an ISP programmer isn’t normally needed for development.

I updated the isp_repair.pde sketch, and then fixed a few remaining problems with it:

And finally, I added a LiPo battery, and 4 config switches, to end up with this tool:

On the software side, the most recent design is called isp_repair2.pde. It supports two different sketches, up to four different bootstrap loaders, and setting the fuses either as 16 MHz crystal or optimized specifically for ceramic resonators.

The include files with the bootstraps included with these sketches are generated from HEX files created by the Arduino IDE. This is done with a small Tcl script called hex2c.tcl, which is located in a slightly older isp_prepare example sketch folder. It’s not needed for normal use, only when one of the boot loaders changes.

Phew. Still there?

In a nutshell: if you need to re-flash your ATmega, pick one of the above options to hook things up, and use the isp_repair2 sketch in the Ports library. By default, it’ll upload a blink demo sketch and the OptiBoot loader.

More bootstraps

In AVR, Hardware, Software on May 28, 2011 at 00:01

Some projects just don’t want to lie down…

The isp_repair example sketch in the Ports library was written for a single purpose: to upgrade a JeeNode to the OptiBoot loader, which leaves more room for sketches and is compatible with the Arduino Uno.

It took two attempts to get it right, but in the end I think it all worked out as intended.

Until featuritis sets in…

First, I added a #define OPTIBOOT in the sketch, to allow re-using that same sketch to revert to the original boot – in case you ever want to go back. So now it’s a setup which can “repair” an ATmega in various ways.

But why stop there?

There are a couple variations for flashing which all make sense in the context of JeeNodes:

  • load a short Blink sketch, or load the entire standard RF12demo sketch
  • OptiBoot vs the original Arduino 2009 bootstrap code
  • faster wakeup after power down, works only with a 16 MHz resonator

The fast wakeup makes it possible to completely power down an ATmega between the reception and transmission of individual bytes via the RF12 driver. It won’t make a huge difference, but it will reduce power consumption just a notch more than staying in idle mode.

So here’s a new setup, and hopefully the last:

Dsc 2536

It includes yesterday’s DIP-switch Plug, which gives me 4 bits of configurability. There’s a new sketch which adds support for these switches and includes all the different pieces if code – it’s called isp_repair2:

Screen Shot 2011 05 26 at 01.34.25

The sketch includes up to four different boot loaders, currently:

Dip Switch Plug

There are two “sketch” code sections, followed by 4 bootstrap code sections:

Screen Shot 2011 05 26 at 03.09.23

With all switches set to “1” (same as not connecting any switches at all, BTW), we get:

Screen Shot 2011 05 26 at 03.06.53

And since (in my case) there’s an on-board LiPo recharger and battery tacked onto the back: this setup is fully self-contained and ready for use at any time.

Hmmm, I wonder what sort of bootstrap loader I could put in that spare slot, one day…

Fixing the isp_repair sketch

In AVR, Hardware, Software on May 26, 2011 at 00:01

A few days ago I posted a new sketch to reprogram an ATmega with the OptiBoot loader when you don’t have an ISP programmer. Worked for me, so I thought… kick it into the world!

Whoops…

First of all, there should have been a warning that if it didn’t work, this would leave you with an unusable ATmega. Never occurred to me, since I have an ISP programmer within reach to recover from such mistakes.

Fortunately, someone on the forum reported that the ATmega can be brought back to life with an old version of isp_repair.pde (which can be found here, BTW).

That’s odd… can’t program with the sketch, but can recover with the same sketch and different data bytes?

Time to dig in. First, I wanted to make sure that the timing was slow enough to work in all cases. Time to fire that logic analyzer up again:

Screen Shot 2011 05 25 at 11.33.22

Looks good – since I’m using standard digitalWrite() calls, the pins aren’t toggling very fast at all:

Screen Shot 2011 05 25 at 11.34.29

Then it dawned on me:

The lock bits don’t look right: 0xFF – should have been 0xCF (top 2 bits are always 1, i.e. same as 0x0F).

Maybe everything was working, except the setting of the fuse bits? That would explain everything: a new boot loader gets loaded in the top 512 bytes, overwriting parts of the old boot loader, but the fuse bits perhaps wouldn’t get adjusted to just to the new boot address!

I changed a couple of things:

  • do the full chip erase before setting the fuse bits
  • set the lock bits to 0x0F at the end, i.s.o. 0x3F
  • included both bootstraps in the updated sketch
  • tri-state the ISP programming pins when done

The erase is needed to recover from a locked fuse state. The programming always took place after the erase, so it went well, but the fuse bits themselves would still be locked while trying to adjust them.

The second step should have been there all along, the way I was doing it the boot section was not protected from overwriting itself. This might explain the occasional report I got of people damaging boot loaders during use.

You can now also adjust the #define OPTIBOOT at the top of the sketch to 0 to revert to the original bootstrap code and fuse settings. So if OptiBoot is not what you want, recompile and restore as needed.

And lastly, the SPI programming pins are now reset to high-impedance after programming, so that the programming connections can be left in place without interfering with the target board.

Here’s the serial output from the updated sketch:

Screen Shot 2011 05 25 at 11.41.31

And here’s why it would sometimes have worked: if your ATmega had the lock bits unset (0x3F i.s.o. 0x0F), then the fuse settings would work as intended even with the chip erase in the wrong order. But with a locked setup, not everything would get set to the proper state.

Which goes to show: bugs can bite at any time!

Update – still some issues to iron out (see forum), but it looks like these are more related to OptiBoot than to this bootstrap replacement sketch.

Update #2 – OptiBoot issue solved.

Saving RAM space

In AVR, Software on May 23, 2011 at 00:01

Yesterday’s post was about finding out how much free memory there is in an ATmega running your sketch.

The most common out-of-memory case is free RAM, which is where all the interesting stuff happens – not surprising, if you interpret “interesting” as “changing”, which by necessity has to happen mostly in RAM.

Let’s go into some ways to reduce RAM usage. As mentioned yesterday, C strings are often a major cause of RAM bloat. Here’s part of a simple sketch to report which one of five buttons have been pressed:

Screen shot 2011 05 22 at 21 34 00

Let’s assume that the checkButton() returns a value from 1 to 5 when a button press has been detected, and 0 otherwise. The problem? We’ve just used about 150 bytes of RAM…

Given how simple and regular this example is, here’s an easy way to improve on it:

Screen shot 2011 05 22 at 21 34 45

Total RAM usage will drop to just over 50 bytes.

Here’s another way to do it:

Screen shot 2011 05 22 at 21 42 43

This one uses 42 bytes for the data, and 26 bytes for the remaining two strings, i.e. total 68 bytes. I’ve included this example because it illustrates a more data-driven approach, but it leads to some waste because the colors array requires a fixed amount of 6×7 character space.

Here’s a variation of that, which is more idiomatic in C:

Screen shot 2011 05 22 at 21 46 14

It differs in a subtle but important detail: the array is now an array of pointers to string constants.

Estimating RAM use is slightly more involved: 1+4+6+5+7+7 bytes for the strings (including the zero byte at the end of each one) = 30 bytes, PLUS 12 bytes for the pointer array (6 pointers, each 2 bytes). That’s still 42 bytes, so no gain compared to the previous fixed-size array.

Using standard C/C++, that’s about all you can do. And it still wastes some 40..70 bytes of RAM. This may not sound like much, but keep in mind that the same will happen everywhere you use a string in your code. C strings are painfully awkward for tiny embedded MPU’s such as the ATmega and ATtiny series.

Fortunately, there is one more trick at our disposal, which removes the need for RAM altogether …

The trick is to place these strings in flash memory, alongside the code, and extract the characters of the string whenever we need them. It’s a great trick, but it will affect our sketch everywhere, unfortunately.

First of all, we need to include this line at the top of our sketch:

    #include <avr/pgmspace.h>

This header file gives access to a number of preprocessor macros and functions, needed to define strings in the proper way, and to read the character data from flash memory at run time.

The reason for this added complexity, is that flash memory isn’t simply an “address” you can read out. The AVR family uses two separate address spaces for code and data. This is called a Harvard architecture. As far as pointers go in C, there is no access to data in flash memory. Well – there is, because function pointers in C automatically refer to code in flash memory, but there is no way to mix these: data pointers cannot access flash, and function pointers cannot refer to RAM.

Back to the task at hand. We need a small utility function which can print a string located in flash ROM memory:

    void showString (PGM_P s) {
        char c;
        while ((c = pgm_read_byte(s++)) != 0)
            Serial.print(c);
    }

Note that the argument is not a const char*, but a PGM_P (defined in the pgmspace.h include file).

Now let’s redo the code with this ROM-based approach:

Screen shot 2011 05 22 at 22 16 10

The result? No RAM is used up by any of these strings, yippie!

The price to pay is a slightly larger compiled sketch, and more importantly: we have to use that “PSTR(…)” notation with each of the strings to make it all work.

This technique is not invasive, i.e. you don’t have to choose between RAM-based and ROM-based C strings for the entire sketch. It’s probably easier to only do this in those parts of your sketch which use lots of strings.

ATmega memory use

In AVR, Software on May 22, 2011 at 00:01

Sometimes, it’s useful to find out how much memory a sketch uses.

Sometimes, it’s essential do so, i.e. when you’re reaching the limit. Because strange and totally unpredictable things happen once you run out of memory.

Running out of flash memory for the code is easy to avoid, as the Arduino IDE will tell you exactly how much is being used after each compile / upload:

Running out of EEPROM memory is harder, but usually not an issue, since very few sketches use substantial amounts of EEPROM, if any.

Running out of RAM space is the nasty one. Because it can happen at any time, not necessarily at startup, and not even predictably because interrupt routines can trigger the problem.

There are three areas in RAM:

  • static data, i.e. global variables and arrays … and strings !
  • the “heap”, which gets used if you call malloc() and free()
  • the “stack”, which is what gets consumed as one function calls another

The heap grows up, and is used in a fairly unpredictable manner. If you release areas, then they will lead to unused gaps in the heap, which get re-used by new calls to malloc() if the requested block fits in those gaps.

At any point in time, there is a highest point in RAM occupied by the heap. This value can be found in a system variable called __brkval.

The stack is located at the end of RAM, and expands and contracts down towards the heap area. Stack space gets allocated and released as needed by functions calling other functions. That’s where local variables get stored.

The trick is to keep RAM usage low, because it’s a scarce resource: an ATmega has a mere 2048 bytes of RAM.

Here’s a small utility function which determines how much RAM is currently unused:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

And here’s a sketch using that code:

void setup () {
    Serial.begin(57600);
    Serial.println("\n[memCheck]");
    Serial.println(freeRam());
}

void loop () {}

The result will be:

[memCheck]
1846

Ok, so we have about 1.8 Kb free in a tiny sketch which does almost nothing. More precisely: a basic sketch uses 2048 – 1846 = 202 bytes for internal bookkeeping and stuff (128 bytes of which are needed for the hardware serial input buffer, BTW).

When that value drops to 0, your sketch will crash. This might show as an endless loop, strange calculations or output, or constant restarts. Don’t expect a nice error message!

Let’s make a tiny change:

Serial.println("\n[memCheck2]");

Output:

[memCheck2]
1844

Huh?

The first part of the explanation is that all C strings are also stored in RAM! This explains why adding a single character to the string reduced available memory.

The second part of the explanation, is that flash memory is organized in words. Therefore, sometimes when you expect a single-byte effect, this may get rounded up due to the way things are stored in flash memory.

And the third part of the explanation, is that all C strings also get stored in flash memory. The reason is that RAM contents is undefined on power-up, so one of the tasks performed by the C runtime startup code, is to copy all the strings from flash to RAM memory.

Moral of the story: be very careful when doing things with strings on an ATmega, because you may find that you quickly run out of memory space. Adding lots of verbose debugging print statements might cause more problems than you think!

Update – Here’s a great AVR RAM memory overview:

(from the avr-libc website)

Self-powered Opti-rebooter

In AVR, Hardware on May 18, 2011 at 00:01

After yesterday’s post about switching to OptiBoot, I decided to go one step further and go for a self-powered solution, a bit like this unit which has been serving me well for many months now.

So here’s the “Opti-rebooter” with a 400 mAh LiPo backpack:

Dsc 2521

Hookup is trivial, given that the JeeNode USB has an on-board LiPo charger. I picked a battery which matches the width of the board and fits quite well:

Dsc 2522

The two connectiosn of the LiPo battery are wrapped up in heat-shrink tubing to prevent accidental short circuits – the currents involved could easily cause trouble. Note that this is a “raw” LiPo cell, without any protection circuitry. That’s fine in this case, because the on-board circuitry takes care of charging.

To make this complete, the isp_repair.pde was extended to completely power down when done. So there’s no need for an on-off switch, the idle consumption is probably lower than the battery’s own self-discharge rate. And it blinks the on-board led twice: once on power up and once when properly programmed. Very convenient!

The way to use this thing, is: connect to a target JeeNode / JeeLink / Arduino, press the RESET button, wait three seconds, disconnect, done.

I also made changes to the very similar but slightly more elaborate isp_prepare.pde sketch, which was presented in this weblog post.

The updated isp_prepare.pde sketch supports a number of variations. These can be configured by adjusting a few values at the start of the sketch:

Screen Shot 2011 05 16 at 15.00.32

You can choose which type of boot loader to install, which sketch to load initially (just to start off, this can be overwritten later), and there’s a third option to adjust some “fuse bits” in the ATmega to select how fast the ATmega can start up after resuming from a power down.

That third option is particularly useful with battery-powered JeeNodes using the RF12 driver. With USE_FAST_WAKEUP set to 1, the power-up sequence is fast enough for an ATmega to wake up when the first data byte is received. This means you can completely power down the ATmega (while leaving the receiver running), and it’ll still be able to pick up incoming packets and respond to them. There is one gotcha: USE_FAST_WAKEUP can only be set to 1 on units running with a resonator – JeeLinks and Arduino’s running with a crystal must be not use the fast wakeup mechanism, as the clock may not start up properly in this case.

Haven’t tried it though – for now, that LiPo powered unit shown above is really the most convenient way for me to upgrade all the JeeNodes, JeeLinks, and Arduino’s floating around the house at JeeLabs.

Switching to OptiBoot

In AVR, Hardware on May 17, 2011 at 00:01

Now that some of the JeeNode/JeeLink boards from JeeLabs come pre-loaded with the OptiBoot boot loader, it’s time to start thinking about switching everything over. Having to constantly switch the Arduino IDE between “Arduino Uno” (OptiBoot) and “Arduino Duemilanove w/ 328” (original 2009 boot) is quickly going to become very tiresome …

See this weblog post for a quick summary of what all this uploading and boot loader stuff is about, and why you should care. In a nutshell: you need a boot loader on the ATmega to save sketches onto it via FTDI and USB.

There’s a nasty detail, though: to upload sketches you need a boot loader, but how does that boot loader end up on the ATmega in the first place? The good news is that this is usually done in the factory, well, ehm… at JeeLabs, in my case. The good thing is, it’s all taken care of, and the boot loader doesn’t normally get damaged or need to be replaced. It just works.

Except when the boot loader itself needs to be changed, as in the case of OptiBoot. Note that it’s quite worthwhile to switch to OptiBoot: the uploads are twice as fast, and you get 1.5 Kb of extra memory for your own sketches.

So how do you go about updating the boot loader on a JeeNode when you don’t have a special hardware tool called an “ISP Programmer”?

Fortunately, there is a simple trick to do this using a second JeeNode (or Arduino). I’ve written about this in a previous post. There’s an isp_repair.pde sketch in the Ports library which does everything (it emulates an ISP programmer, basically).

I’ve just updated the isp_repair.pde sketch to use OptiBoot.

Here’s the setup to upgrade a target JeeNode to OptiBoot using another JeeNode:

Six wires need to be connected as follows:

And then it’s a matter of attaching the target to the programming JeeNode, and then powering up the whole assembly.

If you happen to have the serial port connected to the programming JeeNode, you’ll see this info:

Screen Shot 2011 05 16 at 17.08.48

I made a permanent setup using a JeeNode USB, because I’ve got a pile of JeeNodes to reprogram here at JeeLabs:

Dsc 2518

The connector was constructed from a 2×4 header, with the pins bent in such a way that the whole thing stays in place when pressed into the 2×4 holes of the SPI/ISP header. And then the whole thing was sealed off with a few pieces of heat-shrink tubing:

Dsc 2519

To program a board (in this case another JeeNode USB), just power it all up and wait 3 seconds:

Dsc 2520

That’s it – you could call this an “opti-rebooter” :)

JeeLink v3 w/ OptiBoot

In AVR, Hardware on May 16, 2011 at 00:01

Small changes. Previous, i.e. v2:

Dsc 2515

And here’s the new JeeLink v3:

Dsc 2516

The changes are mostly cosmetic and include a number of changes to simplify the assembly process. Some minor but oh so important tweaks to more accurately fit it in the case:

Dsc 2517

See those four tiny notches line up? Phew!

Two changes which will be more important for everyone using these:

  • The JeeLink v3 comes with the OptiBoot loader pre-installed, i.e. you need to select the “Arduino Uno” as board type when uploading sketches to it.

  • The on-board DataFlash memory has been increased to 16 Mbit. This fast SPI-connected permanent memory makes it possible to use a JeeLink for collecting even more data when the PC is off (but power has to remain, evidently). The RF12demo sketch has a FLASH_MBIT constant defined, it should be set to 16.

You can easily see which JeeLink you have by looking at the gold lettering on the back side.

Apart from that, nothing really changes. All JeeLinks sent out from now on will be this new v3 build.

Onwards!

Assessing the damage

In AVR, Hardware on May 12, 2011 at 00:01

Yesterday’s post was about wearing out the EEPROM memory on an ATmega168. It took over 6.7 million writes to address zero to make it fail. As mentioned, this is a limited test, because reading out the value was done right after writing it. But hey, at least I didn’t have to write 100,000 times to each EEPROM address and wait 20 years @ 85°C to find out whether each byte was still correct…

So we got a failure, now what?

Well, re-running the test caused it to fail after a mere 6,200 write cycles, so that EEPROM definitely isn’t up to spec anymore.

Today, I wanted to see what effect this single massive rewrite of address zero did to the rest of the EEPROM. So I wrote another test which would go through the entire EEPROM and see how well writes + read-backs would work on this same ATmega168 with its massively-abused EEPROM:

Screen Shot 2011 05 11 at 17.23.32

All failures are counted, per EEPROM address. Whenever the maximum number of failures at any single address increases, a map is printed with the counts for each of the 512 bytes. Here’s the startup situation – no errors yet:

Screen Shot 2011 05 11 at 17.23.10

The map counts are encoded as single characters:

 0         =  "."
 1 to 9    =  "1" .. "9"
10 to 35   =  "a" .. "z"
36 to 61   =  "A" .. "Z"
62 and up  =  "?"

Every 100 cycles, the cycle count is printed, just to let me know that the sketch is still running. Unfortunately, re-writing all 512 bytes in EEPROM is way slower than yesterday’s test, over 1 second per cycle. So I also added an LED to toggle on each cycle:

Dsc 2503

Now the waiting begins… it’s going to take hours (maybe even days!) to force the next failure again.

And one thing is clear: it’s not easy to get these chips to fail quickly!

Update – 100,000 cycles later, no new failure yet…

Destruction!

In AVR, Hardware on May 11, 2011 at 00:01

No, not distractions

Had a ATmega168 chip lying around which isn’t going to be used anymore anyway, so why not do some destructive testing on it, eh?

There have been a couple of such tests floating around on the web, so I thought I’d try to replicate them – to try and find out how many read-write cycles the internal ATmega’s EEPROM can sustain. I started from the info on John Boxall’s weblog, and set up a similar configuration, but based on a JeeNode:

Dsc 2497

Note that this isn’t using the LCD Plug, but has direct connections to 6 digital output pins (I used the same pins as in the original sketch: digital 4..9).

Made a simpler sketch to just toggle bits in the EEPROM and display the counter (the display is fast when there’s no I2C expander chip involved):

Screen Shot 2011 05 10 at 18.46.38

It turns out that flipping all the bits in the EEPROM takes a few seconds, and with an expected lifetime well over 100,000 that test would have lasted several days. So instead, I rigged the test to only flip byte 0 in the EEPROM. Let’s see how much beating that single byte can take!

Several hours later…

Dsc 2499

Over 3,260,000 write cycles and still going.

Note that this is only testing EEPROM address 0x000, and that the check is right after the write, so this is not necessarily a very useful test: bad bytes might hold charge, but not for over 20 years as listed in the specs, and some other address might give an error much sooner.

But still… 32x above spec so far. Not bad!

Update – The ATmega168 finally broke down:

Dsc 2502

Then it failed 6200 cycles after the next power-on.

EtherNode on a breadboard

In AVR, Hardware, Software on Jan 30, 2011 at 00:01

After some recent comments on the forum about the etherNode.pde sketch, I wanted to make sure that the code is still working properly on this hassle-free setup (as well as with the Carrier Board):

Dsc 2432

And sure enough, it works as intended:

Screen Shot 2011 01 29 at 21.12.06

The output shows some packets from node 19 – which is the modded RFM12B running the RFM12B_OOK sketch, and it’s working nicely as you can see.

This sketch takes about 12 Kb of code (web server + EtherCard + RF12 driver), so there is ample room to add more features in there. You could use a modded RFM12B module, for example, and have everything you need to create a gateway between 868 MHz OOK devices and the LAN. In both directions in fact, since the RFM12B can also be tricked into sending out OOK packets.

Note that the Ether Card uses a few extra I/O pins from the JeeNode, so be sure to connect the 2×4 headers on the SPI/PSI pins between JeeNode and Bridge Board.

And the best part is that even with this Ether Card attached, all 4 ports on the JeeNode are still available for other uses. They are all brought out on the 8 leftmost pins, clearly labeled with both port numbers and Arduino pin numbers. Also available from the bridge board, as bonus: 2 LED’s and a push button.

As you can see, there’s a lot of empty real-estate on that breadboard – yearning to be put to good use…

PS. In case you’ve been waiting for one of those wooden bases, as included with the JeeNode Experimenter’s Pack: not to worry, I haven’t forgotten about you. The recent batch of packs were sent out without the base – they will be shipped separately once back in stock.

Rethinking the Arduino hardware interface

In AVR, Hardware, Software on Dec 18, 2010 at 00:01

It’s been almost two years since the first design was created from which the JeeNode was born. It went from this very first prototype:

… to this leaner-and-meaner design, which is the current JeeNode v5:

Jlpcb 105

As you can see, it’s still essentially based on the same layout.

The JeeNode has been the flagship product here at JeeLabs for quite some time. It has been expanded to include a JeeNode USB variant which includes a USB interface and a LiPo charger, as well as a USB “stick-like” JeeLink that ties nicely into the WSN use of JeeNodes. And then there’s the bare-bones JeeSMD, which doesn’t have a wireless module built-in, but which is pin-compatible with the other two members of the JeeNode family.

With all the end-of-year stories coming up, and new year’s resolutions to follow soon, it seems like a good time to present my reasons for doing things this way.

Rethinking the Arduino hardware interface
That’s – in a nutshell – the essence behind the JeeNode.

I stumbled upon the fascinating world of Physical Computing and “Arduino’s” over two years ago, around the time when I also discovered an interesting low-cost wireless module. Lots of things “clicked” right away, but a few didn’t. Given that the Arduino is simply an ATmega (hardware), plus an IDE (software), plus a set of conventions (shields), I quickly realized that there might be more ways to skin this cat, and something new was born (inspired by the RBBB) – as summarized here a year ago.

I don’t want to rehash those points, but let me simply state what the JeeNode is about, assuming you know what an Arduino is.

  • the JeeNode lowers the operating voltage to 3.3V (implications)
  • it includes a wireless radio module (with software)
  • it drops the concept of shields (hard to combine)
  • instead, it adds 4 interchangeable 6-pin Ports (layout)
  • each port includes two dedicated I/O pins as well as power
  • there are numerous Plugs using this port pinout (list)
  • about half the plugs use (software) I2C and can be daisy-chained
  • there are many interface classes and code examples (here and here)
  • the remaining I/O pins are on two extra headers (details, PDF)
  • JeeNodes can be mounted upside-down (CB, GB, POF)
  • … or used alongside a solderless breadboard (BB)
  • with extension cables to move plugs further away (EC)
  • … or a prototype board to re-use all the I/O pins differently (PB)
  • reduced cost by using a detachable / reusable USB-FTDI interface

All this, while remaining fully compatible with “the” Arduino’s software + firmware.

But perhaps the most interesting bit coming out of all this, is that the JeeNode has become a practical ultra-low-power platform, with battery lifetimes measured in months, almost a year even, so far. There have already been tons of posts about this topic. It even spawned a nice little add-on to run JeeNodes from a single AA or AAA cell.

You may or may not agree with all the choices, but this is what the JeeNode is about.

Update – the Redmine repository is no longer available, everything is now on GitHub.

Voltage: 3.3 vs 5

In AVR, Hardware on Dec 16, 2010 at 00:01

One of the decisions made early on for the JeeNode, was to make it run at 3.3V, instead of the 5V used by the standard Arduino.

The main reason for this was the RFM12B wireless module, which can only be used with supply voltages up to 3.8V, according to the specs. Running them at 5V seems to give varying results: I’ve never damaged one, but there have been reports of such failures. Given that the older RFM12 (no B) worked up to 5V, my hunch is that something in the design was found to give problems at the higher voltage. It’s just a guess on my part, though.

So what’s the deal with 3.3V vs 5V?

Well, the first thing to note, is that the ATmega328 used in a 3.3V JeeNode runs at the same 16 MHz frequency as a 5V Arduino does. This overclocking is “out of spec”:

You’re not supposed to do this, but in my experience the good folks at Atmel (the designers and manufacturers of ATmega’s and other goodies) have drawn up specifications which are clearly on the conservative side. So much so, that not a single case has been reported where this has caused problems in any of the several thousand JeeNodes produced so far. As I pointed out in a previous post, that doesn’t necessarily mean everything is 100% perfect over the entire temperature range. But again: no known problems to date. None.

This is good news for low-power uses, BTW. It means you can get the same amount of work done using less power, since power = voltage x current. Even more so because both voltage and current are lower at 3.3V than when running at 5V.

A second reason for running at 3.3V, is that you can use 3 AA batteries instead of 4 (either alkaline or rechargeable). And that you can also power 3.3V circuits with LiPo packs, which have this hugely convenient 3.5..4.2V range.

The third important reason to run JeeNodes at 3.3V, is that more and more neat sensor chips are only available for use in the 2.7 .. 3.6V range or so. By having the entire setup operate at 3.3V, all these sensors can be used without any tedious level converters.

Occasionally I’ve been bitten by the fact that I used a chip which doesn’t work as low as 3.3V, as in the first RTC Plug trial. But more often than not, it’s simply a matter of looking for alternative chip brands. One recent example was the 555 oscillator used on the Infrared Plug: the original NE555 needs at least 4.5V, but there’s an ICM7555 using CMOS technology which works down to 3V, making it a non-issue.

Mixing 3.3V and 5V devices

The trouble with these voltage differences, is not just that the power supply needs to be different. That’s the easy bit, since you can always generate 3.3V from a 5V supply with a simple voltage regulator and 2 little capacitors.

The real problem comes from the I/O interface. Placing a 5V signal on a chip running at 3.3V will cause problems, in the worst case even permanently damaging the chip. So each I/O pin connected is also affected by this.

Fortunately, there’s often a very simple workaround, using just an extra resistor of 1 kΩ or so in series. To see how this works, here’s the way many chips have their input signals hooked up, internally:

Screen Shot 2010 12 14 at 23.35.16

There’s a pair of diodes inside the chip, for each pin (not just the inputs), used for ESD protection, i.e. to protect the chip against static electricity when you pick it up.

These diodes “deflect” voltage levels which are above the VCC of the device or below GND level. They do nothing else in normal use, but if you were to place 5V on in a pin of such a device powered by 3.3V, then that would lead to a (potentially large) current through the upper diode.

With electronics (as with humans, btw), it’s usually not the voltage itself which causes damage, but the current flow it leads to, and – in the case of sensitve electronics components – the heat produced from it.

By placing a 1 kΩ resistor in series, we limit the flow through the diode to under 2 mA, which most devices will handle without any problems:

Screen Shot 2010 12 14 at 23.42.27

Ok, so now we can hook up signals to a JeeNode, even if they swing in the 0..5V range. This works best with “slow” signals, BTW. The extra resistor has a bad effect on rise and fall times of the signal, so don’t expect this to work with signals which are in the 1 MHz range or higher. Then again, it’s unlikely you’ll need to tie such fast signals directly to an ATmega anyway…

How about the other direction?

What if you have a chip running at 5V which needs to receive signals from a chip running at 3.3V, i.e. signals going in the other direction?

Well, it turns out that this may or may not work by simply tying the two lines together. The 3.3V output signal will definitely not damage a chip running at 5V. The worst that can happen, is that the 5V side doesn’t consider the signal valid.

We need to look into logic levels to figure this one out, as specified in the datasheet of the chip. The easy part is logic “0”, i.e. a low level. Most chips consider anything between 0 and 0.8V a logic “low”. There will hardly ever be an issue when tying a 3.3V chip to a 5V chip.

The tricky part is logic “1”, i.e. a signal which is intended to represent a high level. Now it all depends on what the 3.3V chip sends out, and what the 5V chip requires.

Most CMOS chips, including the ATmega, send out nearly the full power line voltage to represent a logic “1” (when the load current is low), so you can expect output signals to be just about 3.3V on a JeeNode.

On the input side, there are two common cases. Some chips consider everything above 1.6V or so to be a logic one. These chips will be perfectly happy with the JeeNode signal.

The only case when things may or may not work reliably, is with chips which specify the minimum logic “1” voltage to be “0.7 x VCC” or something like that. On a 5V chip, that translates to a minimum value of 3.5V …

Note that datasheets usually contain conservative specs, meant to indicate limit values under all temperatures, load conditions, supply voltages, etc.

In practice, I find that even with “0.7 x VCC”, I can usually drive a 5V chip just fine from a JeeNode. The only exception being higher power chips, such as stepper motor drivers and such, which operate mostly at much higher voltage levels anyway. For these, you may have to use special “level translator” chips, or perhaps something like the I2C-based Output Plug, which can be powered with voltages up to 50V or so.

This post only addresses digital I/O signals. With analog I/O, i.e. varying voltage levels, you will need to carefully review what voltage ranges are generated and expected, and perhaps insert either a voltage divider or an op-amp to amplify voltages. That’s a bit more involved.

But all in all, living mostly in a 3.3V world is often more flexible than living mostly in a 5V world, nowadays.

Which is the fourth reason why I decided to run JeeNodes at 3.3V, BTW.

Binary packet decoding – part 2

In AVR, Software on Dec 8, 2010 at 00:01

Yesterday’s post showed how to get a 2-byte integer back out of a packet when reported as separate bytes:

Unfortunately, all is not well yet. Without going into details, the above may fail on 32-bit and 64-bit machines when sending a negative value such as -12345. And it’s not so convenient with other types of data. For example, here’s how you would have to reconstruct a 4-byte long containing 123456789, reported as 4 bytes:

Screen Shot 2010 12 07 at 09.56.08

And what about floating point values and C structs? The trouble with these, is that the receiving party doing the conversion needs to know exactly what the internal byte representation of the ATmega is.

Here is an even more complex example, as used in the roomNode.pde sketch:

Screen Shot 2010 12 07 at 08.44.28

This combines different measurement values into a 4-byte C struct using bit fields. Note how the “temp” value crosses two bytes, but only uses specific bits in them.

Fortunately, there is a fairly simple way to deal with all this. The trick is to decode the values back into meaningful values by the receiving ATmega instead of an attached PC. When doing so, we can re-use the same definition of the information. By using the same hardware and the same C/C++ compiler on both sides, i.e. the Arduino IDE, all internal byte representation details can be left to the compiler.

Let’s start with this 2-byte example again:

I’m going to rewrite it slightly, as:

Screen Shot 2010 12 07 at 08.57.23

No big deal. This sends out exactly the same packet. But now, we can rewrite the receiving sketch as follows:

Screen Shot 2010 12 07 at 09.00.14

The effect will be to send the following line to the serial / USB connection:

    MEAS 12345

The magic incantation is this line:

Screen Shot 2010 12 07 at 09.01.45

It uses a C typecast to force the interpretation of the bytes in the receive buffer into the “Payload” type. Which happens be the same as the one used by the sending node.

The benefit of doing it this way, is that the same approach can be used to transfer any type of data as a packet. Here is an example how a Room Node code sends out a 4-byte struct with various measurement results:

Screen Shot 2010 12 07 at 09.07.07

And here’s how the receiving node can convert the bytes in the packet back to the proper values:

Screen Shot 2010 12 07 at 09.10.55

The output will look like:

    ROOM 123 1 78 -15 0

Nice and tidy. Exactly the values we were after!

It looks like a lot of work, but it’s all very straightforward to implement. Most importantly, the correspondence between what happens in the sender and the receiver should now be obvious. It would be trivial to include more data. Or to change some field into a long or a float, or to use more or fewer bits for any of the bit fields. Note also that we don’t even need to know how large the packet is that gets sent, nor what all the individual bytes contain. Whatever the sender does to map values into a packet, will be reversed by the receiver.

This works, as long as the two struct definitions match. One way to make sure they match, is to place the payload definition in a separate header file, say “payload.h” and then include that file in both sketches using this line:

Screen Shot 2010 12 07 at 09.16.47

The price to pay for this flexibility and “representation independence”, is that you have to write your own receiving sketch. The generic RF12demo sketch cannot be used as is, since it does not have knowledge of the packet structures used by the sending nodes.

This can become a problem if different nodes use different packets sizes and structures. One way to simplify this, is to place all nodes using the same packet layout into a single net group, and then have one receiver per net group, each implemented in the way described above. Another option is to have a single receiver which knows about the different types of packets, and which switches into the proper decoding mode depending on who sent the packet.

Enough for now. Hopefully this will help you implement your own custom WSN to match exactly what you need.

Update – Silly mistake: the “rf12_sendData()” call doesn’t exist – it should be “rf12_sendStart()”.

Binary packet decoding

In AVR, Software on Dec 7, 2010 at 00:01

The RF12 library used with the RFM12B wireless radio on JeeNodes is based on the principle of sending individual “packets” of data. I’ve described the reasons for this design choice in a number of posts.

Let me summarize what’s going on with wireless:

  • RFM12B-based nodes can send binary packets of 0..66 bytes
  • these packets can contain any type of data you want
  • a checksum detects transmission errors to let you ignore bad packets
  • dealing with packet loss requires an ACK + re-transmission mechanism

Packets have the nice property that they either arrive intact as a whole or not at all. You won’t get garbled or inter-mixed packets when multiple nodes happen to send at (nearly) the same time. Compare this to some other solutions where all the characters sent end up in one big “soup” if the sending happens (nearly) simultaneously.

But first: what’s a packet?

Well, loosely speaking, you could say that a packet is like one line of text. In fact, that’s exactly what you end up with when using the RF12demo sketch as central receiver: a line of text on the serial/USB connection for each received packet. Packets with valid checksums will be shown as lines starting with “OK”, e.g.:

    OK 3 128 192 1 0
    OK 23 79 103 190 0
    OK 3 129 192 1 0
    OK 2 25 99 200 0
    OK 3 130 192 1 0
    OK 24 2 121 163 0
    OK 5 86 97 201 0
    OK 3 131 192 1 0

Let’s examine how that corresponds with the actual data sent by the node.

  • All the numbers are byte values, shown as numbers in the range 0..255.
  • The first byte is a header byte, which usually includes the node ID of the sender, plus some extra info such as whether the sender expects an ACK back.
  • The remaining data bytes are an exact copy of what was sent.

There appears to be some confusion about how to deal with the binary data in such packets, so let me go into it all in a bit more detail.

Let’s start with a simple example – sending one byte:

Screen Shot 2010 12 06 at 22.32.26

I’m leaving out tons of details, such as calling rf12_recvDone() and rf12_canSend() at the appropriate moments. This code is simply broadcasting one value as a packet for anyone who cares to listen (on the same frequency band and net group). Let’s also assume this sender’s node ID is 1.

Here’s how RF12demo reports reception of this packet:

    OK 1 123

Trivial, right? Now let’s extend this a bit:

Screen Shot 2010 12 06 at 22.38.13

Two things changed:

  • we’re now sending a larger int, i.e. a 2-byte value
  • instead of passing length 2, the compiler calculates it for us with the C “sizeof” keyword

Now, the incoming packet will be reported as:

    OK 1 57 48

No “1”, “2”, “3”, “4”, or “5” in sight! What happened?

Welcome to the world of multi-byte values, as computers deal with them:

  • a C “int” requires 2 bytes to represent
  • bytes can only contain values 0..255
  • 12345 will be “encoded” in two bytes as “12345 divided by 256” and “12345 modulo 256”
  • 12345 / 256 is 48 – this is the “upper” value (the top 8 bits)
  • 12345 % 256 is 57 – this is the “lower” value (the low 8 bits)
  • an ATmega stores values in little-endian format, i.e. lowest-range bytes come first
  • hence, as bytes, the int “12345” is represent as first 57 and then 48
  • and sure enough, that’s exactly what we got back from RF12demo

Yeah, ok, but why should we care about such details?

Indeed, on normal PC’s (desktop and mobile) we rarely need to. We just think in terms of our numbering system and let the computer do the conversions to and from text for us. That’s exactly what “Serial.print(12345)” does under the hood, even on an Arduino or a JeeNode. Keep in mind that “12345” is also a specific representation of the abstract quantity it stands for (and “0x3039” would be another one).

So we could have converted the number 12345 to the string “12345”, placed it into a packet as 5 bytes, and then we’d have gotten this message:

    OK 1 31 32 33 34 35

Hm. Still not quite what we were looking for. Because now we’re dealing with ASCII text, which itself is also an encoding!

But we could build a modified version of RF12demo which converts that ASCII-encoded result back to something like this:

    OKSTR 1 12345

There are however a few reasons why this is not necessarily a good idea:

  • sending would take 5 bytes instead of 2
  • string manipulation uses more RAM, which is scarce on an ATmega
  • lots of such little inefficiencies will add up, once more data is involved

There is an enormous gap in performance and availability of resources between a modern CPU (even on the simplest mobile phones) and this 8-bit few-bucks-chip we call an “ATmega”. Mega, hah!

But you probably didn’t really want to hear any of this. You just want your data back, right?

One way to accomplish this, is to keep RF12demo just as it is, and perform the proper transformation on the receiving PC. Given variables “a” = 57, and “b” = 48, you can get the int value back with this calculation:

Screen Shot 2010 12 06 at 23.11.04

Sure enough, 57 + 48 * 256 is… 12345 – hurray!

It’s obviously not hard to implement such a transformation in PHP, Python, C#, Delphi, VBasic, Java, Tcl… whatever your language of choice is.

But there’s more to it, alas (hints: negative values, floating point, structs, bitfields).

Stay tuned… more options to deal with these representation details tomorrow!

Update – Silly mistake: the “rf12_sendData()” call doesn’t exist – it should be “rf12_sendStart()”.

Spectrum Analyzer

In AVR, Software on Nov 26, 2010 at 00:01

Intrigued by this post, I wanted to try the same thing with the Graphics Board.

So here goes:

Dsc 2330

A real-time Spectrum Analyzer, with due credit to “deif” on the Arduino forum for making Tom Roberts’ simple 8-bit FFT implementation available (three more people are credited in the source code). On the above display you can see a typical “power spectrum”, with one dominant frequency plus harmonics at fixed intervals.

The sketch can be found here:

Screen Shot 2010 11 23 at 00.14.25

This is almost the same code as the 100 KHz DSO sketch, just extended with FFT.

The LCD is refreshed at maximum speed. As you can see, the lag of the LCD itself is actually quite useful in this context. This did bring a bug to the surface: I’ve noticed that the speed-up I implemented for the ST7565 was slightly too fast for this chip. After running for a while, the display would just turn black and stop refreshing.

So I changed these two lines in ST7565::spiwrite() :

Screen Shot 2010 11 22 at 23.48.10

… to this, slightly slower but equivalent code:

Screen Shot 2010 11 22 at 23.48.43

I’ve also updated my version of the ST7565 ZIP file accordingly.

One more note about this code is that it uses most of the available RAM now: the 1 Kb buffer in the ST7565 library, plus two 256-char arrays to store 256 datapoints for running the FFT on.

With code such as this, it would actually be possible to get rid of the ST7565 buffer, since we’re re-constructing the entire display each time.

But for now, I’ll just leave it at this…

2-channel Logic Analyzer

In AVR, Hardware, Software on Nov 25, 2010 at 00:01

Let’s continue the tiny lab-instrument series ;)

Here’s a logic analyzer which takes 512 samples of 2 bits (DIO2 and AIO2):

Dsc 2318

The “trace” starts when either of the inputs changes. I’ve enabled the internal pull-ups, so in this example you can see that DIO2 has no signal. The AIO2 signal is from a JeeNode running the Arduino IDE’s built-in “ASCIItable” demo, which sends out a bunch of characters at 9600 baud (I took the signal from the USB-BUB connector).

Here is the glcdTracer.pde sketch which implements this:

Screen Shot 2010 11 20 at 17.24.06

Lots of trickery with bits. To keep memory use very low, I’m storing the 512 samples in a 128-byte buffer (512 x 2 bits = 128 x 8 bits). Low values are drawn as a pixel, high values are drawn as a little vertical line.

The code includes a minimal triggering mechanism, i.e. it waits for either of the input signals to change before collecting 512 samples.

Samples are collected at about 10 KHz, but this can easily be changed (up to ≈ 200 KHz with the current code).

Note that it would be possible to double the number of samples to 1024 and display them as 8 groups of 2 signals, but then you’ll have to really squeeze the output to fit it onto the 64×128 pixels on the display.

BTW, there’s some shadowing visible on the display – has to do with how the chip drives the GLCD, no doubt.

Soooo… now we also have a portable Logic Analyzer!

100 KHz DSO

In AVR, Hardware, Software on Nov 23, 2010 at 00:01

You might have been wondering why I created the digital-to-analog converter a few days ago.

Well, because I needed a test signal… to build this thing:

Dsc 2307

You’re looking at a <cough> Digital Storage Scope </cough> with 100 KHz bandwidth :)

First of all: please don’t expect too much. There is no signal conditioning and no triggering whatsoever, and there are no external controls. This is simply a JeeNode plus a Graphics Board. It’s using the built-in ADC, with the conversion clock pushed quite a bit higher than what the Arduino’s analogRead() function will do. This speed comes at the cost of conversion accuracy, which isn’t so important since the Graphics Board display only has 6-bit vertical resolution anyway.

The screenshot shows a 1 KHz sine (from that Bleep! thing, obviously). As you can see, one cycle more-or-less covers the entire x-axis. So that’s about 128 samples per millisecond. This is not the maximum value, the ADC can also work twice as fast – i.e. with a division factor of 4 (ADPS2:0 = 2). This translates to 4 µs per sample.

Using the Nyquist–Shannon sampling theorem again, you can detect a frequency if you sample it at least twice per cycle, so that would have to be a cycle of at least 8 µs, i.e. over 100 KHz. Which is why I decided to call this thing a 100 KHz DSO :)

The code tries to get as many samples as possible into a little 128-byte buffer before doing the rest of the work. The graphics display has a fairly limited response time, so I’m refreshing the display at 5 Hz (it’s still visible up to 50 Hz, but only just…).

I find it pretty amazing what an MPU such as the ATmega can do these days, with just a few lines of C code. Here’s the entire glcdScope.pde sketch:

Screen Shot 2010 11 19 at 02.58.10

The rest of the code is in the same modified ST7565 library as used in the past few days.

There’s lots of room for expansion, this code uses less than 4 Kb.

So there you have it – a very crude, but functional, oscilloscope!

Bleep!

In AVR, Hardware, Software on Nov 21, 2010 at 00:01

Puzzle for you – what is this thing?

Dsc 2301

Maybe the demo sketch helps?

Screen Shot 2010 11 18 at 12.25.23

Answer: it’s an 8-bit digital-to-analog converter, using an R-2R ladder network (with 10 kΩ & 20 kΩ resistors).

The above toneGen.pde sketch generates a sine wave of approx 1 KHz:

Screen Shot 2010 11 18 at 12.25.17

There’s lots of ways to improve on this and turn it into a general-purpose function generator for example.

The interesting part is that all four ports are used for the required 8 I/O pins, and that due to the regularity of the pin assignment, they can all be set at once with very little code. The pin assignments for the DAC are:

  • bit 0 = AIO1
  • bit 1 = AIO2
  • bit 2 = AIO3
  • bit 3 = AIO4
  • bit 4 = DIO1
  • bit 5 = DIO2
  • bit 6 = DIO3
  • bit 7 = DIO4

The maximum attainable frequency is about 1.84 Khz with this software approach (1.95 KHz with the sine256 table placed in RAM), but that’s only if you use all 256 steps of the sine wave. The loop itself runs at about 1.84 * 256 = 470 KHz, so based on the Nyquist–Shannon sampling theorem, it should be possible to generate decent signals up to well over 200 KHz. The trick is to increment the “index” variable by larger values:

Screen Shot 2010 11 18 at 12.54.06

Here’s the corresponding output:

Screen Shot 2010 11 18 at 12.55.31

Still a pretty decent sine wave, so 16 resistors are all it takes to cover the entire audible frequency range.

By using fixed-point calculations for “fractional indexing”, you can get even more fine-grained control over the frequency of the generated signal. The following version generates an 8.01 KHz sine wave on my setup (note that “index” is now a 16 bit unsigned integer):

Screen Shot 2010 11 18 at 13.03.55

Update – I’ve changed the main loop to avoid the calling overhead of loop() itself. That increases the maximum attainable frequency by another 50%. Note that interrupts must be disabled to produce a clean tone.

JeeNode Experimenter’s Pack

In AVR, Hardware on Nov 8, 2010 at 00:01

Neat – it looks like JeeNodes are starting to become popular for workshops!

I’m not really surprised: it’s more fun than an Arduino, IMO, because you get to learn the basics of electronics and soldering, and of course every JeeNode comes with wireless connectivity built-in. As I’ve said before, making things happen by wireless is a bit like magic…

FWIW, there are a couple of workshops scheduled for this month (“in-house”, i.e. for a specific audience, and I’m only indirectly involved), all are based on either a JeeNode or an RBBB. Both are well suited for solderless breadboards, which – if you ask me – is one of the greatest inventions ever for tinkering and learning electronics. Sure, soldering works best when the circuit is known and proven, but nothing beats a breadboard, some jumper wires, and a bunch of components and chips to try out things!

This gives me great satisfaction. No, not for the money side of it (it’s all discounted anyway), but because I find nothing more exciting than to see people try out new fun stuff and nurture their tech geek sides :)

Learning is great: if you’re young, it’ll make you wiser – if you’re old, it’ll make you younger … (and it’s fun!)

The big question is always: “what do I need to get started?” – and my answer is usually: “it depends on what kind of adventure you’re after”.

I’ve come up with a new “JeeNode Experimenter’s Pack” to create a baseline for the future. That way, it will be easier for me to set up and document my experiments, knowing that there is a common baseline on which to build. It’s also the logical step after this rubber-band concoction. It consists of the following key components:

Dsc 2221

In prose:

In addition, and only in combination with the rest of the Experimenter’s Pack, I’m throwing in a little 10×17 cm laser-cut wooden base and an LDR to get started with some sensor experiments:

Dsc 2220

The base turns the whole thing into a self-contained “project platform” for all sorts of experimentation. And the AA Power Board will supply 3.3V to make this setup portable and usable anywhere. The rest of the empty space is all yours. That’s where the fun happens :)

The AA Power Board is not just a gimmick, BTW: an AA battery will actually provide more power @ 3.3V than a 9V “block”! As someone pointed out recently, it’s also a great way to drain any half-used AA batteries you might still have lying around (who hasn’t?).

Here’s a recent example of use (which required a bit more power, so I hooked it up to a 12V supply):

Dsc 2215

It’s a little stepper motor tester (using an EasyDriver board). Nothing fancy, but it was a convenient way for me to try something like this out. That project board has now been cleared to make room for new experiments…

That’s the whole point, really – this self-contained setup is intended to provide a quick path for trying out new ideas. USB-connected or battery-powered, serial or wireless, local or remote, whatever.

Once it all works, you could:

  1. take the design and redo it as a more permanently soldered circuit
  2. design a pcb for it (which is what I did for the graphics board)
  3. put it all into a custom enclosure and keep using the setup
  4. stash it all away as is, for some other time
  5. put hot glue on it? (yikes!)

I’ve added this to the shop, as 1- and as 10-pack.

Simple RF12 driver sends

In AVR, Software on Oct 30, 2010 at 00:01

(Whoops… this post got mis-scheduled – fixed now)

Yesterday’s post illustrates an approach I’ve recently discovered for using the RF12 driver in a very simple way. This works in one very clear-cut usage scenario: sending wireless packets out periodically (without ACK).

Here’s the basic idiom:

Screen Shot 2010 10 29 at 13.01.24

What this does is completely ignore any incoming data, it just waits for permission to send when it needs to, and then waits for the send to complete by specifying “2” as last arg to rf12_sendStart().

No tricky loops, no idle polling, everything in one place.

With a few lines of extra code, the RFM12B module can be kept off while not used – saving roughly 15 mA:

Screen Shot 2010 10 29 at 13.07.11

And with just a few more lines using the Sleepy class, you get a low-power version which uses microamps instead of milliamps of current 99% of the time:

Screen Shot 2010 10 29 at 13.09.03

Note the addition of the watchdog interrupt handler, which is required when calling Sleepy::loseSomeTime().

The loseSomeTime() call can only be used with time ranges of 16..65000 milliseconds, and is not as accurate as when running normally. It’s trivial to extend the time range, of course – let’s say you want to power down for 10 minutes:

Screen Shot 2010 10 29 at 13.11.16

Another point to keep in mind with sleep modes, is that it isn’t always easy to keep track of time and allow other interrupts to wake you up again. See this recent post for a discussion about this.

But for simple Wireless Sensor Network node scenarios, the above idioms will give you a very easy way to turn your sketches into low-power mode which can support months of operation on a single set of batteries.

Update – it looks like the above RF12_sleep() arguments are completely wrong. They should be:

  • rf12_sleep(N) turns the radio off with a wakeup timer enabled if N is 1..127
  • rf12_sleep(0) turns the radio off
  • rf12_sleep(-1) turns the radio back on

This list matches what is documented on the wiki page.

Meet the Bridge Board

In AVR, Hardware on Oct 27, 2010 at 00:01

As mentioned not so long ago on this weblog, I’ve been doodling with some ideas to simplify using a JeeNode alongside a solderless breadboard. So – tada! – here’s the new Bridge Board:

Dsc 2167

As the name says, it acts as a bridge between a JeeNode (also USB or SMD variants) and a breadboard. All the I/O and power pins in one row, labeled for easy reference (including Arduino pin numbers), with two pins sticking into the power rail for ground and +3.3V. The JeeNode goes underneath, component-side up, with the radio on the right-hand side.

Two LEDs and a push button are also brought out, available for general-purpose use.

In the most basic form, the Bridge Board has just 4 6-pin male haders to push into the JeeNode ports, and 29 (+ 2 power-rail) pins to push into a medium or large size breadboard.

The generality of this setup increases if you hook up more headers between the JeeNode and the Bridge Board. With the SPI/ISP connector included, you get the ability to hook it up to an Ether Card, for example:

Dsc 2165

The reason this works, is that the 20 pins on the right are compatible with a Carrier Board – with the “BTN” and “LED2” pins extra. Note that with an Ether Card hooked up, all four ports (i.e. 8 DIO/AIO pins) are still fully available for your own use.

If you connect the 8-pin PSIX header on a JeeNode v5 (or both PSI and SPI/ISP on the other variants), plus a 0.1 µF capacitor, then the FTDI header on the left side can be used. This is paricularly useful for the JeeSMD, which doesn’t have an FTDI connector of its own.

Some I/O signals are brought out on more than 1 pin on the breadboard: DIO2/AIO2 and DIO3/AIO3. This maintains compatibility with the Carrier Board and also means that Port 2 is available on the breadboard in the standard port header layout: PWR, DIO, GND, +3V, AIO, IRQ if you want to insert any of the Jee Plugs.

Another way to combine plugs with the breadboard is to use stacking headers, so that the 4 ports can be re-used on the top of the Bridge Board. See the setup I plugged into the lower left:

Dsc 2166

Evidently, I had to make sure that all the I/O pins work properly, so I pre-loaded the SMDdemo.pde sketch onto a JeeNode and hooked up lots of LEDs:

Dsc 2161

Yeay – it works!

(note how the push-button has been turned into a reset button – this requires either the SPI/ISP or the PSIX headers to be hooked up)

I expect this new setup to be very convenient for all the endless experimentation going on here at Jee Labs. I’ll be updating the documentation site and shop shortly to reflect this addition to the Jee product line-up. I’ll also be adding 6- and 8-pin stacking header 10-packs.

Long live the breadboard!

Reporting motion

In AVR, Software on Oct 21, 2010 at 00:01

Yesterday’s post presented a new sketch which did everything the old sketch did, except report motion. The reason was that the requirements for reporting motion are quite different from the rest: it has to be reported right away – using ACKs, time-outs, and retries to make sure this message is properly received.

The latest version of roomNode.pde now adds the missing logic. And it does indeed get a lot messier – doubling the total number of lines in the source code.

Here is the new loop() code:

Screen Shot 2010 10 19 at 22.37.41

The key change is that there is now a check for “pir.triggered()” which will be called outside all normal scheduling actions. Note that this code is still using scheduler.pollWaiting(), so the code is still spending most of its time in power-down mode.

Except that now, we’re also setting up a pin-change interrupt for the PIR sensor:

Screen Shot 2010 10 19 at 22.40.16

The new code to handle these PIR triggers is as follows:

Screen Shot 2010 10 19 at 22.42.14

So instead of folding this complicated case into the rest of the code, when a PIR trigger goes off, we now simply send that packet out and wait for the ACK, repeating it a few times if necessary. The normal measurement and reporting tasks are not affected by any of this, other than that the measurement scheduling is postponed a bit to avoid triggering another report right away.

The new PIR motion sensor turns out to be quite convenient, because it has an on-board trimpot to set the re-trigger timeout. As long as motion is detected more often than this threshold, the PIR output will remain 1, so there is no need to play tricks in software to avoid constant triggers. We’ll get one pin change for the start of motion, and another one when no motion has been detected for a preset amount of time.

Having said that, I’ve implemented a similar re-triggerable one-shot mechanism in software anyway, because my older nodes use the ELV PIR sensor, which send out a pulse for each motion trigger. So all ON pulses within 30 seconds of each other get coalesced into one.

To illustrate that the system is still doing almost nothing most of the time, I added a debug mode which prints a “.” on each iteration of loop(). In normal Arduino sketches, this would cause an incessant stream of characters to be printed out, but in this sketch there are just a few:

Screen Shot 2010 10 19 at 22.12.35

Motion detection now works more or less independently of the normal measure / report tasks.

There are still some rough edges, but I expect this new code to perform considerably better in terms of battery lifetime already. The dreaded battery rundown problem when the central node is not reachable should be gone. All that remains are a few attempts (I’ve set it to 5) whenever the PIR sensor turns on or off. In both cases the ACK has to be received within 10 milliseconds – after that the sketch enters power-down mode again.

The new code should also make it much easier to add sensor types (switches, hall-effect, 1-wire, barometer).

FWIW, this code needs 8238 bytes (without serial I/O), so it’ll still easily fit in an ATmega168. Without SHT11 (which uses floating point) that drops to 5682 bytes, including the RF12 driver. How’s that for a WSN node!

New roomNode code

In AVR, Software on Oct 20, 2010 at 00:01

It’s time to start putting the pieces together now: sensor readout, scheduling of measurements and packet sends, and low-power mode. Looks like the code in the Ports and RF12 libraries is now making this easier than ever.

There’s a new roomNode.pde sketch which illustrates the whole shebang. At 145 lines, it’s a bit too long to include here in full, but I’ll show some of the interesting pieces.

Note that this version implements everything except motion reporting, which is a bit more complex.

Following the good ol’ top-down tradition, first the setup() and loop() code:

Screen Shot 2010 10 19 at 14.06.12

It starts the measurement loop, which then keeps itself running periodically. The report activity is started every once in a while. Note also the “now” variable, which will make it easier to use 2-byte ints in the logic which will decide later about when to report motion, etc.

The measurement code depends completely on what sensors are supported, and is pretty straightforward:

Screen Shot 2010 10 19 at 14.10.36

No surprises, we just have to be careful to do things in an energy-efficient manner. All the readings end up in the “payload” struct.

And here’s the reporting code:

Screen Shot 2010 10 19 at 14.14.24

Here’s some sample output on the serial port:

Screen Shot 2010 10 19 at 14.18.17

I still need to add the logic for motion detection, but with the new scheduling capabiltities, I expect that extra complexity to stay within a small portion of the code – unlike the current rooms.pde sketch, where everything seems to affect everything else.

The best part? My multimeter stays mostly under 60 µa, i.e. the low-power logic is automatically kicking in!

Room Node – next steps

In AVR, Software on Oct 19, 2010 at 00:01

First of all: thanks to everyone who commented on the recent posts, both online and by direct email. Fantastic feedback, lots of ideas, and several valuable corrections.

In yesterday’s post, I agonized about how hard it is to track time in some sort of reasonably continuous way when most of it is spent in comatose state. Fortunately, a Room Node won’t need that awareness very much. I just wanted to show how things get complex in terms of watchdogs running-but-not-yet-expired, and multiple interrupt sources.

For the next version of the rooms.pde sketch, my plan of attack is to simply ignore the issue. The watchdog will be used for guaranteed wake-up, while PIR motion detection and radio reception interrupts will simply cause the millis() clock to lose time, occasionally.

For ACKs, I’m going to start simple and wait for up to 2 milliseconds in idle mode, before resuming lower-power options again. One interesting suggestion was to slow down the clock while doing so (through the system clock pre-scaler), but that has to be done with care because a slower-running ATmega will also respond more slowly to RF12 driver interrupts – and there is not that much slack there.

Here’s the updated Scheduler class, now included in the Ports library:

Screen Shot 2010 10 18 at 22.54.27

Only a minor extension on the API side: by using pollWaiting() instead of poll(), you can tell the system to enter low-power mode until the next scheduled task. If another interrupt pre-empts this wait cycle, then it’ll break out of power-down mode and go through the loop and re-enter the low-power state the next time around.

The other change I’m currently testing is that a few Scheduler functions can be called from interrupt code, so this provides a way for interrupt code to safely schedule, resume, or cancel a task “via the main thread”.

This is the tiny change needed to make the schedule.pde demo energy efficient:

Screen Shot 2010 10 18 at 23.01.24

However, because it now uses the watchdog, you also need to add the following boilerplate to the sketch:

ISR(WDT_vect) { Sleepy::watchdogEvent(); }

The demo now draws 25 µA when I remove the LEDs.

So here’s the deal: if you can manage to write all your code is such a way that it never calls delay() – or delayMicroseconds() with large values – and instead uses this Scheduler-with-tasks approach, then you’ll get a fairly low power usage almost for free… i.e. without having to do anything else! (just don’t forget to turn the radio on and off as needed)

The code has been checked into subversion, and is also available as ZIP archive – see the Ports info.

Update – more changes checked in to better handle watchdog vs other interrupts.

Tracking time in your sleep

In AVR, Software on Oct 18, 2010 at 00:01

No, this isn’t a story about bio-rhythms :)

One of the challenges I’ll be up against with Room Nodes is how to keep track of time. The fact is that an ATmega is extraordinarily power efficient when turned off, and with it a JeeNode – under a few microamps if you get all the little details right. That leads to battery lifetimes which are essentially only determined by self-discharge!

But there are two problems with power off: 1) you need to be 100% sure that some external event will pull the ATmega out of this comatose state again, and 2) you can completely lose track of time.

Wireless packets are of no use for power-down mode: the RFM12B consumes many milliamps when turned on to receive packets. So you can’t leave the radio on and expect some external packets to tell you what time it is.

Meet the watchdog…

Fortunately, the ATmega has a watchdog, which runs on an internal oscillator. It isn’t quite as accurate, but it’ll let you wake up after 16 ms, 32ms, … up to 8 seconds. Accuracy isn’t such a big deal for Room Nodes: I don’t really need to know the temperature on that strict a schedule. Once every 4 .. 6 minutes is fine, who cares…

There’s a Sleepy class in the Ports library, which manages the watchdog. It can be used to “lose time” in a decently accurate way, and will use the slowest watchdog settings it can to get it out of power-down mode at just about the right time. To not disrupt too many activities, the “millis()” timer is then adjusted as if the clock had been running constantly. Great, works pretty well.

It’s not enough, though.

As planned for the next implementation, a Room Node needs to sleep one minute between wakeups to readout some sensors, but it also needs to wake up right away if the motion sensor triggers.

One solution would be to wake up every 100 ms or so, and check the PIR motion sensor to see whether it changes. Not perfect, but a 0.1s delay is not the end of the world. What’s worse though is that this node will now wake up 14,400 times per day, just to check a pin which occasionally might change. This sort of polling is bound to waste some power.

Meet the pin-change interrupt…

This is where pin-change interrupts come in, They allow going into full power-down, and then getting woken up by a change on any of a specified set of pins. Which is perfect, right?

Eh… not so fast:

Screen Shot 2010 10 17 at 22.05.30

Q: What time is it when the pin-change occurred?

A: No idea. Somewhere between the last watchdog and the one which will come next?

IOW, the trouble with the watchdog is that you still don’t really track time. You just know (approximately) what time it is when the watchdog fires again.

If the watchdog fires say every 8 seconds, then all we know at the time of a pin-change interrupt, is that we’re somewhere inside that 8s cycle.

We can only get back on track by waiting for that next watchdog again (and what if the pin change fires a second time?). In the mean time, our best bet is to assume the pin change happened at the very start of the watchdog cycle. That way we only need to move the clock forward a little once the watchdog lets us deduce the correct moment. FYI: everything is better than adjusting a clock backwards (timers firing again, too fast, etc).

Now as I said before, I don’t really mind losing track of time to a certain extent. But if we’re using 8-second intervals to get from one important measurement time to the next, i.e. to implement a 1-minute readout interval, then we basically get an 8-second inaccuracy whenever the PIR motion detector triggers.

That’s tricky. Motion detection should be reported right away, with an ACK since it’s such an important event.

So we’re somehere inside that 8-second watchdog cycle, and now we want to efficiently go through a wireless packet send and an ACK cycle? How do you do that? You could set the watchdog to 16 ms and then start the receiver and power down. The reception of an ACK or the watchdog will get us back, right? This way we don’t spend too much time waiting for an ack with the receiver turned on, guzzling electrons.

The trouble is that the watchdog is not available at this point: we still want to let that original 8-second cycle complete to get our knowledge of time back. Remember that the watchdog was started to get us back out in 8 seconds, but that it got pre-empted by a pin-change.

Let me try an analogy: the watchdog is like throwing a ball straight up into the air and going to sleep, in the knowledge that the ball will hit us and wake us up a known amount of time from now. In itself a pretty neat trick to keep track of the passage of time, when you don’t have a clock. Well, maybe not for humans…

The scenario that messes this up is that something else woke us up before the ball came down. If we re-use that ball for something else, then we have lost our way to track time. If we let that ball bring us back into sync, fine, but then it’ll be unavailable for other timing tasks.

I can think of a couple solutions:

  • Dribble – never use the watchdog for very long periods of time. Keep waking up very frequently, then an occasional pin-change won’t throw us off by much.

  • Delegate – get back on track by asking for an ack which tells us what time it is. This relies on a central receiving node (which is always on anyway), to tell us how to adjust our clock again.

  • Fudge it – don’t use the watchdog timer, but go into idle mode to wait for the ack, and make that idle period as short as possible – perhaps 2 ms. IOW, the ACK has to reach us within 2 milliseconds, and we’re not dropping into complete powerdown during that time. We might even get really smart about this and require that the reply come back exactly 1 .. 2 ms after the send, and then turn off the radio for 1 ms, before turning it on for 1 ms. Sounds crazy, until you realize that 1 ms of radio time uses as much energy as 5 seconds of power down time – which adds up over a year! This is a bit like what TDMA does, BTW.

All three options look practical enough to consider. Dribbling uses slightly more power, but probably not that much. Delegation requires a central node which plays along and replies with an informative ack (but longer packets take longer to receive, oops!). Fudging it means the ATmega will be in idle mode a millisec or two, which is perhaps not that wasteful (I haven’t done the math on that yet).

So there you go. Low power stuff isn’t always trivial, once you start pushing for the real gains…

IR decoding with pin-change interrupts

In AVR, Hardware, Software on Oct 14, 2010 at 00:01

Yesterday’s post described a new “InfraredPlug” class which handles the main task of decoding IR pulse timings. The “irq_recv.pde” example sketch presented there depended on constant polling to keep the process going, i.e. there has to be a line like this in loop():

    ir.poll();

Worse, the accuracy of the whole process depends on calling this really often, i.e. at least every 100 µs or so. This is necessary to be able to time the pulse widths sufficiently accurately.

Can’t we do better?

Sure we can. The trick is to use interrupts instead of polling. Since I was anticipating support for pin-change interrupts, I already designed the class API for it. And because of that, the changes needed to switch to an interrupt-driven sketch are surprisingly small.

I’ve added a new irq_send_irq.pde sketch to the Ports library, which illustrates this.

The differences between using polling mode and pin-change interrupts in the code are as follows. First of all, we need to add an interrupt handler:

Screen Shot 2010 10 13 at 00.26.10

Second, we need to enable those interrupts on AIO2, i.e. analog pin 1:

Screen Shot 2010 10 13 at 00.26.44

And lastly, we can now get rid of that nasty poll() call in the loop:

Screen Shot 2010 10 13 at 00.27.51

That’s all there is to it. Does it still work? Of course:

Screen Shot 2010 10 13 at 00.29.16

Note: I made some small changes in the InfraredPlug implementation to tolerate interrupts and avoid race conditions.

This all seems like an insignificant change, but keep in mind that this completely changes the real-time requirements: instead of having to poll several thousands of times per second to avoid missing pulses or measuring them incorrectly, we can now check for results whenever we feel like it. Waiting too long would still miss data packets of course, but this means our code can now continue to do other lengthy things (or go into a low-power mode). Checking for incoming packets a few times a second is sufficient (IR remotes send out a packet every 100 ms or so while a button is pressed).

So the IR decoder now has the same background behavior as the RF12 driver: you don’t need to poll it in real-time, you just need to check once in a while to see whether a new packet has been received. Best of all, perhaps, is that you can continue to use calls to delay() even though they make the main loop less responsive.

There is another side effect of this change: if your code includes a call to “ir.send()”, then the receiver will see your own transmission, and report it as an incoming packet as well. Which shows that it’s running in the background. This could even be used for collision detection if you want to build a fancy IR wireless network on top of all this.

So there you go: an improved version of the InfraredPlug class, which lets you use either explicit polling or pin-change interrupts. The choice is yours…

Room Node battery life

In AVR, Hardware on Oct 6, 2010 at 00:01

The current Room Node sketch only gets 1..2 months of life out of a 3x alkaline AA battery pack. Not enough – by far – for practical use around the house.

The good news is that it’s almost entirely a software issue. There have been JeeNodes running for many months now, some up to 10 months, so there is no hardware limitation to achieve such lifetimes.

In fact, I’d like to push it a bit further and see how long one could run a Room Node off a single rechargable AA battery using the AA Power board. If it’s not that long, I could still opt for the 3x AA pack.

Let’s estimate the idle current draw of a JeeNode first.

The big consumer is the PIR sensor. I recently switched to a new one, because it only needs 3.3V and because of its low current draw. Note that the PIR motion sensor is the only component in the Room Node which should not be disabled during sleep: the whole point is to be able to detect motion at all times, after all. Also, a PIR sensor needs time to stabilize, in the order of a minute, so turning it on briefly is no option.

Here’s the good news:

Dsc 2077

That’s 41 µA idle current.

The JeeNode draws ≈ 3.3 µa, let’s round it up to 4 µA.

The SHT11 draws 2..5 µW, let’s round it up to 2 µA.

So total idle draw is 47 µA.

As it turns out, transmissions consume a neglegible amount of current – if the frequency of transmission is 5 minutes, for example (i.e. 288x per day). The motion detection is different, this needs to go out as soon as there is motion, but this probably won’t happen more than a dozen times a day, on average).

For a transmission, the RFM12B needs to be on for about 2 ms, at which point it draws around 25 mA. With 2 ms once every 300 seconds, that’s a duty cycle of 1:150000, i.e. under 2 µA when averaged out.

So let’s round up and assume that the average current draw of a Room Node is 50 µA @ 3.3V.

A 3x AA battery pack of 2500 mAh would last 50,000 hours, i.e. over 5 years if we ignore the self-discharge rate … assuming that the low-power code is perfect, that is!

Now for the AA Power Board lifetime estimate. At very low current levels, the efficiency of the LTC3525 regulator is 75..80%, according to the datasheet. But first, we need to estimate the current draw. Keep in mind that the power source will be 1.2 .. 1.3V, so we basically need a 3-fold step up. Let’s calculate the input current draw, assuming 1.2V in, 3.3 V out @ 50 µA, and 75% efficiency:

input current = 50 x 3.3 / 1.2 / 0.75 = 183 µA

With an Eneloop battery, I’ll assume it has 1900 mAh capacity, and loses 15% of its charge in two years. Let’s assume that it’ll be used no more than 2 years, and that it lost that 15% charge right at the beginning. Then this is effectively nothing more than a 1600 mAh battery.

Ok, how long can it power a JeeNode plus Room Board?

lifetime = 1600 / 0.183 = 8743 hours = 364 days

So all in all this setup should be able to run just about one year off a single rechargable AA battery. Note that there was some rounding in several places in these calculations, so these estimates are probably a bit conservative.

One year battery life… that’s in fact exactly what I was hoping for!

Now the “only” remaining challenge is to optimize the “rooms.pde” sketch enough to make this happen.

Software PWM at 1 KHz

In AVR, Software on Oct 3, 2010 at 00:01

While pondering about some PWM requirements for a new project here, I was looking at the rgbAdjust.pde sketch again, as outlined in the Remote RGB strip control weblog post from a few months back. It does PWM in software, and plays some tricks to be able to do so on up to 8 I/O pins of a JeeNode, i.e. DIO and AIO on all 4 ports. The main requirement there, was that the PWM must happen fast enough to avoid any visible flickering.

The rgbAdjust sketch works as follows: prepare an array with 256 time slots, each indicating whether an I/O pin should be on or off during that time slot. Since each array element consists of one byte, there is room for up to 8 such bit patterns in parallel. Then continuously loop through all slots to “play back” the stored PWM patterns.

There is one additional refinement in that I don’t actually store the values, but only store a 1-bit during the change of values. That shaves off some overhead when rapidly changing I/O pins (see the Flippin’ bits post).

There are some edge cases (there always are, in software), such as dealing with full on and full off. Those two cases require no bit flipping, whereas normally there are always exactly two flips in the 256-cycle loop. But that’s about it. It works well, and when I simplified the code to support only brightness values 0..100 instead of the original 0..255, the PWM rate went up to over 250 Hz, removing all visible flicker.

So what rgbAdjust does, is loop around like crazy, keeping track of which pins to flip. ATmega’s are good at that, and because the RF12 driver is interrupt-driven, you can still continue to receive wireless data and control the RGB settings remotely.

But still, a bit complex for such a simple task. Isn’t there a simpler way?

As it turns out, there is… and it’ll even bump the PWM rate to 1 KHz. I have no idea what our cat sees, but I wouldn’t be surprised if cats turned out to be more sensitive than us humans. And since I intend to put tons of LED strips around the house, it better be pleasant for all its inhabitants!

What occurred to me, is that you could re-use a hardware counter which is always running in the ATmega when working with the Arduino libraries: the TIMER-0 millisecond clock!

It increments every 4 µs, from 0 to 255, and wraps around every 1024 µs. So if we take the current value of the timer as the current time slot, then all we need to do is use that same map as in the original rgbAdjust sketch to set all I/O pins!

Something like this, basically:

Screen Shot 2010 10 01 at 01.41.11

(assuming that the map[] array has been set up properly)

No more complex loops. All we need to do is call this code really, really often. It won’t matter whether some interrupts occur once in a while, or whether some extra code is included to check for packet reception, for example. What might happen (in the worst case, and only very rarely) is that a pin gets turned on or off a few microseconds late. No big deal, and most importantly: no systematic errors!

It’s fairly easy to do some other work in between, as long as the main code gets called as often as possible:

Screen Shot 2010 10 01 at 01.51.18

I’ve applied this approach to an updated rgbRemote.pde sketch in the RF12 library, and sure enough, the dimming is very smooth for intensity levels 25..255. Below 25, there is some flickering – perhaps from the millis() timer? Furthermore, I’m back to being able to dim with full 24-bit accuracy, i.e. 8 bits on each of the RGB color controls. Which could be fairly important when finely adjusting the white balance!

So there you have it: simpler AND better! – all for the same price as before :)

Assembling the JeeNode v5

In AVR, Hardware on Sep 26, 2010 at 00:01

New JeeNode means: new build instructions.

Here goes. A long description of how to go from this:

Dsc 1973

… to this:

Dsc 1970

Make sure you’ve got a nice soldering iron (not too hot, not too large) and some solder wick to remove solder in case you need to back up a bit to fix things. The JeeNode printed circuit is very sturdy and can handle a lot of abuse, but some traces are thin, so be careful and don’t apply too much force.

Components are soldered on from lowest to highest profile, because then you can turn over the board and push on it to get each component snugly against the board as you solder it. So let’s start with the resistor:

Dsc 1974 Dsc 1975

Once you’re satisfied with the soldering, turn it over and snip off the leads:

Dsc 1976 Dsc 1977

More…

Read the rest of this entry »

Meet the JeeNode v5

In AVR, Hardware, News on Sep 25, 2010 at 00:01

I’m very pleased to introduce the – Fresh!Updated!New!JeeNode version 5 board:

Dsc 1929

Hold on. Don’t get too excited. It’s not that big a deal. It’s basically still the same JeeNode v4, with just some incremental changes.

Allow me go through each of the differences in some detail:

  • on the left, there is now a diode between the FTDI power input and the rest of the PWR lines – so you can power the board from a 4.5..13V battery, etc. and it won’t fry the FTDI board or cable when plugged in
  • this also means that “PWR” will be about 0.7V lower on the PWR pins in several places across the board, than on the power supplied to the FTDI power pin (i.e. 4.3V when fed from a USB-BUB)
  • for 100% compatibility with the JeeNode v4 and older, the diode can be disabled (i.e. shorted out) with a solder jumper on the back side
  • two extra header pins have been added (+3V and RST), on either side of what was the “PWR/SER/I2C” header on the JeeNode v4 – it is now called the “PSIX” header (X = eXtended)
  • on the right, the RFM12B module was moved a bit to make room for a hole for the antenna wire
  • not as easy to see, but the board is also fractionally longer, so that the RFM12B no longer sticks out
  • slight re-arrangement of components (caps and reset pull-up)
  • most holes are slightly larger, making it easier to unsolder components, if you ever need to
  • the long sides of the board are now routed i.s.o. V-scored, i.e. much smoother and more precise:

Dsc 1966

That’s more or less it. Oh, and D O T Sfour big white dots on each side of the board to be precise, next to the PWR pin of each of the Port 1 .. 4 headers. You’ll be surprised by how convenient that can be when hooking up all sorts of plugs – which have the same dots to mark the proper orientation.

All in all, no big changes. Nothing incompatible with the JeeNode v4, the JeeNode USB, or the JeeNode SMD. This isn’t about planned obsolescence, these are just some tweaks to squeeze the maximum usability out of what is essentially the flagship and workhorse of Jee Labs, if you pardon this odd mix of metaphors.

I did forget to fix two little teeny tiny label name spelling errors which were also on the JeeNode v4 (left as exercise for the diligent reader). Oh well. I hereby claim victory anyway, and now declare this v5 PCB to be TUJ!

… TUJ ?

Yes: TUJ. Shorthand for The Ultimate JeeNode of course! What else?

PS. The JeeNode v5 is shipping now. I don’t play “There’s Something New Coming Soon” games.

Update – I’ve updated the documentation:

  • JeeNode v5 manual (PDF)
  • JeeNode v5 pinout (PDF)

It’s all a bit in transition, with the Café moving to Redmine soon – which is where these docs will go, eventually.

It’s time to Do The Right Thing

In AVR, Hardware on Sep 24, 2010 at 00:01

This is long overdue…

If you have one or more JeeSMD v1 boards, which look tike this:

Dsc 1772 2

… then you are entitled to a free upgrade to the new JeeSMD v2 board, with the fixed VR (and tented vias):

Dsc 1963

Actually, I won’t send you a replacement board for each one you have, but an entire JeeSMD kit.

Likewise, if you ordered one or more Carrier Boards with Boxes, and never got these:

Dsc 1964

… then I owe you that DC Power Jack and matching connector. Ignore the 0.1 µF ceramic capacitor if you already have one – it’s for adding the reset circuitry on the Carrier Board’s FTDI connector.

Email me (please include the order number if possible) and I’ll get it out to you. No questions asked.

Mistakes happen – and I can’t undo the past. But I won’t walk away from my responsibilities either.

Sleepy class

In AVR, Software on Sep 4, 2010 at 00:01

To make it simpler to experiment with the very low-power states of the ATmega on the JeeNode, I’ve moved some code to the Ports library.

It’s all wrapped up into a new “Sleepy” class:

Screen Shot 2010 09 03 at 14.07.54

See the powerdown_demo.pde and radioBlip.pde sketches for examples of use.

This class is documented in the Café:

Screen Shot 2010 09 03 at 14.23.39

FWIW, I’m also evaluating the Redmine system as a way to bring the code repository, Café docs, issue tracker, and Talk forums all into one context:

Screen Shot 2010 09 03 at 14.24.50

That site is still experimental, so I’m not making it public yet. The one missing feature holding me back is that Redmine does not have a good spam prevention mechanism, such as Akismet. At least last time I looked. But all in all, this would be a great way to provide a place to describe projects, fill in the documentation, and track all code changes and bugs collaboratively. If you’d like to have a sneak preview, or want to have a place to describe your project, or perhaps would like to help with the fairly gigantic task of getting a good documentation section going, please email me.

I’ve started copying over some content, but it’s going to take a while before everything has been brought over and adjusted. Both the old and the new system use Markdown, but there are always them pesky little details…

Anyway, back to the topic at hand – enjoy the low-power options, and please consider sharing your explorations, findings, and inventions in the Talk discussion forums.

Sending packets without battery

In AVR, Hardware, Software on Sep 2, 2010 at 00:01

Here’s a fun experiment…

After yesterday’s improved power-down current results, I wanted to find out how much power it really takes to send out a bunch of small packets. No acks, just periodically sending out a packet and sleeping.

Trouble is, I didn’t want to wait for a battery to run down, since that would take months or even years. Bit long to get results for this weblog, eh?

So instead, I used this little chap:

Dsc 1873

It’s a super-capacitor which can handle up to 5.5V and has a capacity of 0.47 Farad! That’s like putting a thousand 470 µF caps in parallel. Amazing stuff, in an even more amazingly small package.

Here’s a JeeNode, fitted with this new power source, to give you an idea of just how small this thing is:

Dsc 1874

The next step was to design a small sketch to test this. Here’s what I came up with:

Screen Shot 2010 08 29 at 11.57.38

Some of the code left out for brevity. Full source code can be found here.

What this demo does is send out a packet with a 2-byte payload, then sleep for approximately 1 second, then send again, etc. Until power runs out.

Sure enough, packets started coming in every second:

    OK 4 0 0
    OK 4 1 0
    OK 4 2 0
    OK 4 3 0
    [...]

I expected it to send out say 100 packets or so, before the charge in the 0.47 F supercap would run out.

Guess how far it went…

    [...]
    OK 4 178 28
    OK 4 179 28
    OK 4 180 28
    OK 4 181 28

That’s packet number … clickety, clickety … 28 * 256 + 181 = 7349 !!!

In other words, the JeeNode was able to send out well over 7000 packets, i.e. two hours of packets sent once a second.

This is fantastic. I think the secret – apart from the 3 µA powerdown mode – is that the RFM12B + RF12 driver require very little time to start up, send off a packet, and go back to sleep again. There is no ACK involved, the RFM12B is hardly ever in reception mode.

With real-world use, I expect power requirements to be considerably higher. First of all, a Room Board will draw around 50 µA, due to the on-board PIR sensor. And second, I’m going to want to use ACKs for at least the motion detector reports, so that the system has a robust mechanism for reporting motion whenever it is detected. This means putting the RFM12B in receive mode for a few milliseconds, waiting for the ACK. And repeating this process a few times if that ACK isn’t immediately received.

But still … over 7000 packets without a battery!

Update – with one packet per 5 seconds, the charge lasted 4523 packets, i.e. just over 6:15.

Update #2 – with one packet per 60 seconds, 771 packets got sent out, that’s 12:51 hours … looks like the self-discharge of the supercap is eating up the remaining energy.

Sleep!

In AVR, Software on Sep 1, 2010 at 00:01

The “powerdown_demo.pde” sketch in this recent post draws 20 µA, which surprised me a bit…

A while back, I got it down to a fraction of that, by turning off the brown-out detector (BOD) through a fuse bit on the ATmega. That’s a little circuit which prevents the ATmega from coming out of reset and doing anything if the voltage is too low.

As it turns out, you can turn off the BOD in software, but only for sleep mode. The reasoning being that there’s no point in protecting the processor from going berserk while it’s not doing anything in the first place…

Well, my code to turn off the BOD was wrong. You have to do this right before going to sleep. Here’s the updated powerdown_demo.pde sketch:

Screen Shot 2010 08 28 at 12.50.18

(correction – I mixed up my bits: change “PINB |= …” to “PINB = …” or “PORTD ^= …”)

The result?

Dsc 1872

Now we’re cookin’ again!

Fractional bits?

In AVR, Hardware, Software on Aug 28, 2010 at 00:01

To continue this little weblog series on bits, I’m going to go into bit fractions.

Yeah, right… there is no such thing, of course – unless you’re into probabilities or fuzzy logic, perhaps.

What I actually want to do, is describe “analog output” on the ATmega, using the Arduino library’s analogWrite() function. And throw in some bit manipulations along the way, to stay somewhat on topic.

The little secret with analogWrite() is that it doesn’t do what its name suggests. The ATmega has no way of generating an analog signal, i.e. a voltage level between 0 and VCC.

Instead, a pulse is generated, with a varying duty cycle. I.e. the “on” and the “off” times of the pulse will be different, the ratio of these times being proprtional to the 0..255 value passed as argument to analogWrite(). With “0”, the signal will be 100% off, with “255” the signal will be 100% on. With “128” the pulse will be on the same amount of time as off. With “1”, it will be on very briefly, and then off most of the time, and so on…

The neat thing is that you connect it to an incandescent lamp, or a motor, then the effect will be that these will light/turn at less than their full power, due to the time it takes for these devices to try and follow the pulse. So the effect is similar to a fractional adjustment: you can dim / slow down these devices by using analogWrite().

It even works with LEDs, although these turn on and off very fast. In this case, the reason is that our eyes can’t follow such fast changes, and so we perceive the result as dimmed as well. A whole industry was once created around this “persistence of vision” property of our eyes – it’s called TV…

Here’s a sketch which uses this pulsed output to control the brightness of a LED connected to DIO3 (i.e. D6):

Screen Shot 2010 08 27 at 16.44.38

Note that I didn’t have to define pin 6 as an output, analogWrite() does that.

What the above does, is ramp up gradually from 0 to 255, and then repeat:

Screen Shot 2010 08 27 at 16.49.06

Suppose we want it to fade in and out instead:

Screen Shot 2010 08 27 at 16.49.17

Try implementing this yourself.

Note that you’re going to need at least 9 bits of information to do this: 8 for the brightness level and 1 to keep track of whether you’re currently in the up ramp or in the down ramp:

Here’s one way to do it, using some bit trickery:

Screen Shot 2010 08 27 at 17.05.15

A few notes:

  • I’ve changed the “level” variable from an 8-bit byte to a 16-bit word
  • bit 8 toggles from 0 to 1 and back every 256 level counts
  • it’ll be 1 when level is 256..511, 768..1023, etc
  • when it’s 1, we flip the bits, i.e. 0 becomes 255, 1 becomes 254, etc
  • the analogWrite() function ignores all upper bits

If you think that was an obscure call to analogWrite(), try this one:

    analogWrite(6, level ^ -((level >> 8) & 1));

Maybe you can decypher it when written slightly differently?

    analogWrite(6, level ^ -bitRead(level, 8));

(hint: bitRead() always returns either 0 or 1)

It’s all pretty geeky stuff, and let’s hope you’ll never have to deal with code such as this again, but the point of this story is that there’s no magic. You just have to know what each operator does, and how to translate an integer from decimal to binary notation and back.

I’ll summarize my intuitive interpretation of bit operators below:

  • X | Y” = take X and copy all the 1’s of Y into it
  • X & Y” = take X and copy all the 0’s of Y into it
  • X ^ Y” = take X and flip all the bits where Y has 1’s
  • ~ X” = flip all the bits of X
  • – X” = arithmetic minus (same as “(~X) + 1” !)
  • ! X” = 1 if X is zero, 0 otherwise
  • X << N” = multiply X by 2, N times
  • X >> N” = divide X by 2, N times

Some tricks based on this:

  • ~ 0” = all bits set to 1 (same as “-1” !)
  • ~ 0 << N” = all bits 1, but N lowest bits set to 0
  • bit(N) – 1” = a constant with N lowest bits set to 1
  • X & (bit(N) – 1)” = the N lowest bits of X, the rest is 0
  • X & ~ (bit(N) – 1)” = X, but with the N lowest bits set to 0
  • !! X” = 0 if X is zero, 1 otherwise

An useful rule when writing logical expressions is: when in doubt, parenthesize! – see C operator precedence.

Sooo… use bit(), bitRead(), bitWrite(), bitSet(), and bitClear() wherever you can, since it usually makes the code easier to read. But there’s no need to get lost if you see ^&|~!’s in your expression – just slow down and decode such expressions step by step!

Flippin’ bits

In AVR, Hardware, Software on Aug 27, 2010 at 00:01

After yesterday’s post about setting and clearing bits, let’s explore reversing bits, i.e. changing them from 0 to 1 and back. And let’s do it by blinking an LED attached to DIO of port 1 – i.e. Arduino digital pin 4:

Screen Shot 2010 08 26 at 10.31.26

The “if (onOff = 0)” etc is the logic that toggles onOff between 0 and 1 on each pass through the loop:

    if (onOff == 0) onOff = 1; else onOff = 0;

But there are lots of ways to do the same thing, coded differently:

    if (onOff == 0) onOff = 1; else onOff = 0;
    if (onOff == 0) onOff = bit(0); else onOff = 0;
    if (onOff == 0) bitSet(onOff, 0); else bitClear(onOff, 0);
    onOff = onOff ? 0 : 1;
    onOff = (~ onOff) & 1;
    onOff = (onOff + 1) & 1;
    onOff = ! onOff;
    onOff = 1 - onOff;
    onOff = onOff ^ 1;
    onOff ^= 1;

See if you can figure out all of these.

Take your pick. Those last two use C’s XOR operator. I tend to prefer shorter source code, so I’d use that last notation (note that the resulting compiled code is not necessarily shorter than the other examples).

Now suppose you have a byte value “X” and you want to flip the 4th bit in it, while not changing anything else. That’s a bit more work. It could be done like this, for example:

    if (bitRead(X, 4) == 0) bitSet(X, 4); else bitClear(X, 4);

Or like either of these:

    X = X ^ bit(4);
    X ^= bit(4);

This shows clearly that the “^” XOR operator does exactly what we need: flip bits.

Back to blinking an actual LED, as done with the above sketch. Here’s a little mind bender – another sketch, doing the same using raw ports and the XOR operator:

Screen Shot 2010 08 26 at 10.58.10

The first example was doing things “the Arduino way”, using pinMode() and digitalWrite(). It compiles to 890 bytes of code. This second example goes straight to the hardware and uses 554 bytes of code:

  • Arduino digital pin 4 is bit 4 on the “D port” of an ATmega
  • “DDRD” is the “Data Direction Register”, where we set up pin 4 as an output
  • “PORTD” is the out “Port Register”, which controls the actual output signal

You can see the XOR in action in that last example. It takes all the output bits of port D (Arduino pins 0 .. 7), and flips just a single bit, i.e. bit 4.

Just for kicks, I’ll show you one more way to blink the LED:

Screen Shot 2010 08 26 at 11.03.44

This uses a relatively little-known feature of the hardware, which actually has “bit flipping” built-in. The “PIND” register is normally used for input, i.e. for reading the state of a pin as an input signal. But you can also write to that register. When you do, it will be used to flip output pins, but only for the bits which were set to 1. It’s essentially a built-in XOR.

That last example uses 550 bytes of code, most of which is overhead from the Arduino run-time library (setting up the milliseconds timer, etc). So what’s in a measly 4 bytes, right? Wrong. There is a minute, but sometimes important difference: the other approaches all had to read the register value first, flip the bit, and then write the value back. This last version only writes a (constant) value to a register. With interrupts, that can be very important: this last version can’t ever go wrong, it will always flip the requested bit. The other version could have an interrupt occur between the read and the write. It’s a known issue for the Arduino Mega. It can lead to code which runs for a week, and then fails mysteriously. Bugs like these are fiendishly hard to properly diagnose.

Bit-flipping can be quite useful for physical computing. Not only does it let you easily toggle specific bits, and change the state of some output pins, it can also be a way to clear a bit. Let’s say you need to generate a (very) quick pulse. Here are four ways to accomplish the same thing:

    bitSet(PORTD, 4); bitClear(PORTD, 4);
    PORTD |= bit(4); PORTD ^= bit(4);
    PORTD |= bit(4); PIND = bit(4);
    PIND = bit(4); PIND = bit(4);

That second one based on XOR works, because bit 4 is known to be one, so setting it to zero is always the same as flipping it. That’s also why the third PORTD/PIND example works, with PIND doing the XOR in hardware. Lastly, the fourth approach will only work if bit 4 was initially zero. It’s the fastest one, and does not suffer from the interrupt race condition mentioned above.

Ok, that’s enough flippin’ for one day!

Tomorrow, I’m going to go into, ehm… “fractional bits” (haha!) ;)

Update – see comment below on why “bitSet(PORTD, 4); bitClear(PORTD, 4);” are also interrupt-safe (mostly – but not on every pin of an Arduino Mega!).

Bit manipulation

In AVR, Software on Aug 26, 2010 at 00:01

Today I’d like to go into bit manipulation, ehm, a bit

You need bit manipulation when you’re dealing with the individual bits in a byte, such as on the I/O ports of an ATmega, for example.

First the easy approach – use these predefined macros from the Arduino library:

  • bit(N) returns an integer with the N’th bit set to 1
  • bitRead(X,N) – returns the N-th bit of X as 0 or 1
  • bitWrite(X,N,B) – sets Nth bit of X to B (0 or 1)
  • bitSet(X,N) – sets the Nth bit of X to 1
  • bitClear(X,N) – sets the Nth bit of X to 0

This is why you might see code such as the following:

    bitSet(WDTCSR, WDIE);

This means: “set the Watchdog Interrupt Enable to 1 in the Watchdog Timer Control Register”. The WDTCSR and WDIE terms are predefined constants. WDIE is 6, for example.

Note that some of these routines can be written in terms of the others, i.e.

  • bitSet(X,N) is the same as bitWrite(X,N,1)
  • bitClear(X,N) is the same as bitWrite(X,N,0)

But what does it all mean?

Well, let’s dive in. First make sure that you are comfortable with “bit shifting”. The expression “bit(3)” is the same as “1 << 3”, which in turn is the same as doubling the value 1 three times, i.e. the value eight. So “bit(0)” is 1 doubled zero times (i.e. 1) and “bit(7)” is 1 doubled 7 times, i.e. 128. Bytes have 8 bits numbered 0 to 7, so all you need for (byte-sized) hardware registers is to remember that bits 0..7 map to (specific!) integers with values 1 to 128.

Setting a bit, is like OR-ing the bit with the rest of the value. The following statements are all identical:

    WDTCSR = WDTCSR | bit(WDIE);
    WDTCSR = WDTCSR | (1 << WDIE);
    WDTCSR = WDTCSR | (1 << 6);
    WDTCSR = WDTCSR | 0b1000000;
    WDTCSR = WDTCSR | 0x40;
    WDTCSR = WDTCSR | 64;

This, in turn, can be abbreviated in C as:

    WDTCSR |= bit(WDIE);
    WDTCSR |= (1 << WDIE);
    WDTCSR |= (1 << 6);
    etc...

Or you could write:

    bitSet(WDTCSR, WDIE);

It’s all the same. So OR-ing is about setting bits (to 1).

Likewise, AND-ing is about not clearing bits (to 0). Whoa, that’s confusing. This expression returns a value which is what X was, but only for bit N:

    X & bit(N);

So this will change X to a value with all bits except bit N set to zero:

    X = X & bit(N);

To put it differently: X will lose its original bits, except bit N, which will be left alone. All the bits are set to zero, except bit N.

Usually, you want the opposite, setting only bit N to zero. That too is accomplished with AND-ing, but you have to flip all the 0’s to 1 and all the 1’s to 0 first. Hang in there, it’s a slightly longer story. This sets bit N to zero:

    X = X & ~ bit(N);

Let’s examine what’s going on here. First, “bit(N)” is a value with only the Nth bit set. Now, “~ bit(N)” is a value with all the bits flipped around (“~” is called the complement operator in C), so that’s a value with all but the Nth bit set. Everything is 1, but bit N is 0.

Now we can tackle the expression “X & ~ bit(N)”. Since AND-ing is about “not clearing bits”, that means that the result of this expression is all the bits of X unchanged where “~ bit(N)” was one, which is almost everywhere. The only bit that differs is bit N – it is zero in “~ bit(N)”, therefore that particular bit will “not not clear …” (a double negation!): it will be cleared (to 0) in the result.

Finally, we replace X by that result. So X will change in precisely one bit: bit N. That bit will be cleared to zero, the rest is not affected. In short: we’ve cleared bit N.

Confused?

Well, that’s why the bit/bitSet/etc macro definitions were introduced. These expressions are all identical:

    X = X & ~ bit(N);
    X = X & ~ (1 << N);
    if (X & bit(N)) X = X - bit(N);
    bitClear(X, N);

That last one is clearest by far, because it conveys the actual operation with a well-chosen name: clear bit N, leave the rest alone.

So why would anyone ever choose to use anything but the bit/bitRead/etc routines?

Many reasons. Habit, perhaps. Coming from another environment which doesn’t have these macros. Being so used to this bit-manipulation that the use of words doesn’t really look any clearer. Whatever…

But another more important reason is that you can’t do everything with these bit/bitSet/bitClear routines. Sometimes you just have to go to the raw code. Such as when you need to set multiple bits at once, or flip bits. That’s why the ATmega datasheet has examples like these:

    WDTCSR |= (1<<WDCE) | (1<<WDE);

By now, you should be able to decode such a statement. It’s the same as:

    WDTCSR |= bit(WDCE) | bit(WDE);

In other words:

    WDTCSR = WDTCSR | bit(WDCE) | bit(WDE);

Which in turn is almost the same as these two statements together:

    WDTCSR |= bit(WDCE);
    WDTCSR |= bit(WDE);

That in turn, can be written as these two lines:

    bitSet(WDTCSR, WDCE);
    bitSet(WDTCSR, WDE);

Much clearer, right? Except… it’s not 100% identical!

The problem is a hardware issue: timing. The above two statements will set both bits, but not at the same time! For hardware register settings, that difference can be important. There is a fraction of a microsecond between the WDCE bit being set and the WDE bit being set. Unfortunately, in some cases that causes real problems – your code won’t work as expected.

Tomorrow, I’ll continue on this topic, but it’ll be a bit more fun, because there will be LEDs involved!

Dsc 1385 2

(Please ignore the cable on the left, I snatched the above picture from this post)

Update – see this excellent Wikipedia article for more details about bitwise operations.

Simplified button interface

In AVR, Software on Aug 24, 2010 at 00:01

The Blink Plug has two pushbuttons and two LEDs. The buttons are simple miniature switches, but nothing is ever simple in microcontroller-land: reading out the state of a pushbutton reliably can be deceptively hard, due to mechanical bounce issues.

The Ports library has had a BlinkPlug class for some time now, including a “pushed()” function to do all the debouncing. Unfortunately, that function turned out to be a bit harder to use than I originally intended.

Time to add some more code to the BlinkPlug class!

I’ve added a new “buttonCheck()” member, which returns events instead of state. That makes it a lot easier to detect when people press a button, which is usually all you’re after anyway.

Here’s a new button_demo.pde example sketch, which illustrates the new functionality:

Screen Shot 2010 08 23 at 17.44.21

Sample output:

Screen Shot 2010 08 23 at 17.44.39

As you can see, it’s now a lot simpler to detect when people press or release one of the two buttons on a Blink Plug. Each time you call buttonCheck(), you’ll get one of the following events:

ALL_OFF, ON1, OFF1, ON2, OFF2, SOME_ON.

You have to keep calling “buttonCheck()” reasonably often, at least 10 times per second, if you don’t want to miss any events. Calling it all the time in the main loop is fine. Keep in mind that ON1, etc. will be returned only once for each actual button press.

You can still call “state()” whenever you want, to check the position of either button. But when you use buttonCheck(), you should not call the old – now deprecated – “pushed()” function, as these two will interfere with each other.

This code is now part of the Ports library (subversion and ZIP). Gory details are in Ports.cpp, near line 230.

Assembling the JeeSMD, part 2

In AVR, Hardware on Jul 9, 2010 at 00:01

Yesterday’s post was about assembling all the SMD components of the JeeSMD kit.

The last step is to program a sketch into the ATmega. This isn’t as straightforwards as with a JeeNode, because there’s no on-board FTDI or USB serial port hookup.

It’s fairly easy to create an FTDI connection, but even if you do, you’ll still need an ISP programmer to install a boot loader (see this recent post for some background).

So let’s hook up an ISP programmer first:

Dsc 1787

I’m using a somewhat weird setup: first of all, my cable connector was attached the wrong way around, so I always have to use this one in that weird folded-over position.

But a more important issue is that the ISP connection needs to use pins 1..6 of the 2×4-pin SPI/ISP connector on the JeeSMD. That doesn’t work with normal flat cable connectors, which assume 2×3 pins and are too wide to fit in a 2×4-pin header. My solution is to insert wire-wrap pins the wrong way around into the cable header. This effectively extends the connector, but now it won’t be as wide and it’ll fit just fine. Another solution would be to only solder 2×3 pins in the SPI/ISP position – you can always add two more pins later.

Once you’ve passed that hurdle, you can use any ISP programmer you like. There have been several posts about this on the weblog, as listed here.

Now, if you want to use FTDI, then presumably you just uploaded a bootloader into the ATmega, with all the proper fuse settings, etc. The next step then, is to somehow connect to a 6-pin FDTI header.

There are several ways to do this. The one I use nowadays, is through a Carrier Board, which includes the 6-pin FTDI connector:

Dsc 1786

The point about the FTDI connector, is that it’s almost trivial. All you need is 4 wires to GND, PWR, TX, and RX – plus a way to reset the board from the RTS signal. The clever way to generate a reset is to insert a 0.1 µF capacitor between the serial side RTS and the ATmega’s reset pin. Tiny trick, huge implications (does the name “Arduino” ring a bell?).

So how does the Carrier Board implement FTDI? Easy: it adds the capacitor. And you can easily do that yourself without a Carrier Board. Here’s how:

Screen Shot 2010 07 08 at 23.20.52

Note that what FTDI calls “RX” is connected to what the ATmega calls “TXD”, and vice versa. It’s all a matter of perspective… Once you have the FTDI connection set up, you can upload sketches using the Arduino IDE just as with any other board. All you need is a USB-BUB or some other equivalent USB-to-FTDI interface.

Congratulations: that’s all it takes to build and use the Arduino-compatible JeeSMD!

Assembling the JeeSMD

In AVR, Hardware on Jul 8, 2010 at 00:01

The JeeSMD is a kit with tiny “Surface Mounted Device” (SMD) components. SMD was designed for automated assembly with Pick & Place machines, but with a bit of patience it’s fairly easy to assemble a board by hand – see this post for an overview of what you will need.

You won’t be able to do this without at least a fine-tipped (0.4..0.6mm) soldering iron plus the following tools:

Dsc 1773

A magnifier lamp also helps, I know I couldn’t do this without one anymore!

This is a step-by-step guide on how to assemble the SMD kit, which consists of these parts:

Dsc 1772

The tiny ones (don’t sneeze!) are hardest to tell apart:

Jee smd Closeup

(thanks to Steve E for the macro shot – I just added some labels)

There are 2 10 kΩ resistors in there, although you only need one. That lets you get started without having to worry too much – if you mess up completely, just remove it and start over with the other one.

For a fantastic resource with detailed videos about hand-soldering SMD, see this Curious Inventor page.

So let’s get started. First thing to do is to apply flux wherever you’re going to solder things. The flux is essential because the flux in your solder wire will have evaporated longe before you can move your tip from the wire to the part.

I’m right-handed, so that’s how I hold my soldering iron. That leaves only my left hand for the tweezers – and no hand at all for the soldering wire:

Dsc 1774

Use your tweezers for all these parts, and don’t let go – once a 0603 part flies off or drops on the floor, your chances of finding it again are next to zero. Best is to work on a clean flat surface with everything around you removed.

The trick is to place the part and then push it down while you touch it with your iron with solder already on it. The moment a part is soldered down on at least one pin, it becomes a lot easier:

Dsc 1775

The matte “stain” you see around these pads is the flux, which has dried up but is still active.

(Remainder continued after the break…)

Read the rest of this entry »

Uploading? ISP? FTDI? Huh?

In AVR, Hardware, Software on Jul 4, 2010 at 00:01

There seems to be a fair bit of confusion in- and outside the Arduino world, and it’s spilling over to JeeNodes …

I’d like to go through some terms and buzzwords to try and clarify how to get your Arduino or JeeNode to do the thing you want it to do. I’m going to assume that you are familiar with the process of writing software (“code”), compiling it, and running it – at least on a Windows, Mac, or Linux computer (let’s call them all PC’s for now). With software for the ATmega, there are two approaches, depending on whether you use the Arduino IDE or not:

Screen Shot 2010 06 28 at 23.50.22

Both lead to the same result: a “hex” file with code that needs to be transferred from the PC to the ATmega.

The step which can be puzzling when starting out with physical computing and embedded hardware is how to get things across from your PC to that little Arduino or Arduino-like system you’re holding in your hand. And vice versa, since we often want to get results back or see some confirmation that things are working properly.

The confusion comes from the different conceptual levels involved, and things like:

  • do you mean how to connnect? – plug in a USB cable
  • do you mean how does the ATmega change its own code? – through a boot loader
  • do you mean via ISP (In System Programming)? – no, that’s normally not needed
  • do you mean via FTDI? – yes, that’s the name of the chip which is hooked up to USB
  • isn’t FTDI a connector? – yeah, that too, sort of… i.e. a 6-pin convention
  • isn’t a power + serial cable enough? – no, resets also play a key role
  • do I have to use the Arduino IDE? – no, you can also use a program called “avrdude”
  • what’s avrdude? – a program which can upload to a boot loader or an ISP programmer
  • do I need an ISP progranmmer? – nope, the boot loader does essentially the same thing
  • so why not just get rid of ISP? – because you need ISP to install the boot loader

Confused? Welcome to the club…

In case you’re wondering… the process is called “uploading” because the PC initiates this as outbound transfer:

Screen Shot 2010 06 29 at 01.51.50

To get your code (“sketch” in Arduino-speak) into an ATmega, you need three things, working together to make uploading happen under all possible conditions:

  1. An electrical connection – to power the ATmega, to communicate with it, and to restart the ATmega when it is stuck or busy doing something else.

  2. A common language / protocol – the communication must be understood by both sides, i.e. PC and ATmega.

  3. Software on both sides of the connection – Sending something when the other side isn’t listening, or listening while no-one is sending will not have the desired outcome.

Let’s go through each of these separately.

1. An electrical connection

There are several ways to make the connection. With an Arduino, or any similar board which has a USB connector, you can simply plug in the USB cable:

Screen Shot 2010 06 28 at 23.52.41

Some boards use a separate USB interface (“FTDI adapter”), allowing reuse of that interface for multiple boards:

Screen Shot 2010 06 28 at 23.54.08

The end effect is the same: a connection which powers the ATmega and allows communicating with it using a simple serial protocol. There’s also a trick in this hookup to let the PC reset the ATmega whenever it wants.

2. A common language / protocol

Ah, now it gets interesting. First thing to note is that there is no single common language / protocol!

That’s right. It all depends on what you want to do. Here we want to upload code from the PC to the ATmega. That requires exchanging “ISP commands” over the connection. But once uploading is done, we really want to reuse the connection as a regular two-way serial link.

The way it works is that the PC will reset the ATmega just before uploading new code. This activates a “boot loader” on the ATmega. Now both sides will be in sync (briefly) so they can exchange the necessary information to make an upload happen. IOW, right after reset the protocol is “ISP commands”. Once the upload is done, the connection can be reused for any protocol you like – as determined by the code that was uploaded.

3. Software on both sides of the connection

Back to the software now. We need to send ISP commands over the connection.

As you may have guessed, that’s exactly what the Arduino boot loader on the ATmega understands. When reset, the boot loader in the ATmega gets control. It waits and listens for incoming STK500 ISP commands. If none come in within a second or so, it relinquishes control to whatever was previously uploaded to the ATmega.

On the PC side, we need software which resets the ATmega and then immediately sends all the ISP commands needed to transfer and program the contents of a hex file.

This is what “avrdude” does. You can either use it implicitly from the Arduino IDE by starting an “Upload” from the menu, or you can launch it manually from the command line – avrdude needs a few options to tell it where the USB port is, what baudrate to use, the type of ATmega, the protocol to use (i.e. STK500), etc.

There’s more…

The above describes the different pieces and concepts involved in getting code into an ATmega. The beauty of it is that once it works, it really works well. Supplying power, uploading, communication, control, debugging … all with one simple USB cable. You only need to go back a few years to appreciate just how much this approach simplifies embedded development.

But there’s one important detail: the ATmega has to have a functioning boot loader. Placing a boot loader into an ATmega is a bit more complicated (and involves other things such as “fuses”). It’s a chicken-and-egg problem.

This is where the ISP programmer comes in. An ISP programmer is a fairly simple piece of hardware. In fact, you can make your own, as I’ve described in several posts on this weblog. See this and this post for some quick solutions which require nothing more than a working Arduino or JeeNode.

The good news, is that you usually don’t have to worry about installing the boot loader – it’s all done for you. Once. For the mechanism described above, you’ll never need an ISP programmer.

Some people actually prefer to use the ISP technique for uploading their sketches. In fact, sometimes you have no choice, i.e. when you need the serial port at all times, or when you can’t spare the 1..4 Kb required by the boot loader code, or when working with ATtiny chips which don’t support bootloaders.

In thoses cases, you’ll need a setup with an ISP programmer. But for most people doodling around with ATmega’s and the Arduino IDE, the above boot loader mechanism is usually very convenient and the easiest to get going.

Either way, it helps to understand the process. I hope the above was helpful in that direction.

Fixing a faulty ATmega (Arduino)

In AVR, Hardware, Software on Jul 2, 2010 at 00:01

After a recent post on how to repair an ATmega with a faulty (or even missing) bootloader and helping someone out with it, it occurred to me that this mechanism will work for any Arduino – not just JeeNodes.

Any 3.3V or 5V Arduino’ish system which lets you upload the isp_repair.pde sketch can be used to program any board with an ISP connector on it. The code is for ATmega328’s, because that’s all I use around here these days.

The trick is to hook up a few power and I/O lines in a specific way:

Screen Shot 2010 06 28 at 16.59.11

I’m using an Arduino Pro as example, but that’s just one of many you could use. Now connect these six wires:

  • ISP pin 1 = BLUE = Digital pin 4
  • ISP pin 2 = RED = VCC (+5V)
  • ISP pin 3 = GREEN = Analog pin 0
  • ISP pin 4 = PURPLE = Analog pin 3
  • ISP pin 5 = ORANGE = Digital pin 7
  • ISP pin 6 = BLACK = GND

Note: if your working board operates at 3.3V, then you should connect the RED wire to +3.3V, not +5V (that way signal levels and power supply will match). Also: the target board should not be connected to anything, since it will be powered through the ISP connector.

The only thing left to do is to upload the isp_repair.pde sketch to your working board, and open up a console window. You should see something like this:

That’s it – disconnect all the wires. The ATmega on the target board now has a boot loader and the standard pin 13 blink sketch. Ready again to accept whatever sketch you upload to it!

Uploading without avrdude

In AVR, Software on Jul 1, 2010 at 00:01

In the future, I’d like to upload new firmware to JeeNodes, Arduino’s, and other AVR boards through channels other than a serial port or USB. Uploading to a “slave plug” via I2C would be neat, for example.

That means the standard avrdude won’t do. Besides, after having coded various types of ISP sketches recently, I realized that the upload mechanism is really quite simple. If all you need is STK500 compatibility (as used by several ISP programmers and by the Arduino boot loader itself), then avrdude is overkill.

So here’s a demo “rig” for JeeMon which does the same thing as avrdude, i.e. upload a sketch over a serial port:

Screen Shot 2010 06 27 at 23.19.45

That removes the need to compile and install avrdude. Better still, this should work as is on every platform supported by JeeMon.

(Note: the above code is now part of JeeMon, but the source code can also be found here on the web)

Onwards!

Update – the above code has been integrated into JeeMon as new Upload rig – with dudeLoader renamed to “stk500” and readIntelHex now called “readHexFile”. Here’s a new demo “application.tcl” using this:

Screen Shot 2010 06 28 at 01.46.48

Now works with the Arduino boot loader as well as with the Flash Board ISP programmer (add “19200” arg).

(Reminder: the Jee Labs shop will be closed from July 14th through August 14th)

TwitLEDs finale

In AVR, Hardware, Software on Jun 29, 2010 at 00:01

The TwitLEDs project by Myra and Jean-Claude Wippler (daughter and father) has come to a conclusion. It was great. I’ll just summarize by pointing to the six posts on the Jee Labs weblog describing the technical details, and some pictures and videos, showing the results.

Here you can see the finished TwitLEDs robot:

Dsc 1741

This is the, ehm… print head?

Dsc 1749

And last but not least, some videos. First a trial run for the print mechanism:

Next, a trial run for the vehicle, trying to stay out of trouble:

And here the result!

And one more:

Ok, that’s it. Myra and I both had oodles of fun building this and trying things out – hope you did too :)

Onwards!

(If you can’t view the videos on vimeo, see 1, 2, 3, and 4)

TwitLEDs robot – action shots

In AVR, Hardware, Software on Jun 25, 2010 at 00:01

As promised in the previous post, some pictures and movies of the TwitLEDs robot in action.

First another view of the robot, with the different pieces:

Dsc 1747

We don’t have the proper “arena” yet, i.e. a big fenced-off floor area covered with glow-in-the-dark paint. Instead, these first trials used two pieces of foam board, taped together. It’s not perfect because the robot keeps running off track, and because the hump between the two pieces is quite high. Foam board isn’t really suited for this: it curls up too much from the moisture in the paint. We probably should have waited a bit longer for everything to dry completely…

The inital test code just printed out its name (povGlow) and the compilation date. In the first tests, one of the LEDs wasn’t working (a software bug, not hardware), so the text isn’t quite right:

Dsc 2039

You can clearly see the fading of the letters over time. This happens very quickly, but those faded letters then remain visible for quite a while. That’s why you can still see several trial runs “printed out” on the foam board.

So the basic idea of printing with light works, as you can see!

Here is a video (sorry, not inline), showing how the robot veers to the right as I put my hand in front of it to prevent it from running off the track. Note that I’m not touching the robot, I just briefly trigger the distance sensor. The on-board LED lights up in red when the correction takes place. It’s not very smooth, but it works.

Another picture, showing the decay of the printed text brightness:

Dsc 2067

Maybe 7 pulsed blue lasers (from DVD writers, perhaps?) could be used to create even more intense blue dots. As it is, with these blue LEDs the writing is very clear – but only in a relatively dark room. With the lights on, the text becomes virtually invisible. Even though the LEDs are bright enough to be painful to look at:

Dsc 1749

The quality of this “printer” is actually pretty good, considering how simple its technology is:

Dsc 2056

Finally, a run where the robot happened to stay a bit longer on track, allowing it to display its brief message a few times. Again as video – you can see the wobbling foam board, and this thing driving like a drunken duck, leaving its trail of fading messages behind.

All that remains, is to try and get some tweets into it in real time. Stay tuned…

Several days of testing have now drained the 4 alkaline AA to the point where the robot advances noticeably slower. Looks like we’re getting no more than an hour or two out of these batteries. Which is not really surprising: the DC motors must be eating quite a bit of current, and the LEDs probably draw up to 200 milliamps or so. Self-powered autonomous motion is really hard!

TwitLEDs robot, part 3

In AVR, Hardware, Software on Jun 24, 2010 at 00:01

To continue on yesterday’s post, here is how we got a little autonomous robot going.

The main part was solved by picking the Asuro robot kit. It’s really low-end, but it has just enough functionality for this project, and at €50, it’s very affordable. In fact, Myra built a spare one because the first unit broke down. In the end, I was still able to fix it: a burnt out transistor (both H-bridges are done with discrete components!). So now we have two Asuro’s:

Dsc 1750

The nice bit about the Asuro is that it has an odometer on each wheel. IOW, there are IR LEDs + sensors to count the number of steps (8 per rev) made by the wheel, and the C library code includes logic to adjust the speed of the motor. It’s a bit crude, but because of this the Asuro can drive fairly straight. As we found out later, it has a bit more trouble doing so while driving slowly, so it’s still a bit wiggly.

But it works. Two small DC motors, some simple gears, motor axles soldered to the PCB (what a great low-cost solution), and room for an extension board. To give you an idea of how crude this thing really is: there is no on-board voltage regulator. When used with 4 alkaline AA batteries, you have to remove a jumper so the extra voltage drop over a diode gets the supply voltage down to under 5.5V …

The Asuro is full of such nifty cost-cutting tricks. It even includes a bidirectional IR link, over which new code can be uploaded. The IR link is very short-range, so it would have been insufficient for our purposes – but for quick code tweaks, the IR link works fine.

Speaking of code, here is the main avoider.c logic running on the ATmega8:

Screen Shot 2010 06 18 at 23.57.08

This is not an Arduino sketch, but I made it look a bit like one by using the same setup() and loop() functions.

This code has to be compiled with avr-gcc. The Asuro comes with several examples with Makefiles. I simply copied one and started extending it. A little optional USB-IR adapter is used to connect to the Asuro (an RS232 one is included with the Asuro kit, but I don’t have any RS232 ports). The whole setup works pretty well from the command line, especially considering that it’s a completely different setup than the Arduino IDE.

Anyway, back to the design of the TwitLEDs robot.

The challenge was to find a simple way to make this robot drive around without bumping into things. The Asuro has a row of switches at the front, but these are not very reliable, and besides: bumping and stopping and turning would mess up the LED strip being “printed” on the glow-in-the-dark paint.

So instead, we mounted a Sharp 10..80 cm distance sensor on top. It’s very easy to read out, since it produces an analog voltage, inversely related to the distance of objects in front of it.

The logic for collision avoidance is crude, but sufficiently effective: turn more and more right as you get nearer to an obstacle. The on-board LED turns from off to green to yellow to red as the distance decreases, so it’s easy to see what the robot is doing. I’ve tweaked it so that when it drives straight towards an obstacle, then turning will be quick enough to never bump into that obstacle.

Here’s the completed unit, with the Sharp proximity sensor on a little expansion board at the front, and the LED blinker glued to the side of the battery pack – the LEDs hover 1 .. 2 mm above the ground:

Dsc 1741

Myra’s idea was to have this thing drive inside a more or less circular “fence” made of corrugated cardboard. The whole area inside the fence will be made of some panels, covered with 3 layers of glow-in-the-dark paint.

There is a flaw in the current design, in that the robot can only evade an obstacle by turning to the right. If it approaches a wall obliquely from the right, it will do the wrong thing and drive straight into the wall. But we’re hoping that as long as it doesn’t over-correct, and by sending it off in a tangent, it will keep adjusting slightly to the right as it drives around and around in “sort of” circles.

More tests and tweaks will no doubt be needed.

But as it is, this thing really seems to stay out of trouble. We can let it loose in the room and it’ll veer to the right whenever it comes near an obstacle. Sometimes it veers to far, though. Again, I hope a more controlled “arena” will be sufficiently simple to keep it going.

When the robot does bump into its front switches, it turns both motors off, blinks for 10 seconds, and then starts off again. Time enough to pick it up and aim it in a different direction.

So that’s it. An autonomous unit with two independent computers, IR distance sensing, a short range IR link, and the JeeNode with a longer-range wireless RF link. Even including a JeeLink on the laptop side, the cost of all this was only slightly over €100.

Tomorrow, some pictures + movies. Gives me time to finish the Twitter link, and then on to the grand finale!

(Reminder: one week left for the June special in the Jee Labs shop!)

TwitLEDs robot, part 2

In AVR, Hardware, Software on Jun 23, 2010 at 00:01

Yesterday’s post introduced the robot Myra and I have been working on. Here’s the first part we built:

Dsc 1725

It’s basically a backplane for the LED blinker component. Or to put it differently: a simple persistence-of-vision (POV) unit, using a JeeNode, and Output Plug to drive a few LEDs. Only the output plug was soldered-in permanently. The removable JeeNode allows it to be easily programmed and re-used, and the removable LEDs allow trying out different units. This turned out to be important, because I only had a few green LEDs when starting this, and had no idea then as to what sort of LEDs would give the best POV results later on.

Myra did all the soldering. Here are the two LED mounts we ended up with:

Dsc 1745

The one on the left is the super-duper LED concoction we built as final version. The one on the right was great for initial testing.

Everything is held together with rubber bands, zip-lock ties, tape, and ample amounts of hot glue (once verified to work!) – hacking at its best, clearly:

Dsc 1742

Here’s the LED blinker with the final LED strip, side view:

Dsc 1743

Side view close-up – with the foam board cover:

Dsc 1746

Bottom view:

Dsc 1744

Seven blue LEDs, ready to shine very brightly and controlled by the JeeNode.

The software started out very simple, of course. Things like this, just to make sure it all works:

Screen Shot 2010 06 18 at 23.01.21

This is the main part of what is more or less the final twitLEDs.pde sketch:

Screen Shot 2010 06 18 at 23.03.06

I found a suitable font table by googling around a bit. This is needed to go from ASCII characters to dots-in-a-readable-pattern. No room for Unicode (don’t laugh: some tweets are in Japanese and Chinese, and they won’t show properly).

The amazing bit is that everything worked essentially on first go. It blinked! But does it blink in the proper pattern? Our first test consisted of Myra taking a long-exposure shot, as I waved this thing around in the air – with the lights off. Liesbeth tracked progress through all the shrieks and laughs… but from a safe distance :)

Dsc 1793

Yippie. It really works!

Tomorrow: driving around without bumping into things.

Something different…

In AVR, Hardware, Software on Jun 22, 2010 at 00:01

Ok, so I’ve got tons of projects on my plate to do and to finish. And tons more that are still very experimental, or haven’t even been started. Plenty to keep me busy, with the summer vacation period nearing fast.

Yet here’s something different. The timeline for this project was imposed by external factors: my daughter Myra doing a project for the last quarter of her second year at the Design Academy in Eindhoven.

She wanted to do something which triggers human interaction, and she wanted to try something with Physical Computing. “Terrific, I’ll help!” – I shouted, completely ignoring all the pending work on my own plate…

So here’s the start of a few articles about the “TwitLEDs” project we’ve been working on recently. All the basic ingredients work as I write this, but we have yet to finish the final setup and go through a last rehearsal.

What is it?

It’s a mix between a matrix printer and a persistence-of-vision (POV) display.
It’s called the TwitLEDs robot. And it’s hooked up to the internet.

Get it? No? Ok, then let me try again. I think this picture tells it best:

Dsc 2069

The idea is to have a little autonomous robot driving around, leaving messages behind on a floor covered with glow-in-the-dark paint. The messages are collected off Twitter using a configurable search term. This is done from a laptop and then sent to the robot by wireless.

There were several fairly non-trivial problems to solve here, with some experimentation needed to find a workable mix – as well as some time contraints. A few days of work would be the most I could set aside for this. Luckily, I didn’t get lost in too many dead alleys, so it worked out nicely.

Here are the pieces we used:

  • A low-cost robot kit called Asuro – based on an ATmega8, so I had all the software ready for it. In fact, I played around a bit with it a while back – as reported here.
  • A JeeNode for wireless connectivity.
  • An Output Plug to drive some LEDs.
  • Seven blue LEDs. I picked a bright one with a very focused beam (C503B-BAN-CY0C0461).
  • Glow-in-the-dark paint. Green stuff. Three coatings.
  • Some panels to create a floor. Covered with the green stuff.
  • Some cardboard to create an “arena” on the floor to contain the robot.
  • JeeMon running on a MacBook, with a JeeLink to send out the messages.
  • A fairly dark room. This just won’t work with the lights on, unfortunately.

As with every project, the first part is the hardest and the most critical success-factor: figuring out what to do, what not to do, and finding solutions within the many constraints we had to operate under. I’ll spare you the ideas that didn’t make it, and the (really neat) ideas we simply didn’t have time for.

Being the sole programmer on the team, I got to deal with all the software. Yummie! :)

The most important insight for me was that we could implement this project with three completely independent subsystems:

  • The LED blinker, driving 7 LEDs in the proper pattern, basically a POV unit (plus receiver).
  • The robot, moving around while continuously trying to stay out of trouble.
  • The server process running on the laptop, connecting to Twitter and sending messages into the air.

We started off with the LED blinker because it was a major component with few unknowns, i.e. we picked the low-hanging fruit first. Here’s a picture of it, still under construction:

Dsc 1726

More on the LED blinker tomorrow…

Battery savings for the Pressure Plug

In AVR, Hardware, Software on Jun 20, 2010 at 00:01

Reducing power consumption is fairly tricky, as you can see in the many previous posts about this topic. And to be honest, I haven’t quite gotten to the point where I want to be with the Room Board. My first “major” (ahem) setup with about a dozen nodes around the house didn’t quite go as I had hoped. Most batteries were empty within a month. A few nodes are still going, but those are hooked up to power adapters…

I’d like to revisit this issue and try to improve things a bit. To make the rooms sketch perform better, and also to make the code structure a bit clearer. The current rooms code is quite complex and hard to follow.

But before messing with the rooms.pde sketch, let’s tackle something simpler: the wireless sensor node based on the Pressure Plug, as described here, and then simplified here. I’ll use that last version as starting point.

The first point to note is that to get a substantial first power reduction, you have to focus on the portion of the code where it’s spending most of the time. Which, in the case of “bmp085demo”, is here:

Screen Shot 2010 06 17 at 01.55.06

That’s right: it’s waiting for the next second to “happen”. And even with a slow’ish sensor such as the BMP085 at maximum resolution, it’s spending more than 90% of its time there… waiting!

I’ll use an approach which might be a bit surprising: let’s not change any of the current logic. The idea is that once we’ve done our thing for the current second, we can go into low power mode, as long as we make sure to get back to normal operating conditions in time for the next second.

So what we’re going to do is add some code to the end of the loop() function. It’s functionally equivalent to adding it at the start, since loop(), eh, loops – but I think it makes a better point.

The end of loop() used to look as follows:

Screen Shot 2010 06 17 at 02.01.01

I’m changing it to this:

Screen Shot 2010 06 17 at 01.43.00

IOW, at this stage all the hard work has been done. We wait a bit for all interrupt-driven I/O to complete (serial and RF12). And then we need to figure out how much time remains until the next second. The power saving happens by spending that time in power off mode.

But this requires some preparation. When inducing a comatose state like this, you have to make absolutely sure that something is still able to get you out of coma and back up and running again. This is what the ATmega’s “watchdog” is for: we set it up to wake us up in 16 milliseconds, just before entering sleep mode. And then we keep doing that until it’s almost time to take another reading. The actual watchdog interrupt handler does nothing, btw – all we want is to get back out of power down.

Note that the radio also needs to be turned off and back on again. It’s the biggest power consumer when enabled. Turning it off and going into power down mode is what lets us go from a tens-of-milliamps current drain to a tens-of-microamps current drain.

All the logic for this is located in the loseSomeTime() function, which was adapted from a slightly different version in the rooms.pde sketch:

Screen Shot 2010 06 17 at 01.42.33

And that’s about it. The average power consumption of this sensor node will go down by an order of magnitude. It’ll still be 1..2 mA, but it’s a major improvement: this node should now run 2..3 months on AA batteries. The source code for bmp085demo.pde has been updated.

I’d like to stress that such gains require very little effort for many types of sketches. All you have to do is figure out where the sketch is spending most of its time, and deal with just that part of the code. Getting into yet lower power consumption levels would require more work.

IR trigger for Nikon camera

In AVR, Hardware, Software on Jun 12, 2010 at 00:01

Here’s a fun project: sending out infrared remote codes to takes snapshots :)

This is the code:

Screen Shot 2010 06 10 at 17.19.44

This sketch is doing everything in software, and it’s sort of pushing the limits by pulsing a TSKS5400S IR emitter LED at 38.4 KHz using software delay loops.

The timing diagram on this website was a great help to get this working in no time. Here’s another site.

With the 33 Ω resistor in series, total current through the IR LED should be somewhere between 20 and 50 mA. Since the latter is beyond the ATmega’s current sourcing capapbility, I suspect that the pin voltage will actually drop quite a bit below VCC. A transistor or MOSFET could be added for more power. As it is, this seems to trigger reliably up to about a meter away.

Here’s the setup, triggering my trusty D40 Nikon:

Dsc 1692

a self-portrait!

Lot’s of people have already done this ages ago, btw. Here’s a sketch which uses assembler to get the timing more accurate. But the above does work – the main point is to avoid digitalWrite(), which is relatively slow.

A Happy Ending!

In AVR, Hardware, Software on Jun 10, 2010 at 00:01

The multi-ISP programmer I built and started using some two weeks ago, turned out to be quite a nightmare. Not only were incorrectly programmed ATmegas sent out to about two dozen people, I also had to go through about 70 kits, prepared as new stock just days after I started using this programmer. Twice!

Yes, twice. Because the first “fix” turned out to be insufficient. Doh.

This was a clear case of one bug hiding another, and another, and another. Yep, four bugs: a bug in the MemoryStream class in the Ports library, a timing problem exposed by fixing that bug, and two incorrect assumptions about how the “avrdude” utility works. I’ve now got an explanation for everything that went wrong.

There’s no doubt some interesting psychology at work here … I was so proud of my idea op programming multiple ATmega’s! The main idea was to create an AVRISP-compatible unit which stores everything sent through it and then just replays the saved stream as often as needed. Trouble is, I jumped to conclusions the minute a first “run” worked. Roll the presses! Print it! Tell it to the world!

Anyway. There is a happy ending to all this!

The latest version of the isp_capture.pde sketch in the Ports library has been working properly for over a week now, programming well over a hundred ATmega’s (and it now does auto shut-down a few minutes after use):

Isp Capture Output

The last bug was a very puzzling one: everything worked, but sometimes the fuses wouldn’t get programmed. It turns out that avrdude first reads the fuses, and only sends out commands to program them if the fuses don’t match the new value. Since the programmer needs to work with brand-new as well as previously-programmed chips, the replay mechanism would have depended on the prior state of the chips: not good.

The solution is very simple: I now always program each fuse twice, with two different (valid) values. The second one will remain in force, evidently. Since the replay code was already ignoring fuse mismatch checks, this now means that even if the first setting is skipped by avrdude, the second will always be emitted.

Here is the shell script to prepare the Flash Boards:

Screen Shot 2010 05 30 at 01.35.40

So this has now become a very useful tool at Jee Labs:

Dsc 1432

I love the on-board LiPo battery: I can grab it, use it where I need it, and put it back – no wires = freedom!

For pre-loading the fuses, boot loader, and RF12demo, it already saved me a huge amount of time. Its “burn rate” is up to 500 chips/hour. And Mr. Murphy taught me some valuable lessons along the way…

And now it’s time to move on!

Repairing a faulty ATmega

In AVR, Hardware, Software on Jun 9, 2010 at 00:01

This post is being written after a pretty nasty foul-up on my part w.r.t. sending out badly-flashed ATmega chips. It’s probably too late to be of use to anyone involved in that little débâcle, but I thought I’d describe a DIY fix here in full detail anyway. I’ve simplified the code to make it even easier to use than what was described here.

So what is this about, eh?

The ATmega328 chip used in JeeNodes (and Arduino’s, and various other similar board) comes with a serial boot loader pre-loaded into the high end of its flash memory. This is arguably one the most important features that made the Arduino popular: it lets you upload a new “sketch” into the ATmega over the serial or USB port.

Lots of little details, but the point here is that the boot loader itself can’t easily be damaged, even if you load a non-functional sketch into the ATmega. Just resetting it will let the boot loader overwrite the flash memory with a new version – hopefully a better one. Basically, no matter what goes wrong, there’s always the boot loader in the ATmega to upload a new sketch to it.

There’s a chicken-and-egg problem, though: how do you get that boot loader into the ATmega in the first place? Well … you don’t. It’s normally placed there by the supplier of your ATmegas.

Since Jee Labs is one of the suppliers of JeeNodes (for Europe, and Modern Device for the US), I do need to do a little more. I use an “ISP” programmer to place that boot loader there, along with the RF12demo sketch.

But there’s really not much to all this, and this whole boot loader / ISP stuff can easily be performed by anyone. Keep in mind that’s it’s just about getting that first step right: proper fuses and the boot loader stored in flash memory. Nothing more.

All you need is a working unit and a second target unit with the ATmega that needs to be repaired (or initialized for the first time – same thing). For Arduino’s, it’s all explained at http://arduino.cc/en/Tutorial/ArduinoISP.

As it so happens, there’s now even simpler software to do this, so I’m going to describe the process in terms of using one (working) JeeNode to repair another JeeNode (note that this still should work for Arduino’s as well).

The basic idea is still the same: we need to connect 6 wires. There are 2 wires for +3V and GND and 4 wires connected to ports 1 and 4. On the target JeeNode, the wires will be connected to the ISP connector:

Screen Shot 2010 05 29 at 01.37.23

The target JeeNode will receive its power from the working JeeNode, so don’t plug it into anything. Note that this can also be done with JeeNode USBs. All we need, is to make a few connections for power and I/O.

The working JeeNode should be plugged into a USB-BUB, or something similar. Do that now, because the following wiring step can be a bit sensitive to movement.

The following six connections need to be made:

Screen Shot 2010 05 29 at 02.57.58

On the working unit, the wires or wire jumpers can be inserted into the 6-pin port headers.

On the target side, you’ll probably just have gold-plated holes for the ISP connector. The nice thing about gold plating is that it easily makes contact. So one way to hook up the wires is to insert all six as shown above, and position the whole thing in such a way that there is a slight tension on the wires – just enough to make contact.

Ok, you should now have the working unit powered up, and the target unit receiving power and signals through these 6 wires. Good, leave them alone now.

To do the actual reflashing, I’ve added an isp_repair.pde sketch to the Ports library, which does everything. Upload that sketch to the working JeeNode, and open up the console. Here’s what you should see:

Screen Shot 2010 05 29 at 02.24.05

That’s it. The target ATmega has been set up with the proper fuse settings and a boot loader. You can remove all the wires, and hook up the JeeNode to a USB-BUB. It’ll now accept sketches like any other JeeNode. Fixed!

EtheRBBBreadboard

In AVR, Hardware, Software on Jun 7, 2010 at 00:01

Please excuse the crazy title. This picture probably tells you more:

Dsc 1509

You’re looking at an RBBB from Modern Device, hooked up to the Ether Card from Jee Labs. The hookup is trivial, it need 6 wires: 2 for power and 4 for SPI:

Screen Shot 2010 05 29 at 04.18.26

And that’s all you need to create a webserver!

Here’s a sample screen (yep, it’s been running for almost 12 hours):

Screen Shot 2010 05 29 at 00.03.48

And here’s the code for it:

Screen Shot 2010 05 28 at 12.05.03

It presents a self-refreshing page with the “uptime”, i.e. how long the server has been running since power-up.

The code is available as “rbbb_server.pde” example sketch in the EtherCard library and is a simplified adaptation of the etherNode sketch, omitting the RF12 driver and calls, of course. It compiles to 6 Kb of code.

As with the etherNode sketch, the MAC address and IP address have to be set to suitable values in the source code before uploading it to the RBBB.

BTW… did you notice anything?

The RBBB is running at 5V. And it works. Because the Ether Card is compatible with 3.3V and 5V signals!

Which also means that the Ether Card can be used with any Arduino board. It’s not specific to JeeNodes and it’s not limited to being used with the Carrier Board, either.

The generic software for the Ether Card is contained in the “EtherCard” library, listed on the software page in the Café. It doesn’t depend on Ports or RF12 libraries, so this thing really is a completely independent product.

It just “happens” to fit gorgeously into a box alongside a JeeNode :)

So there you have it – the Ether Card can be used with just about any microcontroller setup. All it needs is a power supply of 3.6V or more, 4 SPI I/O pins, and the proper software to make it sing of course…

Onwards!

JeeNode as web server

In AVR, Software on May 31, 2010 at 00:01

The new Ether Card add-on makes a lot of new fun stuff possible. Even with a measly 8-bit ATmega chip, it’s possible to create some pretty neat things. Like a little webserver for displaying the last received RF12 packets.

I’ve added an EtherCard library to the subversion repository, next to the Ports and RF12 libraries, etc. It’s now listed on the software page in the Café.

This is mostly the Ethernet code by Guido Socher and Pascal Stang, but I’ve moved some stuff around a bit, and kept the changes added by Andras Tucsni to make this work together with the RF12 driver.

A new “BufferFiller” class has been added, to help create web pages and such:

Screen Shot 2010 05 22 at 00.04.55

What it does is expand a PSTR given to it, by replacing $S, $F, and $E with strings copied from RAM, flash, or EEPROM, respectively. A bit like “printf” in standard C. It’s easiest to just show an example of use:

Screen Shot 2010 05 22 at 01.42.00

The $D code is expanded as integer, for convenience. And since BufferFiller derives from the Arduino’s “Print” class, all the usual “print()” and “println()” members are also available.

The above code will generate the following web page (and yes, it’s been up and running more than 3 days):

Screen Shot 2010 05 25 at 09.55.06

It’s part of the etherNode.pde sample sketch in the EtherCard library – a little web server which shows the last few incoming RF12 packets and continuously self-refreshes to present the latest info.

There’s also a configuration page:

Screen Shot 2010 05 21 at 18.46.32

The whole etherNode demo sketch is under 10 Kbyte, including both EtherCard and RF12 drivers, leaving plenty of room to implement more features.

Dear Mr. Murphy

In AVR, Hardware on May 28, 2010 at 00:01

Dear Mr. Murphy, you must have had a ball these past few days…

I goofed. Again. Big time. Well, not Toyota- or BP-scale big time, but still. It’s all your fault, Mr. Murphy!

About two dozen faulty ATmega’s were shipped as part of the JeeNode Kits. And another five dozen or so were packed into kits-in-stock:

Dsc 1505

What happened? Well, that “flashy” new multi-ISP programmer I was so proud of has a bug when the “isp_cpature.pde” sketch is used in replay mode: it doesn’t program the fuse bits properly. Whoopsy daisy. I thought I had all the scenarios covered and tested, but clearly I didn’t. Those ATmega’s are shipped running at 1 MHz, and the pre-loaded RF12demo is initializing the serial port to a totally useless 57600 / 16 = 3600 baud.

This morning (i.e. yesterday by the time this post comes out), I went through the stock of ATmegas, including those in already-packaged-and-labeled JeeNode kits, and redid the fuses and uploads. Not quite my idea of fun.

Anyway. The good news is that everyone has been contacted, and that I’ve sent out replacement ATmega’s to those people who I’m quite certain have the botched version. A few people will have run into the problem (that’s how I found out!), but most kits are probably still in transit, and will now be followed by the fixed ATmega(s) shortly.

In case I missed anyone, here are the symptoms: the LED on the USB-BUB stays on relatively long when a JeeNode kit is plugged in, there is no greeting from the pre-loaded RF12demo or there are only garbled characters, and you can’t upload to the JeeNode. The problem is only with ATmegas sent out in the past few days, no more than perhaps a week ago. JeeNode USBs and JeeLinks are not affected. If you run into exactly this problem, please email me and I’ll send you a replacement ATmega.

To make matters worse, I also mixed up some of the early Carrier Board and Ether Card orders, fogetting to include this or that. All issues reported to me have now been resolved.

Oh well, live and learn.

Now go home, Mr. Murphy, and don’t come back. Please? :)

Meet the Ether Card

In AVR, Hardware, Software on May 24, 2010 at 00:01

Yesterday’s post was a sneaky way to show you a glimpse of an exciting new addition to the always-evolving Jee Labs product range – meet the Ether Card !

Dsc 1454

It’s a low-end Ethernet extension card, with a form-factor specifically made for the Carrier Board + Box:

Dsc 1467

It is based on the good ol’ trusty ENC28J60 chip, with all the components needed to hook it up to a JeeNode (or any other unit running the SPI bus at 3.3V).

I’ve started working a bit on the software side. The Ether Card is pretty standard in every respect, with the GPL2 code by Pascal Stang and Guido Socher working just fine with it. All it needs is a different chip select pin (PB0, Arduino pin 8) and proper interrupt guards to prevent the RF12 driver from interfering.

The card has been running smoothly for days on end here. It gets slightly warm, I’d estimate some 20°C above ambient. The regulator stays cool when powered from 5V. Total current draw is ≈ 150 mA, incl. JeeNode.

The Ether Card only uses through-hole parts, no SMDs. It has been added to the shop as kit and as PCB-only version. Here’s the PCB – in glorious blue-and-gold:

Dsc 1433

Here’s a sample web server requiring under 10 Kb of flash and showing a page with the last 25 RF12 packets:

Screen Shot 2010 05 19 at 11.33.18

So there you have it. JeeNodes can now handle wireless and wired networking.

It’s going to be oodles of fun to develop software for / on / with this Ether Card!

Credits: I would like to thank Andras Tucsni, who started the ball rolling by prototyping a complete working system and implementing the chip-select and interrupt changes needed for inter-operation with the RF12 driver on SPI. Andras also wrote the demo sketch which generated the above output. Knowing that it can be done and having working sample code makes a huge difference!

Multi-ISP programmer

In AVR, Hardware on May 18, 2010 at 00:01

This is a project I’ve been meaning to do for a long time:

Dsc 1432

It’s a portable ISP programmer which can program four 28-pin ATmega’s independently. It takes about 12 seconds to program fuses, bootloader, and RF12demo sketch into each chip, so with this unit I can essentially keep going and program some 20 chips per minute. Just what I need for yesterday’s batch of fresh ATmega’s. For reference: a USBtinyISP needs a few minutes per chip! (update: but it can be speeded up, see comments below)

Not that I need to program 1200 chips/hour! The point is that at this speed, I can now flash ATmega’s just-in-time, i.e. with the very latest version of RF12demo, etc.

This multi-ISP programmer is built from 4 Flash Boards, 1 JeeNode USB, 3 JeeSMD’s, a 450 mAh rechargeable LiPo battery, and a couple of ZIF sockets, resonators, and resistors. I’ve got roughly a dozen more ZIF sockets for the shop of there is interest. Also some 6-pin IDC headers and flat-cable.

The unit uses the capturing ISP programmer sketch and is very simple to use: plug the JeeNode USB in and use it as a normal AVRISP programmer @ 19200 baud. Use as many programming steps as you want. When idle for 3 seconds, the process stops – blinking the LED twice. Then exchange its Flash Board with one of the others and repeat the process until all flash boards have been set up.

From then on it can also work in battery-powered mode: insert chip, press button, wait for LED to start blinking, then rinse and repeat. Total current draw will be well under 90 mA, so this programmer should get over 5 hours of autonomy on one charge – up to 6000 chips… :)

The programmers are independent, so I can upload different contents in each of them. I’ve labeled each flash board to be able to do this without mixing things up.

The JeeNode USB v3 powers all the boards and includes the LiPo charge circuit, so the battery can be recharged by simply plugging it in. There’s a slide switch to disconnect the LiPo battery.

Some more build pictures. As you may have noticed, there is no connection from the 2×3-pin ISP header to the ZIF socket. That’s because I wired those up from below by using stacking headers for 2 of the 4 ports:

Dsc 1422

Here is the other side, wired up manually with wire-wrap wire. I’ve since covered it up a bit to avoid accidental shorts. The risky one is a direct short between the LiPo power pins, the rest is probably harmless.

Dsc 1430

And here’s the side view:

Dsc 1431

I’m looking forward to using this thing: swap chip, push button, swap chip, push button, … how convenient!

New ATmega batch

In AVR, Hardware on May 17, 2010 at 00:01

At last, 250 new ATmega328’s came in from DigiKey:

Dsc 1419

You may not have noticed, but in these past months there has been a major shortage of ATmega328 chips – everywhere. Once that happens, people start stockpiling, driving the shortages and delays up yet further, etc.

That’s 250 chips to intitialize with a boot loader + RF12demo sketch! Kinda illustrates my need for a good ISP programmer setup, eh?

There’s a substantial amount of capital investment involved in this stuff, so I’ve been cautiously moving about while trying to keep all the essential items in stock for the shop. So far, so good, mostly. But this batch sure is welcome… one less thing to worry about.

Onwards!

Setting up the thermocouple node

In AVR, Hardware, Software on May 10, 2010 at 00:01

This is part 2 of my reflow controller series. Unlike what was announced yesterday, I’m going to first describe how to set up the temperature sensing wireless node. JeeMon hookup to follow soon.

Our very first step could be to connect the thermocouple via a JeeNode and USB to the PC, but I’m going to do something more interesting and go straight for a wireless hookup. One reason for this is due to a problem with direct connections, but since this is going to be used in un-tethered mode anyway, it’s a good excuse to use a wireless configuration right from the start.

Here is the “thermoSend.pde” sketch I’m going to use (code here):

Screen Shot 2010 05 09 at 14.29.35

This contains all the ingredients needed for a simple basic sensor node: all we do is set up wireless, and then read out the thermocouple value and send it off once a second.

The easy transmissions code works with broadcast packets, so we don’t need to define a destination for the wireless packets, just this sensor node’s ID (1), the choice of frequency band (868 MHz), and a group ID (6). That’s done with the rf12_initialize() call.

The readings are converted to an integer in the range 0 .. 3300, representing a temperature range of 0 .. 330.0°C. Then we send that 2-byte integer in binary mode over wireless. That’s what the code inside loop() does. The map function is part of the Arduino library code.

The easy transmit system will take care of re-transmission if a packet is lost. All the transmission details are handled by rf12_easyPoll(), which needs to be called often.

One detail of the easy transmit system to keep in mind, is that only changed values are sent. No packets will go out if the reading is the same as the last one. In this scenario, that’s fine – there’s always some jitter in the readings, so we should see new packets at least a few times a minute, even when the sensor temperature is constant.

Ok, let’s get going. If you haven’t installed the Arduino IDE yet, go do it now.

Create the above sketch named “thermoSend” in the Arduino IDE. On my Mac, it ends up as a folder named “Documents/Arduino/thermoSend/” in my home directory. Plug in the JeeNode via an FTDI adapter such as the USB-BUB (or use a JeeNode USB) and check your Arduino IDE / Tools / Serial Port settings to make sure you’re hooked up to it. With multiple nodes on USB, it’s easy to mess up the wrong one – happens to me all the time…

Now the node is ready. Unplug, hook it up to a battery, and power it up.

You’re sending packets into the ether now. Quick, let’s try and collect those packets before they falll on the floor!

To do that, hook up a JeeLink or a second JeeNode. It needs to be running the RF12demo sketch, which is what it does out of the box if you got it from Jee Labs or Modern Device.

We need to connect to the JeeLink. Easiest way is to use the Arduino IDE. Make sure you are connected to the proper USB port. So again, check the Arduino IDE / Tools / Serial Port menu and select the JeeLink serial port.

Now open the Arduino IDE’s serial console. You should see something like this:

[RF12demo] A i1 g212 @ 433 MHz
Available commands:
[etc]

You are now in direct communication with the JeeLink. We need to set it up to listen to the proper transmissions. Sort of like tuning to the proper radio station. So type the following line and press “Send”:

2i 8b 6g

This sets node ID = 2, frequency band = 868 MHz, and net group= 6.

If all is well, and the wireless node is powered up, you should start to see packets come in, something like this:

OK 33 212 0
 -> ack
OK 33 209 0
 -> ack
OK 33 212 0
 -> ack
OK 33 209 0
 -> ack
OK 33 212 0
 -> ack

That’s a header byte (i.e. 33, associated with node ID 1) and 2 data bytes.

There won’t be packets every second, because only changed readings are sent. But there will be packets, and if you touch the thermocouple end, you should immediately see the rise in temperature:

OK 33 212 0
 -> ack
OK 33 226 0
 -> ack
OK 33 24 1
 -> ack
OK 33 44 1
 -> ack

No, I’m not suffering from sudden hypthermia: that’s not 4.4°C :) – what you’re seeing is binary overflow of the first data byte. A byte can only hold values 0..255. Anything higher and it will wrap around. That’s why two bytes are sent. The second byte contains the reading divided by 256, i.e. the number of wraparounds. You’re looking at the binary representation of an “int” on Atmel AVR chips.

So the above readings are: 21.2°C, 22.6°C, 28.0°C, and 30.0°C.

IOW, the actual temperature is: (byte1 + 256 * byte2) * 0.1°C

The next episode will be about hooking up JeeMon to the Jeelink and using it to read out the data and do something more meaningful with it. Stay tuned.

Assembling the Flash Board

In AVR, Hardware on May 7, 2010 at 00:01

Here is a step-by-step instruction for assembling the Flash Board, starting from these components:

Dsc 1386

The 24M01 1 Mbit EEPROM is already on the board. The build proceeds essentially in flattest-to-higher order, so that when you turn the pcb around for soldering, you can push down the part properly.

We start with the 470 Ω current limiting resistor for the LED:

Dsc 1388

Try to make nice and shiny joints:

Dsc 1387

Cut off the excess wires:

Dsc 1389

Next is the little start button:

Dsc 1390

There are four pins to solder:

Dsc 1391

They are a bit long, so it’s best to cut them off:

Dsc 1393

Next, the LED. This one is polarized, be sure to put it in the right way:

Dsc 1394

The last component on the top is the 2×3-pin ISP header:

Dsc 1396

Again, make sure all pins have good solder joints:

Dsc 1397

Now, all we need to do is solder in the 4 6-pin headers. The easiest way to do so is to push these headers into a JeeNode for proper positioning:

Dsc 1398

The push the Flash Board on top and you’ve got a convenient way to solder them:

Dsc 1399

That’s it, done!

Dsc 1400

Now you can upload the isp_capture.pde sketch on this page and use this brand new ISP programmer.

Happy programming!

Low-level development

In AVR, Hardware on May 6, 2010 at 00:01

I’m working on some ideas which require some low-level code, and fairly accurate timing. Serial or wireless I/O are not an option, and hooking up the logic analyzer is not convenient (I may have to, if the going gets tough).

For now, here’s a very simple setup which ought to be sufficient:

Dsc 1385

Two boards, hooked up via two USB ports. They are on the same computer, so there should be no issues with voltage levels when leaving them both connected at the same time (I’m not too worried about the ground loop).

The board at the top is the Flash Board as ISP programmer (I’m not using the new capturing features here). The board below is the “target”, a plain JeeNode hooked up to a USB-BUB. Nothing fancy.

I’ve added 8 bits of “I/O” by hooking up 8 LEDs with current-limiting resistors – red on the DIO pins, green on the AIO pins as debugger, as described here.

The target board also has the option to communicate over serial (i.e. through its USB connection), but that adds code and affects timing – something which I probably can’t tolerate in my specific tests.

Nothing very unusual here, but it’s worth pointing out that a couple of years ago, a setup like this could easily have cost over 1000 <pick-your-favorite-currency>, whereas this one is well under 100.

Let’s see how it goes…

A capturing ISP programmer

In AVR, Hardware, Software on May 5, 2010 at 00:01

Meet the new, improved, autonomous, self-guiding, hassle-free, portable ISP programmer!

Dsc 1381

It works as follows:

  • hook up a JeeNode or JeeNode USB to your computer
  • upload the isp_capture.pde sketch to it
  • insert the Flash Board and hook it up to the target
  • program the target, using this as a standard STK500/AVRISP programmer @ 19200 baud
  • wait for the LED to blink twice
  • done

And this is where the fun starts:

  • connect the JeeNode to a battery or any other power source
  • insert the above Flash Board again and hook it up to the target
  • press the button on the Flash Board
  • wait for the LED to first turn off and then start flashing
  • done

You’ve just programmed another target MPU … look ma, no hands!

The first hookup went through a normal programming cycle, but it also stored everything in the EEPROM on the Flash Board: code, data, fuses, verification bytes, everything. That’s why I’m calling this a capturing programmer.

When pressing the button, it essentially repeats all the same steps.

This works for anything you can program with an AVRISP programmer: ATmega, ATtiny, whatever. And it will even capture multiple programming cycles, as long as they are started before the LED blinks twice, i.e. within a few seconds. So you could set up a script to call avrdude with a few different things to do – e.g. set fuses, program the flash, program the AVR EEPROM, set the lock bits.

There are some tricks under the hood to make this work. First of all, the baudrate as ISP programmer is set to 19200, so that the bootloader in the JeeNode doesn’t accidentally take over after reset (it listens at 57600 baud).

Another trick, and the main reason this all works transparently, is that the entire serial communication session is stored in EEPROM as is. When pressing the button, it simply replays the input to the programmer code as if it was coming from the serial port (and matches the results, also against EEPROM). There is some logic involved to be able to store both input and output streams, and keep them properly apart.

The EEPROM is connected via I2C to port 3. I used the MemoryPlug and MemoryStream classes from the Ports library to access it.

Lastly, there is some debugging built in. While used as AVRISP programmer, the serial port is in use for programming @ 19200 baud. But when in replay mode, the serial port is set to 57600 baud and used to report what the programmer is doing. Here is a transcript:

[isp_capture]
ISP bytes: 39680
Code size: -32768
Page size: 128
Data size: 1024
Signature: 86 00 00 01 01 01 01 03 FF 95 0F
Programming...
Done in 13.9 seconds.

That’s it. There is visual feedback when programming succeeds in the form of a flashing LED, so that this setup can be used without serial link. I’d like to add auto power-down one day, for serious battery use.

I’m going to use a bunch of Flash Boards here, pre-loaded with the different contents of ATmega’s and ATtiny’s I’m constantly preparing here at Jee Labs. Will probably also dedicate a bunch of JeeNodes to this, but that’s optional – any available JeeNode can be temporarily turned into an ISP programmer by simply uploading the “isp_capture.pde” sketch to it and inserting a Flash Board.

Now I can easily reprogram all those Room nodes in the house!!

PS. There’s nothing JeeNode-specific about this setup. The on-board wireless isn’t used (yet?).

PPS. For your convenience, I’ve tagged all related posts on this weblog with ISP.

ATtiny 8-pin ISP programmer

In AVR, Hardware on May 1, 2010 at 00:01

Yesterday’s ISP programmer used a 28-pin socket wired up for ATmega328 chips (and the older 48/88/168 versions).

As it turns out there are enough unused pins available in that socket to also support the ATtiny 8-pin series (such as 25/45/85). The trick is to add a few extra wires so that the ISP programming signals have the proper setup for these smaller chips as well:

Dsc 1376

This allows placing an ATtiny in the socket at the top end, i.e. using just pins 1..4 and 25..28:

Dsc 1377

This trick works, because the I/O pins used by the ATtiny happen to be normal I/O pins for the ATmega, so it doesn’t mind having some logic signals there (pins 9..12 and 17..20 can probably also be used, but then inserting the chip becomes more error-prone).

And sure enough, avrdude can now program the ATtiny as well:

Screen Shot 2010 04 25 at 02.44.46

For other chips, you’ll need to wire up a chip-specific socket, but at least for these ATtiny chips an ATmega setup will work just fine!

ATmega 28-pin ISP programmer

In AVR, Hardware on Apr 30, 2010 at 00:01

The Flash Board presented a few days ago was only half the story. Here is the other half, i.e. the chip socket.

What you need is a board with a 10 kΩ reset pull-up resistor, an 8..16 MHz resonator for the clock, and – just to be safe – a 0.1 µF decoupling capacitor. I used an empty JeeNode v4 PCB to hook it all up:

Dsc 1372

I added the ISP connector in a slightly unusual way: with long pins bent sideways. The reason being that the ZIF socket won’t fit on the board otherwise. In fact, it won’t fit directly anyway because the holes are too small and the socket is too long. So I pushed it (hard!) into a 28-pin IC socket first:

Dsc 1371

Then I soldered the socket in, and there it is:

Dsc 1373

An ISP programmer for 28-pin ATmega’s!

Tomorrow, I’ll describe how I’ve modded this setup to also allow programming 8-pin ATtiny DIP chips …

Decoding a pulse train

In AVR, Hardware, Software on Apr 27, 2010 at 00:01

The (planned) Input Plug uses an ATtiny chip to decode a 16-channel selection code using a single I/O pin.

Here is the relevant part of the schematic:

Screen Shot 2010 04 19 at 19.50.37

The DIO pin is connected to PB4 of the ATtiny. The ATtiny PB0..PB3 pins in turn are hooked up to the A..D select inputs of the analog multiplexer. So all the ATtiny needs to do is decode an incoming “pulse train” on its PB4 pin, and send out the decoded value on its PB0..PB3 output pins.

My first attempt used a simple serial protocol: a start bit and 4 data bits, clocked at a fixed rate:

Screen Shot 2010 04 19 at 19.52.59

This worked, but it was a bit flakey because the internal clock of the ATtiny is not accurate enough to ensure everything stays in sync for the entire duration of the transmission, i.e. across 5 bit periods. This is clearly explained in the following image (from here):

async1

It’s better to use a self-clocking format, for example 5 pulses of varying width, because then only the length of each individual pulse matters. Above a certain threshold = 1, below = 0. And we can reset when there are no pulses.

Here’s the a transmit test sketch, which sends a 0..15 counter every 100 ms:

Screen Shot 2010 04 19 at 19.57.36

As you can see, the pulses are 4 or 8 µs wide, with one pulse every 12 µs. Roughly.

Note that interrupts have to be disabled during each “transmission”, since these pulses are very short and need to be fairly strictly controlled.

The decoder on the ATtiny (ATtiny85 in this test) is also quite simple. It waits for a pulse start and then counts in a loop until the signal drops to zero again. Counts above a certain value are treated as “1”. Missing pulses and pulses which are way too long cause the decoder to be reset and start from scratch:

Screen Shot 2010 04 19 at 20.01.21

This can be compiled with avr-gcc, and it’s of course just a few bytes (even an ATtiny is overkill here):

Screen Shot 2010 04 19 at 20.02.44

I’m using yesterday’s Flash Board for ISP programming. Makes a good test that it also works with ATtiny MPUs.

Here’s the test setup (with the ISP programmer disconnected):

Dsc 1362

And sure enough, the LEDs display a little running 4-bit counter, driven by data sent over a single DIO pin.

Should be good to go for the Input Plug!

Preparing ATmega’s with ISP

In AVR, Software on Apr 25, 2010 at 00:01

Here’s a second use of yesterday’s ISP plug: pre-loading ATmega’s with a fixed sketch and bootloader.

This uses a very nice trick from the Arduino Boot-Cloner: store the code to be sent to the target MPU as PROGMEM data inside the ISP sketch itself!

I’ve adapted that Boot Cloner so that it takes its data from a separate C include file, added a couple of other features, and speeded the whole thing up a bit.

The result is called “isp_prepare” (code here).

Here’s what you’ll see on the USB serial port when starting it up:

Screen Shot 2010 04 18 at 23.14.22

The list reports the files which have been integrated into this sketch at build time, using this C code at the top of isp_prepare.pde:

Screen Shot 2010 04 18 at 23.23.36

Here is the contents of that include file, with most of the data bytes omitted:

Screen Shot 2010 04 18 at 23.24.51

The data consists of “sections” of code, to be programmed into the target ATmega using ISP. In this case there are two sections, a RF12demo sketch starting at address zero, and a bootloader in high memory.

Here’s is isp_prepare in action:

Screen Shot 2010 04 18 at 23.14.47

So the steps to load RF12demo onto a JeeNode with a fresh ATmega are as follows:

  • upload this isp_prepare.pde sketch to a “master” JeeNode
  • insert the ISP plug described yesterday,
  • connect the target JeeNode to this master JeeNode via ISP
  • enter G to start programming and wait for it to complete
  • done: disconnect, now the target JeeNode is ready to run with RF12demo on it

I’ve also included a “data_blink.h” header file, if you want to preload the ATmega with the standard Arduino blinking LED demo. Just change the include in isp_prepare and upload the sketch again.

I can now use this setup for initializing all the ATmega’s here at Jee Labs, since it means I no longer have to start up the Arduino IDE or use avrdude.

Convenience!

ISP plug

In AVR, Hardware, Software on Apr 24, 2010 at 00:01

For one of my projects, I needed a quick way to reflash an AVR via ISP. Didn’t want to have to use any of the several ISP programmers around here, so I made my own “ISP plug” for use on a JeeNode:

Dsc 1353

The pins are connected as follows:

  • ISP pin 1 = MISO = DIO1
  • ISP pin 2 = VCC (+3.3V)
  • ISP pin 3 = SCK = AIO1
  • ISP pin 4 = MOSI = AIO4
  • ISP pin 5 = RESET = DIO4
  • ISP pin 6 = GND

Here the top view, made from a little JeePlug board:

Dsc 1354

Bottom side:

Dsc 1355

Note that this ISP setup draws 3.3V from the JeeNode and uses it to power the target, so the target board should not have its own power and it should not draw more than say 100 mA of current @ 3.3V.

The code for this is called “isp_flash.pde” and is derived from the “ArduinoISP” sketch. I added software-based (bit-banged) SPI communication for use with the above I/O pins, and did a fair bit of cleanup of the source code.

The nice thing about this ISP programmer is that it works out of the box with Arduino IDE 0018:

  • upload the ISP_flash.pde sketch to the JeeNode
  • insert the ISP plug and hook it up to the test circuit (or one of these …)
  • burn the boot loader using the Arduino IDE:

Screen Shot 2010 04 18 at 18.04.06

The result will be a properly initialized ATmega, with protected bootloader and the default blink demo pre-loaded.

It’s not terribly fast because it uses a 19200 baud connection, but it’s simple and can be a life-saver if you ever damage the bootloader on an ATmega, or want to prepare blank ATmega’s for use with a JeeNode.

This plug can in fact be used as ISP programmer for any type of ATmega or ATtiny with “avrdude”:

Screen Shot 2010 04 18 at 18.14.42

You’ll need to adjust the serial / USB port, fuse settings, and sketch as needed, of course.

Debugging with LEDs

In AVR on Apr 10, 2010 at 00:01

There was a problem in the RF12 driver with startup, with hard-to-reproduce behavior, unfortunately. I couldn’t make heads or tails of it, until more details started coming in via the Jee Labs forumlong live open source!

The problem, as originally identified: sketches don’t start reliably, when power is applied through batteries.

The diagnosis: it’s not related to battery power, it’s due to the RFM12B staying in some sort of “powering-up” limbo mode for several seconds.

Trouble with this sort of problems is that they can be very hard to reproduce, and even harder to debug. It all happens at startup, before any comms with the outside world is possible, and what’s worse: sending out some debug bytes over the serial port may affect the problem, due to the time it takes to do so, or the interrupts taking place, or even RAM memory being changed by the debugging.

They’re called Heisenbugs, and they’re the worst…

In this case, the breakthrough came when I had a “reliably failing” setup: running the lcd_demo.pde sketch and inserting a call to rf12_config() was enough to get a hang after each power-up. Good – now I can chase this bug!

In this case, there was an LCD hooked up, but it gets initialized after the rf12_config() call. All I wanted to know at first, is where the code hangs.

Time for the LED debugger:

Dsc 1331

Two LEDs, inserted in an unused port. Both with 1 kΩ current limiting resistors in series (470 Ω would be brighter). One between DIO and GND, the other between +3V and AIO.

The code to init this is quite simple:

pinMode(5, OUTPUT);
digitalWrite(5, 0);
pinMode(15, OUTPUT);
digitalWrite(15, 1);

I used port 2, i.e. DIO = Arduino pin 5 and AIO = Arduino pin 15. Due to the way these LEDs are connected, the one on the left will light when DIO is set high and the one on the right will light when AIO is set low. The above code starts with both LEDs off.

Now, all I have to do is turn DIO on at the start, and move the code to turn it off further and further into the initalization code:

digitalWrite(5, 1);
rf12_config();
digitalWrite(5, 0);

As expected, the LED never turns off again – rf12_config is going haywire.

Then I tried simplifying, replacing rf12_confg() by a call to rf12_intialize(). Same outcome: hangs. So it’s not the EEPROM code.

Tried out several things: delays, sending stuff to the RFM12B driver to try and initialize it better, or even twice – no difference: stil hangs.

Hm. The RF12 driver uses interrupts. Maybe it’s in there (yuck, even harder to debug). I called rf12_inititalize() with 0 as first arg, so attachInterrupt() would not be called – and bingo … no more hang.

So the RFM12B is generating interrupts, at a point when I don’t expect it: i.e. right after initialization. Interrupts should only happen when sending out data bytes (TX FIFO empty) or when receiving them (RX FIFO full).

To make a long story short: the RFM12B is pulling the IRQ line low for some eight seconds after power up. Since the IRQ line is set up as a level interrupt, that means it’s generating interrupts all the time!

No matter what I tried, I couldn’t make the RFM12B stop generating interrupts. But then, after about 8 seconds, it ended up going high and all was fine. Go figure.

So now I’ve added a loop which waits and polls the RFM12B in the init code, until it stops pulling IRQ low. On power up, that takes around 8 seconds. On reset, there is no wait. This should fix the remaining issue reported with hanging of JeeNodes, battery-powered or otherwise, i.e. any scenario which doesn’t use resets to restart the ATmega when the RFM12B is ready. If this affected you, get the latest code and re-compile / upload your sketch.

In hindsight, I’m surprised it worked before this fix!

Case closed. One more victory over bits and silicon. Onwards!

After-burner

In AVR, Hardware on Apr 3, 2010 at 00:01

To reply to a comment posted yesterday, this is the contraption I use to re-flash a JeeNode or JeeLink after the fact via its ISP connector:

DSC_1295.jpg

It has two diodes, dropping the incoming 5V power from the programmer to around 3.8V – this turns out to be needed in the case of JeeLinks, which has the VCC pin on the ISP header connected to 5V instead of the 3.3V driving the ATmega. The high voltage was causing problems with logic signal levels.

The other component on the board is a 100 µF capacitor, to reduce voltage fluctuations (it.s probably superfluous, I added it while debugging the setup).

Here’s this “after burner” in action:

DSC_1296.jpg

The long pins are at an angle, because that way they can be gently pressed into the holes and they will stay there during programming.

Like most hacks, it looks awful, but it works pretty well!

AVRISP mkII w/ 5V power

In AVR on Apr 2, 2010 at 00:01

I’ve been using the USBtinyISP AVR programmer for some time now, to set the fuses, burn the boot loader, and burn the RF12demo.pde compiled sketch into each ATmega.

Trouble is, it’s slow as molasses …

So I got the AVRISP mkII programmer a while back, but the problem is that it’s unpowered. Not good for my setup, which expects power from the USB programmer:

2937E56E-F019-4E55-99F4-60B1B15111DB.jpg

So I went looking around for tips on how to bring 5V to pin 2 of the 6-pin ISP connector. Found this mod which uses a 5-to-3.3V regulator, and this one which draws 5V directly from the board.

I decided to tap the 5V USB power, but after the polyfuse, so that a short won’t damage the computer or USB hub as easily:

DSC_1294.jpg

The connection is jumpered, so this can still be used in its original form when needed.

And then I spent ages chasing ghosts…

It turns out that avrdude needs a “-B 3” time adjustment to reliably program the chips. Now how am I supposed to know that!

Anyway, here’s the shell script I’m currently using on my old PowerBook, which automates it all:

Screen shot 2010-04-01 at 23.08.28.png

That last character being echoed is a CTRL+G, i.e. an audible bell to signal when the process is done. It used to be essential, since the USBtinyISP took so much time for each burn. Now, it’s clocking in at 17 seconds, and that could probably be reduced even further by combining the three separate avrdude runs.

A roughly 10-fold improvement!

Meet the JeeNode USB v3

In AVR, Hardware on Mar 19, 2010 at 00:01

Just got a couple of new boards back (this was an experiment, expediting some of the boards to get them several days ahead of the rest of this prototype batch).

Meet the new JeeNode USB v3 (this unit was soldered by hand – phew!):

DSC_1248.jpg

As you may know, the main reason for this revision was to resolve a problem with the voltage regulator, but since I had to rework the design anyway I also added a LiPo charge circuit.

The good news is that everything seems to work fine so far. There are some cosmetic problems with this board, but no show stoppers.

And of course the big deal is being able to hook up a Lithium Polymer (LiPo) battery:

DSC_1249.jpg

There is an extra LED in the corner, left of the USB jack, which will be orange (once I get them in). It lights up while charging. The charge current is max 280 mA, so this board won’t draw more than that from USB.

Without LiPo connected, the current still goes through the charge circuit, so another major change is that the PWR pin on all the headers of this board never carries more than 4.2V – don’t use the JeeNode USB if you need 5V in your circuit (use a JeeNode + USB-BUB if you really need the 5V).

Two BIG honking warnings, since LiPo batteries can be quite dangerous: one is that they need to be charged with the proper circuitry, such as on this new board, so don’t hook ’em up any other way. The other issue to keep in mind at all times, is that LiPo’s can discharge at a very high rate! That “20C” label above means that this particular little battery is rated to sustain a discharge @ 20 x 450 mA = 9 amps!

You can probably cause a fire with those wires shown above, by simply shorting out a fully charged battery!

And you will probably fry the circuit and vaporize PCB traces by connecting the battery in reverse!

I’m exploring some options to reduce these risks. Hard-wiring the LiPo would be one way to reduce the chance of loose wires shorting out something. Perhaps a small custom PCB glued to the battery, with a fuse or polyfuse and a switch, wrapped in heat-shrink tubing? The trouble is that battery sizes and capacities vary greatly.

Some first tests w.r.t. power consumption: it looks like the JeeNode USB v3 will draw about 120 µA when in sleep mode. With the above 450 mAh battery, it would last up to 5 months without recharging (and without doing anything useful, such as turning on the radio module once in a while). There’s probably still some room for improvement here, but for now it’ll have to do.

FWIW, I’m going to hand-assemble a few of these boards in the coming weeks, but unfortunately that means there won’t be many v3 units available in the shop, initially. I’m also having solder paste stencils made up right now. Once these are in, the new boards will be much easier to assemble – using the reflow grill that gets a lot of work done here at Jee Labs.

Meet the JeeSMD kit

In AVR, Hardware on Mar 18, 2010 at 00:01

Meet the new kid kit in the Jee family – the JeeSMD !

DSC_1246.jpg

At a glance:

  • Same pinout as a JeeNode – same 4 port headers, same PWR/SER/I2C, same SPI/ISP
  • No wireless, no FTDI, just an ATmega328 – all SMD (32-TQFP, SOT-23, and 0603)
  • Two extra pins on the right side (allocated to the RFM12B module on JeeNodes)
  • Has a 3.3V regulator, a 16 MHz resonator, and four passive components

What’s the point? Well, it’s going to be made available as an SMD kit, and it’s going to be low-cost. If you don’t care about wireless or FTDI, then this is a convenient and compact way to hook up some Jee Labs plugs.

Of course, all the other stuff fits as before, including the Proto Board, for example:

DSC_1247.jpg

Here’s the board in more detail:

DSC_1243.jpg

(don’t look too closely at this prototype PCB – there are some silly cosmetic mistakes…)

There are some trade-offs w.r.t. JeeNodes:

  • No FTDI on board – you have to either add the equivalent connections yourself via the left and right headers plus a 0.1µF cap, or use ISP for flashing the ATmega328 chip
  • No wireless, so this isn’t a “node” in the usual sense – just a tiny Arduino’ish board
  • It’s all SMD, so if you want to practice soldering SMD by hand – this is one way to get started!

I’ve got a few boards for people who want to get their hands on them. The kits will be ready in about a week.

Now the JeeSMD kit needs a detailed set of instructions and close-up shots on how to assemble and start using it – more work to do!

Plug shield on Arduino Mega

In AVR, Hardware on Feb 7, 2010 at 00:01

The Plug Shield can also be used on an Arduino Mega:

DSC_1175.jpg

Note the two extra wire jumpers, since the I2C interface is on pins 20 and 21 on the Mega board.

The above has an RTC plug and an LCD plug hooked up, so let’s to set up a simple clock with this – and use it to demonstrate the brand-new RTClib along the way:

Screen shot 2010-02-05 at 17.22.01.png

I’ve omitted the details of the Wire coding, but you can get the full sketch here.

New date / time / RTC library

In AVR, Software on Feb 5, 2010 at 00:01

Not so long ago, I had the opportunity to work a bit on something which has bugged me for a long time – the lack of date and time handling in connection with RTC chips. There are a few libraries out there, but I think I could do better – i.e. make it simpler, smaller, yet sufficiently powerful for real day-to-day use.

Seeing where this was going on the Arduino developer mailing list (and disagreeing with just about everything that happens over there), I decided to put my money time where my mouth is, and build my own library.

Here’s the header file of the new RTClib Arduino-compatible library:

Screen shot 2010-02-04 at 13.52.13.png

This lets you do date / time calculations, and it provides two different ways to implement a clock: via a hardware chip or using the built-in millis() timer.

RTClib has been checked into subversion, see the CODE page for details on how to get it.

It includes four example sketches:

  • datecalc illustrates how to do calculate with dates and times
  • ds1307 interfaces with a DS1307 RTC chip, connected via the Wire library
  • plugrtc interfaces with the RTC Plug, connected via the Ports library
  • softrtc demonstrates how to do the same with just software

One fun trick I added, inspired by a comment from Limor Fried, is to allow initializing a DateTime object from the DATE and TIME strings generated by the C compiler. That means you can run that “softrtc” sketch without hardware support, and it’ll automatically have its clock set to the compilation date of the sketch, i.e. fairly close to correct. Not good enough for general use, but great during quick debug cycles when you’re re-compiling your sketch all the time anyway.

Note that to use RTClib, you need to include the “Wire.h” library – even if you don’t use it!

The inability to properly deal with libraries, particularly in a resource-constrained embedded processor context, is one of the aspects of the current Arduino direction which irritates me – see an older post for more details.

Fascinating concurrency

In AVR, Software on Feb 4, 2010 at 00:01

There is a new language for the Arduino / JeeNode / ATmega328, called Occam-π.

I found out about it yesterday, at http://concurrency.cc/ – it’s high level, and it supports parallel programming. The current development environment release is for Mac OS X, with Windows and Linux coming soon.

Here is a complete program with 4 blinking LED’s, one on each DIO pin of the JeeNode ports:

Screen shot 2010-02-03 at 01.13.19.png

That’s it. Compiles to roughly 2 Kb. Each extra blink adds just 20 bytes, btw.

And yes, it really makes four LEDs blink at an independent rate:

DSC_1167.jpg

There is slightly more to it than that, but this is mind-blowing stuff. The “parallelism” is simulated, of course. Looks like the ATmega can do around 6000 context switches per second (i.e. parallel task switches).

There is a roughly 20 Kb interpreter part that needs to be uploaded once (which is why this requires at least an ATmega328). After that, the IDE will upload just the bytecode for your program, i.e. 2 Kb in the above case.

B R I L L I A N T .

Imagine hooking up the RF12 driver to this – there’s plenty of room for the extra 3 Kb or so. And for doing all sorts of things… in parallel! My earlier complaint post about how awful it is to do several things at once on an ATmega board might just have been wiped off the table.

Looks like I’ve got some very serious learning ahead of me to try and get to grips with all this.

Single AA room node

In AVR, Hardware on Jan 21, 2010 at 00:01

The range of things to try is just endless…

Here is a (v2) JeeNode with a (prototype) room board and a 1-cell battery:

DSC_0942.jpg

Note that this prototype board is turned 180° w.r.t. the official Room Board, to match the Rooms sketch.

This node uses a 1.5 => 5V converter from SparkFun, which I had lying around. It’s far from optimal, with one third of the energy eaten up by the 3.3V voltage regulator, but it’ll have to do for now. Let’s see how long it lasts…

The whole thing is mounted on a little piece of foam board with dual-sided adhesive tape. Just to try it out.

To give you an idea of what’s flying around over the 868 MHz airwaves around here:

Screen shot 2010-01-20 at 00.18.35.png

That’s some 10 room nodes, the OOK relay with a bunch of sensors, and the energy/gas metering packets. Note how the Linux system time is exactly in sync with the DCF77 atomic clock receiver (using UCT i.s.o. CET). Note also that the OOK relay data is currently reported twice: once through a direct USB connection, once over the air.

Lots of fun! And that’s just the beginning, as far as I’m concerned :)

On a related note: I’m investigating whether it would be feasible to bring out a complete kit for the Room Board – with motion, light, temperature, and humidity sensors all included. If I can find the right distributors and order in sufficient quantity, it might be possible to get such a kit in the shop for €39, incl. VAT. Let me just say that if it can be done, you’ll be the first to know!

Sleep mode fix

In AVR, Software on Jan 20, 2010 at 00:01

The Rooms sketch (latest code here) had problems with the sleep mode added about a month ago:

Screen shot 2010-01-17 at 14.05.55.png

The first value is the current consumption in µA.

For some reason or other, the node would stop working and enter a permanent-on mode, drawing over 7 mA and draining the battery in a matter of days. Not good.

It seems to be related to the way the power down mode was implemented. To get absolutely rock bottom power draw, I was using the RF12’s watchdog timer. The ATmega watchdog time draws slightly more current and isn’t quite as configurable.

I’ve now reverted to using the ATmega watchdog anyway. Here is the modified logic:

Screen shot 2010-01-18 at 12.09.39.png

The watchdog is set to interrupt every 16 milliseconds, constantly. When the node is powered down, this will wake it up again. What the new loseSomeTime() code does, is simply to power down a couple of times, until the target delay time has been reached. There is some inaccuracy in these timings since the watchdog timer is free-running, but this should not matter too much when waiting for a second or so.

The new code has been running fine for over a day on six nodes. Here’s a sample from my power tracker:

Screen shot 2010-01-19 at 16.56.22.png

That’s 110 µA right now, 265 µA in the last minute, and 230 µA in the last hour.

At around 250 µA average, the power consumption is a bit higher than before, but my main concern is first to get the nodes running reliably. Even @ 250 µA, the AA batteries should last several months.

The average power down current draw is 110 µA/sec, 40 µA of which is due to the PIR sensor. The total current draw while transmitting is around 29 mA – during reception it’s about half, i.e. 14 mA. Still, due to the very brief on-times, this current consumption averages to only about 400 µA during 1 second for a normal send + ack sequence. Under optimal RF conditions, the long-term average consumption of a node will be under 150 µA. I’m confident that further optimizations could reduce this to well under 100 µA.

But there is one known flaw, which can be observed to happen once in a while: the nodes always wait for an ack in full-power mode, i.e. with the receiver on. This will normally be within milliseconds, but if the connection is flakey or if the central node is unresponsive, then nodes can spend a great deal of time in full-power mode. This needs to be fixed one day.

I’ve started re-flashing all the room nodes and replacing their dead batteries, here at Jee Labs – let’s see how it goes this time around.

More C++ template trials

In AVR, Software on Jan 18, 2010 at 00:01

Here are some more results in trying to use templates for embedded software on JeeNodes. This time, it’s about using Jee Plugs with bit-banged I2C on one of the 4 ports and with built-in TWI hardware on pins A4/A5.

Let’s start with an extract of the Latest JeeLib.h header:

Screen shot 2010-01-17 at 11.50.27.png

I’ve omitted all the actual code, for brevity in this example. The full code is here. The previous version of JeeLib has been moved to the avr-jeelib-first branch in subversion.

The Port<N> class is essentially the same as in an earlier post. It generates efficient code for raw pin access, given fixed pin assignments known at compile time.

The above code adds a templatized PortI2C<N,W> class, where N is again the port number (1..4) and W is a constant which determines the bus speed. As with Port<N> class, this leads to a class definition which requires no state and which can therefore consist entirely of inlined static members.

A HardwareI2C<W> is also defined, with the same API as PortI2C<N,W>, but using the hardware TWI logic in the ATmega. The point is that in use, PortI2C<N,W> and HardwareI2C<W> objects are interchangeable.

You can see how all this templating stuff complicates the naming of even simple classes such as these.

The final class implemented above is DeviceI2C<P,A> – it does the same as DeviceI2C in the original Ports library, but again using templates to “bring in” the underlying port classes and the device I2C address.

Here is an example sketch built with all this new code:

Screen shot 2010-01-17 at 12.48.05.png

It supports two bit-banged I2C devices on ports 1 and 2, respectively, as well as a third I2C device driven by the built-in TWI hardware.

This compiles to 980 bytes (using Arduino IDE 0017).

The good news is that this generates pretty efficient code. It’s not 100% inlined – but quite a bit is, especially at the lower levels, so the result looks like a pretty good implementation of a high-level I2C driver which can be used for both bit-banged and hardware-supported I2C, all by changing one declaration at the top of the sketch.

But there are quite a few inconveniences with this approach…

First of all, note that the declarations at the top are fairly obscure. I did my best to simplify, but all this template mumbo-jumbo means you have to understand pretty well how to declare a port, and how to declare an I2C device object for that port. The “typeof” keyword in there is a GCC extension, without which these declarations would have looked even more complex.

The major trade-off is that the above example essentially generates separate code for each of these three I2C devices. There is virtually no code sharing. This can lead to code bloat, despite the fact that each version generates pretty good code. In practice this might not be so important – it is not likely after all that you’ll need all three types of I2C buses in the same sketch. Just keep in mind that you’re trading off efficient hard-wired coding against the need to generate such code for each type of I2C access you might need.

So would this be a good foundation to build on? I don’t know yet…

C++ templates do seem to get a lot more of the logic “into” the compiler. Instead of passing say an I2C device address as constant to an object, we generate a highly customized class which is special-cased to implement just one device at just one address. With the result that the compiler can perform quite impressive optimizations. In the above example, there are lots of cbi and sbi instructions in the generated code, just as if you were to dig in and hand-craft an optimized implementation for exactly what you need. All from a small general-purpose library!

But it comes at a price. There is no (non-template) “DeviceI2C” class anymore. Writing a class on top to implement access to the UART Plug for example, means this class has to use templates as well. It’s a bit like “const” – once you start on the path of templates, they will start to permeate all your your code. Yikes!

The other “cost” is that all templates have to end up in header files. The size and complexity of the “JeeLib.h” header file is going to increase immensely. Not so great if you want to get to grips with it and just use the darn stuff. On the plus side, I was pleasantly surprised that error messages are fairly good now.

These drawbacks may be acceptable if all the template code can indeed remain inside the library – I sure wouldn’t want to impose the need for all library users to learn the intricacies of templates. So maybe it’s all doable – but this approach has major implications.

Is it all worth it? Hm, big decision. I do not like big decisions, not at this stage…

New library experiments

In AVR, Software on Jan 14, 2010 at 00:01

Encouraged by the previous post, I started writing a bit more code based on C++ features such as templates and namespaces, in the form of an Arduino library (compatible with it, not depending on it):

Screen shot 2010-01-09 at 02.08.27.png

Things to point out:

Less #defines (none so far), I turned bitRead() and bitWrite() into template functions (getBit and setBit), so that they can be used with 1..4 byte ints, just as the macros.

The Port class is inside a new “Jee” namespace, so there is no conflict with the existing Ports library.

Atomic access hasn’t been solved. Some of this won’t work if I/O pins get changed by interrupt code. I’m hoping to solve that at a higher level.

There are compatibility definitions for pinMode(), digitalRead(), and digitalWrite() using the normal Arduino pin numbering conventions (only Duemilanove so far). These are in their own namespace, but can also be used without any qualifiers by adding “using namespace Jee::Arduino;” to the sketch.

Totally incomplete stuff, untested, and not 100% compatible with Arduino in fact.

The other thing I want to explore, is to treat the choice of what a pin does as a pin initialization mode. Hence the enum with Mode_IN .. Mode_PWM definitions. The underlying code is PortBase::modeSetter(), but it hasn’t been written yet. It’s all steamy hot vapor for now.

Update – I’ve placed the code in subversion, but the API is going to be in flux for a long time.

Update #2 – Atomic access is actually better than I thought. With constant pin numbers, setBit() will use the cbi/sbi instructions, which are atomic.

C++ templates

In AVR, Software on Jan 12, 2010 at 00:01

A recent post described the performance loss in the Arduino’s digitalRead() and digitalWrite() functions, compared to raw pin access.

Can we do better – i.e. hide the details, yet still get the benefits of raw I/O? Sure.

If you’ve used JeeNodes and in particular the “Ports” library, you’ll have noticed that there is a C++ class which hides the details of each port (i.e. JeeNode port, not ATmega port). Let’s look at that first:

Screen shot 2010-01-06 at 12.40.09.png

I’ve omitted the implementation, but there are still lots of secondary details.

The main point is that this is now C++, and uses a “Port” object as central mechanism. Each object has one byte of data, containing the port number (1..4).

Due to heavy inlining, there is almost no additional overhead for using the Port class over using digitalRead() and digitalWrite(), on which they are based. I verified it by running similar tests as in the recent post about pin I/O:

Screen shot 2010-01-06 at 12.48.50.png

Using the definition “Port orig (1);” – and sure enough the results are nearly the same.

There are two issues which make this approach sub-optimal: using the slow digital read/write calls, and storing the port number in a memory location which needs to be accessed at run time. There is no way for the compiler to optimize such calls, even “orig.digiRead()” should be the same as writing “bitRead(PORTD, 4)” in this example.

That’s where C++ templates come in. Check out this definition of a new “XPort” class (named that way to avoid a name conflict) and an example of use for port 1:

Screen shot 2010-01-06 at 12.54.02.png

(As you can see, I’m switching to a different, and hopefully clearer, API along the way)

There’s some funky <…> stuff going on. We’re in fact not declaring one class, but a whole family of classes, parametrized by the integer included in the <…> notation on the last line.

The big difference, is that each class now has that integer value “built-in”, so to speak. So we can define member functions which directly pass that value on to the corresponding bitRead() and bitWrite() macros. And then all of a sudden, all the overhead vanishes: since the member needs no access to object state, it can be made static, and since all the info is known in the header, it can be made inline as well.

So the above template is C++’s modern way of doing far more at compile time, allowing the optimizer to generate much better code.

Note that templates come with some pitfalls: first of all, it’s very easy to inadvertently generate huge amounts of code, so very careful inlining and base class derivation is essential. The second problem is that templates tend to be “instantiated” as late as possible by the compiler, which can lead to confusing error messages when the templates are wrong or used wrongly.

I’m still just exploring this approach for embedded use. The potential performance gains are substantial enough to give it a serious try. My hope is that the hard work can be done in a library, so that everyone else can just use it and benefit from these gains without having to think much about templates, let alone implement new ones. The “one” object declared above acts like any other C++ object, so using it will be just as easy as non-template objects.

Does the above lead to fast code? You bet. Here’s a test sketch:

Screen shot 2010-01-06 at 13.05.29.png

And here’s some sample output:

Screen shot 2010-01-06 at 13.06.14.png

As you can see, values 5 and 6 are virtually the same as values 7 and 8. We’ve obtained the performance of direct pin access while using a high-level port-style notation to access those pins. This is why templates are so attractive for embedded use.

The timings are different from the previous post because the loops are coded differently. In this case, only the relative comparisons are relevant.

Pin I/O performance

In AVR, Hardware, Software on Jan 6, 2010 at 00:01

There was a discussion on the Arduino developer’s mailing list about the impact of a small change to the digitalWrite() function, and for some time I’ve been hearing that digitalWrite() has a huge amount of overhead.

Time to find out.

Here is the sketch I used to measure how often a pin I/O command can be issued using various mechanisms:

Screen shot 2010-01-05 at 11.42.53.png

The logic is that I’m counting how often the same command can be called between timer overflows, i.e. every 1024 µs (one byte, incrementing @ 16 MHz / 64), before the timer tick count changes again.

And here’s the sample output:

Screen shot 2010-01-05 at 11.42.14.png

There’s a small amount of jitter, which tells me the loops are syncing up almost exactly on the timer ticks. Interrupts have not been disabled, so the timer interrupt is indeed being serviced – once for each loop.

What these values tell me, is that we can do about:

  • 10 analog 10-bit readings per millisecond with analogRead()
  • 128 pwm settings per millisecond with analogWrite()
  • 220 pin reads per millisecond with digitalRead()
  • 224 pin writes per millisecond with digitalWrite()
  • 1056 pin reads per millisecond with direct port reads
  • 1059 pin writes per millisecond with direct port writes

(I’ve corrected the counts by 1000/1024 to arrive at these millisecond values)

So the Arduino’s digital I/O in IDE version 0017 can do roughly 1/5th the speed of direct port access on a 16 MHz ATmega328.

But WAIT! – There’s a large systematic error in the above calculations, due to the loop overhead. It looks like the loop takes 1024000/1251 = 819 ns overhead, so the actual values are quite different: digitalRead() -> 3712 ns, direct port read -> 151 ns. Now the values are more like 1/25th!

So let’s redo this with more I/O in each loop iteration (all 4 ports):

Screen shot 2010-01-05 at 11.55.31.png

The sample output now becomes:

Screen shot 2010-01-05 at 11.56.59.png

With these results we get: one digitalRead() takes 4134 ns, one direct port read takes 83 ns (again correcting for 819 ns loop overhead). The conclusion being that digitalRead() is 50x as slow as direct port reads.

Which one is correct? I don’t know for sure. I retried the direct port read with 16 entries per loop, and got 67 ns, which seems to indicate that a direct port read takes one processor cycle (62.5 ns), as I would indeed expect.

Conclusion: if performance is the goal, then we may need to ditch the Arduino approach.

Update – Based on JimS’s timing code (see comments): digitalRead() = 58 cycles and direct pin read = 1 cycle.

Update #2 – The “1 cycle” mentioned above is indeed what I measured, but incorrect. The bit extraction was probably optimized away. So it looks like direct pin access can’t be more than 29x faster than digitalRead(). As pointed out by WestfW in the comments, digitalRead() and digitalWrite() have predictable performance across all use cases, including when the pin number is variable. In some cases that may matter more than raw speed.

Update #3 – Another caveat – Lies, damn lies, and statistics! – is that the register allocations for the above loops make it extremely difficult to draw exact conclusions. Let me just conclude with: there are order-of-magnitude performance implications, depending on how you do things. As long as you keep that in mind, you’ll be fine.

Arduino Duemilanove

In AVR, Hardware on Dec 30, 2009 at 00:01

Not everything is about wireless. Nor about nodes, ports, or plugs. Of course not – that would be boring :)

To offer more choices, I’ve added the Arduino Duemilanove to the web shop:

Duemilanove_HI.JPG.jpeg

Jee Labs is now an official distributor for these famous boards. Woohoo!

Carrier detection

In AVR, Software on Dec 26, 2009 at 00:01

Wireless communication is a complex process. The ISM bands used by the RFM12B module get used in various ways – some quite simplistic. For “serious” use, what you want is to avoid transmissions interfering with each other – which means at most one transmitter should be active at any given time for a specific frequency band.

Easier said than done. This is what CSMA/CA is all about. It’s quite similar to ethernet: you listen to the “ether” and wait until there is no carrier before starting to send yourself. If everyone does so, then there will be fewer “collisions” – i.e. messed up packets.

CSMA/CA isn’t perfect. It doesn’t scale all that well if there are lots of nodes, all trying to find a free slot to send their packets out. There is always a non-zero probability of collision, when two nodes decide at nearly the same time that there is no-one else transmitting. And then, BOOM! … as they say.

One solution for that is another acronym: TDMA. Basic idea: have all the nodes agree to only send in specific time slots allocated to them. This requires a central coordinator, as well as pretty accurately keeping track of time (which is non-trivial with RC-based watchdog timers for sleep modes used with low-power nodes!).

In the ISM band, at least the 868 MHz one used in Europe, a simpler solution is used: keep the air-waves more or less free. The rule is that each transmitting node should send no more than 1% of the time, on average. With one or two dozen nodes and a bit of randomness in timing, the idea is that collisions will be relatively rare.

I recently added the 1% rule to the easy transmission mechanism in the RF12 driver (for the 868 MHz band only). So with the rf12_easy…() calls, adhering to the 1% rule is now automatic.

The 1% rule is a very simple system, yet it works surprisingly well. I’ve got over a dozen nodes around the house, sending out packets whenever they feel like it. The off-the-shelf commercial weather station nodes I use are very simplistic – they just send, ignore collisions, and send new data again a minute or two later. Those nodes probably don’t even have receive capability.

The RFM12B transceiver module in the JeeNode is slightly more sophisticated, in that communication can take place in both directions. So the receiver can send back an “ack” packet, and the originating node will have some idea of whether its last data packet ever made it to the destination (note that ack’s can get lost as well – but that’s another story).

Still – the RF12 driver used in JeeNodes is just as careless as the other nodes: it starts sending the moment it feels like it – except if a packet for its own net group is currently being received. Sending packets with the RF12 driver can still easily mess up whatever is currently going on in the air.

Well, as of today, things will improve a bit further. I’ve extended the RF12 driver code to look at the RSSI status bit before starting to transmit. If a carrier is detected, even one that isn’t being recognized by the RFM12B, then transmission will be delayed a bit. Here is the latest code in the RF12.cpp driver:

Screen shot 2009-12-21 at 02.16.28.png

This isn’t perfect – nothing ever is – because most nodes will be polling very frequently and then start to send right after the carrier drops. So the chance increases that nodes two and three will both try sending when node one finishes. But let’s assume that the RSSI signal doesn’t drop to 0 for all nodes at exactly the same time. If that turns out to be insufficient, a timer-based exponential back-off mechanism can be added later.

And there is a substantial benefit: nodes will no longer mess up packets which are currently “on the air”. As more nodes are being added around here, I expect this change to cause less degradation due to collisions.

In summary: the RF12 driver is a very simple system. No CSMA/CA, no TDMA. There are definitely limits as to what it can be used for. There are some severe limits on how much data it can send, given that (on 868 MHz) each node can only send up to 1% of the time, but this is also why such a simple approach is actually quite effective. And why the RF12 driver is still just a few Kb on an 8-bit ATmega, leaving lots of room for application specific code. I happen to think that the RF12 approach strikes a pretty decent balance between simplicity and effectiveness – and I’m always open for suggestions on how to take this further.

OOK reception with RFM12B ?

In AVR, Software on Dec 25, 2009 at 00:01

Yesterday’s post described a setup to see the RSSI and DQD status bit reported by the RF12 driver in real time.

One of the interesting results is that I can see the RSSI light come on when pressing a button on the FS20 remote transmitter – even though that’s an OOK signal, not FSK!

When adjusted to run at 433 MHz, the RSSI indicator also lights up with the KAKU remote.

In both cases, the DQD signal appears useless – it just shimmers all the time.

The RSSI signal is encouraging, though. It turns out that getting it to blink reliably did depend on setting the threshold right. At -103 and -97 dBm, it was on all the time – only the -91 dBm value produced a usable signal. I hope that’s the case with all units.

Could this be used to receive FS20 or KAKU?

Well, I just had to try. My idea was to continuously poll the RSSI status bit and then “mirror” its value to a DIO output pin. Then use a second JeeNode to treat this as a normal OOK pulse train.

Here’s the “rssiMirror” sketch I used:

Screen shot 2009-12-20 at 17.07.34.png

Does it work? Unfortunately … no :(

Time to hook up the Logic Analyzer to see what’s going on. I connected the above digital output to the first channel, and a real OOK receiver on the second channel:

uuu.png

Guess what… the RSSI signal is indeed detecting the presence of a transmitted signal, but it’s way too slow!

Here’s the same sample, zoomed in on the real OOK pulse train:

ooo.png

As you can see, there’s a pretty good sequence of transitions, 400 µs and 600 µs apart. Oh well, so much for the RSSI status bit – it’s nice to detect the presence of a carrier, but not more than that.

Next thing I tried was the DQD signal. After tweaking the DQD threshold to 3, this is what came out:

eee.png

Yeah, sure, it seems to track the signal, but not reliably, and with a huge number of extra transitions. Note how the top timings are all multiples of 25 µs apart – that’s because it takes 25 µs to read out the DQD status bit. Coarse, but fine enough in principle to track 400 / 600 µs pulses from an FS20 remote.

So, again: nice, but no dice. Neither the RSSI nor the DQD status bits are fast and accurate enough to decode a slow OOK pulse train with.

Next attempt was to try and pick up the ARSSI signal, direct off the RFM12B module – as mentioned in this forum discussion. There’s a German forum which describes where to pick up that signal:

rfm01.JPG.jpeg

And sure enough, here’s a scope capture of an FS20 transmission:

www.png

Yeah, it’s there alright. But the signal is a bit weak. I’d rather not dedicate the analog comparator or ADC to it, and besides – that still leaves the need to compare against the average level – there’s a nasty 0.4V bias in that signal.

Here’s the same signal, AC coupled:

qqq.png

And here’s a zoomed-in area, showing what looks like pretty decent 400 µs and 600 µs pulses:

hhh.png

So yes, a small self-adjusting comparator can proabably turn this into a nice digital pulse train – but it’ll require some extra components, and I’m a bit out of my league on designing such a circuit.

Oh well – perhaps this information will help someone else further along. It’s been a good learning experience for me, even if the result is not quite what I had hoped…

Tomorrow, I’ll describe another – successful! – outcome from this RSSI / DQD exploration.

Power tracker – software

In AVR, Software on Dec 22, 2009 at 00:01

Yesterday’s post described a small circuit to track power consumption of JeeNodes to help optimize sketches for minimal power consumption.

Let’s put that circuit to use, with a bit of software to measure actual power consumption. The basic idea is to continuously measure current and then integrate these measurements to determine the sum of all power consumption intervals, regardless of levels.

The reason for this is that we’re not really interested in current draw but in the amount of charge consumed by the JeeNode. As far as the battery is concerned, drawing 1 mA for 1 hour is the same as drawing 100 µA for 10 hours (in the ideal case, anyway). The fancy way to say this is that we need to measure Coulombs, not Amps. Or rather micro-Coulombs, i.e. µC. That’s really easy once you realize that 1 µA is the same as 1 µC per second. Or to put it differently again: 1 mAh = 3600 mC. So a 1000 mAh battery is really nothing but a 3600 C charge.

Ok, back to the problem at hand: measuring average current draw per second.

Here is a simple sketch which does all the auto-ranging and integration:

Screen shot 2009-12-19 at 19.34.25.png

It reports averaged power drain in µA/sec (the second value is the number of samples per second). The 10% correction which I had to apply in my setup could be due to a number of factors – most likely it’s due to resistor tolerances (they are all 5%).

Here’s an interesting case with the latest rooms node:

Screen shot 2009-12-19 at 20.01.21.png

As you can see, the baseline power drain is a fantastically low 56 µA/sec in this case, but once or twice a minute it goes up to 14 mA/sec for several seconds. Not sure what’s going in here – need to investigate (now that I can!).

It would be nice to automatically detect the baseline, i.e. the average low-level sleep consumption, and things like the peak current and the percentage of the total consumption caused by such peaks. Extending the software to handle this is more work.

With slightly more elaborate software, it will be possible to place the power measurement plug between the measuring JeeNode and the JeeNode under test, and then leave it alone. A 1-day or 1-week average should give an excellent estimate of battery lifetimes.

UartPlug class

In AVR, Hardware, Software on Dec 20, 2009 at 00:01

Here is a utility class for the UART Plug:

Screen shot 2009-12-18 at 13.42.26.png

The interface is exactly the same as the Serial class, so it can be used interchangeably. Here is the updated “uart_demo” example in the Ports library:

Screen shot 2009-12-18 at 13.38.44.png

Here’s a test setup with a second JeeNode running RF12demo plugged in:

DSC_0866.jpg

Sample output:

Screen shot 2009-12-18 at 13.38.29.png

Both input and output are supported by this UartPlug class – this demo is essentially a serial pass-through.

The UART supports accurate baud rates all the way up to 230400, which is in fact beyond the current I2C rates of the Ports library. Even at 57600 baud, I’ve seen several serious overruns with the above demo. One reason is that it’s only reading out one byte at the time, going through a multi-byte I2C bus sequence for each one (!). Note also that the Serial class does not buffer its output, so it can easily bog down everything else.

The UART hardware can support both hardware handshaking and XON/XOFF throttling, so this would be another way to avoid buffer overruns.

Up to say 9600 baud the UartPlug class should work fine, even with several UART plugs on the same I2C bus.

Battery life – refinement

In AVR, Hardware, Software on Dec 19, 2009 at 00:01

Yesterday’s post described how to estimate the battery life of a JeeNode running the “rooms” sketch with the SHT11, ELV PIR, and LDR sensors. To summarize:

  • the code started out using 370 µA average current, i.e. roughly 7 months on 3 AA cells
  • of these, 200 µA were caused by the 1-second periodic wakeup “blip”
  • another 120 µA were due to the actual measurements and packets sent every 30 seconds
  • and finally, the remaining 50 µA come from the PIR + JeeNode current draw in sleep mode

Yesterday’s post was also about reducing that 200 µA blip consumption to somewhere around 20 µA.

Today, let’s tackle the other power “hog”: the 300 ms @ 12 mA spike. Here is that pattern again:

b1.png

The high peak at the end is the RF transmission of a packet, followed by a “knee” during which the node is waiting for the ack packet in RF receive mode.

Note that the main power drain is NOT caused by wireless communication!

This period of over 300 milliseconds is when the ATmega is polling the SHT11, waiting for a fresh reading. Twice in fact: once for the temperature and once for the humidity measurement.

So the explanation is very simple: we’re polling and waiting in full-power mode. Quelle horreur!

The fix requires a small modification to the SHT11 driver in the Ports library. Instead of a fixed delay, it needs to be extended to allow using an arbitrary function to waste some time. Here’s the modified code:

Screen shot 2009-12-18 at 01.00.53.png

A new second arg has been added, specifying an optional function to call instead of delay(). The code remains backward compatible, because this argument defaults to zero in Ports.h:

Screen shot 2009-12-18 at 01.02.45.png

So now all we need to do is define a delay function which goes into real power down mode for a little while:

Screen shot 2009-12-18 at 01.52.23.png

… and then adjust the two measurement calls to use this function:

Screen shot 2009-12-18 at 01.05.08.png

Does all this make a difference? You betcha:

b2.png

That’s a substantial fraction of a second in which the ATmega will draw considerably less than 12 mA. How much less? Let’s expand the vertical scale:

b3.png

Most of the time, the voltage is around 50 mV, i.e. 1 mA over 47 Ω. That’s the SHT11 current draw while active. There are two measurements – so everything behaves exactly as expected!

A couple of quick wake-ups remain, to check whether the SH11 measurement is ready. And so does the wireless TX/RX peak, of course. Here is an isolated snapshot of that RF activity (200 mV/div and 4 ms/div):

b4.png

Approximate current draw: TX = 35 mA, RX = 20 mA. Total time is about 10 ms.

Looks like we’ve reduced the power consumption of this once-per-30-second spike by perhaps 90%. As a result, the node now consumes about 20 (blip) + 20 (spike) + 50 (sleep) = 90 µA on average. Even with much smaller 800 mAh AAA cells, the battery life of these low-power nodes should now be over a year.

There are several conclusions to take home from this story, IMO:

  1. The biggest drain determines battery lifetimes.
  2. Measuring actual current profiles always beats guessing.
  3. A simple USB storage scope is plenty to perform such measurements.

If I had followed my hunches, I’d no doubt have spent all my time on getting the current draw of packet transmissions down – but as these experiments show, their effect on power drain is minimal.

There are more optimizations one could explore. There always are. But the gains will be limited, given that the ELV PIR sensor consumes 30..40 µA, and that it needs to be on at all times anyway, to be able to detect motion.

Sooo… end of story – for now :)

All source changes checked in. The entire rooms sketch still compiles to under 8 Kb of code.

Battery life estimation

In AVR, Hardware, Software on Dec 18, 2009 at 00:01

To get an indication of battery power drain, I measured the voltage drop over a 47 Ω resistor in series with the 5V supply, using a JeeNode with Rooms Board and the latest version of the “rooms” sketch.

Here’s the blip I see, once a second (100 mV/div and 20 msec/div):

on-time-1.png

That’s a 40 msec pulse of about 5 mA, in other words: 5 mA during 4 % of the time, which averages out to around 200 µA current draw continuously. Not bad, but not stellar either: it’s 4 times the sleep mode current.

Every once in a while, a much longer and bigger spike shows up:

occasional-peak.png

Which looks like roughly 350 msec @ 12 mA.

Let’s assume the big one is a real transmission. It sort of fits: the spike at the end is a brief transmission at ≈ 35 mA total, followed by a 20-ish mA period of reception (waiting for the ack to come in).

Very roughly speaking, the area of that extra spike at the end is about the same as the 5-to-10 mA step at the start of this period. So as an estimate, we’re consuming about 12 mA during 350 msec – let’s round down to 300 msec.

Let’s also assume these bigger current patterns happen every 30 seconds, when the node is reporting changed values (everything other than motion gets reported at that rate in the latest “rooms” sketch).

So 1% of the time (300 ms every 30s), power consumption is 12 mA. This averages out to 120 µA continuous current consumption.

In other words: a JeeNode running this latest rooms sketch with the SHT11 and ELV-PIR sensors, is consuming roughly 200 (blip) + 120 (spike) + 50 (sleep) = 370 µA.

Using a 2000 mAH 3-cell AA battery, this should lead to a 225-day lifetime – over 7 months.

Can we do better? Sure.

It’s basically a matter of figuring out what’s going on during those 40 and 350 msecs, respectively. Interestingly, more can be gained by improving non-transmitting “blips” than twice-a-minute high-power RF packet exchanges.

Do those 40 ms @ 5 mA every second look a bit suspicious? Yep – that’s the “idling” power level. What happens is that I was a bit too pessimistic in the time spent in sleep mode. This was the code:

Screen shot 2009-12-17 at 00.51.26.png

Looks like this is about 40 ms off, and so the code ends up waiting for the 1 sec timer to expire… in idle mode!

Let’s change this to end up closer to the desired time:

Screen shot 2009-12-17 at 02.59.16.png

Here’s the new blip (different scales):

better-blips.png

We’re down from 40 to 10 msec blips – tada!

That translates to an average 50 µA current draw from the blips, bringing the total down to 220 µA. Which translates to a 375-day battery life: over a year!

Now we’re cookin’ … but could we do even better? Sure.

Note that only the 2 ms spike at the end of the 5 mA blip is the actual active period. The time up to then we’re just waiting in idle mode – and wasting power.

We could shorten the sleep timer to 994 ms, since we don’t care whether readings are taken exactly 1 second apart. Now the RFM12B-based watchdog timer will wake us up just 2 ms short of the target time. And sure enough, the 5 mA blip is down to around 3 ms – shown here with an even further expanded time scale:

final-blip.png

But that’s silly. We’re tweaking a millisecond timer, and we’re not even interested in an “exact” 1000 ms cycle in the first place! It makes much more sense to just use the RFM12B wakeup timer to get us close to that 1 second cycle, and then immediately take a measurement. Here’s the corresponding code change in periodicSleep():

Screen shot 2009-12-17 at 02.35.36.png

Does this make a difference? Definitely:

best-blip.png

One final remark: the above battery lifetime estimates do not take into account the increased power consumption when motion is detected and more packets are sent (up to once every 5 seconds). On the plus side, when no light / temperature / humidity changes happen, the packet frequency will drop further, to once-a-minute.

The above changes have been checked into the source code repository.

Update – I just found out that the DSO-2090 scope has a high-pass low-pass filter option:

smooth.png

Sure wish I’d found out about that feature sooner… it’s so much more informative: the initial ramp is probably the clock starting up, and the little peak could well be the LDR pull-up during ADC conversion!

Rooms sketch, reloaded

In AVR, Hardware, Software on Dec 16, 2009 at 00:01

With the new easy transmission mechanism and the low power logic implemented, it’s time to revisit the “rooms” sketch, which I use for all my house monitoring nodes based on the Room Board.

I’ve wrapped the code used in POF 71 a bit further, with these two extra functions:

Screen shot 2009-12-15 at 22.25.44.png

With this, the main loop becomes very simple – even though it will now power down the RFM12B and the ATmega328 whenever there’s nothing to do for a while:

Screen shot 2009-12-15 at 22.25.57.png

The lowPower() and loseSomeTime() code is still the same as in POF 71 – this is where all the hardware low-power trickery really takes place:

Screen shot 2009-12-15 at 22.24.57.png

Note that these need an “#include <avr/sleep.h>” at the top of the sketch to compile properly.

I’ve also disabled the pull-up resistor on the LDR while not measuring its value. This drops power consumption by over 100 µA, depending on actual light levels.

A quick measurement indicates that power consumption went down from 20 mA to some 50 µA (much of that is probably the PIR sensor). These are only approximate figures, because my simplistic multi-meter setup isn’t really measuring the charge (i.e. integrated current draw), just the current draw while in sleep mode.

These changes have been checked into the repository as “rooms.pde”.

This code isn’t perfect, but since “perfection is the enemy of done” I’ll go with it anyway, for now. One difference with the original rooms sketch is that the motion sensor is not read out as often so brief motion events might be missed. Another issue with this code is that if the central node is off, a lot of re-transmissions will take place – without the node going into sleep mode in between! IOW, a missing or broken central node will cause all remote nodes to drain their batteries much faster than when things are properly ack’ed all the time. Oh well, let’s assume this is a perfect world for now.

With these levels of power consumption, it’s finally possible to run room nodes on battery power. I’ll use some 3x AAA packs, to see what sort of lifetime this leads to – hopefully at least a couple of months.

Will report on this weblog when the batteries run out … don’t hold your breath for it ;)

Update – I just fixed a power-down race condition, so this code really goes back to sleep at all times.

Re-flashing and ISP

In AVR, Hardware on Dec 11, 2009 at 00:01

This is the second of two posts about everything related to uploading, re-flashing, bootstraps, FTDI, and ISP.

Yesterday’s post described the process of uploading new sketches via USB or RS232 using a boot loader.

But how did that boot loader get into the ATmega328?

That’s a bit of a chicken-and-egg problem. Ya’ can’t use a boot loader to get the boot loader into flash memory!

This is where a lower-level hardware-based mechanism called In System Programming (ISP) comes in. ISP is a clever trick in the ATmega chip which in effect activates a special boot loader built into the hardware. This is done by holding the RESET line of the ATmega low, at which point the chip becomes essentially useless, since the reset prevents the chip from starting to run its firmware. The trick is that in this mode, some of the pins on the ATmega become an interface to that special hardware-based built-in boot loader.

So what we need to do, is to manipulate those pins to send commands which will store data into the flash memory. What we’re going to send in most cases, is the data for the boot loader in upper memory. With that boot loader in place we can then switch to “normal” uploading via the serial interface and USB.

ISP programming is also used to change “fuse bits” on an ATmega. There are a few configuration settings for the ATmega – what type of clock it uses, how it boots up, enabling a watchdog timer, etc. These are stored in “fuses” which can only be adjusted via ISP programming.

There are 3 I/O pins involved in ISP programming, plus the reset line and power. On the Arduino as well as on the JeeNode and JeeLink boards, these lines are available via a 2×3-pin ISP connector with the following layout:

ISP pins.png

The interesting thing is that you don’t even need an Arduino or JeeNode to set up flash memory and fuses. ISP is so low-level that it works directly on the pins of an ATmega chip. This is very useful to pre-load the boot loader (or test program – anything you like, really) onto a chip before soldering it permanently onto a board.

(continued…)

Read the rest of this entry »

Uploading and FTDI

In AVR, Hardware on Dec 10, 2009 at 00:01

This is the first of two posts about everything related to uploading, re-flashing, bootstraps, FTDI, and ISP.

First, our goal: what we want to do is get our software (“sketch”) from the PC/Mac into the AVR ATmega328 microcontroller on our Arduino or JeeNode. This is a fairly simple process once all the pieces are in place…

The effect is that the flash memory built into the ATmega is re-flashed. Being flash memory, your software will remain in the microcontroller even without power – ready to start again once power is applied.

There are two ways to get your software into the ATmega: In System Programming (ISP) and uploading. ISP will be described tomorrow, here we’re going to focus on uploading.

Uploading works with a “boot loader”. This is a small piece of software started after power-up (or a reset), which usually listens on the RX and TX pins of the serial interface for commands. These commands then tell it what data to store in which part of the flash memory:

Screen shot 2009-12-09 at 12.25.31.png

The surprising thing is that the boot loader itself is also stored in flash memory. It’s stored in a small (1..4Kbyte) area in upper memory, and the data it writes always goes to the lower part of memory. That’s why it’s called a bootstrap or boot loader – imagine lifting yourself by pulling on the straps of your own boots. In this case the ATmega is lifting its own functionality up by reprogramming its flash memory via its own boot loader.

(continued…)

Read the rest of this entry »

Low power mode again

In AVR, Software on Dec 9, 2009 at 00:01

After yesterday’s Wireless Light Sensor was announced, I wanted to push a bit more on the low-power front.

The POF described two simple tricks to get the power consumption from 19 to 3 mA, roughly. It turns out that a single extra step will get the idle consumption down to some 20 µA. That doesn’t mean we’re getting a 15-fold battery lifetime increase, because I’m measuring the current at idle time but not accounting for the brief periods of high-current activity which also occur. But it’s a major reduction in power consumption.

Here’s how … but this requires going a bit deeper into some low-level AVR/ATmega chip features.

First, here are some utility functions we’re going to need:

Screen shot 2009-12-08 at 10.04.31.png

The lowPower() routine disables the ADC subsystem and then enters the specified low-power mode in the ATmega. Once it resumes, the ADC subsystem setup will be restored to its previous state.

The loseSomeTime() does just what is says on the box: go into comatose mode for a more-or-less controlled amount of time. The trick is to activate the RFM12B watchdog just before passing out. This leads to larger power savings than we would have with the ATmega’s watchdog, btw – and it’s easier to implement.

The complication is that we risk losing all track of time. It’s a bit hard for an ATmega to count heartbeats when its heart has stopped beating – not only are there no beats, it’s also stripped of its counting abilities while in coma…

So instead, we estimate just how long we’ve been away from the watchdog time chosen for the RFM12B, and correct the milliseconds timer built into the Arduino. That’s what the “timer0_millis” stuff above is about. It will not be quite as accurate as before, but that’s probably acceptable for a sensor node like this one.

The last issue is that we need an indication about how long we can go comatose. I’ve added a “remaining()” member to the MilliTimer class to obtain this information.

Now, all the pieces are in place to change the code in the Wireless Light Sensor from this:

Screen shot 2009-12-08 at 10.14.23.png

.. to this:

Screen shot 2009-12-08 at 10.15.53.png

So there you have it. Most of the time between each measurement once a second, the node will now go into a very low-power mode of around 20 µA. My current measurement tools are inadequate to measure exactly what amount of charge is being consumed, which is what this is really about. So accurate battery lifetime calculations are not yet possible – but I expect it to be in the order of months now.

I’ve updated the Wireless Light sensor POF to point to this post and include this trick.

Wireless Light Sensor – POF 71

In AVR, Hardware, Software on Dec 8, 2009 at 00:01

After last week’s Hello World POF to get started, here is a new Project On Foam:

DSC_0824.jpg

A battery-powered wireless light sensor node. This is POF 71, and it’s fully documented on the wiki.

This project goes through setting up the Ports and RF12 libraries, setting up a central JeeNode or JeeLink, and constructing the light sensor node.

It also describes how to keep the node configuration in EEPROM, how to make a sensor node more responsive, and how to get power consumption down for battery use.

The POF includes code examples and uses the easy transmission mechanism, with the final responsive / low-power sketch requiring just a few dozen lines of code, including comments. The sketch compiles to under 5 Kbyte, leaving lots and lots of room to extend it for your own use.

All suggestions welcome. Anyone who wants to participate in these POFs, or in the wiki in general, just send me an email with the user name you’d like to use. I’m only restricting edit access to the wiki to prevent spamming.

FTDI Reset Supressor

In AVR, Hardware on Dec 5, 2009 at 00:01

Sometimes the simplest things are so obvious that it’s easy to miss them…

I occasionally do not want to reset a JeeNode when accessing it via USB. The reset is great for uploading, because the ATmega’s bootloader runs right after reset and intercepts such upload requests in a very convenient way. But sometimes, you just want to leave the ATmega running when re-connecting to it.

Meet the “FTDI Reset Suppressor”:

DSC_0827_2.jpg

All it does is break the reset connection between an FTDI interface such as the USB-BUB and the JeeNode.

Just to make this post a little longer, here are the steps to make one:

DSC_0827.jpg

And here is an action shot:

DSC_0828.jpg

Tada! And it’s totally voltage, baud-rate, and platform independent… :)

Update – it just occurred to me that this already exists, it’s a 5-pin stacking header! Or a 6-pin one, as follows:

DSC_0836

Hello World – POF 52

In AVR, Hardware, Software on Dec 1, 2009 at 00:01

The first Project On Foam is inevitably a blinking LED:

DSC_0814.jpg

Not very exciting, but it’ll allow me to go through the steps needed to set up the development environment, the first-time USB hookup, and getting a first sign of life out of a JeeNode in Physical Computer terms…

There is a new section on the Jee Labs wiki which I’m going to use for POFs. For rather obscure reasons, this POF is #52 (new POF numbers always increase).

Note that as Project On Foam, this Hello World example is rather silly – because it doesn’t really need a foam base at all. But bear with me – this step is intended to help people through the first (and sometimes daunting) steps of getting started.

The challenge for me right now is to provide the proper information as concisely as possible. These POFs are being placed on the wiki so they can be updated and improved. There will be a few more people involved in this, which again makes the wiki much more suitable to collect and maintain all the POFs than say this weblog. New POFs will be announced on this weblog, but updates are an ongoing process on the wiki pages themselves.

There have been a lot of experiments and projects at Jee Labs over the past year, in various stages of completion. From hooking up all sorts of sensors to the house-monitoring network currently running here at Jee Labs. It is my intention to redo a number of these as POF, in more detail and with more background information. Other POFs will be completely new, though – the list of fun stuff one can do with Physical Computing is endless!

Other news: since assembly and reflow soldering of the JeeLink and the JeeNode USB has been going a lot better lately, their price has been reduced to €29.50 (incl. VAT and shipping) – see the shop for details.

JeeNode comparison matrix

In AVR, Hardware on Nov 26, 2009 at 00:01

All the final boards are in now. It’s time to step back a bit. Let’s start with a picture:

DSC_0785.jpg

From left to right: JeeLink (v2), JeeNode USB (v2), and JeeNode (v4).

Here is a summary of the similarities and differences between these units:

jee-comparison.png

(this comparison matrix is also available as PDF)

So there you have it – one happy JeeFamily :)

Update – Nov 30: lower prices for the JeeNode USB and the JeeLink!

Update – Dec 1: added the new low-cost “JeeNode NoRF” kit.

Node, node, node

In AVR, Hardware on Nov 24, 2009 at 00:01

Ok, finally got around to building a bunch of JeeNodes for all those room boards I had waiting:

DSC_0775.jpg

Just for the heck of it, I decided to leave the boards joined together, as they come from the pcb manufacturer. This picture was taken just before separating these final units.

Small detail: on the left the original 10 µF capacitors, lying down, and on the right the new ones I will be using from now on, which are much smaller and leave the battery connection pads exposed.

The good news is that these units all worked out of the box. Great, eight of ’em will go straight to their room :)

I’m not having quite as much luck so far with the assembly of JeeLink and JeeNode USB boards, both using SMT parts. There, I often have to debug 2 or 3 out of 10 boards before they work. Occasionally, even that doesn’t solve it so once in while a board gets set aside, awaiting further debugging some other time.

It’s called “production yield”, I think, and I’m not quite there yet… oh, well.

Arduino?

In AVR, Hardware, Software on Nov 23, 2009 at 00:01

What is it? Hype? Hobby? Hacker stuff? Here is the best overall introduction I’ve seen so far – by Dave Jones. It’s 19 minutes – plenty of time to get used to his accent :)

(view directly on YouTube)

I think he really touches on all the important aspects and inevitable trade-offs.

Me, I use the Arduino bootloader for JeeNodes and JeeLinks all the time, and the Arduino IDE to compile and upload stuff to them, as well as the serial console in many cases. I do use my own editor environment – which is easy to do once you disable Arduino’s built-in one (this is not well documented, Google for “Arduino external editor”). So for me the Arduino is really the bootloader, plus the IDE just as compile/upload system.

As Dave points out, the Arduino is a wrapper around the avr-gcc compiler + avrdude in combination with a convenient USB-based upload/console/power hookup. The rest is libraries, conventions, a Java based IDE (based on Wiring), and optionally a Java-based PC-side front end called Processing.

On the embedded software side, it’s really standard full-scale C and C++.

Which is great, IMO. I can keep going with the Arduino-compatible JeeNodes and JeeLinks, and their built-in wireless, port conventions, 3.3V operation, and all the add-on plugs – knowing that much of this will work fine with as well as without all the stuff going on in the Arduino ecosystem right now.

OOK unit

In AVR, Hardware, Software on Nov 21, 2009 at 00:01

Here’s an ELV 868 MHz OOK receiver, connected to the new JeeNode USB:

DSC_0771.jpg

Note that this plug can be used for any of the four ports, simply by plugging this thing in one of the four possible orientations. In this case, it’s hooked up to port 1.

The receiver is mounted on a JeePlug for stability:

DSC_0768.jpg

There really are only three wires: GND, +3V, and the received bit stream, which is tied to the AIO pin:

DSC_0769.jpg

You can clearly see the built-in pcb antenna on these last two pictures.

The code for this is similar to the one used in an earlier post and basically runs a couple of bit decoders in parallel to recognize FS20, (K)S300, and EM10 commands. It’s available here. Sample output:

Screen shot 2009-11-19 at 15.02.31.png

Or have a look at the OOK relay, with which this plug will also work.

I really need to clean up and merge the different OOK decoding sketches – they all have slightly different capabilities…

One thing which would be very nice to do with this unit, is a general sketch which reports incoming OOK packets but which also uses the OOK sending capabilities of the RF12 driver to send out such packets, to control FS20 devices for example. That mould make this a general-purpose bi-directional 868 MHz OOK unit, connected via USB and controllable via simple serial-port commands.

I’ll punt for now. Don’ have time to go into this. Or perhaps I should say… exercise left for the reader :)

And maybe one day we’ll get OOK input going without extra hardware ?

PS. Good news: everything is now in for the JeeNode USB, so I’ve started shipping them.

New RF12demo

In AVR, Software on Nov 19, 2009 at 00:01

An updated version of the RF12demo sketch has been checked in. Also available as ZIP.

This adds preliminary support for the 1 Mbyte dataflash memory present in the JeeLink v2.

The idea is very simple: the RF12demo app reports all incoming packets as before, but now also stores all valid packets in flash memory, if present. This is done by collecting packets into a 248-byte RAM buffer, and saving it to flash whenever it fills up. Small portions at the high and low end of flash memory are reserved for future use, the remainder is treated as a circular buffer of 256-byte pages – 3808 to be exact (i.e. 952 Kbyte).

The RF12demo commands have been extended accordingly, here is the startup screen on a JeeLink v2:

Screen shot 2009-11-18 at 18.33.06.png

There is a “DF” line at the top which shows that dataflash memory was found, with page #41 written to last, and that we’re in the 3rd reboot since the flash was wiped. This unit picks up incoming data in group 5 @ 868 MHz.

The new “d” (dump) command reports which pages contain data:

Screen shot 2009-11-18 at 18.31.34.png

At this point, I did a reset of the JeeLink, and then left it on to collect some more data. Here are the last few lines of a subsequent dump:

Screen shot 2009-11-18 at 18.45.14.png

The new entries were added starting on page 42, and the clock started at zero again (there is no RTC). Some 248 seconds later, new entries were logged on page 43. The last number on these lines is a page checksum, btw.

The new “e” (erase) and “w” (wipe) commands require specific constant values as input arguments so that these destructive commands are not activated by a mere typo.

So far so good. The JeeLink can now keep track of what is coming in. But that’s just half the story. We also need to be able to get data out again, “replaying” the log from a certain point. This takes a bit more work.

Firstly, whenever a page gets saved to flash, something like this is sent out to USB:

Screen shot 2009-11-18 at 18.45.52.png

This means that page 44 with seqnum 3 was saved with some entries starting at time 505 (seconds since the JeeLink was powered up). Here are the last few lines of a dump made right after that save:

Screen shot 2009-11-18 at 18.46.18.png

The sequence number is an integer which increments on each reboot, and whenever the flash memory buffer wraps back to the first page. So the combination (seqnum,time) is unique and monotonically increasing, over time and across reboots.

On the PC side, these DF “packets” should be treated as readings and stored like any other incoming packet.

To get the saved entries out of the JeeLink, the PC has to send a “replay” command when it connects to it. This replay command must contain the last sequence number and time stored on the PC for the above DF packets. The JeeLink will look for the location of this page in flash memory (or the earliest one thereafter) and will then replay everything stored from there on.

This code is still work-in-progress, but the plan is to replay these packets as lines starting with “R seqnum time” instead of the usual “OK” prefix. Replay takes place at full speed, but depending on the amount of data stored this can still take a substantial amount of time.

After the requested data has been replayed, the JeeLink resumes its normal mode of reporting “OK” packets, “?” checksum errors, and “DF S” save commands.

I haven’t finished implementing the replay command yet, but storage of incoming packets seems to be working, so an updated version will be able to get at that stored data later.

One last point to note is that this storage implementation has built-in automatic “wear leveling” and hence creates no “hot spots”: there is no page in flash memory which gets written to more often than others, so this memory will be usable for at least its full 100,000 rated cycles. This is done by scanning the entire flash memory on startup to determine the last page written to, and by erasing 4 Kbyte blocks only when needed, ahead of the write pointer.

Total size of the new RF12demo is under 10 Kb, so there’s still lots of room left.

Update – several fixes and replay code added. Not 100% right yet, but all functions are implemented now.

Arduino plug stack

In AVR, Hardware on Nov 13, 2009 at 00:01

You could combine all these …

DSC_0750.jpg

… and create an Arduino sandwich like this – with full access to all the Arduino pins:

DSC_0751.jpg

That’s a Plug Shield with, from left to right / top to bottom:

Each of the plugs can be accessed via I2C, i.e. using the Arduino’s “Wire” library.

Would all this work? Yes, I’m pretty certain it would.

Would it be useful? Probably not in this combination…

I just wanted to show off the I2C plugs and shield ;)

Build and pinout errors on older posts

In AVR, Software on Nov 8, 2009 at 00:01

There has been an unfortunate dependency between the Ports library and the RF12 library for some time now, causing the Arduino IDE to generate errors such as these:

ide-errors.png

(etc…)

The workaround right now is to include both in your sketch, even if you only need one:

Screen shot 2009-11-04 at 10.50.42.png

I’ve been planning to do a major overhaul of the library and software in general, but until then this is the way to avoid those pesky errors. It probably affects quite a few sample sketches on this weblog.

Another thing to watch out for (thanks, Ian!) is that some older examples on this weblog use the JeeNode v2 or even v1, which have a different pinout. To uses those examples with the latest JeeNodes, you have to swap pins 4 and 5, i.e. +3V and AIO.

Please let me know when examples from earlier weblog posts don’t work as described. A small fix and note added to these posts might be all that is needed!

LCD Plug

In AVR, Hardware, Software on Nov 1, 2009 at 00:01

Here’s the new LCD Plug:

DSC_0722.jpg

It’s a little piggy-back board for standard LCD modules with 16-pin connectors. The middle 4 pins are not connected, so that two 6-pin male headers are in fact enough to hook this board up to the LCD.

Here is a setup using a 2×16 character display:

DSC_0721.jpg

The interface uses I2C, so this “plug” can be daisy-chained like all the others. The plug uses an I2C expander chip with a fixed I2C address of 0x24. There are two jumpers to select the voltage level for driving the logic supply and the backlight, respectively. The backlight can be turned on and off under software control.

A generalized version of the LiquidCrystal library included with the Ardiuno IDE 0017 is used to redirect the actual interface through a bit-banged I2C bus, using the Ports library. This was described in an earlier post. Details about how this code works are also available, see this post.

The latest Ports library now includes the new code, including the “lcd_demo” example as shown above:

Screen shot 2009-10-31 at 16.06.14.png

The only difference with the LiquidCrystal example is the definition of port 1 as I2C bus, and defining the “lcd” object to connect to the display via this I2C bus.

Updated RF12demo

In AVR, Software on Oct 29, 2009 at 00:01

The RF12demo software which comes pre-loaded on all JeeNodes and JeeLinks has been extended a bit:

Picture 1.png

The new commands are:

  • l – to turn the activity LED on or off, if present
  • f – send a FS20 command on the 868 MHz band
  • k – send a KAKU command on the 434 MHz band

The new FS20 and KAKU commands were added so that a JeeLink can be used out-of-the-box to control the commercially available remote switches of these types. The updated demo is included with all new JeeNodes and JeeLinks from now on.

For example, to turn on channel 1 of a FS20 unit with housecode 0x1234, you can type in “18,52,1,17f” – i.e. the house code in bytes, the channel, and 17, which is the “on” command. Likewise, to turn on channel 1 of group B on KAKU, type “2,1,1k”.

The KAKU transmission range is not very high because the RFM12B radio used is tuned for the 868 MHz band, but even more so because the attached wire antenna is completely wrong for use at 434 MHz. If you want to use this for controlling KAKU devices and don’t get enough range, try extending the antenna wire to around 17 cm, i.e. double its current length. You can just attach an extra piece of wire to the end.

Which – unfortunately – is going to substantially reduce the range at 868 Mhz… so if you really want to use both frequency bands, you’ll have to use two JeeNodes or JeeLinks, each with their own properly sized wire antennas.

For more info about FS20, see these posts on the weblog. For KAKU, see these.

Four generations

In AVR, Hardware on Oct 26, 2009 at 00:01

After one year, I thought it’d be nice to compare all the JeeNode versions which have come out – up to and including the latest v4:

DSC_0581.jpg

Here is the back side of each of them:

DSC_0582.jpg

The back side in particular illustrates the evolution which has taken place this year.

In version 1, there were no labels – mainly because I hadn’t figured out how to do those and I was eager to just see the darn thing work

Version 2 added some minimal labeling (in copper, to save on production charges!) and a ground plane. Port pairs 1+4 and 2+3 were moved 0.1″ further apart. The mounting holes were dropped.

Version 3 was really the first production-ready one. It added lots of text on the component side, plus a bit of eye candy by going for blue solder masks. I switched to yellow wire for the antenna, to help remind me that this is the version with the final port and pin layout – the one which matches all the new JeePlugs. Version 3 did get the silkscreen for the regulator wrong, but it also made it to the Make Magazine weblog – cool! :)

Version 4 now takes this evolution to its logical conclusion: a clear visual “identity” in the form of blue-and-gold color choices and lots of labels on both sides of the board. No more guessing! The PWR/I2C connector moves a bit and is augmented with two more pins. This JeeNode is the narrowest of all, it now has precisely the same width as all the plugs (21.1mm / 0.83″). This is the grown-up version at last, focusing on actual usage convenience along with a proud & pleasing appearance.

It’s time to move on. The JeeNode is done.

Assembly service

In AVR, Hardware on Oct 24, 2009 at 00:01

It’s time to try something new!

Sometimes, this DIY electronics stuff can be a bit daunting. Maybe you’ve never soldered microprocessor circuits before. Or maybe you’re worried about that RFM12B “SMD” module on the JeeNode. Or maybe you just want to get going fast, and not spend your time on the hardware side of things.

Meet the new Assembly service option:

DSC_0676.jpg

For a small fee, I’m going to offer to assemble JeeNode kits for you, as well as soldering headers onto any of the plugs available from the shop.

This can help more people get started on this wireless and sensor hookup stuff. And it lowers your risk – you could get two kits, have one of them assembled, and build the other one yourself. Or if you don’t care about soldering at all, just get all the pieces you want to hook up in assembled form.

In fact, I’m going to extend this new service even further: if you get a kit to build yourself and it turns out that you can’t get it to work, then you can send it back and I’ll assemble / finish it for you. I can only do this if all the components are still undamaged, otherwise you’ll need to get a replacement kit. Since I don’t know whether this will work out, nor whether I can handle such a “return/repair” flow of items, I will only commit to do this until the end of November. If it works well enough, I’ll prolong this service.

The reason for doing this is not to add a massive amount of assembly to my workload, but to help people take the plunge with less risk. Especially if you’re new to all this physical computing stuff and electronics, I think you’ll find out that assembling kits can be a lot of fun and very rewarding. But hey, if you’re in doubt, just get a kit and some assembled parts so you don’t have to worry about everything at the same time.

OOK relay, revisited

In AVR, Software on Oct 21, 2009 at 00:01

The OOK relay to pass on 433 and 868 MHz signals from other devices has been extended:

DSC_0665.jpg

Spaghetti!

The following functions are now included:

  • 433 MHz signals from KAKU transmitters
  • 868 MHz signals from FS20 and WS300 devices
  • the time signal from the DCF77 atomic clock
  • pressure + temperature from a BMP085 sensor

Each of these functions is optional – if the hardware is not attached, it simply won’t be reported.

The BMP085 sensor in the top of the breadboard could have been plugged directly into port 3, but it’s mounted on a tiny board with the old JeeNode v2 pinout so I had to re-wire those pins.

Sample output:

Picture 1.png

There are still a few unused I/O lines, and additional I2C devices can be connected to port 3. Room to expand.

The source code for this setup is available here. It compiles to 10706 bytes, so there is plenty of room for adding more functionality.

This code includes logic for sending out the collected data to another JeeNode or JeeLink with acknowledgements, but I’m working on a refinement so it gracefully stops retransmitting if no receiver is sending back any acks.

As it is, this code will forever resend its data every 3 seconds until an ack is received, but this doesn’t scale well: all the “rooms” nodes do the same, so when the central receiver is unreachable every node will keep pumping out packets while trying to get an ack. It would be better for nodes to only re-send up to 8 times – and if no ack ever comes in, to disable retransmission so that only the initial sends remain.

I’m also still looking for a way to properly mount all this into an enclosure. There is some interference between the different radio’s, maybe all in one very long thin strip to maximize the distances between them?

An OOK relay

In AVR, Hardware on Oct 12, 2009 at 00:01

After having hooked up OOK radios in a few ways, I’ve decided to create an “OOK relay” – a little unit which listens for OOK-encoded data on the 433 and 868 MHz bands, and then re-transmits the decoded data as “normal” packets via the RF12 driver. OOK stands for “On-Off Keying” as opposed to the more advanced FSK – “Frequency Shift Keying” used by the RFM12B’s – i.e. AM vs. FM.

The benefit of an OOK relay is that OOK reception then automatically gets integrated into all the data collection from other JeeNodes that’s already going on anyway. Since an RFM12B can send both 433 and 868 MHz OOK signals, the end result is a pretty complete solution for all sorts of things going on over the air.

Here’s the hardware test setup:

DSC_0650.jpg

The 433 MHz receiver is seen from the side, standing almost straight up with the white antenna wire. It’s connected to DIO of port 1. The 868 MHz receiver is lying flat, with the red antenna wire, and is connected to AIO of port 1. Both receivers are powered from the 3.3V supply.

The reason for this particular setup is that I can use two different pin change interrupts for both: PCINT1_vec for 868 MHz and PCINT2_vec for 433 MHz. No need to decide inside the interrupt routine which is which – this saves some interrupt routine overhead.

The code was created from the two existing decoders for these receivers, and will be made available once everything is finished. Right now, the decoders work happily alongside each other:

Picture 3.png

Sample output:

Picture 2.png

I cheated a bit though by selectively powering the receivers, because there is a hardware problem… it looks like these receivers are interfering with each other. They only work when the other one is off. It’s not that surprising, given that one frequency is almost an exact harmonic of the other. Maybe placing the two receivers physically further apart, or adding better RF power supply decoupling will fix it. They should be able to work together, even receive signals on the two frequency bands at the same time.

More work left to do…

Experimentation setup

In AVR, Hardware on Oct 11, 2009 at 00:01

After coming up with the JeeBoard, which needs a PCB with at least an I/O expander and two LEDs/switches, I decided to go one step simpler and just wire up a version with no active components at all:

DSC_0565.jpg

It connects the same 3.6 .. 4.5 V battery pack through a slide switch, and ties a breadboard to the AIO + DIO pins of ports 1 .. 3, along with +3V and GND. With a few headers placed flat on the board for various plugs.

Wiring this up is simple – note the added rubber feet:

DSC_0566.jpg

Now it’s ready to go, with 3 rechargable NiMH’s:

DSC_0568.jpg

And here’s the final setup:

DSC_0571.jpg

Just to show how you can go nuts with plugs:

DSC_0570.jpg

The battery pack connection is removable to give me a nice spot to insert a current-measuring multimeter.

First demo of this board coming up tomorrow…

Expander Plug, revisited

In AVR, Hardware on Oct 9, 2009 at 00:01

Got some revised plugs. The Expander Plug now works:

DSC_0626.jpg

Here’s a sketch which blinks all pins on the expander:

Picture 3.png

I forgot to check the A0 solder jumper orientation, so I accidentally wired my first plug up for address 0x21 instead of 0x20. Each Expander Plug can be configured for I2C addresses 0x20..0x23, i.e. up to 4 expander plugs can be daisy-chained on each port.

Expander plugs work nicely with the Breadboard Connector, to hook up a mini-breadboard like this:

DSC_0627.jpg

The width of a mini-breadboard is slightly less than an Expander Plug + sideways headers, so daisy-chained plugs can each have their own breadboard.

In summary: the Blink, Expander, Memory, RTC, and UART Plugs all work. So do the unpopulated Proto Board and Breadboard Connector, of course.

More news about prices and availability in the shop tomorrow… once I finish my homework and figure out a few remaining pesky little details and logistics issues.

More serial ports

In AVR, Hardware on Oct 4, 2009 at 00:01

Here’s an easy way to add more serial ports via I2C:

DSC_0547.jpg

I got the wrong crystal size, so it’s mounted a bit awkwardly:

DSC_0548.jpg

There are two jumpers, allowing up to 4 serial ports to be added to each I2C bus – i.e. up to 16 on the bit-banged I2C buses, and 4 more on the hardware I2C line. Since the A0/A1 jumpers actually support up to 16 addresses with a bit of extra wiring, you could theoretically connect up to 80 serial ports to a single JeeNode!

Here’s some sample code:

Picture 5.png

It sets the serial port to 57600, 8 bits, no parity and then sends whatever comes in to the “normal” serial port. The default fast I2C bus rate of over 1 Mhz appears to work just fine.

The header of the UART plug is compatible with FTDI, so you can hook up another JeeNode to it:

DSC_0559.jpg

In this case, I used a JeeNode with a room plug prototype. Sample output:

Picture 3.png

This demo code has been added as “uart_demo” example in the Ports library and is also available here.

Voltage Plug

In AVR, Hardware on Oct 2, 2009 at 00:01

The Voltage Plug generates up to four 0 .. 3.3V levels using MCP4725 12-bit DAC’s controlled from I2C:

DSC_0546.jpg

This sketch switches between 0 and 4095, displaying as 1.2 mV and 3.295 V on my multimeter, respectively:

Picture 1.png

The cycle time was set to 5 seconds to give my auto-ranging multimeter time to adjust itself.

There is room for 4 DAC chips, which seems like a bit of overkill, but I couldn’t think of anything else to put there and the board looked so empty :) – perhaps some sort of voltage-follower op-amp or amplifier stage would make more sense? Anyway, I’ll probably remove two of those chips from the plug again.

The MCP4725 only has one pin to specify the lower address bit. There are in fact 4 different chips available from the manufacturer, to support up to 8 DAC’s on a single I2C bus. Since I got the “A3” version – and since I mixed up high and low again – this particular test uses address 0x67. For the final version I’ll fix the low-address bit and use “A0” versions, i.e. 0x60 and 0x61.

Analog Plug

In AVR, Hardware, Software on Sep 30, 2009 at 00:01

The second plug panel has arrived. I’ll document my test results in the coming days.

First, the Analog Plug – an 8-channel 12-bit ADC connected via I2C:

DSC_0545.jpg

It’s based on the ADS7828 chip. Here’s a demo sketch to read it out:

Picture 3.png

I hooked it up using various gimmicks lying around here – this ties a trim pot to channel 4, with range 0 .. 3.3V on the wiper:

DSC_0544.jpg

As you can see, the Breadboard Connector can be used to hook up to 8 of the 12 pins of this plug.

Here’s some sample output:

Picture 1.png

I slowly turned the wiper as you can see. It stops at 4095 counts, which represents the 2.5V of its internal reference. Appears to work fine in this test setup at the maximum I2C rate, somewhere over 1 MHz. The readings didn’t change by more than one count when touching various parts of the circuit, so as first impression it looks like it’s pretty stable.

This plug has two solder jumpers, to configure its I2C address to 0x48 .. 0x4B, which in hindsight is a bit overkill. Only minor nit is that I mis-labeled the A0 jumper – as shown in the picture, the address ends up being 0x49 i.s.o. 0x48. Oh well, a small silkscreen fix will resolve that later.

So there you have it – eight 3.5 digit voltmeters on one tiny blue-and-gold plug :)

LCD display via I2C

In AVR, Software on Sep 28, 2009 at 00:01

Ok, it’s working – always takes longer than expected, especially if you mess up in both hardware and software!

DSC_0534.jpg

There’s a miniature trim pot on the left to set the contrast level. I haven’t yet added the transistor to turn the backlight on and off.

Note that with an MCP23017 chip there are 9 I/O lines available for other purposes. On the upcoming LCD Plug, I’ll probably use the smaller MCP23008 instead.

This particular setup works at the maximum I2C bus speed supported by bit-banging, which should be well over 1 MHz – I haven’t measured it. If the bus is long or is shared with slower peripherals it can be lowered to 400 KHz or 100 KHz by specifying an extra argument in the PortI2C constructor.

The sample code is available here. It will be integrated with the Ports library later.

PS. There are a few days left for the special offer in the shop. If you’ve ordered before or have participated on this weblog or in the forum, you can get 20% off until the end of September. Email me for a discount code.

Generalized LiquidCrystal library

In AVR, Software on Sep 26, 2009 at 00:01

Let’s dive into some C++ code for a change…

The Arduino version 0017 IDE has a nice library for driving standard character LCD’s, called… “LiquidCrystal”. The nice thing is that it mixes in the print() / println() functionality which is also used in the Serial library.

That makes it very easy to change a sketch to use either the serial port or the LCD screen to display results. Here’s how – let’s say you used this code in your sketch to print a value to the serial port:

Picture 2.png

The first thing to do is to generalize this slightly:

Picture 3.png

Functionally, nothing has changed. That’s the whole point, because you can develop and extend the sketch while testing everything via the serial port, as usual. Just use “Output” everywhere.

To change the output to the LCD, replace that “#define” line by the following lines of code:

Picture 4.png

This adds a bit of logic to easily switch between serial and LCD, without having to change a thing in the rest of the sketch. The “(2, 3, 4, 5, 6, 7)” parameters have to be set to the pin numbers actually used for your specific setup, of course.

So far, so good, although none of this applies to the I2C-connected LCD I’m working on. But by extending and re-organizing it a bit, it is possible to re-use most of the code of the original LiquidCrystal library.

The first thing I had to do was to rip apart the general and the pin-specific logic. That’s where C++’s abstract base classes and virtual member functions come in. I created a new “LiquidCrystalBase” class which has all the original code except for the pin-specific parts:

FlySketchExport.png

The “virtual … =0” is C++’s funny way of saying it doesn’t need definitions for these three functions yet. The result is an incomplete class – you can’t create objects of type LiquidCrystalBase, you can only derive other subclasses from it. Tricky stuff, but bear with me…

Note that all the pin-specific member variables have been removed as well.

The next step is to re-define the original LiquidCrystal class in terms of LiquidCrystalBase:

Picture 5.png

If you compare this to the original code, you’ll see that most functions member definitions are missing. That’s because they have already been defined in what is now LiquidCrystalBase, and the new LiquidCrystal inherits everything from it.

What LiquidCrystal does add, is a definition and implementation for each of the virtual config(), send(), and write4bits() members. It is sort of “filling in” the missing functionality. So the result is… a LiquidCrystal class which does exactly the same as the original.

That seems pretty useless, but it isn’t – what we now have is a generic part and a specialized part. Which means it is now very easy to implement a variant which works exactly like the original, but going through the I2C port interface instead:

Picture 6.png

Nice. Only a little bit of new code was needed to create a completely different hardware interface which is fully compatible with the original LiquidCrystal class.

Here’s the original example, using this new LCD-via-I2C library:

Picture 8.png

Note that the I2C port is available as “myI2C” and can be shared with other devices by defining them here as well. You could even daisy-chain multiple LCD displays on the same port if you wanted to.

That’s all there is to it. The sketch code itself remains the same. Welcome to the world of abstraction, à la C++ !

Update – the final version and source code are described in this followup post.

Clock Plug v1

In AVR, Hardware on Sep 20, 2009 at 00:01

The Clock Plug adds a real-time clock to a JeeNode:

DSC_0507.jpg

A demo for setting it and reading it out follows:

Picture 2.png

Unfortunately, there seems to be a problem with it – it does not start up reliably, and connecting the backup battery makes it stop?

Oh, wait – the DS1307 is specified for a 4.5 .. 5.5V power supply, and I’m driving it from the 3.3V line! And yes, sure enough, it works fine when powered from 5V.

Whoops!

Time to look for another chip. Ah, looks like there is a pin-compatible one which does work at 3.3V – here’s a post from someone who fell into the same trap.

Update – the DS1340Z works fine, see this followup post.

Memory Plug v1

In AVR, Hardware on Sep 19, 2009 at 00:01

The Memory Plug adds flash memory to a JeeNode:

DSC_0505.jpg

This particular one has 2 different brands of 512 Kbit chips on it: a AT24C512B by Atmel and a M24512 by STMicroelectronics, for a total of 128 Kbyte. By fully populating it with 1 Mbit chips, this plug can contain a whopping half megabyte of memory :)

Here’s small sketch to test reading and writing to it:

Picture 1.png

A value will be incremented each second. When restarted, the value will continue to increase since the last setting, demonstrating the non-volatile memory. The demo uses I2C address 0x50 to address chip #0 – chip 1 #is at 0x52, chip #2 at 0x54, and chip #3 at 0x56.

This demo is available as the eemem example in the Ports library.

Here’s the plug hooked up to a JeeNode:

DSC_0506.jpg

This plug supports daisy-chaining of more I2C-type plugs.

So there you have it – a Solid State Disk!

Boot loader problems

In AVR, Software on Sep 11, 2009 at 00:01

Whoops – I messed up with several packages I’ve sent out to people. Ouch.

The gory details are in the discussion forum, but here’s the short version:

  • I’m shipping ATmega’s pre-programmed with the Arduino bootstrap and the RF12demo sketch. Mighty convenient, since it can get you going a lot quicker.
  • And to simplify my work I, ehm… sort of tried to automate it a bit.
  • So I burn the bootloader with the Arduino IDE and the burn the RF12demo sketch using “avrdude” from the command line.
  • Cool. Except that the second step undid the work of the first step… doh!
  • So I ended with ATmega328’s which have the RF12demo but no bootstrap loader.

It turns out that avrdude erases a chip by default when re-programming it. So the bootloader, which is loaded in high-mem, got cleared when storing the demo in low-mem. And of course that doesn’t show in a quick test: the demo on the chip, which I always check, works just fine. Which is why I sent out a few bad JeeNode kits and JeeLinks.

All it took to fix this was one lousy little “-D” command option for avrdude!

So now I’ve decided to automate all the way, and burn the fuses, the bootloader, and the demo sketch all in one go – from the command line.

Here’s what it takes – I have these files in one directory:

Picture 1.png

The hex files were copied from the Arduino “bootstrap” area and the RF12demo “applet” build area, respectively.

The makefile contains these commands:

Picture 2.png

So all I need to do now is to plug in the ISP programmer and put a fresh ATmega chip in its socket, then type “make”. This works for both the JeeNode and the JeeLink chips.

Easy… once done right!

Smaller still?

In AVR, Hardware on Sep 9, 2009 at 00:01

Now that the JeeLink is a reality, and SMD has become an option, I’m already wondering how far to take this…

Because, well, there’s this neat USB stick case available:

DSC_0491.jpg

I suspect that the same FTDI + ATmega + RFM12B as on the JeeLink can be fitted in there, but at the cost of omitting all expansion. No ports, no headers, no reset, nothing – but nevertheless an Arduino / JeeNode / JeeLink compatible unit.

There may even be room for a few Mb of flash memory. So this could be used as central interface to a PC/Mac, and it could collect data while the computer is off – as long as the USB port is on (a powered hub perhaps).

Would it make sense to create a separate unit for this? Just for the wow factor? Let me know, please…

Final JeeLinks

In AVR, Hardware on Sep 8, 2009 at 00:01

After the goof-up of not heating the boards up enough for lead-free solder, I simply re-did the reflow with a 250°C temperature profile. This appears to be near the limit of what my reflow grill can do, btw.

Here’s a fully assembled JeeLink:

DSC_0490.jpg

Note that I soldered all headers in, including two which aren’t supplied standard with the JeeLink:

DSC_0489.jpg

As shipped, the JeeLink comes with the 4 port headers, not yet soldered in.

While it still takes me quite a bit of time to assemble these JeeLinks, all four of the ones I did are now working (ahem, that’s a lie: I shipped two JL’s without proper testing… impatient as I was!).

So this story has a happy ending – the JeeLinks are ok now, it’s time to move on …

Meet the JeeBoard

In AVR, Hardware on Sep 2, 2009 at 00:01

I hate wires. Wires to power up stuff. Wires to transfer data. What a mess.

I just want to try out physical computing ideas on my desk, next to my (wireless) keyboard and my (wireless) mouse – while exploring the possibilities of hardware + firmware + software running on my “big” computer.

So here’s to scratching my own itch: meet the JeeBoard – a little 8×10 cm unit with no strings attached – heh ;)

pastedGraphic.png

A first mock-up with real parts, here still using a green JeeNode v2:

DSC_0469.jpg

On the left, a couple of demo plugs have been inserted. Those that use I2C can be daisy-chained.

One port is permanently hooked up to an I/O expander chip with 6 digital I/O lines for the mini-breadboard, 2 LEDs, and 2 pushbuttons. The on-board battery pack provides 3.6V with NiMH or 4.5V with alkaline cells.

The little overhanging board on top of the mini-breadboard “feeds” 8 wires into the center of the breadboard: +3.3V, ground, and the 6 general-purpose I/O lines.

I’m going to mess around with the layout a bit and explore some actual hookups before designing a real PCB for this. But even just looking at the mockup makes me want to start trying out stuff with it. Wireless, of course!

JeeNodes now with 328

In AVR, Hardware on Aug 31, 2009 at 00:01

Starting now, I will be replacing the ATmega168 by the ATmega328p in all future JeeNode kits:

DSC_0467.jpg

Twice the memory: 32 Kb flash, 1 Kb EEPROM, and 2 Kb RAM – and twice the creative fun!

JeeLink issues solved

In AVR, Hardware on Aug 23, 2009 at 00:01

It turns out that there were two problems with the new JeeLink boards, one major and one minor.

The reason why my assembled JeeLinks wouldn’t show up as USB devices is that the FTDI chip’s TEST pin was left floating instead of being tied to ground. It’s trivial to fix: a small dab of solder between pins 25 and 26 of the FTDI chip does the trick. Now all but one of my 6 JeeLinks show up as USB devices – yeay!

The second problem is not as critical: the +3.3V pin of all ports isn’t actually connected to anything… whoops. But this too is relatively easy to fix – a small wire from the VR output to the +3V pin on port 2 will fix it.

Thanks to Paul Badger of Modern Device and Marius Kintel for helping out and coming up with suggestions. I’m regaining my sanity now…

DSC_0449.jpg

In the coming week, I’ll send out new JeeLinks to everyone who pre-ordered these units. I’ve run out of SMD LEDs, so I have to replenish my (limited) supplies before assembling and testing more boards.

But rest assured, they work and pass all tests. There are several JeeLinks on my desk right now, each of them running as intended.

To celebrate this milestone, all JeeLinks will be shipped with ATmega328’s instead of 168’s – including all the pre-ordered units.

Update – the above two issues and their fixes have been documented here.

Lots of nodes

In AVR, Hardware on Aug 22, 2009 at 00:01

I’m gearing up to install over half a dozen nodes around the house to monitor temperature, humidity, light levels, and to detect motion:

DSC_0444.jpg

The plug at the bottom is a one-off to check out the connections for the EPIR version.

These are my last JeeNode v2 boards, salvaged from various experiments, with all their port headers replaced by the new 6-pin-female-up standard.

Given that these are v2 boards, I’m hand assembling the plugs to match the “old” port pinout. Beyond these, I’ll use the new v3 boards with a little pcb “room plug” to be created later.

Back to soldering a few more of these little sensor critters!

JeeLink status

In AVR, Hardware on Aug 21, 2009 at 00:01

The plot thickens… and I’m pulling my hairs out along the way.

The good news is that I have assembled 6 boards now, and they all behave in (nearly) the same way. The on-board ATmega is working and correctly running the blink test sketch installed when setting up the boot loader via ISP.

So the basics work. The voltage regulator is probably also ok.

The bad news is that none of these 6 boards is showing up as USB device. Whoops.

I’ve gone through a couple of build techniques, from reflow to hand-soldering, as well as various combinations. But after some obvious solder bridge removals and a few loose connections after hand-soldering, at least 5 of these boards exhibit identical behavior. I’m either getting it right or consistently doing something wrong.

Also found a problem in the PCB traces, i.e. a trace between 3.3V power and the 3.3V pins on all 4 ports is missing. But this is relatively minor – a tiny extra wire should fix that.

I’m at the point where I really need to step back to re-think what else could possibly be wrong. It must be some silly / stupid oversight… I’m still hopeful that the aha-slap-on-the-head-erlebnis will come soon.

Meanwhile, I’m also exploring some alternatives. Today, I visited a nearby “Fab Lab”, which has laser cutters, CNC routers, 3D-printers, and more such mind-blowing geek stuff. Absolutely fascinating – I’ll never look at an object in the same way again. Any object.

One of the things I wanted to try out is to create SMD stencils like the big boys do. A first trial on cardboard, paper, and 0.5mm polystrol came out as follows:

DSC_0443.jpg

The layer on top was my first attempt, using thin cardboard. As you can see, it’s not quite perfect since the holes are too large – there is no vector adjustment for the 0.1mm laser beam overhead. Then again, the plain paper example in the middle shows decent separation, and having paste overlap is not necessarily a problem.

I’ll try some more adjustments next time and will get a bottle of paste with squeegee to play around with this stuff. Who knows, maybe even a 1-time use plain paper sheet can work?

LED polarity

In AVR, Hardware on Aug 17, 2009 at 00:01

Ok, first puzzle solved. I had the two 0603 LEDs reversed.

The silly part is that I had actually built a test rig to make sure this wouldn’t happen:

DSC_0433.jpg

As trivial as it gets: a battery with a series resistor. By holding the SMD LED against two copper contacts it’s easy to check which side is which. Here’s a green LED lighting up:

frame3.jpg

Then I got confused and placed all the LEDs exactly the wrong way around – doh!

There are three copper pads. The middle one is PLUS, the other two are GROUND.

Ok, now the RX+TX LEDs blink a few times when plugged in. Onwards!

JeeLink build woes

In AVR, Hardware on Aug 16, 2009 at 00:01

Ok, I’m back. The Jee Labs blog resumes…

This first post is a progress report on the JeeLinks. Here are three partial builds (the bottom one has some hand-soldered parts, the rest use reflow soldering):

DSC_0432.jpg

I had to remove some solder bridges from the FTDI chips, but apart from that everything looks pretty tidy now. The JeeNode-based reflow controller is working very nicely.

Here are a couple of extreme close-ups:

frame1.jpg

frame2.jpg

frame4.jpg

frame5.jpg

Unfortunately, I’ve not been able to get any of these boards working so far. The FTDI chip ought to be visible as a serial USB port, even if the MPU isn’t working properly, but it isn’t showing up.

I’m probably missing something but for now it’s bad news. I’ll continue debugging this, of course…

Building the JeeNode v3

In AVR, Hardware on Jul 15, 2009 at 00:01

The v3 boards are finally ready! Here’s a step by step overview on how to assemble a JeeNode v3 kit:

DSC_0427.jpg

You’ll need some basic skill at soldering but don’t worry, as there are only a few parts to solder on. The best way is to start with the lowest-profile part, that way you can place things flat on the table and press down to keep the parts in place. So let’s start with the 10 KΩ resistor:

DSC_0408.jpg

Turn the board around and solder the leads:

DSC_0409.jpg

Then carefully cut them off:

DSC_0410.jpg

Continue in a similar vein with the four 0.1µF ceramic capacitors:

DSC_0413.jpg

Next the IC socket, which is a bit more work. The best thing is to solder two diagonally opposite pins, then check that the socket is pushed in all the way:

DSC_0414.jpg

If not, reheat and fix it. Then solder the remaining 26 pins:

DSC_0415.jpg

The 10 µF electrolytic capacitor is polarized – there is a “+” marking to indicate which way it should be soldered in. I normally bend the leads first and then make it lie flat on the board:

DSC_0416.jpg

Next the voltage regulator IC. This one needs special attention because it has to be mounted differently from what the marking on the board says. The reason is that the board was designed for an LP2950, but the kit includes an MCP1702 which has a different pinout. Here is how it should be mounted:

DSC_0417.jpg

The 16 MHz resonator is next, it’s the tallest part on the board:

DSC_0418.jpg

You’re almost there now. The radio module is a surface mounted module, which needs a slightly different approach. Put a bit of solder on one pad, then place the module over it and reheat to stick it in place:

DSC_0419.jpg

Once correctly positioned, add solder to each of the remaining pads to make shiny round joints:

DSC_0420.jpg

The 6-pin male FTDI connector can now be soldered on, I usually mount it sideways, but the choice is yours:

DSC_0421.jpg

A simple wire acts as antenna for the radio – attach it to pin 1 of the radio module. You can bend it as needed afterwards. I used a red wire, even though the kit probably has a yellow one.

One more step and you’re done: add the four 6-pin port headers.

Good, the soldering is over. Now bend the pins of the ATmega microcontroller slightly inwards so it fits into the socket. Make sure you only press it firmly down after all the pins are in the proper position.

Voilá! Your finished JeeNode:

DSC_0424.jpg

If you have a USB-BUB adapter, you can now plug it in and try out the board (note the 3.3V jumper – the JeeNode uses 3.3V logic signals). The ATmega that comes with the kit is pre-loaded with the RFM12demo sketch to get you up and running in no time:

DSC_0428.JPG

That’s it. Congratulations with your new JeeNode v3!

Reflow controller

In AVR, Software on Jul 14, 2009 at 00:01

Yesterday, I presented my new reflow system. Here’s the temperature graph from a sample run:

graph.png

The purple steps are the different phases:

  • Preheat (50) is whatever time it takes to reach 140°C.
  • Soak (100) is a 30-second temperature ramp up to 170°C.
  • Dwell (150) is defined as whatever time it takes to reach 220°C.
  • Reflow (200) is defined as 20 seconds at 220°C.
  • Cool down (250) is where the buzzer goes off and I open the lid.

The green bands indicate when the heater is on. The blue line is the target temperature which the system is trying to reach. The red line is the actual temperature. As you can see, the heater stops well before target temperatures are reached, and does a pretty good job of ending up in the desired range.

All in all, this appears to be ok. The 700-watt heater isn’t quite hot enough to ramp up 3°C/sec, more like 2°C/sec at best. Since the grill isn’t heating up quickly enough, the soak phase ends up taking 60 seconds instead of the planned 30, so the target stays pinned at 170°C a bit longer. This could probably be shortened by aiming directly for 170°C, but I don’t think this phase is critical. My only concerns are that it took about 80 sec to “dwell” from 170°C to 220°C and that the system is above 200°C for some 60 sec. This was shorter in other trials, but as you can see the heater is turning on a few times to nudge the system towards 220°C as things slow down a bit.

This plot was produced by a really nice free package for the Mac, called Plot (how original). The readings were obtained by logging the sketch output from the USB port and reformatting it to tab-separated numeric values.

Programming a 32-TQFP chip

In AVR, Hardware on Jul 11, 2009 at 00:01

With SMT parts, all sorts of things change. For the JeeLink, I’d like to set the fuses and flash the bootstrap code to the ATmega chip before soldering it to the board. Here’s how:

DSC_0399.JPG

This is a zero-insertion-force socket for 32-TQFP chips. You put the chip on, press down, and the whole thing presses these 32 gold-plated contact fingers onto the chip. There are several alignment edges in there making it relatively easy and quick. It’s no doubt made for machine operation but it works nicely by hand as well.

And here’s the result – an ISP programmer which works with the Arduino IDE:

DSC_0401.JPG

I’ll start flashing a couple of ATmega168 chips, in eager anticipation of the JeeLink boards…

IO Expander

In AVR, Hardware, Software on Jul 7, 2009 at 00:01

Here’s a way to expand the number of digital I/O lines on a port:

3686066291_f856efcb63_o This is a JeePlug filled to the rim with tiny components and connectors. It’s based on a PCA8574A I2C 8-bit I/O expander. Each of 8 pins can be used either as inputs or as “mostly” open collector outputs. See the datasheet for details.

Here’s the bottom side of the plug:

3686871488_b2366a7459_o

Crowded indeed!

And here’s a demo sketch called “expander” which blinks the eight LEDs connected between PWR and the respective I/O pins:

Picture 3.png

As with yesterday’s example, this is running the I2C at maximum bit-banging speed, and seems to work fine. It’s used to make 8 leds blink:

3686871410_0e325c3a2b_o

The connector block on this plug has 8 sets of three connections: GND, PWR, I/O. Note that PWR is connected, not +3.3V. The reason for this is that I’d like to try driving a bunch of servos from this plug one day – it’ll load the JeeNode down a bit but it should be feasible.

The “expander” sketch has been added to the Ports library and is available as ZIP file and in subversion.

External memory

In AVR, Hardware, Software on Jul 6, 2009 at 00:01

For one of the projects in the Jee Labs, I needed a bit more “permanent” memory than the ATmega’s EEPROM or even flash could provide. Here’s what I came up with:

3683813851_d524fedae2_o

That’s a 64 Kbyte AT24C512B serial EEPROM memory which talks via I2C.

It takes only 4 wires to hook this thing up:

3684626986_c2c8f1119c_o

And this is the mess you get in when you don’t have the right connectors and need to deal with older boards:

3683813971_e00e924cb0_o

That’s the “regret plug” mentioned a few days back, to turn the downward pointing male header into an upward pointing female header, plus a “cross-over plug” to let me wire this thing up for the new JeeNode v3 pinout, yet use it on a (minimally populated) v2 board. Yuck!

Lesson: think about headers before deciding how to solder them on …

All future JeeNodes will be supplied with 6-pin female headers for the ports. Soldering them on pointing up is probably most convenient: it lets you stick little LEDs and wires in there, and JeePlugs can be placed pointing upright – such as this memory.

Back to the memory expansion. Here’s a test sketch:

Picture 5.png

Sample output:

Picture 4.png

As you can see, the count did not start with 255, as it would have if the EEPROM had still been empty. The JeeNode was powered off in between to demonstrate data retention.

This example code runs at full bit-banging speed – seems to work just fine.

The “eemem” demo sketch has been added to the Ports library and is available in this ZIP file as well as here.

There you go … a whopping half million extra bits of permanent storage :)

Ligthy power save

In AVR, Software on Jul 5, 2009 at 00:01

Getting the power consumption down of yesterday’s “Lighty” example turns out to be quite a challenge.

One thing to do is to separate out the logic for enabling the different sensors, and extending it to also support disabling all of them:

Picture 3.png

Powering down completely works best when all internal peripherals are also turned off, as implemented in the following code:

Picture 4.png

Now the trick is to enable some interrupt source to take us out of this deep sleep phase again. This could be the ATmega watchdog, but the radio watchdog uses even less power, so here’s how to stay off for about 4 seconds:

Picture 5.png

So far so good. This disables all power consuming sensors and internal circuits, preps the radio to wake us up in 4 seconds, powers off, and then reverses the whole process.

Bug there is a bug in all this – somewhere… From some earlier experiments, I would have expected to see a power draw of a few microAmps with this code. But for some reason, it never drops below 2.7 mA, i.e. still “burning” 1/10th of full power!

I haven’t been able to figure out yet where these milliamps are going :(

For the sake of argument, let’s assume this works properly. Then the next problem will come up, which is that measuring and sending packets every 4 seconds drains more power than I’d like to. It takes several milliseconds to measure all readings and send out a packet. But who needs readings every 4 seconds?

So the solution to this is to just sleep a bit longer, using the 4-sec wakeups to quickly read-out some sensors, and calculate their averages. Here’s is the final loop of the power-saving “LightySave” sketch:

Picture 8.png

This will integrate readings for 75x 4 seconds, i.e. 5 minutes, and then send out a single packet. Note how the power-hungry radio module is only enabled at the very last moment. All we have to do is make sure it’s ready to send, then send one packet, then wait again until the send is complete.

Then the loop restarts, sleeping in low-power mode, etc.

Only issue is to find out where the 2.6 mA are going! I’ll try to figure this out, and will post here once fixed …

Lighty

In AVR, Software on Jul 4, 2009 at 00:01

Let’s call yesterday’s mystery JeeNode “Lighty” from now on. As promised, here is the first sketch:

Picture 3.png

LightySerial reads out several sensor values each second and dumps the results to the serial port. Plain and simple – using the Ports library for most pins and Arduino’s analogRead() for reading out voltage levels on A4 and A5.

Sample output:

Picture 4.png

FYI, all the Lighty sketches are available for download as a ZIP file.

Now let’s turn that into a wireless version using two JeeNodes. The first step is to separate the measurement and reporting sides of things.

Here is the main code of LightyTransmit, causing it to send out its readings once a second:

Picture 8.png

It puts all values into a structure defined as follows:

Picture 6.png

… and then sends that off to the broadcast address, i.e. whoever is listening. No acknowledgements are used. If the packet arrives, great, if not then the next one will.

The receiver then takes it from there, here is the entire LightyReceive sketch:

Picture 7.png

Note that the Ports library is not needed here since the receiving JeeNode does not use ports, it merely picks up packets and reports them on the serial line.

That’s basically it. Each of these sketches compiles to some 3 .. 4 Kb code.

We’ve got ourselves a Wireless Sensor Network!

LightyTransmit uses about 24 mA. Tomorrow, I’ll go into reducing the power drain, because Lighty’s tiny 20 mAh LiPo battery won’t even last an hour this way.

Mystery JeeNode

In AVR, Hardware on Jul 3, 2009 at 00:01

Some more pictures from yesterday’s puzzle…

3681641100_900fdf0f6e_o

Added a second LDR on the left and a DS18B20 1-wire temp sensor. A 4.5V @ 35mA solar cell has also been soldered in.

The sensor is a TSL230R light sensor, as Milarepa correctly commented:

3679117790_f89f0caa7d_o

It has one frequency pulse output, with two other port pins used to control sensitivity (1x/100x) and frequency divider (2x/50x). The fourth I/O pin is used as power supply for the chip, so that it can be turned off completely in sleep mode.

Here’s the whole assembly from the side:

3681641152_3a6d49194e_o

And here the complete JeeNode (using a different solar panel which turned out to be too weak):

3679151344_f871517b7c_o

So what does it do? And what is it for?

Well, two things really – but I’ll be the first to admit that this isn’t truly general purpose and unlikely to be very meaningful for anyone else.

The first use is to help me take better pictures. The photos on this weblog are all taken using nothing but a white sheet of paper and plain old-fashioned daylight. Benefits are that it’s free and abundant, it needs no space for a light-box setup, and it tends to produce beautiful images.

The problem which you may have seen on this weblog, is that daylight ≠ daylight. Sometimes it’s too dark outside, and sometimes the light is too harsh. Worse still, many of the photos end up with a blueish tint. I’m having a hard time predicting this, so it seemed like a nice idea to just throw a bunch of light sensors together and try to correlate this to picture quality over a few weeks time.

The other purpose of this unit is to act as test-bed for long-term solar-powered use. That means getting the power drain down to very low levels of course. But I also added the ability to read out the voltage of the solar cell and of the battery, as well as temperature (solar cells are sensitive to that). And LDRs facing opposite directions, to try and detect sun vs. cloud cover weather info.

This seemed like an excellent project for JeeNodes and JeePlugs. Once it’s working well enough – auto-ranging the light sensitivity and such – I intend to put this up on the roof and just let it send out packets every 5 minutes or so, day and night. This will make an excellent yet non-critical test setup as well as allow me to track solar intensity over the entire year. Think solar panels…

Tomorrow I’ll post several sketches: one showing how to read out everything and report it over the serial FTDI connection, then two more to show how to turn this into a send/receive solution with two JeeNodes, and the last one showing how to get power consumption down.

Stay tuned!

Breadboard limits

In AVR, Hardware on Jun 29, 2009 at 00:01

Here’s something which isn’t a good idea with breadboards:

Breadboard limits

I used a socket with wire-wrap pins to be able to connect a few wires yet still be able to use the whole thing in a breadboard. If you look closely, you can see that the 5-pin metallic connectors inside the breadboard are pushed out – making the adhesive separate from the rest. Whoops.

Wire-wrap pins are clearly too thick to be pushing into breadboards…

Arduino Mega + shield

In AVR, Hardware on Jun 28, 2009 at 00:01

Got myself an Arduino Mega – an Arduino on steroids:

Arduino Mega + shield

Compatible with current Arduino shields, but extended to support a lot more pins.

Ordered it from NKCelectronics, along with their new extended shield for it:

Arduino Mega + shield

There’s a lot of them pins on there…

I decided to attach a solder-less breadboard to it, to be able to experiment with projects which need more I/O lines or comms than a standard Arduino:

Arduino Mega + shield

It fits, but just barely. Had to cut off the little hooks on the plastic. Using a breadboard in this way covers up all the identifying pin texts on the silkscreen, alas.

Actually, it doesn’t quite fit – couldn’t get all headers on:

Arduino Mega + shield

I’m using a mix of 4- and 6-pin headers, since I had them lying around. As you can see, the last 4-pin header makes it impossible to fit that other header in, so I left off pins 22 and 24. It might have worked with an 8-pin header i.s.o. 2x 4-pin.

And here’s the final “stack”:

Arduino Mega + shield

Conclusion so far? I’m not sure this is the way to go. I think it’s an abomination, to be honest. There are so many pins to connect that the two boards are very hard to separate once stacked up. You don’t want to pull too hard on one side and end up with bent pins when the thing finally comes apart.

And how often do you need that many I/O pins one one fixed board setup? Sure, the ATmega1280 has 128 Kb of flash memory, which is plenty to get fairly complex sketches going. But it also builds on that trend of using stacked shields – and let’s face it: a single shield is often great, but with 2 or 3 you end up with pin allocation nightmares (for designers) or conflicts (for users). Multi-stacking is tricky, requiring special stacking headers.

Nah, I’d much rather go with ports, and extensions for that, and connecting two or three independent units over a bus if need be. But then of course I would, that’s why I went for such an approach with JeeNodes after all.

Meet the JeeLink

In AVR, Hardware on Jun 24, 2009 at 00:01

I’m proud to announce a new board next to the JeeNode, called the JeeLink. Yes, there’s a pattern in the naming choices made for products on this site.

The JeeLink is very much like a JeeNode, but in the format of a USB stick and with a few small differences listed below. Here’s the layout:

Picture 2.png

As you can see, the JeeLink has basically the same headers as the JeeNode, but with a USB plug in the place of the JeeNode’s FTDI connector.

The JeeLink is useful in two different ways, I think: first of all, if you have a couple of remote JeeNodes, you’ll probably need a central node as well to tie the whole network to a personal computer. The second use case is that it can be used as a JeeNode with built-in FTDI-to-USB conversion – which is exactly what it is, technically speaking.

A major difference with the JeeNode also, is that the JeeLink is built with SMD parts. The intention is to make it available in pre-assembled form and as bare board. No kits with parts – that’s reserved for the JeeNode since I don’t want to stretch myself too thin.

There will be a more detailed description of the JeeLink once it is ready and working, but here’s a first overview:

  • the dimensions of a JeeLink are slightly different, obviously
  • the I2C and SPI/ISP headers are not in exactly the same position as on the JeeNode
  • there’s no battery connector (who needs one with USB?)
  • the FTDI-type USB connection includes two on-board activity leds

So there you have it – a new descendant in the Jee family. With on-board RFM12B wireless radio of course, and 4 ports to connect absolutely anything you like to. Just like the JeeNode.

The JeeLink is the initiative of – and was designed in collaboration with – Paul Badger of Modern Device. We’ve been having a heck of a time together, hammering out all the details and making sure the result will be as good as we can possible make such a new concept. I’m proud of the result, and hope you’ll like it as well. Should have properly working JeeLinks in my hands in July, assuming Mr. Murphy doesn’t barge in to spoil the party.

More SMD stuff

In AVR, Hardware on Jun 21, 2009 at 00:01

My adventures in SMD miniaturization-land continue:

SOIC chips

Those are two Atmel chips – an ATtiny85 (SOIC-8) and an ATtiny84 (SOIC-14).

Compared to 0603 parts, these are actually quite large. The distance between the pins is 1.27mm (0.05″), half of regular through-hole parts.

But you do need fine tweezers, and a ZIF socket to flash them or try them out without soldering is also nice:

SOIC chips

The lid snaps down, making a firm connection with each of the 14 pins.

Hm, I see now that the SOIC-8 dimensions are a bit wider than the SOIC-14 package. So the smaller package doesn’t fit in this (pricey) ZIF socket.

So not only is this stuff small – it’s also easy to overlook such differences!

Fortunately there are datasheets.

JeeNode headers

In AVR on Jun 17, 2009 at 00:01

More details about how to connect stuff to any of the four “ports” of a JeeNode. Each port has this pinout:

A few notes:

  • the DIO pin is for digital I/O only, the AIO pin can be for analog in or for digital I/O
  • a port has six pins, with both 3.3V (VCC) regulated and +V (PWR) unregulated power
  • with just a 4-pin header on pins 2..5, you still get the most important pins
  • if all you need is a single I/O line, you could even use a 2-pin header on pins 3..4
  • the IRQ signal is shared between all ports

Another thing to note is that the ports all have an identical pin-out, when looking from the outside of the board:

(the above two diagrams are from the JeeNode v2 PDF documentation)

And then there is the aspect of distances between the port headers:

headers.png

This is where the story gets a bit fuzzier:

  • JeeNode v1 uses A and B as distance between the port headers
  • JeeNode v2 and v3 use A and D as distance between the port headers

If you want your plugs to remain usable on all future JeeNode designs, then you will need to make sure that they can deal with separations between the headers as small as C and E.

I’m not saying there will be such JeeNodes any day soon, I just want to keep the option open to go there.

Prototyping with JeeNodes

In AVR, Hardware on Jun 16, 2009 at 00:01

Here’s a little board I used for a while with a JeeNode:

Pulse prototype

It has 6 female header underneath, which get plugged into a JeeNode with its header pins sticking upwards. It has an LDR, a diode I tried to use as voltage reference, a plugged-in SHT11 temperature / humidity sensor, a 3-pin connector to plug in a Parallax PIR sensor, and a 2-pin header (top right, behind the SHT11) which was used to connect a couple of 1-wire temperature sensors).

There are a couple of issues with this, though some are probably unavoidable for such one-off / ad-hoc solutions. For one: it’s a bit of a mess. One reason is that with this setup the 1-sided perf-board I used has to be mounted upside down to allow soldering in the female headers. That’s awkward, because it means you have to “surface mount” most components.

One option is to use perf-boards with plated-through holes. These are several times more expensive than single-sided boards, though. But more importantly, cheap one-sided boards are often based on “Pertinax” (SRBP) which is a lot easier to handle than FR-4 epoxy: you can simply break them on a sharp edge, with the row of holes acting as perforation.

The other problem with putting everything on a single board is reduced flexibility. In this case I had to add a second 4-pin female header on top to accommodate the SHT11 plug I had already made – which would have fitted just as well directly on the JeeNode.

One nice benefit of per-port prototyping is that it is easy to re-use this stuff in different configurations. In fact, as with the SHT11 plug showing in the picture, that’s precisely what happened.

So I’ve been thinking a bit about ways to use JeeNodes for experimentation. Which happens a lot around here. One simplifying convention is to always use male headers on the JeeNode. That leaves essentially two choices (ignoring sideways mounting for now):

Picture 1.png

I’m thinking of having a bunch of, ehm, “JeePlugs” made: tiny boards with a 6×8 “prototype” area containing plated-through holes, plus a 6-pin female header and connecting pads. Three ways to use these:

Picture 2.png

You’ll need male headers for use with a breadboard, but I’m assuming you’ve used the breadboard to figure out the connections with the bare parts, so this post focuses on using female headers for the JeePlugs.

In all cases, the orientation of the pins is the same, so once you have a plug set up with stuff on it, you could still use it in multiple ways. And plug them onto any of the 4 ports at will, of course.

One last refinement is to make these plugs around 20 x 25 mm – i.e. long enough to optionally plug onto two ports in that inverted 3rd example shown above. Here’s a first design:

Picture 3.png

It’s really not much more than a tiny perf-board of the proper size for JeeNodes with a couple of doubled-up connections. Using plated-through holes so components and wires can easily be soldered from either side.

The plugs are not labeled with pin numbers or signal names, because those depend on the orientation in which you use them. For that, use the markings on the JeeNode itself (starting with v3, that is).

These JeePlugs only makes sense in larger quantities, so I haven’t yet decided whether I really want to order them. I sure could use some, but it wouldn’t be practical to have less than a hundred or so of them produced.

New JeeNode v3 design

In AVR, Hardware on Jun 14, 2009 at 00:01

Here’s an – improved! – board design for the JeeNode:

Picture 1.png

The main two changes are: labeling of all the components and pins, and a change in the ISP/SPI pin header (pin 1 is now also pin 1 for ISP). All connectors are in exactly the same place, but the board is a tiny fraction wider.

For details, see the EAGLE files (jee-pcb-011.sch and jee-pcb-011.brd). The PDF of the schematic shows that the functionality is unchanged – other than the ISP/SPI header pinout change, this board should be 100% compatible with the JeeNode v2.

The v3 board was designed in collaboration with Paul Badger of Modern Device, to whom I’m most grateful.

I’ve just ordered a batch of these boards. Should be able to report here in ten days or so as to whether they are working properly. Let’s hope so!

JeeNode v2 kit notes

In AVR, Hardware on Jun 11, 2009 at 00:01

Just to make sure I didn’t forget anything – here’s the contents of a JeeNode v2 kit with parts:

JeeNode kit contents

For those of you who are about to receive the kits: they should match what’s shown above. If I forgot anything please let me know and I’ll take care of it right away.

The ATmega168 is pre-flashed with the standard Arduino boot loader and the RF12demo sketch.

As for assembling these kits, the main thing to keep in mind is the orientation of a few components and the ways things should be hooked up – see the recent post and the reference doc and close-ups on this site such as this one:

JeeNode v2

These are first-generation boards without silkscreen (I’m still learning about all this PCB design stuff!), although there are tiny markings on the top copper layer if you look really closely.

One important detail I forgot about is the antenna: for these 868 MHz units, I use a piece of 85 mm insulated wire. It needs to be connected to the ANT pin, which is the one in the corner as you can see in the above picture. You need an antenna, I’ve not been able to bridge even the shortest distance without one.

A tale of stand-alone builds

In AVR, Software on Jun 10, 2009 at 00:01

The JeeBot Duo runs off a Baby Orangutan controller by Pololu, which isn’t entirely compatible with the Arduino IDE. Well, it can be made to work with it but in this case it looks like just using avr-gcc and avrdude directly from a Makefile would be just as simple.

Boy, was I wrong.

I’ve spent nearly two days trying to understand why this thing wasn’t working. Or rather, it was. Sometimes. But with resets all the time, and the watchdog being tripped even though I never enabled it.

One problem is that the BOC has no other signaling on board than a single LED. So first thing was to set up serial communication. Well, that worked. But then it didn’t. And then things got really totally erratic…

The problem turned out to be in the highlighted portion of this Makefile:

Picture 2.png

Without the $(CFLAGS) on the linker line, everything   s o r t   o f   works.

Until you start using RAM for data, such as statics/externals and strings. Or C++ classes inside the Pololu libraries for example.

Then the system goes berzerk. Because the linker wrongly assumes that RAM starts at 0x0060. So strings and data variables end up being written into the extended I/O area. Want to know what’s at address 0x0060? The watchdog control register.

Anyway. It took me many hours of complete despair to figure this one out. Salvation came from “avr-objdump -h”, which clearly showed that the “.data” segment was in the wrong place compared to an Arduino sketch. With many thanks to Ben @ Pololu for nudging me towards the solution and for patiently responding to my emails, some of which must have been pretty weird…

I think that what baffled me most of all was the fact that the simplest bits of code worked just fine. You can get a lot of little tests going without ever using strings or allocating static variables. And the failures being random resets (from the watchdog) kept me looking for hardware problems – silly me.

At one point, I had figured out the incorrect starting RAM address and added this linker option: “-Wl,-Tdata,0x800100”. Unsure why it had to be specified but it got past the most erratic behavior.

But then interrupts wouldn’t work. Disassembly (with “avr-objdump -D”) showed that the generated code was using an incorrect set of vectors. And then it dawned on me: the $(CFLAGS) includes “-mmcu=atmega328p” which the linker needs to put things in the right place and to use the right vectors.

Doh. Totally obvious in hindsight.

Now I can finally generate and upload code without having to go through the Arduino IDE.

Building the JeeNode

In AVR, Hardware on Jun 9, 2009 at 00:01

Now that a few people have started building JeeNodes for themselves, here’s a close-up:

MCP1702 detail

Make sure you put that MCP1702 voltage regulator in exactly as shown. That’s the TO-92 package in the middle.

The board was intially designed for an LP2950, which has a different pinout. The MCP1702 does not have ground in the middle, hence the twisted positioning.

Note also how I use flat 6-pin headers, even for the FTDI connector. All the header pads are large enough to solder them on in any orientation you like.

FWIW, I’ve still got 9 JeeNode boards left (and probably all the parts needed as well). So if you want ’em let me know. I can send bare PCBs for €5 each. Or the PCB with all parts including 868 MHz radio and pre-flashed ATmega168 for €17.50. Shipping included if you order more than one.

JeeBot Duo schematic

In AVR, Hardware on Jun 8, 2009 at 00:01

Heh – my most “sophisticated” robot so far. Here’s the plan for the electrical hookup of the JeeBot Duo:

Picture 1.png

There’s quite a bit of functionality in there, all the way to an on-board LiPo battery charger. Other things to note: the Baby Orangutan controller (BOC) can shutdown all power (to avoid running down the battery too far) and the JeeNode can reset the BOC if need be.</