Computing stuff tied to the physical world

Keeping track of the milli’s

Let’s recap: we have a simple “blip” node sending out test packets, and we’re picking them up with another node attached to the Raspberry Pi’s I2C bus as a slave device.

This is clearly only the beginning of a general-purpose wireless sensor network setup. There is no return “send” path yet, not even for ACKs, and there is nothing yet to manage the reception, i.e. polling the I2C slave periodically in the background. There is also no easy way to upgrade the firmware in these nodes, not even the central one – we currently need to unplug, re-flash, and re-insert the LPC810 chip if we want to make changes to it.

Which means that this I2C setup is really not much more than a proof of concept.

But this design does have some interesting properties:

  • it’s as low-end as it gets in terms of the micro-controller and the wireless radio
  • there is no hidden complexity, everything is inspectable – and improvable!
  • more central nodes can be added, for different net groups or frequency bands
  • there is no USB involved, no drivers, no interface chips – not even a 3.3V regulator
  • the I2C bus is fast enough to handle all RFM69 traffic, in both directions

One of the less convenient aspects of this design is that the I2C bus is a master-slave setup, with the Raspberry Pi acting as the master. It needs to continuously poll the slaves to pick up newly received packets.

The good news is that polling the I2C bus 10 times per second consumes less than 2% CPU (this was measured with a small Go application used for testing). It’s not a show stopper.


But one drawback is that we’ll get the packets into the Raspberry Pi a little later than when they actually are received by the central node, due to the periodic polling. For replies which need to be sent out in response, this is a bad thing: the longer a remote node has to wait for a reply, the longer it has to stay in receive mode – which means it’ll drain its battery faster.

A related drawback is that we’ll have less accurate information as to the exact arrival time of each packet. The inaccuracy is determined by how often the master polls the slave on the I2C bus. For some use cases, this might be important.

To start with this second issue, there is a fairly simple way to fix this: we could include an “age” field in the reply sent over I2C, i.e. “45” meaning: the reply you’re now looking at is 45 milliseconds old. The receiving end on the Raspberry Pi can then turn this into an accurate timestamp, by subtracting that value from its (absolute) internal clock.

The other problem is more difficult to deal with – here are some ideas:

  • raise the master-slave poll frequency, at the cost of a higher overhead and bus load
  • put more smarts into the slave, so that it can handle responses on its own
  • add an I/O pin to let the slave signal when there is a new packet
  • abandon I2C and switch to a conventional bi-directional serial protocol

At this point, it’s not yet clear which approach will be best, so for now let’s just keep it in mind along with all the other functions we still need to implement to arrive at a general-purpose central node setup.

Part of the story also depends on whether we want to use a Raspberry Pi (or similar) as our central server. For a laptop or desktop machine, I2C would not be a convenient option.

[Back to article index]