Using eInk bargraph SCD722002 for an ultralow power indicator, a blinky

An eInk device is persistent: visible even after your embedded, energy harvested system exhausts power. This reports my experience using an eInk bar gauge instead of LEDs. Software is included.

Context

I build systems that are solar powered, without batteries, with only super capacitors. They can exhaust power when they don’t get enough ambient energy, say during a few days of cloudy weather. I want to indicate or show software faults and system state. The indicator must use little power to set, and zero power to maintain. eInk does that.

An alternative is to write to persistent memory, then read it after plugging in a debug probe. An indicator lets you simply walk up and look at it.

Another alternative is to use wireless. But that adds complication, and requires the system to have more power when relaying the indication.

The eInk bargraph

eInk sells a 5 segment bar gauge, part number SCD722002. It is available on Digikey.

The datasheet says it requires 5V. But I found that you can drive it with only 3.3V.

It has an invisible, top electrode (pin 1) that covers all the visible segments. It has six segments: the background and five bars of a bar graph.

The datasheet says a segment must be driven for a half to two seconds. But I found that a half second is adequate, if you can accept gray rather than black. You can drive from white to gray and back again.

The datasheet says the device uses 0.5uA per cm squared. This device is about a centimeter squared. Thus it takes 0.5uA for a half second to drive the device, which is not much energy.

To drive a segment white, you drive the top electrode high, and the segment low (grounded.) Wait a while, then remove the drive: all segments to the same potential (voltage) or all segments inputs (floating.)

You don’t need a negative voltage rail (with respect to ground.)

I found that you also must drive all non-changing segments to the voltage of the top electrode (you can’t leave them floating), otherwise nearby segments can also change. In other words, the field for the changing segment bleeds to floating segments, and the ink appears to bleed.

You can drive any segment to any voltage for a short duration without changing the segment. This can simplify the code. A segment only changes color during a relatively long (seconds) delay.

Some documents say the driving must be “balanced”. Apparently this just means you must drive a segment to the same voltage, for the same duration, in both directions, whether changing white to black, or vice versa. I don’t think it means that the device “burns in” if you drive it too long in one direction.

Code

The code is in my msp430Drivers repository, in the src/eInk directory. The high level code should be portable. The high level code abstracts what you must do to drive eInk.

The low level code uses the Texas Instruments MSP430 DriverLib. You can change it to use for example, Arduino. The low level code deals with GPIO pins.

The code is C++, object oriented.

The code sleeps the MCU in low power mode while delaying for the eInk to change color. (If you just spin delay, a typical, active MCU takes 1000 times more power then does the driven eInk device .)

The code keeps state variables for indicator state in persistent memory.

The code does not implement a bar graph, it implements a set of five separate indicators.

Indicator terminology

The word “indicator” is apropos. You can search for electronic parts using that word, or “indicator lamp.” Usually they are LED’s. But an LED does not indicate unless it is powered. Usually indicators are binary, on or off.

Here, the eInk is like a mailbox flag. It takes power to set it, then requires no more power, forever.

Here, I use different segments of a bar gauge, each as in indicator. The code doesn’t implement a BarGauge object, it implements a set of five indicators. eInk does not sell a single indicator device.

I fear they might not sell their five segment bar gauge very long, their large displays are probably more in demand.

Connecting

You need a GPIO pin for each segment, and one for the top plate. The device does not have a power and ground pin. Thus you need seven GPIO pins for this device, if you use all segments. You don’t have to use all segments, you can leave them unconnected, but then their color is not determined, they might not stay white.

Persistent state variables

I use the MSP430, and use it’s LPM4.5 low power mode. In that mode, the CPU is powered off and all registers, stack, and RAM contents are lost. You should put a state variable for an eInk indicator in persistent memory (FRAM in this case), otherwise you won’t know the state of the indicator when you wake up.

Indicating the browned out condition

Can you use a single eInk indicator to tell the power state, specifically whether an energy harvesting system is or has browned out?

The MSP430 does not have a hardware monitor that detects imminent brownout. The MSP430 does have hardware to reset the system when brownout occurs, so there is never a time when the system is executing in undefined manner, yet there is never time to execute code before going into reset. You must implement brownout detection in software, using an ADC to read the system’s own voltage.

Suppose you detect system voltage (Vcc) near brownout (say less than 1.9V) and set an eInk indicator. You probably have enough power left to set the indicator. But ambient energy could be enough to keep voltage near brownout, without actually browning out. The set indicator only means the system might have browned out and is again near brownout, or never browned out and is still near brownout.

Suppose you have a persistent variable didBrownout. The variable is loaded at program load time with false. You detect voltage near brownout (say less than 1.9V) and set the variable to true. Then the system browns out (say less then 1.8V). Then ambient power comes back and the system does a POR (power on reset) boot (which does not initialize variable didBrownout to false), and checks the variable didBrownout. Finding it true, the code sets an eInk indicator. The set indicator means the system browned out at least once in the past.

Whether the system has ever browned out is relevant if your system is keeping a clock without battery backup. If you brownout, the clock becomes wrong.

In this example, you have already used two of five indicators.

Image

In the image, the background and top segment were driven white, the next two segments black, and the bottom two segments were unconnected, floating always. Driving at 3.3V, for a half second.

The system (with an external AB0815RTC, not shown) can sleep at about 60nA. None of that current is used to keep the indicator visible.

A TI Lauchpad MSP430FR2433 at 3.3V and an eInk bar gauge.

Installing TI’s CCS Desktop on Ubuntu for use with MSP-EXP430FR2433 Launchpad

A log of my experience.

Context

I tried Energia and CCS Cloud but ran into their limitations.

Apparently CCS Cloud is usually for running their example projects.  My code initially used the TI MSPWare.DriverLib libraries, and the Energia SPI librares.   I had difficulties using those libraries in CCS Cloud.  I started with an example project for DriverLib.  It was configured for the MSP430FR4133 chip, and I could not seem to reconfigure the project for the MSP430FR2433 chip on the MSP-EXP430FR2433 Launchpad.

So I decided to byte the bullet and use CCS Desktop.  It is not a big leap for Eclipse IDE users, since apparently CCS is based on Eclipse.

Steps

See instructions.

Install dependent library.

sudo apt install libc6-i386

Run installer

Download and extract the installer.

Execute the installer.  It has a .bin suffix that is foreign to Linux, so you can’t just click on it.

cd <install location>
./cc*.bin

Expect it to take a while, since it is downloading over the net.  I assume you install to default ~/ti

Install drivers

cd ~/ti/ccsv8/install_scripts
sudo ./install_drivers.sh

Expect the command to return quickly.  I think it sets up udev for the USB link to your Launchpad.

After this, expect an icon for Code Composer Studio on your desktop, that works.

This worked for me on Ubuntu 16.04, CCS 8.1.0

Initial experience with CCS Desktop

It almost immediately asked me to update, which I did, although it seemed to be only Help files.

In the initial “Getting Started” screen, I chose “Would you like to use CCS in ‘Simple’ mode?”.

Now since I had previously used a DriverLib example project while evaluating CCS Cloud,

(You can program at the HAL level, using names of registers and bits, or use DriverLib, which abstracts the hardware to a higher level.  I had already coded to use DriverLib, and implemented my own library for SPI that used DriverLib.)

I used “Resource Explorer” to navigate to and download that same example project.

Import example project from MSPWare

In the "Getting Started" panel, choose "Resource Explorer" 
Choose "MSP430Ware" icon  
Navigate to "Libraries/Driver Library/MSP430FR2xx_4xx/
Example Projects/00_EMPTY_Project/emptyProject
Select emptyProject (single click on it)
Choose the "Import to IDE" icon in upper right.

(Don’t choose “Download and Install” icon. Apparently that downloads ALL the example projects for MSPWare, quite a lot.)

Expect the “emptyProject” project to appear in the IDE in the “Project Explorer” panel.

Put your own source in the project

I copied my /src folder from a github repository into the project.  Use copy and paste.

Build

Choose the “Build” icon (looks like a hammer.)

Now I ran into the compile error I had with CCS Cloud: the project is configured for the wrong target FR4133 instead of FR2433, and the macro symbol ESUCI_A1_BASE was missing.  (This in only because I foolishly used a high numbered device that is present on some chips and not on others.  Use low numbered devices, UCA0 or UCB0 instead of UCA1).

Retarget the project

This is more or less standard Eclipse stuff.

Click on the project ("emptyProject" row) with the right mouse button.
Expect a pulldown.
Choose "Properties"
Expect a dialog.
Left mouse button click on "General"
Expect the right panel to change.
Under the "Project" tab, in the "Variant" field, choose the down arrow.
Expect a list of chips.
Select "MSP430FR2433" (the one on the MSP-EXP430FR2433 LaunchPad)
Choose "Apply and Close"

Now if you rebuild, expect a cleaner compile. (In my case, I forgot to delete the main.c from the example, and had provided a duplicate main.c in my own /src.)

Debugging

Another reason I wanted to switch from CCS Cloud or Energia to CCS Desktop is for more sophisticated debugging.  The CCS Cloud debugger is limited.

Plug in the USB cable of the Launchpad.
Choose the "Debug" icon (looks like a bug.)
Expect a dialog saying "Initializing debugger first time..."
Expect another dialog saying "Loading program..."
Expect main.c to open in the edit panel, with the first line of code highlighted.
Expect the icons in the toolbar to include "Step into", "Step over", etc.

 

You can also change the Eclipse “Perspective” using an icon in the upper right.  You can change from the “Simple” perspective (because I chose “Simple” from the Getting Started panel) to the “CCS Debug” perspective, which will let you examine memory etc.

You are on your way…


Using a “Run To Completion Task” model in embedded programming

This is about the architecture or high-level structure of an embedded app.  You don’t always need an RTOS, or you can implement a very simple one.

References

I read these sources prior to this post.   This post is largely a hasty summary of these links.

Super Simple Tasker

Real Time For the Masses

Fearless Concurrency in your microcontroller

Context

Embedded programming is event/interrupt driven.

Embedded programming is multiprocessing:  devices are processors too.

Some chips e.g. Nordic NRF52 chips have event and task notions implemented in hardware.

Most chips have a NVIC (Nested, Vectored Interrupt Controller).

Traditional advice about ISR’s:

Interrupt service routines (ISR) should be kept short.   The references above dispute that dictum.

Traditional, typical software architecture

Your ISR’s are short and set flags (events).  Your main loop is an event loop:

main() 
  while(true)
    if (eventFlagA)
        taskA()
    if (eventFlagB)
        taskB()
    wait for event (WEV or WFI instructions on ARM)

Tasks are just functions.  They run in the main context (not in an ISR) where interrupts are enabled but no interrupt is being serviced.  Tasks are interruptible by any interrupt.  Interrupts come from concurrent device operations that your software Tasks start.  (And some chips call device operations “tasks”, that eventually generate “events” that trigger interrupts.)

Another example might be:

main()
   while true
      taskA()
      sleep(duration)
      taskB()
      sleep(duration)

sleep(duration)
   start Alarm
   while()
      wait for event
      if event is Alarm event
          return
      else
          handle other event, set flags, etc.

Again, your code dispatches ( an if sequence) on events.  You might need several sleep functions, each anticipating a different set of possible events.

Run to completion task architecture

main()
   initialize things
   schedule(taskA)
   while (true)
       wait for Event

taskA()
    do something useful
    schedule(taskB)

taskB()
   do something useful
   start a task on a device  (to generate event for taskC)

taskC()
   service device event
   schedule(taskA)
   
etc....

Here each task runs to completion.  That means it doesn’t sleep.  It does not mean that it can’t be interrupted by a higher priority task.  Each task is-a  ISR for an event/interrupt.

Here, it is important that each task runs to completion and insures that some other task is scheduled or that some device task is running and will generate an event/interrupt that will in turn schedule another task.  I.E. you must insure that you don’t sleep forever.

As discussed above for SST, the NVIC (Nested, Vectored Interrupt Controller) is the dispatcher.  Your code does not dispatch, the HW does (or an “OS” scheduler.)

You can schedule many tasks to run at the same priority at the same time in the future.  When they run, they execute pseudo-concurrently.  One will run, to completion, when the interrupt triggers, from its scheduled alarm.  The interrupt from the other task’s scheduled alarm will trigger at the same time, but since it is at the same priority, will be pended and be serviced only when the first task completes.

Difference between this and SST

SST described above has a broader notion of Task:

  • implemented in an “OS” i.e. by a Scheduler
  • has-a priority
  • that other Tasks can schedule, i.e. put in a list of ready tasks
  • that does not run on events, only when the Scheduler jumps to it.

But the “OS” scheduler can often be simpler: just set an Alarm on a HW timer, arranging that the task runs in response the the alarm, as the ISR of the HW timer.  You can use such a simpler scheduler when you don’t need the notion of a set of prioritized, software tasks.  The HW interrupt priorities can still insure that time critical code is run (to service devices) but your lowest priority tasks (the logic of your main application) don’t need to be structured as a set, each having different priority.

When you want to schedule for immediate, next execution, you can just pend the Alarm interrupt, or use a SWI?

Wrapping your mind around it

In the traditional architecture, the code structure shows the most likely (anticipated) sequence of events, and code executed in response (e.g. taskA, taskB.)  It might be easier for readers to grasp.

In the RTC Task architecture, it is harder for readers to see the sequence.  But it is easier to interpret the code as the “actions” for state machine transitions.  You can label each task to indicate its event, e.g. “onEventA.”

When to use this architecture

As discussed above for SST, when your application is a state machine.

 

 

 

 

Upgrading tools for next version of a radio chip NRF52810

A log of process debugging when I started using a newer version of the Nordic radio SoC ship:  nrf52810.

I am using:

  • Eclipse
  • gnu arm compiler
  • gnu mcu plugin for eclipse
  • nrfjprog
  • JLink

I found the need to upgrade nrfjprog and JLink.  When a newer chip comes out, old versions of the tools don’t understand the new chip.

The first symptom is that nrfjprog doesn’t recognize the chip and says something like “the connected chip is not the right family” even though the nrf52810 is in the 52 family and you specified –family NRF52.  You need to upgrade to the latest nrfjprog version.

When I overwrote the existing nrfjprog directory, I seemed to have problems with nrfjprog not finding the “DLL”, meaning the JLink shared library .so.   I seemed to fix that by deleting the directory and installing fresh.

The next symptom might be, if you use an old debug configuration with device equal to nrf52832, is that the debugger flashes the chip, but then your target program crashes.  You need to specify the correct device in the debug configuration.

The next symptom is that you specify in an Eclipse debug configuration, under the Device tab, that the device is nrf52810_xxAA, but the debugger gives “Failed to set device (nRF52810_xxAA). Unknown device selected?”  You need to upgrade to the latest JLink version.  That involves:

  • download a JLink (say .deb) installer and run it
  • update Eclipse settings for JLink

See https://gnu-mcu-eclipse.github.io/debug/jlink/ for one way to do it (in Window>Preferences>SEGGER J-Link.

Change the jlink_path variable in Eclipse say from “JLink_v60i”to “JLinkv630f”.  In the Debug config>Debugger tab>Executable field, choose the “Variables” button.  Expect a list of variables.  Scroll to and select  “jlink_path” and choose “Edit variables” button.  Expect another list.  Scroll to an select “jlink_path” and choose “Edit…” button.  Change value, and choose OK, OK, etc.

Also, you might need to change the “jlink_gdbserver” variable from “JLinkGDBServer” to “JLinkGDBServerCLExe”.  The name has changed, by the addition of “CLExe”?  Note that JLinkGDBServerExe has a GUI, but the GNU MCU plugin says to use the command line version JLinkGDBServerCLExe

After you do all that, you should be able to execute a debug configuration and flash your app to the device.

My app still crashes.  Now I find that I need a different softdevice for this chip, S112 instead of S132.  I need to change my build config:

  • use headers for S112
  • use linker script for S112

 

Why change to nrf52810?

For me, because it is cheaper in dollars per unit.  Fanstel sells a module BT832A for less than $4, which is cheaper than the Waveshare nrf518122 that I was using.   I am already developing and testing on the nrf52DK which uses the NRF52 family nrf52832, and which is the dev kit that support nrf52810.

Here is a comparison of the family members.

For me, the main difference is: has less memory (192k or ROM instead of 256k.)  So I will need to change my build process to include optimization for small size, and to build for a different Softdevice.  That will be costly in development time for a new build process.

I can use the nrf52810 because my app is small, doesn’t use many periherals (none that are missing on the 52810), and doesn’t use many BT features (only one connection.)

 

 

 

Modern build systems for embedded (radios)

About

I ramble about my experiences with build systems for developing for embedded systems.  I use radio, ARM, SoC’s (Nordic NRF5x family), but the discussion might apply more generally.  I try to provide links, so you can explore.

Summary: I gradually migrated to CLI command line tools, using more recent tools instead of make.

Background

History of what build systems I have used:

Those tools are in order of age,  ease of use, and speed.

For example, make is:

  • ancient
  • hard to use
  • slow

while Meson is (?):

  • recent
  • easy to use
  • fast

 

Factors to consider for a build system in this context

  • supports cross compilation
  • integrated with your IDE
  • handles frequent changes to underlying SDK (Nordic’s)
  • handles very many target embedded systems (platforms)

You might have many targets if you  have a long-lived product that you will upgrade with new hardware:

  • different vendors e.g. Nordic vs Silicon Labs)
  • chip families NRF51x/52x
  • versions within a family e.g.  52832, 52810, 52840
  • devices and protocols that you use (i.e. Softdevice with Bluetooth, or other, or proprietary protocols.)

Makefiles

They get very large.  They are not easy to understand or modify.   But the ones Nordic provides are templates:  you will need to modify them, and re modify them whenever you change the SDK.

Eclipse CDT managed build

Eclipse projects are distinguished by kind:

  • “CDT managed build”: Eclipse generates makefiles.
  • “Makefile managed build”: you provide and edit a makefile

CDT managed build uses a GUI.  You must learn the structure of the GUI instead of the structure of a text configuration file (the makefile.)

Very few people seem to use it in the niche of embedded radios.

Nordic provides a tutorial for  using Eclipse IDE for development, but the examples don’t use Eclipse “CDT managed build”, just “makefile managed build.”  Again, that means you must edit the makefiles.

CMake and the Nordic SDK

Several people have implemented and published their own CMake scripts (macros) specific to the Nordic SDK:

Apparently Nordic realizes the benefit of newer build systems.  Nordic CMake macros:  IMO they are not very modular or extendable.

I found that my own scripts are fragile wrt SDK version.

There are a plethora of options for integration with the IDE:

The fact that there is a plethora is discouraging.  It requires much reading to decide which to choose.  It tells me there is no settled easiest way.

I disliked the projects generated by CMake.  They were too different from my usual way of structuring a project.

Often I just used Eclipse as an editor, debugger, and  version control wrapper, and built using the command line.

Meson

(I haven’t used Meson yet, I am still exploring it.)

One comparison of CMake and Meson.

Apparently Meson supports cross compiling: their documentation.

Meson is written in Python.  That is encouraging, that they used a high-level, modern language to implement what is a very complex task.  I would guess that one might even be able to understand any exceptions in the Meson implementation.

Apparently integration with IDE is in the future.

There is a Eclipse plugin editor for meson files.

The big picture

You need a mental model of the build process.  You acquire that mental model after long experience.  Learning and discarding build systems can help you form that mental model.  The newer build systems more clearly represent the model.  For example, using make you must remember what a “dependency” line looks like (foo: bar) while in newer build systems, a dependency might be labeled with text that says “dependency.”

 

 

 

 

 

Quick start Bluetooth BLE Swift iOS

This is a running commentary for a development session where I attempt to quickly build a Bluetooth app on an iOS iPhone using an example from Github (the Zero to BLE example.)

I already have Xcode installed on an iMac and know and like Swift language.

My goal is a simple app that scans for a BLE advertiser (a peripheral providing a service), connects to it, and writes one BT characteristic of the service.  The app has a simple GUI: one button that means: do the aforementioned.

I choose iOS because it is prevalent, and I have already developed other apps for it.  I can worry about cross-platform to Android later.

Here, I just want to establish the processes and validate the example project.  Later, I will modify the example to suit my app needs.

Getting an open source project

First I searched for open source.  I decided that a Cloud City example on GitHub is a likely candidate.

Clone the project into say ~/git/ using a terminal and command line.

Building and testing the project

Start Xcode.

Choose the button “Open another project” in the lower right corner of the “Xcode welcome” screen, which you can always get to by choosing “Window>Welcome to Xcode.”  Expect a file browser to open.  Navigate to the …xcodeproj file in your repository clone, select that file, and choose OK.  Expect for the project to open in Xcode.

Build and run it by choosing the Right-arrow icon in the upper left.  Expect the project to build and for an iPhone simulator window to open.  (There already exists a “scheme” of the project to build for the simulator.)

Unfortunately, the iPhone simulator does not support BLE, so expect a dialog box in the simulator saying to that effect.  IOW, you really won’t be able to test the app using the simulator.  Instead you need to download the app to real iPhone hardware.

Downloading to a real device

Choose the Square icon in the upper left (meaning “stop the running app”).  Expect the simulator window to remain, but to quit the simulated app and show you the iOS home screen.

Now plug in a real BLE capable (4s or later) iPhone or iPad (some early iPads are not BLE capable.)  Use a USB cable.  Expect more “schemes” to appear in the combo box for “Set the active scheme” in the upper left of Xcode.  Click on the combobox and choose “Device><foo’s>iPhone.  Expect the current scheme to change to that.

Now click the “Build and Run” icon.  Expect the app to download and run on your device.

Distraction: I get: "Could not find Developer Disk Image."  This is a mismatch between Xcode and iOS on the device.  Each version of Xcode requires a minimum version of OS X and supports a maximum version of iOS.  See the section below: Upgrading various tools
Another distraction: I get error messages about the provisioning profile which Xcode offers to fix, and apparently does by using my Apple ID.  Then I get "An App ID with identifier io.cloudcity.BLETemperatureReader is not available...".  See the section below: Fixing the bundle identifier

Finally, the app downloaded to my phone and began working, displaying debug messages in Xcode.

My next post might be about modifying the example project.

 

Upgrading various tools

A quick search shows this SO post suggesting a mismatch between Xcode version and iOS version on my phone.   Skip this section if you don’t have that problem.

Choose “Xcode>About Xcode” to see your current version.  Mine is 7.2.

Choose “Apple>About this Mac” to see your current OS X version.  Mine is 10.11.6  El Capitan.

Start the “App Store” app and choose the “Updates” tab.  Expect it to show you whether there are any updates available.  For me, none were.

On your iPhone, choose “Settings>General>About>Version”.  My installed iOS is version 9.3.5.

Searching showed that the latest Xcode is 9.2.  I don’t know why the App Store did not suggest it exists.  A quick search shows that in App Store you must search for “Xcode” and then click the “update” button from that result.   That didn’t seem to work, I got a spinning wheel but nothing seemed to happen.

The Xcode page on App Store says it is compatible with OS X 10.12.6 or later.  So I need to upgrade OS X first?  I think I have missed some updates so can’t updated directly from 10.11.6 to 10.12.6?  Anyway I went to this Apple page and downloaded a 10.12.6 update directly.  It takes several minutes.  When I clicked on the .dmg, etc.  I eventually got the message “… not supported on your system.”

Now a search reveals that 10.12 is “High Sierra” and that I need to “upgrade” not update.  But the upgrade page says I need an iMac later than 2009, while mine is circa 2007 as shown by “About this Mac.”  So I can’t upgrade to the latest Xcode.

But I can upgrade to a version that supports iOS 9.3.5  Wikipedia shows that Xcode 7.3.1 might support iOS 9.3.5 and run on my OS X.

So I downloaded and installed it (replacing my old installation) which took say an hour.

Fixing the bundle identifier

After Xcode complained about the provisioning profile and fixed it, Xcode did not like the original bundle identifier.  So I changed it by clicking on the project, choosing the “General” tab, and changing the field “Identity:Bundle Identifier” to <my apple id email address>.BLETemperatureReader.   The first part identities the developer or company building the app, the second part is the name of the app.

This post explains you can develop and provision to real devices without becoming a paid member of Apple Developer Program.  You do need to have an Apple ID (but everyone does who uses an Apple product) but you don’t need to pay the annual fee to the ADP.

 

 

 

 

 

Nordic Timers

This is an overview of timers on Nordic radio SoC.

On the NRF52 family of radio SoC, there are these Timer devices:

  • RTC: low power, and low frequency
  • Timer: high power, and high frequency

The RTC is misnamed.  RTC is Nordic’s  acronym for “Real-Time Counter” but more generally RTC means “real time clock” and provides calender like functions: time measured in years and days.  The Nordic RTC is only 24-bit, so  it typically rolls over frequently, say in minutes.  Whereas most people expect a RealTimeClock to never roll over, practically speaking.

On the NRF52, there are three RTC’s, RTC0, RTC1, and RTC2.

  • RTC0 is used by the Softdevice
  • RTC1 is used by the Nordic app_timer module
  • RTC2 is not generally used by the Nordic SDK

So your app should use RTC2 as the first choice, so that if your app also uses Softdevice or app_timer, there is no conflict.

Nordic’s app_timer module implements virtual Timers.  That is, many Timers are implemented in software on one real Timer (i.e. one compare register of RTC1.)

Timers might better be called Alarms.  A Timer is implemented on a Clock and an Alarm, where a Clock is a counter that rolls over and an Alarm is a compare register that generates an event/interrupt when the compare register matches the clock.

Each of the RTC’s has a counter and multiple compare registers.  Thus you can implement many real Timers on each RTC.

A real Timer is implemented on hardware devices like the RTC.  It consumes no cpu cycles while it is running, and few cpu instructions to set it up.

Because virtual Timers are implemented partially in software, it takes a few more cpu cycles than a real Timer.  But that’s not important.  What is important is that the virtual Timers be implemented correctly.  There are outstanding bug reports on Nordic’s app_timer implementation.  And the test suite is no public.

Other software kits such as freeRTOS implement virtual Timers.  These might be more likely to be correct since they are open source and widely used?

Algorithms for setting an Alarm on a Clock are not trivial but are well understood.  It requires careful use of modulo arithmetic.  Modulo arithmetic is “clock like”: results of operations roll over, loosely speaking.  Correctly setting an alarm on a clock also requires use of Lamport’s rule.  Finally, a hardware implementation of a clock has limitations that the software (the Timer driver) must account for: a compare register cannot be set too near the current counter value, else the hardware event might not occur in a timely fashion.

 

 

Pragmatics of nano power radios

This is a brief note about high level concerns with nano power radios, solar powered without batteries.

Don’t rely on this, study it yourself, especially until I add proper links.  Some of it is just crude notes, even speculation.

Other References

A note at Mouser about ultra low power mcu design.

Context: nano power

The power supply:

  • provides low average current, around 1uA
  • has no large reserve
  • is is expected to provide zero current often (say every night)

For example:

  • solar power with a capacitor
  • no battery
  • indoor light
  • solar panel smaller than a credit card

Overview

  • radio is duty-cycled
  • a voltage monitor/power supervisor and load switch chip provides clean reset/boot
  • boot sequence must be short and monitor mcu Vcc
  • use a power budget for design
  • use synchronization algorithms
  • testing is hard
  • over voltage
  • energy harvesting

Duty-cycled radio

The radio is sleeping most of the time.  When sleeping, a low-power timer runs to wake the system.  The sleeping radio cannot wake the system when it receives.

Example: the system may sleep for a few seconds, and be awake (with radio on) for about a millisecond.  That is, the duty cycle is around 1000.

Voltage monitor/Load switch

A microprocessor (in a radio SoC) needs a fast-rising voltage to boot cleanly.  Otherwise it may enter a state where it consumes power without booting. (Fibrillating?)  It may be in that state for a long time.  The solution is to use an external voltage monitor aka power supervisor aka reset chip.  E.g. TPS3839 (ultra-low power of 150nA.)

You can’t just connect the voltage monitor to the reset line of the mcu.  Otherwise, the mcu will still consume power while its reset line is held in RESET state. (Between the time voltage is high enough for the voltage monitor to have active outputs say 0.6V and the time the voltage is high enough to run the mcu say 1.8V.)  An mcu may draw a fraction of a milliamp while held in reset.

So the voltage monitor drives a high-side load switch that switches power (Vcc or Vdd) to the mcu.  I use the TPS22860.  (You can switch ground i.e. low-side with a NMOS mosfet but it’s not so easy to design your own high-side switch.  You can’t switch the low-side of an mcu because many pins may leak to ground?)

Voltage monitor hysteresis and boot sequence

The voltage monitor asserts its Out (sometimes call Not Reset) at a certain threshold voltage but then unasserts if the voltage falls below the threshold a certain amount called the hysteresis.  While the mcu is booting, it must not use so much current that Vcc falls below the hysteresis.  The boot sequence typically does a bare minimum, then checks Vcc, and sleeps until Vcc is much beyond the the minimum.  That is, allowing time for the ‘challenged’ power supply to catch up and store a reserve.  Only then does the software proceed to use the radio, duty-cycled.

You could use a voltage monitor with higher hysteresis.  But they don’t seem to make them.  The hysteresis of the TPS3839 is only 0.05V.  You can play tricks with a diode/capacitor on the input of the voltage monitor to make it seem to have a higher hysteresis (to delay longer before un asserting.)  And there are application notes on the web about adding hysteresis to voltage monitors.  But they seem to apply to older voltage monitor designs, and don’t seem to apply to the ultra-low power TPS3839 (which samples Vcc.)

Also, you could design your own voltage monitor with more hysteresis.  For example, see the Nordic solar powered sensor beacon.  That uses a few mosfets to provide a 0.2V hysteresis (say booting at 2.4V and resetting at 2.2V).  Unfortunately, they don’t seem to have exactly documented how the design works.

Power Budget

A power budget calculates the average current of a system, given certain phases of certain durations, where each phase uses certain devices/peripherals.

Here the main phases are:

  • sleeping (say 1.5uA for 1 second)
  • radio and mcu on (say 6 mA for 1 milli second)

You can almost ignore any phases where only the mcu is active, it should be a small portion of your budget.

A discussion at Digikey.

Synchronization algorithms

These make your units wake at the same time, so they can communicate with each other.

A beacon is usually unsynchronized.  The thing that hears a beacon (e.g. a cell phone) has  enough power to listen a long time.  You also might not need to synchronize if you have a “gateway” that is always powered and listening.  (See Zigbee.)

This seems to still be a research topic, there is much literature to read and few open source code examples.

Testing is hard

With such a challenged, nanopower supply, testing is hard.  A bug may exhaust power so that the system brown out resets, losing information about what happened.

Most hardware debuggers make the target consume more power than the power supply can provide?  TI seems to have ultra-low power debugging tools, but I haven’t studied them.

You can implement fault/exception handlers that write to non-volatile flash so that you can subsequently connect to a debugger and read what happened.   Default handlers typically just infinite loop (which will brown out reset.)  Typical handlers will do a soft reset.  Unless your app makes a record or communicates that, you might not even know the system reset itself.

Agililent (formerly Hewlett-Packard) sells expensive instruments for monitoring power consumption.  These may tell you you when (in relation to other events) you are consuming more power than you expect, but not exactly why.

Over voltage

A solar cell is a current source, and provides a variable voltage.  Voc is voltage open circuit (when your capacitor is fully charge.)  It can exceed the Vmin of your radio (typically 3.6V.)

Voltage regulators (such as shunt regulators) that prevent that are themselves current wasters.

You can choose a solar panel whose Voc is less than the Vmin, but there are few choices in that range (Voc < 3.6V, Vope around 2.4V, for indoor light.)  Or you can require that your solar panel never be exposed to strong light.

I haven’t found a zener diode that would clamp the voltage to 3.6V, and not leak much, at such nano currents.

Energy Harvesting

This is another buzzword, but good to search on.  It often means: with a single coin cell battery.

Energy harvesting chips are available.  They solve some problems you might not have, such as over-voltage protection, or voltage boosting.

It often refers to other power sources such as heat or vibration.  Those power sources are usually even smaller than solar (light) power, but solar power is episodic (diurnal.)

Solar power in different setting differs by orders of magnitude.  Direct sun is ten times stronger than outdoor, blue-sky shade, which is ten times more than strong indoor light, which is ten timer more than  dim indoor light.

 

 

Writing custom libraries for Energia (Arduino)

This is just about the pragmatics of: where do I put source files so that they are a shared library?

Custom: one you write yourself.

Library: a set of C++ source files (.h and .cpp) that you want to share among projects.

The simplified Energia/Arduino view

Outside the simplified Energia/Arduino world, libraries would be in a separate, shared directory and they would be pre-compiled into an object and separately linked into your projects.  In the Energia/Arduino world, that is all hidden.

Also, in the Energia world, a library seems to be a zipped directory of source files that follow some conventions that identify the version and documentation of the library.   So you can share the library.  I don’t know what the conventions are.  But if you are going to share your custom library, you should follow the conventions, and zip it up.  Then others can use the simplified user interface for installing zipped libraries.  Here, I don’t bother with the zipping.

Creating a custom library

Briefly, you just need to create your source files in the place that Energia looks.

Find where your sketchbook directory is:  In Energia choose “Sketch>Show Sketch Folder.”  Expect a file browser dialog (the Finder on the Mac) to show you the directory.

You will see a sub directory named “libraries”, and it will probably be empty.  (I don’t know where Energia keeps all the other pre-installed libraries.)

In that directory, create a directory with the name of your library e.g. “PWM”.

In the “PWM” directory, create your .h (and maybe .cpp) files, e.g. “pwm.h”

Now switch back to Energia and select “Sketch>Include Library>”   Expect a hierarchal menu to appear.  Expect to see “PWM” in the “Contributed libraries” section of the menu.

You can also choose “Sketch>Include Library>Manage Libraries”.  Expect a browser kind of window to open.  You should be able to browse to a line saying “PWM version unknown INSTALLED”.  (In my opinion, this should not be called “Manage Libraries” because it seems all you can do is view a list of the libraries.)

(Note that Energia expects at least one source file in your library directory.  Until then, Energia may give an error “Invalid library found in….”)

Referencing the library

In your main sketch “#include <pwm.h>”

Then define an instance of the PWM class and call its methods.

Developing and managing your library

You can just edit the files in place, using another editor.   When you use Energia to “verify” the main sketch that uses the library, it will recompile your changed library.

By managing I mean: copy the files out of the sketchbook folder to a safer, more shared place.  The sketchbook is in /Users/foo/Documents/sketchbook (on a Mac).  I prefer to put them under source control in a “git” folder, or in the “Dropbox” folder, so when I am done developing, I copy the library folder somewhere else.

I suppose you could use git in that directory, and when you are done, commit and push that repository to a your shared (master) repository on github.

Brief Summary

A library is just a named directory in the directory “sketchbook/libraries”.  You can create a library yourself using a file browser and editor.

Some notes on Panasonic Amorton solar cells

These are just rough notes that might help someone else in their personal electronic projects.  About Amorton’s indoor solar cell products, AM1456, AM1417, etc.

These solar cells are like what you see in calculators.  They are only a few square centimeters or larger.  Typically like pieces of glass.

For low light

These indoor products are for low light.  They are characterized for as little as 50 lux, which is not much light, typical of an indoor space with average lighting.  A room with a sun facing window, on a clear or overcast day, typically has much more light.  Even typical artificial lighting provides this much light.

The power available at these lighting levels is only a few uA.  Also, the Vope (which is the operating voltage, which really means the maximum power voltage, see MPPT) is a fraction of the Voc (voltage open circuit)  in much stronger light.  For example, if the panel has four cells which each deliver a maximum of 0.6 volts, the Voc might be 2.4V but the Vope in 50 lux might be only 1.4V.

You should design your circuits to operate around Vope, since if you design to operate at the Voc, it will take strong light, and the power delivered will be smaller than you could get at Vope.

(PowerFilm does not characterize their film solar cells at such low light levels.  But they recently started selling LL3-37, which IS targeted for low light.)

Availability

Some of the glass ones are available from Digikey and Mouser.  The film versions don’t seem to be readily available in small quantities to retail buyers.

Solderability

The models that are commonly available have pre-soldered wires, AWG 30.  I have had good success in unsoldering the wires, leaving the solder ball, and soldering on a different wire (including tinned piano wire.)

Surface Mount

I also tried unsoldering the wire, cleaning the pad with flux and desoldering braid, and trying to reflow surface mount.  With very poor results (say one success in three.)  The manufacturer said this is not a supported use.  After the failure, you see a brown surface that solder won’t stick too.  Evidently the ‘interface’ between the solder and the semiconductor is very thin and its solder ability easily destroyed.

Some of the product variations for AM1456, AM1417 have no pre-soldered wire, but only conductive paste, and they are available only in large quantities (AFAIK.)  I don’t think these are intended for reflow soldering either.

Amorton recently started selling model AM1606, which IS intended for surface mount (SMD.)  Available from Mouser.

Durability

They seem relatively robust.  I have dropped them from desktop height onto concrete and they don’t seem to break.  I have had a few, small, conchoidal chips out of the edge, seeming cosmetic, not affecting the power out.

Under extreme mechanical stress, the soldered pads occasionally detach at the ‘interface’.  See above re surface mount.

Safety

The glass edges are not sharp.  I have never cut myself on the edges.  I suppose the manufacturing process somehow rounds the edges a little, even though they appear quite square.  However, I suppose the edges are intended to be enclosed in a frame.

But since they are small and glass, they ARE a hazard for small children, and if they should break into pieces.