{"id":25747784,"url":"https://github.com/elixir-circuits/circuits_spi","last_synced_at":"2025-04-06T06:11:49.220Z","repository":{"id":33297708,"uuid":"151843143","full_name":"elixir-circuits/circuits_spi","owner":"elixir-circuits","description":"Communicate over SPI from Elixir","archived":false,"fork":false,"pushed_at":"2025-03-08T21:49:54.000Z","size":243,"stargazers_count":27,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-30T05:07:18.464Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elixir-circuits.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSES/Apache-2.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-06T13:34:46.000Z","updated_at":"2025-03-08T21:49:57.000Z","dependencies_parsed_at":"2024-03-06T04:24:05.605Z","dependency_job_id":"09547df8-ca01-41ea-80db-5a5bd46e72e3","html_url":"https://github.com/elixir-circuits/circuits_spi","commit_stats":{"total_commits":138,"total_committers":13,"mean_commits":"10.615384615384615","dds":0.3405797101449275,"last_synced_commit":"e1e020f8a08e27ed4e06a4b593a79efcdbf3cba1"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-circuits%2Fcircuits_spi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-circuits%2Fcircuits_spi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-circuits%2Fcircuits_spi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-circuits%2Fcircuits_spi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-circuits","download_url":"https://codeload.github.com/elixir-circuits/circuits_spi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247441056,"owners_count":20939239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-26T12:18:02.131Z","updated_at":"2025-04-06T06:11:49.201Z","avatar_url":"https://github.com/elixir-circuits.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Circuits.SPI\n\n[![Hex version](https://img.shields.io/hexpm/v/circuits_spi.svg \"Hex version\")](https://hex.pm/packages/circuits_spi)\n[![API docs](https://img.shields.io/hexpm/v/circuits_spi.svg?label=hexdocs \"API docs\")](https://hexdocs.pm/circuits_spi/Circuits.SPI.html)\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/elixir-circuits/circuits_spi/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/elixir-circuits/circuits_spi/tree/main)\n[![REUSE status](https://api.reuse.software/badge/github.com/elixir-circuits/circuits_spi)](https://api.reuse.software/info/github.com/elixir-circuits/circuits_spi)\n\n`Circuits.SPI` lets you communicate with hardware devices using the SPI protocol.\n\n*This is Circuits.SPI v2. Circuits.SPI v1.x is still maintained in the [maint-v1.x branch](https://github.com/elixir-circuits/circuits_spi/tree/maint-v1.x).*\n\n`Circuits.SPI` v2.0  is an almost backwards compatible update to `Circuits.SPI`\nv1.x. Here's what's new:\n\n* Linux or Nerves are no longer required. In fact, the NIF supporting them won't\n  be compiled if you don't want it.\n* Develop using simulated SPI devices with\n  [CircuitsSim](https://github.com/elixir-circuits/circuits_sim)\n* Use USB-\u003eSPI adapters for development on your laptop (Coming soon)\n\nIf you've used `Circuits.SPI` v1.x, nearly all of your code will be the same. If\nyou're a library author, we'd appreciate if you could try this out and update\nyour `:circuits_spi` dependency to allow v2.0. Details can be found in our\n[porting guide](PORTING.md).\n\n## Getting started on Nerves and Linux\n\nIf you're using Nerves or compiling on a Raspberry Pi or other device with SPI\nsupport, then add `circuits_spi` like any other Elixir library:\n\n```elixir\ndef deps do\n  [{:circuits_spi, \"~\u003e 2.0\"}]\nend\n```\n\n`Circuits.SPI` doesn't load device drivers, so you'll need to load any necessary\nones beforehand. On the Raspberry Pi, the [Adafruit Raspberry Pi SPI\ninstructions](https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-spi)\nmay be helpful, (This is already enabled for you if you are using Nerves)\n\n\nA [Serial Peripheral\nInterface](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus) (SPI)\nbus is a common multi-wire bus used to connect components on a circuit board. A\nclock line drives the timing of sending bits between components. Bits on the\nController Out Peripheral In `COPI` line go from the controller (usually the processor\nrunning Linux) to the peripheral, and bits on the Controller In Peripheral Out `CIPO` line go\nthe other direction. Bits transfer both directions simultaneously. However, much\nof the time, the protocol used across the SPI bus has a request followed by a\nresponse and in these cases, bits going the \"wrong\" direction are ignored. This\nwill become more clear in the example below.\n\nThe following shows an example Analog to Digital Converter (ADC) that reads from\neither a temperature sensor on CH0 (channel 0) or a potentiometer on CH1\n(channel 1). It converts the analog measurements to digital, and sends the\ndigital measurements to SPI pins on the main processor running Linux (e.g.\nRaspberry Pi). Many processors, like the one on the Raspberry Pi, can't read\nanalog signals directly, so they need an ADC to convert the signal.\n\n![SPI schematic](assets/images/schematic-adc.png)\n\nThe protocol for talking to the ADC in the example below is described in the\n[MCP3002](http://www.microchip.com/wwwproducts/en/MCP3002) data sheet. The\nprotocol is very similar to an application program interface (API) for\nsoftware. It will tell you the position and function of the bits you will send\nto the ADC, along with how the data (in the form of bits)\nwill be returned.\n\nSee Figure 6-1 in the data sheet for the communication protocol. Sending a\n`0x68` first reads the temperature and sending a `0x78` reads the\npotentiometer. Since the data sheet shows bits, `0x68` corresponds to `01101000b`.\nThe leftmost bit is the \"Start\" bit. The second bit is SGL/DIFF, the third\nbit is ODD/SIGN, and the fourth bit is MSBF. From table 5-1, if SGL/DIFF==1,\nODD/SIGN==0, and MSBF==1 then that specifies channel 0 which is connected to\nthe thermometer.\n\n```elixir\n# Make sure that you've enabled or loaded the SPI driver or this will\n# fail.\niex\u003e {:ok, ref} = Circuits.SPI.open(\"spidev0.0\")\n{:ok, #Reference\u003c...\u003e}\n\n# Read the potentiometer\n\n# Use binary pattern matching to pull out the ADC counts (low 10 bits)\niex\u003e {:ok, \u003c\u003c_::size(6), counts::size(10)\u003e\u003e} = Circuits.SPI.transfer(ref, \u003c\u003c0x78, 0x00\u003e\u003e)\n{:ok, \u003c\u003c1, 197\u003e\u003e}\n\niex\u003e counts\n453\n\n# Convert counts to volts (1023 = 3.3 V)\niex\u003e volts = counts / 1023 * 3.3\n1.461290322580645\n```\n\nAs shown above, you'll find out that Elixir's binary pattern matching is\nextremely convenient when working with hardware. More information can be\nfound in the [Kernel.SpecialForms documentation](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1)\nand by running `h \u003c\u003c\u003e\u003e` at the IEx prompt.\n\n## FAQ\n\n### How do I only receive data?\n\nSPI always sends a bit for every bit it receives. That means that to receive a\nbyte, you have to send a byte. Luckily, devices are designed with this in mind\nand discard or ignore bytes in these situations. For example, if you have a\nsensors and need to read 9 bytes of data, send 9 zeros to read it. The zeros\nwill be ignored and you'll get the data.\n\n### How do I debug?\n\nThe most common issue is communicating with a SPI device for the first time.\nFirst check that a SPI bus is available:\n\n```elixir\niex\u003e Circuits.SPI.bus_names()\n[\"spidev0.0\", \"spidev0.1\"]\n```\n\nIf the list is empty, then a SPI bus is either not available, not enabled, or\nnot configured in the kernel. If you're using Raspbian, run `raspi-config` and\ncheck that SPI is enabled in the advanced options. If you're on a BeagleBone,\ntry running `config-pin` and see the [Universal I/O\nproject](https://github.com/cdsteinkuehler/beaglebone-universal-io) to enable\nthe SPI pins. On other ARM boards, double check that SPI is enabled in the\nkernel and that the device tree configures it.\n\n### How do I set the speed of the SPI bus?\n\nSPI bus options like frequency (`:speed_hz`) and bits per word (`:bit_per_word`)\nare set as optional parameters to\n[`Circuits.SPI.open/2`](https://hexdocs.pm/circuits_spi/Circuits.SPI.html#open/2).\n\nFor example, the following configures the SPI bus to run at 122,000 Hz:\n\n```elixir\n{:ok, my_spi} = Circuits.SPI.open(\"spidev0.0\", speed_hz: 122000)`\n```\n\nThe ability to set the bus speed is device-specific. Please verify with a logic\nanalyzer that the speed is actually being set and consult the documentation for\nlimitations.\n\n### Where can I get help?\n\nMany issues are unrelated to `Circuits.SPI`. If you expand your searches to\ninclude Python and C forums, it's possible that someone else has run into your\nproblem too. SPI libraries in other languages should be similar to\n`Circuits.SPI` so hopefully you'll find the answer.\n\nIf that fails, try posting a question to the [Elixir\nForum](https://elixirforum.com/). Tag the question with `Nerves` and it will\nhave a good chance of getting to the right people. Feel free to do this even if\nyou're not using Nerves.\n\n### Can I develop code that uses Circuits.SPI on my laptop?\n\nYou have a few options:\n\n1. Use the CircuitsSim backend\n2. Create a custom backend and use it to mock interactions with the Circuits.SPI\n   API\n\nWe hope to have support for USB adapters that have SPI interfaces in the future.\n\n## License\n\nAll original source code in this project is licensed under Apache-2.0.\n\nAdditionally, this project follows the [REUSE recommendations](https://reuse.software)\nand labels so that licensing and copyright are clear at the file level.\n\nExceptions to Apache-2.0 licensing are:\n\n* Configuration and data files are licensed under CC0-1.0\n* Documentation files are CC-BY-4.0\n* Erlang Embedded board images are Solderpad Hardware License v0.51.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-circuits%2Fcircuits_spi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-circuits%2Fcircuits_spi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-circuits%2Fcircuits_spi/lists"}