TL;DR:
Successful toolchain setup, flashing and functional radio network! Still todo: Fix network connectivity between the radio network and host system, and find/fix why the CPUs run constantly (drawing excess current) instead of sleeping.
Over the last few weeks (er, months?), I build up and tried out some circuit boards implementing OpenWSN, an open-source low-power wireless mesh networking project. OpenWSN implements a stack of kid-tested, IEEE-approved open protocols ranging from 802.15.4e (Time-Synchronized Channel Hopping) at the physical layer, 6TiSCH (an interim, hardcoded channel/timeslot schedule until the smarts for deciding them on the fly is finalized), 6LoWPAN (a compressed form of IPv6 whose headers fit in a 127-byte 802.15.4etc. frame), RPL/ROLL (routing), and finally CoAP/HTTP at the application level. The end result is (will be) similar to Dust SmartMesh IP, but using all open-standard and open-source parts. This should not be a huge surprise; it turns out the project is headed up by the original Berkeley Smart Dust guy. Don’t ask me about the relationship between this and Dust-the-click-n-buy-solution (now owned by Linear Technology), TSCH, any patents, etc. That’s above my pay grade. My day-job delves heavily into low-power wireless stuff, and here SmartMesh delivers everything it promises. But it’s rather out of the price range of hobbyists as well as some commercial projects. That, and if you use it in a published hobby project Richard Stallman might come to your house wielding swords. So how about a hands-dirty crash course in OpenWSN?
Boards
At the time of this writing, the newest and shiniest hardware implementation seems to be based on the TI CC2538, which packs a low-power ARM Cortex core and radio in a single package. OpenMote is the (official?) buyable version of this, but this being the hands-dirty crash course, I instead spun my own boards. You don’t really own it unless you get solderpaste in your beard, right? The OpenMote board seems to be a faithful replication of a TI reference design (the chip, high and low-speed crystals, and some decoupling caps), so we can start from there. To save time I grabbed an old draft OpenMote schematic from the interwebs, swapped the regulator for a lower-current one and added some pushbuttons.
Here is the finished product. Boards were ordered thru OSH Park, and SMT stencil through OSHStencils (no relation). Parts were placed using tweezers and crossed fingers, and cooked on a Hamilton Beach pancake griddle. 2 out of 3 worked on the first try! The third was coaxed back to life by lifting the chip and rebaking followed by some manual touch-up.
Software
I first smoke-tested the boards using the OpenMote firmware, following this official guide. No matter where you start, you’ll need to install the GCC ARM toolchain. Details are on that page.
This package REQUIRES Ubuntu (or something like it), and a reasonably modern version of it at that (the internets say you can theoretically get it working on Debian with some undue hacking-about, if you don’t mind it exploding in your face sometime in the future.).
If your Ubuntu/Mint/etc. version is too old (specifically, package manager version), you’ll get an error relating to the compression type (or associated file extension) used in the PPA file not being recognized. You can maybe hack about to pull in a ‘future’ version for your distro version, but who knows which step you’ll get stuck at next for the same reasons. (Maybe none, but I just swapped the hard drive and installed a fresh Mint installation on another one.)
First build the CC2538 library: In the libcc2538 folder: python libcc2538.py
This will build libcc2538.a. Probably after you got a “libcc2538.a does not exist. Stop.” error message.
Next, try compiling a test project to make sure the toolchain works:
chmod 777 test-projects.sh
./test-projects.sh
Assuming all goes well, now you can flash the resulting binary onto the board!
sudo make TARGET=cc2538 BOARD=openmote-cc2538 bsl
Needless to say, you need some kind of serial connection to the bootloader UART (PA0, PA1) on the board for this to work (I used a USB-serial dongle with 3.3V output).
Successful output from this step looks something like:
Loading test-radio into target...
Opening port /dev/ttyUSB0, baud 115200
Reading data from test-radio.hex
Connecting to target...
Target id 0xb964, CC2538
Erasing 524288 bytes starting at address 0x200000
Erase done
Writing 524288 bytes starting at address 0x200000
Write done
Now you can actually try compiling OpenWSN.
OPTIONAL STEP: If you foresee doing active development on OpenWSN, you might want to install Eclipse. NOTES:
Direct from website; even Mint package manager version as of 12/15 is still on v3. Follow the instructions on this page, for the most part.
If you installed arm-none-eabi etc. from the previous step, it “should” be ready to rock.
The options in Eclipse have changed a bit since this was written. When creating a new (blank) test project, select “Cross ARM GCC”. Create a main.c file with a hello-world main() (or copy & paste from the page above), then save and build (Ctrl-B).
You may get a linker error similar to: “undefined reference to `_exit’” . I solved this by selecting ‘Do not use standard start files (-nostartfiles)’
I’m currently getting a 0-byte file as reported by ‘size’ (actual output file has nonzero size). Not sure whether to be concerned about this or not:
Invoking: Cross ARM GNU Print Size
arm-none-eabi-size --format=berkeley "empty-test.elf"
text data bss dec hex filename
0 0 0 0 0 empty-test.elf
The actual .elf and .hex are 13k and 34 bytes on disk, respectively.
This is not actually crucial to compiling OpenWSN, so I gave up here and went back to the important stuff:
NON-OPTIONAL: Download and set up SCons. This is the build tool (comparable to an advanced version of ‘make’) used by OpenWSN.
Again, anything in your package manager is horribly out of date, so grab it from the web site, unpack and ‘sudo python setup.py install’.
Clone the ‘openwsn-fw‘ repository somewhere convenient (preferably using git, but you could just download the .zip files from github), change into its directory and run scons without any arguments. This gives you help, or is supposed to. It gives some options for various ‘name=value’ options, along with text suggesting that the options listed are the only valid ones. However, popular options like the gcc ARM toolchain and OpenMote-CC2538 are not among the listed options. Luckily, they still work if you googled around for the magic text strings:
scons board=OpenMote-CC2538 toolchain=armgcc goldenImage=root oos_openwsn
This results in an output file of decidedly nonzero reported size:
arm-none-eabi-size --format=berkeley -x --totals build/OpenMote-CC2538_armgcc/projects/common/03oos_openwsn_prog
text data bss dec hex filename
0x16303 0x28c 0x1bd8 98663 18167 build/OpenMote-CC2538_armgcc/projects/common/03oos_openwsn_prog
0x16303 0x28c 0x1bd8 98663 18167 (TOTALS)
Add ‘bootload /dev/ttyUSB0’ (or whatever your serial device shows up as) and run it with the mote in boot mode (hold Boot button / pin PA6 low and reset), and it should Just Work. Upload takes a while. Ideally, you need to flash at least 2 boards for a meaningful test (one master, or ‘DAG root’ in OpenWSN parlance, and one edge node).
Now, need to run openvisualizer to see if anything’s actually happening.
First… currently ‘setup.py’ for this package is broken, and barfs with errors e.g.:
Traceback (most recent call last):
File "setup.py", line 34, in
with open(os.path.join('openvisualizer', 'data', 'requirements.txt')) as f:
IOError: [Errno 2] No such file or directory: 'openvisualizer/data/requirements.txt'
‘pip install’ might be another way to go, but this appears to install from an outdated repository, and barfs with some version dependency issue.
Since the actual Python code is already here, we can just try running it, which seems to be expected to go through SCons: run ‘sudo scons rungui’ in the openvisualizer directory.
Traceback (most recent call last):
File "bin/openVisualizerApp/openVisualizerGui.py", line 29, in
import openVisualizerApp
File "/home/cnc/workspace/openwsn-sw/software/openvisualizer/bin/openVisualizerApp/openVisualizerApp.py", line 17, in
from openvisualizer.eventBus import eventBusMonitor
File "/home/cnc/workspace/openwsn-sw/software/openvisualizer/openvisualizer/eventBus/eventBusMonitor.py", line 18, in
from pydispatch import dispatcher
ImportError: No module named pydispatch
Well, that doesn’t actually work, but it’s at least a starting point to flushing out all the unmet dependencies by hand. Install the following packages:
pip (to install later stuff)
pydispatch (pip install…)*
pydispatcher (pip install…)
python-tk (apt-get install…)
*No, wait, that one’s already installed. According to the externalized Google commandline, http://stackoverflow.com/questions/17802792/no-module-named-pydispatch-when-using-pyopengl sez you actually need to install a separate package named ‘pydispatcher‘.
Finally, let’s give it a go.
cnc@razor ~/workspace/openwsn-sw/software/openvisualizer $ sudo scons rungui
It works! Sort of. I get a mote ID, and can toggle it to be DAG root, and after a while, the 2nd board appears with a long-and-similar address in the neighbor list. It’s receiving packets and displays a RSSI. So at least the hardware is working. However, I can’t interact with it, and it doesn’t show up as a selectable mote ID (presumably just an openvisualizer issue). Nor can I ping either one as described in the tutorial, even though the part of the console dump relating to the TUN interface looks exactly as it does in the example (warning messages and all):
scons: done building targets.
cnc@razor ~/workspace/openwsn-sw/software/openvisualizer $ ioctl(TUNSETIFF): Device or resource busy
created following virtual interface:
3: tun0:
link/none
inet6 bbbb::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::1/64 scope link
valid_lft forever preferred_lft forever
22:43:24 INFO create instance
22:43:24 INFO create instance
22:43:24 INFO create instance
Killing openvisualizer, plugcycling both radios and restarting it returns a screenful of:
[Errno 11] Resource temporarily unavailable
device reports readiness to read but returned no data (device disconnected?)
Lets try rebooting, it fixes stuff in Windows… Actually, it looks like the GUI window sometimes persists after openvisualizer is supposedly killed at the console and can’t be closed via the UI; there is probably a task you can kill as a less drastic measure.
That cleared up the ‘no data’ errors, but still can’t ping any motes:
cnc@razor ~ $ ping bbbb::0012:4b00:042e:4f19
ping: unknown host bbbb::0012:4b00:042e:4f19
Well, at any rate we know the radio hardware is working, so let’s see the next moment of truth: power consumption. That’s really the point of this whole timeslotted radio exercise; otherwise you’d just drop an XBee on your board and hog as much bandwidth and electrons as you like. The 802.15.4e approach is for wireless networks that run for months or years between battery changes.
Firing up the ol’ multimeter is not the best way to measure current draw of a bursty load, but as a quick first peek it’ll do. On startup, the radio node draws a steady ~28mA, which is not all that unexpected (it needs a 100% initial on-time to listen for advertisements from the network and sync up.) After a few moments, the current drops to 11mA and the node appears in OpenVisualizer. Wait a minute… 11mA you say, with an ‘m’? That’s not that low. Scoping the 32MHz crystal confirms that the CPU is running all the time, rather than sleeping between scheduled activity. Scoping the 32KHz crystal mostly confirms that you can’t easily scope a low-power 32KHz crystal (the added probe capacitance quenches it), but doing so causes the node to drop off the network, then reappear a short time after the probe is removed, so that crystal appears to be functional (not to mention important).
Now, is it software or hardware?
Back to the OpenMote (not OpenWSN) example projects, let’s try an example that ‘should’ put the CPU to sleep:
cnc@razor ~/OpenMote/firmware/projects/freertos-tickless-cc2538 $ make TARGET=cc2538 BOARD=openmote-cc2538 all
Building 'tickless-cc2538' project...
Compiling cc2538_lowpower.c...
Compiling ../../kernel/freertos/croutine.c...
Compiling ../../kernel/freertos/event_groups.c...
...
cnc@razor ~/OpenMote/firmware/projects/freertos-tickless-cc2538 $ sudo make TARGET=cc2538 BOARD=openmote-cc2538 bsl
Loading tickless-cc2538 into target...
Opening port /dev/ttyUSB0, baud 115200
Reading data from tickless-cc2538.hex
Connecting to target...
Target id 0xb964, CC2538
Erasing 524288 bytes starting at address 0x200000
Erase done
Writing 524288 bytes starting at address 0x200000
Write done
Sure enough, with this example project loaded, the board’s current consumption drops to the uA range (actually, I was lazy and concluded the “0.00” reading on the mA scale told me what I wanted to know), with the 32MHz crystal flatlined except for very brief (<1msec) activity periods.
That’s it for Part 1. Stay tuned, Future Tim, for the part where we track down the source of the missing milliamps!
Leave a Reply