Saturday, 4 April 2020

SPI access to multiple ToF sensors is working

I've been ploughing through the steps towards my goal of connecting multiple distance sensors to Anastasia's micro:bit.

I now have a pair of Arduinos connected via SPI, with the slave reporting distances from two VL53L0X sensors.

The wiring is a mess and the code needs cleaning up.

But it's working, and replacing the Arduino master by a micro:bit should be pretty straightforward.

I'll report on progress.

The code is on GitHub.

Friday, 3 April 2020

7 steps to add multiple ToF LiDAR sensors to a micro:bit

I'm happy with the solution I came up with to attach multiple Time-of-Flight (ToF) sensors to a Raspberry Pi or CircuitPython board.

Now I want to add one or more ToF sensors to Anastasia, my Python-powered micro:bit robot.

Anastasia needs at least one distance sensor to stop her running into things.

Since she can travel backwards as fast as she goes forwards, she really needs two sensors: one looking forwards, and one looking behind.

I've been looking for a simple solution but I have hit a snag.

I've found several Python drivers for the VL53L0X chip I'm using, but none will run on the micro:bit.

Some are Python wrappers for C code; others are just too big to fit on the micro:bit.

I finally came up with an approach which looks as if it may work.

The goal is to use a board with an Arduino-ish clone, programmed in C, driving the sensors and returning results via SPI.

Seven steps to ToF success

I've broken the project plan into seven steps which will build up into a complete solution.

  1. Arduino driving one sensor
  2. Arduino with more than one sensor
  3. Arduino(s) with one as SPI slave
  4. Arduino with more than one sensor that's interrupt-friendly
  5. Arduino with more than one sensor as SPI slave
  6. Arduino with level shifter and micro:bit
  7. 8MHz 3V3 Arduino and micro:bit
So far I've got, and run, sample code for the first three steps. The code so far has all come from reliable sources on the web. The core driver code and code for multiple sensors are Adafruit Arduino libraries for the VL53L0X. The SPI slave code comes from Nick Gammon's excellent site.

Step 4 needs a bit more thought. It's tempting to return floating-point values that show the measured distances, but there's a potential snag. The SPI save code is interrupt-driven, and I'd need to make sure that the code does not try to return a multi-byte value while that value is changing.

Concurrency rules

Rule one of concurrent programming is to avoid it if you can! Concurrent code is often hard to write, hard to read, and hard to test.

What I'll do is allow an SPI request that specifies which sensor to read. I'll return a single byte of data which will be a scaled distance measurement. If a valid distance can't be read I will return a value of zero.

I will be working on this over the next day or two and will report progress as I go.


I forgot to mention that the code I'm using/developing is on GitHub.

Wednesday, 1 April 2020

Muliplexing I2C with the Adafruit TCA9548A multiplexer

I want to attach multiple VL53L0X Time-of-flight sensors to a single I2C bus. It looks as if that should be easy, but it's not.

One solution involves disabling the sensors and then enabling them one at  a time to change their address. It's workable, but fiddly.

If you only have two sensors you could use different I2C buses, but I eventually want to run 8 sensors, so that won't work.

The TCA9548A I2C multiplexer

There is another approach that is easy to implement and works out of the box.

The TCA9548A is an I2C device that acts a little like a telephone exchange.

You can use it to route I2C transactions to one of eight separate I2C busses. That allows you to have eight devices with the same I2C address, one on each bus.

I did a first experiment using an Adafruit CircuitPython m4 feather.

That worked well, and I've just confirmed that it works just as well with a Raspberry Pi. Since I'm using Adafruit's CircuitPython libraries, the same code runs on the Adafruit m4 and the Pi.

As you can see from the image above, the Pi I used was a veteran Pi model 2.

Kudos to the team at Raspberry Pi for maintaining software compatibility, and to Adafruit for making CircuitPython so portable.