Making an always-on device Mar 2017

It’s all nice and well, but a JeeNode Zero which needs to remain tethered to a host to set it up after each reset is not very useful. Fortunately, this can be fixed using a simple recipe:

That’s it. Now the source will first clear any definitions in flash after the <<<core>>> words, and then set up to compile to flash. As the last step, the special init word is redefined to call the core setup, and then our code.

In between sits the crucial unattended word which allows us to switch between development mode and unattended / untethered mode. The distinction is made on startup by checking whether the serial RX input pin on the FTDI header is floating. If so, read-enc will be started.

This way, we’ll always get back to a prompt when plugged in - allowing us to update the flash.

While still attached to FTDI, we simply type read.enc to start it up. So even when in flash and ready to be used in detached mode, development is straight-forward: 1) press Ctrl-C to regain control, 2) send new code with “!s ...”, and 3) enter “read-enc” to launch the new code.

So much for making the node work unattended. The above is sufficient to allow unplugging it from FTDI and inserting a coin cell (remember: never connect power from both FTDI and the coin cell at the same time!). A coin cell will work fine, but… it’ll it’ll be drained within days!

We really need to get power consumption down if this “rotary knob node” is to be used for a long time, and even more so if it is to remain in always-on mode.

The first step is to pick the low-hanging fruit to take care of the main “power hogs” (relatively speaking). This can be done with a single line added to the read-enc code:

led-off 2.1MHz only-msi 10 systick-hz

But first, let’s set up a way to measure power consumption:

That’s a µCurrent from EEVblog, which is very convenient for measuring low currents with a standard multimeter - in the back you can see the receiving node (running unmodified code).

The baseline measured with the code from jz4/ex/rot5.fs is 5 mA. That’s quite a lot for a CR2032 coin cell, nominally rated at just 200..230 mAh: only ≈ 40 hours of run time, ouch!

The above one-line change takes care of the two main consumers: LED and µC. The LED is simply turned off, saving ≈ 2 mA, and the µC is set to run at 2.1 MHz instead of its default 16 MHz. The result is a ten-fold reduction: 460 µA. The coin cell will now last for ≈ 18 days.

Still not good enough, but we can take the µC clock rate quite a bit lower by using this line:

led-off 2.1MHz only-msi 65KHz 10 systick-hz

Note that this slow 65 KHz clock rate can only be reached by first switching to the 2.1 MHz clock and that we also lower the SysTick timer rate to 10 Hz. The result: 45 µA, i.e. 6 months.

Here is the full sender-side code, which can also be found in jz4/ex/rot6.fs on GitHub:

<<<core>>>
compiletoflash

PA3 constant ENC-A
PA5 constant ENC-B
PA4 constant ENC-C  \ common

1000 variable counter

: ab-pins ( -- n )  \ read current A & B pin state as bits 1 and 0
  ENC-A io@ %10 and  ENC-B io@ %01 and  or ;

: step ( n -- )  counter +!  7 <pkt counter @ +pkt pkt>rf ;

: read-enc
  IMODE-HIGH ENC-A io-mode!
  IMODE-HIGH ENC-B io-mode!
  OMODE-PP   ENC-C io-mode!  ENC-C ioc!
  rf-init
  led-off 2.1MHz only-msi 65KHz 10 systick-hz

  %11  \ previous state, stays on the stack
  begin
    2 lshift  \ prev pins in bits 3 and 2
    ab-pins tuck  \ new pins, also save as previous for next cycle
    or  \ combines prev-a/prev-b/curr-a/curr-b into a 4-bit value

    \ process this 4-bit value and leave only prev state on stack
    case
      %0001 of -1 step endof
      %0010 of  1 step endof
      %0100 of  1 step endof
      %0111 of -1 step endof
      %1000 of -1 step endof
      %1011 of  1 step endof
      %1101 of  1 step endof
      %1110 of -1 step endof
    endcase
  again ;

: init init unattended read-enc ;

Not bad for a one-line change. Can we do better? First of all, the rotary encoder readout is starting to become erratic again at this very low clock rate. And second: having to insert a fresh coin cell every six months is really still a bit too often. Yes, we can fix both, stay tuned…

Weblog © Jean-Claude Wippler. Generated by Hugo.