Setting up a remote node Feb 2017
To try out RF communications, we need to go through a number of steps:
- hook up two JeeNode Zero boards, so we can develop on both in parallel
- work out the code needed for the receive and send nodes
- lower the average power consumption of the send node
- install the send code in flash so it can run unattended
- add a coin cell, and turn the sender into a standalone unit
- as a bonus, we’ll also update the node with a modified version
Let’s jump right in… by the end of this one article, you’ll have it all.
1. Preparing two JNZ’s
Here is a 2-node setup, one via a USB-BUB type board, the other via a HyTiny-based SerPlus:
By running two instances of Folie, each in their own terminal session, and making sure that we can connect and easily reset ‘em with Ctrl-C, everything is ready for some Forth development.
2. Setting up RX & TX nodes
On the receiving end, it can’t get any simpler than entering “
For sending, the first test is to manually send one packet with “
The result is that you should see one packet come in for each one sent out:
|TX node, typed in||RX node, printed out|
As you can see, the payload contains the ASCII representation of the number sent out, in hex.
Excellent! This shows that all the hardware involved is doing its job.
Next, let’s continuously send one packet per second, with an incrementing counter in it:
: blips 1000000 0 do i rf-txtest 1000 ms loop ; rf-init 0 rf-power blips
It’s the same
rf-txtest call, but now as part of a loop.
The receiver output will be:
RF69 21EB2AC301FE60803D01 30 RF69 21EB2AC201FF42803D01 31 RF69 21EB2AC301FF4E803D01 32 RF69 21EB2AC301FF9A803D01 33 RF69 21EB2AC301FC92803D01 36
Not all packets are guaranteed to arrive. As you can see, we got packets 0, 1, 2, and 3, missed packets 4 and 5, and then got packet 6. That’s to be expected - it’s not that these sensitive radios are so unreliable, we’re simply placing them far too close together - even at minimal power, the radio waves from the transmitter will overload a receiver placed a few cm away!
To quit the infinite send loop, we can press Ctrl-C to get the Forth prompt back. Since this resets the JNZ, all code in RAM will be lost.
3. Low-power transmissions
The transmitting node is now sending one packet every second. The rest of the time it’s just twiddling its thumbs and wasting energy. Let’s fix that:
: blips 1000000 0 do i rf-txtest rf-sleep stop1s loop ; lptim-init rf-init 0 rf-power blips
As before, running this should produce new output once a second on the receiver end.
Actual power consumption measurements will have to wait for another time, but the average current draw is likely to be under 10 µA, some three orders of magnitude lower than before.
Which means we’re almost ready to run the transmit node off a coin cell - but
there’s a snag: the
blips code lives in RAM, so the send node won’t start when
simply powering it up.
4. Unattended operation
For such unattended operation, we need to save the
blips code in flash and add
logic to start it up immediately after power-up (or reset). Appending to flash
is a matter of telling Mecrisp:
compiletoflash : blips 1000000 0 do i rf-txtest rf-sleep stop1s loop ;
Automatic startup is also easy: Mecrisp looks for an “
init” word on startup,
and launches it.
But it’s also a bit risky. What if there is a mistake in the code, or we want
to change it later? Once a new
init is installed, we lose the default
command-line prompt! Even a hard reset won’t get it back, since it’ll simply
launch that same
init override again.
The solution comes in the form of a special
unattended word, defined in
This is designed specifically for making
init overrides safe:
compiletoflash : init init unattended lptim-init rf-init 0 rf-power blips ;
Some notes of what’s happening, since it’s fairly critical to get this right:
- we re-define the
initword, overriding its original definition
- first we have to call the original
init, which is why it appears twice
- then we call
unattended, which will act as a safety escape hatch
- lastly, all the code that is to be run on startup follows
unattended escape hatch is that when connected to a serial port, anything
after it will be skipped. Instead, this
init definition will immediately
return to the Forth command prompt.
If you run the above and reset the board, you will see that nothing happens.
You still have to start everything up by manually entering “
0 rf-power blips”.
But that’s exactly the point. Even when a node has been set up to automatically go live without serial FTDI connection, the development workflow remains unaffected.
5. Running off a coin cell
And now the real test - we take the JNZ out of its FTDI connector and insert a coin cell:
(see the red glow? more on that in a moment…)
And here’s some sample output printed by the receiver, while moving away a bit:
RF69 21EB2AC201009C803D02 3231 RF69 21EB2AB801FF34803D02 3232 RF69 21EB2AA3020026803D02 3233 RF69 21EB2AB101FDA6803D02 3234 RF69 21EB2AB40100FE803D02 3235 RF69 21EB2AC0010078803D02 3236 RF69 21EB2A9E02002A803D02 3237 RF69 21EB2A9F02002C803D02 3238 RF69 21EB2A9F02002A803D02 3239 RF69 21EB2A9D020012803D02 3330
But… whoops, there’s a silly little mistake in there: the LED is still on, drawing some 2 mA. Leaving that LED on would drain the coin cell within a matter of days…
6. Updating the code
So as last step, here is how to fix the LED issue by installing an improved version:
Remove the coin cell (this is important, it cannot coexist with power from FTDI!)
Put the JNZ back in its FTDI adapter, and it’ll show the normal welcome message again.
Remove the code we added to flash by entering “
<<<core>>>” to restore the flash memory to its previous state. This was explained in the previous article.
Improve the code, i.e. we can simply add a call to turn the LED off on startup:
compiletoflash : blips 1000000 0 do i rf-txtest rf-sleep stop1s loop ; : init init unattended led-off lptim-init rf-init 0 rf-power blips ;
Now disconnect from FTDI again, put the coin cell back in, and we’re done.
That’s all. With a mean current consumption in the 10 µA’s (i.e. sleep mode + transmit power use), this node should be able to run at least a year or two on a fresh coin cell. Piece of cake!