fhunleth

fhunleth

Co-author of Nerves

Circuits GPIO, I2C and SPI - Use Elixir to control hardware and read sensors

Elixir Circuits is a set of libraries for interacting with hardware. We previously announced Circuits.UART, and now we’re ready to announce Circuits.GPIO, Circuits.I2C, and Circuits.SPI. Here are examples of devices that you can control with the libraries:

  • Circuits.GPIO - buttons, switches, and lights
  • Circuits.I2C - accelerometers, gyroscopes, compasses, some thermometers, displays, lighting and motor controllers and more
  • Circuits.SPI - analog to digital converters, small displays, and custom programs running on FPGAs

These libraries work on Raspberry Pis with Raspbian, other embedded Linux devices and the official Nerves platforms. The libraries also include test backends for compilation and limited testing on development machines.

The Circuits GPIO, I2C, and SPI libraries can be thought of as Elixir ALE 2.0. During the development of Elixir ALE 2.0, we decided to break apart the library based on hardware interface. The APIs are similar to Elixir ALE, but different enough that if you are currently using ALE, we recommend that you review the porting guides in the documentation. All users of Elixir ALE are highly encouraged to update their projects to the appropriate Circuits libraries.

Changes from Elixir ALE 1.0 include:

  1. Circuits GPIO, I2C, and SPI now use NIFs. The performance improvement is noticeable - especially for GPIOs. Yes, there’s a trade off in stability. Based on our experience with ALE, we felt we could achieve a similar level of stability with NIFs and support use cases that were limited by ALE’s performance.
  2. Various API improvements and conveniences like supporting iodata when writing to the I2C and SPI buses and more configuration in open calls to support “glitch-free” initialization
  3. Support for internal pull-ups and pull-downs on GPIOs on Raspberry Pis. This saves you from having to connect a resister to buttons
  4. More user-friendly support for finding devices on I2C buses
  5. Timestamped GPIO interrupt messages to improve pulse measurement precision

Check out https://elixir-circuits.github.io/ for more information.

We really enjoy using the Elixir programming language with hardware and we hope that you will too.

Happy hardware hacking!

Frank Hunleth
Mark Sebald
Matt Ludwigs

Most Liked

fhunleth

fhunleth

Co-author of Nerves

We just released circuits_gpio v0.4.1 which has important updates for Raspbian. All Circuits projects should work well on Raspbian now.

While many of us primarily work with Nerves, we want Circuits to have a great out-of-box experience with Raspbian and other Linux distros running on Raspberry Pis, Beaglebones, etc. If you’re using one of these, please let us know (via GitHub issue) if anything doesn’t work or is confusing.

fhunleth

fhunleth

Co-author of Nerves

Circuits.GPIO 2.1.3 is now available that fixes a serious issue that caused interrupt messages to stop being sent. Please update when you can. I went ahead and marked the hex packages for versions prior to 2.1.3 as invalid since this issue can be quite hard to track down. Thanks to @akoutmos for providing me a Nerves Livebook that reproduced it and @gus who also was able to reproduce and confirm the fix in a different context.

The bug affects anyone using two or more GPIOs in interrupt mode. If you’re not using interrupts or use only one, then upgrading is less important. In practice, the issue occurred when a GenServer using one GPIO in interrupt mode crashes and restarts. Another open GPIO in interrupt mode could stop getting interrupt messages. Internally, the ordering of events matters, so it was possible to get inconsistent outcomes.

fhunleth

fhunleth

Co-author of Nerves

circuits_gpio v0.4.2 is available now. It has an important update that makes GPIO pullup and pulldown settings work with the Raspberry Pi 4. This feature is frequently used by Raspberry Pi hats that have buttons on them.

fhunleth

fhunleth

Co-author of Nerves

circuits_gpio v0.4.3 and circuits_i2c v0.3.5 are available now.

circuits_gpio has a fix for handling fast GPIO transitions. One example of these are the spurious transitions from button presses. The normal route is to add debounce handling code to remove them. circuits_gpio does some debouncing due to it being slow. In some cases you don’t want to miss the GPIO transition. This release fixes a bug when turning it off. See the :suppress_glitches option.

circuits_gpio also supports forcing GPIO emulation on for testing libraries that use it. See CIRCUITS_MIX_ENV.

circuits_i2c fixes an issue when scanning the I2C bus for devices. There’s no spec for enumerating an I2C bus, so it’s done heuristically. There’s still an outstanding issue for an improvement in this area.

A final note: Several people have contacted me about cdev support for circuits_gpio. This would be a significant and important update. I am not working on this, but others have expressed interest. Since this is a sizable unfunded effort, I’m not sure when this work will be available - no changes have been pushed to any public repo yet. If you are interested in contributing to this effort, I will gladly put you in contact with others.

fhunleth

fhunleth

Co-author of Nerves

Thanks for the heads up on the Elixir Circuits website. It’s back up now.

Elixir Circuits handles the communication to each of those devices. I’m not sure if anyone has published libraries for those sensors. I feel like the ADC and color sensor have code out there some where.

There are three main approaches to adding support for a chip if no one has made an Elixir library already:

  1. Download the part’s datasheet and implement it yourself by making calls to Circuits.I2C. The SHTC3 part is probably a good one to start since it has a short datasheet and you could experiment with it at the iex prompt.
  2. Port a Python library. This works with the datasheet is hard to understand.
  3. Don’t use Elixir Circuits at all and go through a Linux device driver

I’d start with the SHTC3 or TCS34725 since those seem more straightforward than the others. I think that it depends on what you want to do with the IMU (ICM20948) and ADC. If you just want to get values out of it, Elixir is fine. If you’re using those to control a drone or something where dropping a sample would be really bad, then I’d look at Linux’s IIO drivers. This isn’t meant to be a critique of Elixir, but more that writing timing critical device drivers in Linux userland can be hard.

One last thing: if you want to experiment with the devices at the IEx prompt, the Circuits Quickstart can help. That project has pre-built images for many Nerves boards. You can copy/paste short Elixir modules into the prompt if you’d like. Of course, you’ll eventually want to make your own firmware image and get away from copy/paste programming at the iex prompt, but for little things and experimentation, I find it pretty convenient.

Where Next?

Popular in Announcing Top

RobinBoers
Renders Jinja templates, either from disk or defined at runtime, with support for all native Jinja features (including extends). It does...
New
zachdaniel
:smiling_face_with_sunglasses: New package usage_rules released! Just place a usage-rules.md file in your package and users can sync it t...
#ai
New
fteschke
Announcing: playwright_ex A simple Elixir client for the Playwright node.js server. Automate browsers like Chromium, Firefox, Safari an...
New
lucaong
CubDB is an embedded database written in pure Elixir, designed for robustness and minimal use of resources. It strives to be as developer...
New
jsm
Once is an Ecto type for locally unique 64-bits IDs generated by multiple Elixir nodes. Locally unique IDs make it easier to keep things ...
New
leandrocp
MDEx is a fast and extensible Markdown parser and formatter. Fast Leverage Rust to parse, manipulate and render documents using: comra...
New
martosaur
Hello, I’m excited to introduce InstructorLite – a fork of the Instructor package. Instructor brought the very idea of structured LLM p...
New
Asd
Hi, I am happy to release the Repatch library for mocking and patching implementation in tests and anywhere else. It brings new possibili...
New
taro
I took lessons from the last discussion and cobbled together an example as a proof-of-concept. Mar demonstrates a Flask-like web dev int...
New
volcov
Hello, How is everyone? I hope you’re well =) I worked on a project with some legacy code that existed before Oban’s arrival. This leg...
New

Other popular topics Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New

We're in Beta

About us Mission Statement