Interact with simulated I2C devices
CircuitsSim requires Elixir Circuits 2.0 libraries.
You may need to add override: true
since not many libraries have been updated
to allow Circuits 2.0 versions. Circuits 2.0 is mostly backwards compatible, so
this should be safe.
CircuitsSim works by providing an alternative backend for interacting with
hardware. This is setup via config/config.exs
. In your project, you may only
want the simulated backends for MIX_ENV=test
configurations, so you'll want to
add the following appropriately. For trying it out, it's fine to start with
adding this to config.exs
:
config :circuits_i2c, default_backend: CircuitsSim.I2C.Backend
config :circuits_spi, default_backend: CircuitsSim.SPI.Backend
config :circuits_gpio, default_backend: CircuitsSim.GPIO.Backend
Note that you don't need to replace all backends. If you're only using I2C, there's no need to bring in SPI and GPIO support.
CircuitsSim takes a configuration for how to set up the simulated I2C buses and devices. Here's an example configuration:
config :circuits_sim,
config: [
{CircuitsSim.Device.MCP23008, bus_name: "i2c-0", address: 0x20},
{CircuitsSim.Device.AT24C02, bus_name: "i2c-0", address: 0x50},
{CircuitsSim.Device.ADS7138, bus_name: "i2c-1", address: 0x10},
{CircuitsSim.Device.MCP23008, bus_name: "i2c-1", address: 0x20},
{CircuitsSim.Device.MCP23008, bus_name: "i2c-1", address: 0x21},
{CircuitsSim.Device.TM1620, bus_name: "spidev0.0", render: :binary_clock},
{CircuitsSim.Device.GPIOLED, gpio_spec: 10},
{CircuitsSim.Device.GPIOButton, gpio_spec: 11}
]
This shows two simulated I2C buses, "i2c-0"
and "i2c-1"
, one SPI bus,
and two GPIO.
The "i2c-0"
bus has two devices, an MCP23008 GPIO expander and an AT24C02
EEPROM.
Here's how it looks when you run IEx:
$ iex -S mix
Interactive Elixir (1.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex> Circuits.I2C.detect_devices
Devices on I2C bus "i2c-1":
* 16 (0x10)
* 32 (0x20)
* 33 (0x21)
Devices on I2C bus "i2c-0":
* 32 (0x20)
* 80 (0x50)
5 devices detected on 2 I2C buses
You can then read and write to the I2C devices similar to how you'd interact with them for real. While they're obviously not real and have limitations, they can be super helpful in mocking I2C devices or debugging I2C interactions without hardware in the loop.
Many I2C devices follow a simple pattern of exposing all operations as register
reads and writes. If this is the case for your device, create a new module and
implement the CircuitsSim.I2C.SimpleI2CDevice
protocol. See
CircuitsSim.Device.MCP23008
for an example.
If your device has a fancier interface, you'll need to implement the
CircuitsSim.I2C.I2CDevice
protocol which just passes the reads and writes
through and doesn't handle conveniences like auto-incrementing register
addresses on multi-byte reads and writes. See CircuitsSim.Device.ADS7138
for
an example.
Simulated SPI devices implement the CircuitsSim.SPI.SPIDevice
protocols. See
CircuitsSim.Device.TM1620
for an example.