# `Circuits.I2C`
[🔗](https://github.com/elixir-circuits/circuits_i2c/blob/v2.1.0/lib/i2c.ex#L5)

`Circuits.I2C` lets you communicate with hardware devices using the I2C
protocol.

# `address`

```elixir
@type address() :: 0..127
```

I2C device address

This is a "7-bit" address for the device. Some devices specify an "8-bit"
address in their documentation. You can tell if you have an "8-bit" address
if it's greater than 127 (0x7f) or if the documentation talks about different
read and write addresses. If you have an 8-bit address, divide it by 2.

# `backend`

```elixir
@type backend() :: {module(), keyword()}
```

Backends specify an implementation of a Circuits.I2C.Backend behaviour

The second parameter of the Backend 2-tuple is a list of options. These are
passed to the behaviour function call implementations.

# `bus`

```elixir
@type bus() :: Circuits.I2C.Bus.t()
```

Connection to a real or virtual I2C controller

# `open_options`

```elixir
@type open_options() :: keyword()
```

I2C open options

See I2C backend documentation, device driver caveats, and function calls in this
module for notes. In general,

* `:retries` - the number of times to retry a transaction. I.e. 2 retries means
  the transaction is attempted at most 3 times. Defaults to 0 retries.
* `:timeout` - the time in milliseconds to wait for a transaction to complete.
  Any value <0 means to use the device driver or hardware default. The default
  value is -1 to avoid setting it, but it is very common for the default to be 1000 ms.

# `present?`

```elixir
@type present?() :: (Circuits.I2C.Bus.t(), address() -&gt; boolean())
```

Function to report back whether a device is present

See `discover/2` for how a custom function can improve device detection when
the type of device being looked for is known.

# `transfer_options`

```elixir
@type transfer_options() :: keyword()
```

I2C transfer options

See I2C backend documentation, device driver caveats, and function calls in this
module for notes. In general,

* `:retries` - override the number of times to retry a transaction from what was
  passed to `open/3`.

# `bus_names`

```elixir
@spec bus_names() :: [String.t()]
```

Return a list of available I2C bus names

If nothing is returned, it's possible that the kernel driver for that I2C bus
is not enabled or the kernel's device tree is not configured. On Raspbian,
run `raspi-config` and look in the advanced options.

```elixir
iex> Circuits.I2C.bus_names()
["i2c-1"]
```

# `close`

```elixir
@spec close(Circuits.I2C.Bus.t()) :: :ok
```

Close the I2C bus

# `detect_devices`

```elixir
@spec detect_devices() :: :&quot;do not show this result in output&quot;
```

Convenience method to scan all I2C buses for devices

This is only intended to be called from the IEx prompt. Programs should
use `detect_devices/1`.

# `detect_devices`

```elixir
@spec detect_devices(Circuits.I2C.Bus.t() | binary()) ::
  [address()] | {:error, term()}
```

Scan the I2C bus for devices

Since there's no official way of enumerating I2C devices, this attempts to
figure out what's on the bus by seeing what devices respond.

```elixir
iex> Circuits.I2C.detect_devices("i2c-1")
[4]
```

The return value is a list of device addresses that were detected on the
specified I2C bus. If you get back `'Hh'` or other letters, then IEx
converted the list to an Erlang string. Run `i v()` to get information about
the return value and look at the raw string representation for addresses.

> #### Warning {: .warning}
> This is intended to be a debugging aid. Reading bytes from devices can
> advance internal state machines and might cause them to get out of sync
> with other code.

If you already have opened an I2C bus, then pass that to `detect_devices/1`
instead of the string name.

# `device_present?`

```elixir
@spec device_present?(Circuits.I2C.Bus.t(), address()) :: boolean()
```

Return whether a device is present

This function performs a simplistic check for an I2C device on the specified
bus and address. It's not perfect, but works enough to be useful. Be warned
that it does perform an I2C read on the specified address and this may cause
some devices to actually do something.

# `discover`

```elixir
@spec discover([address()], present?()) :: [{binary(), address()}]
```

Scan all I2C buses for one or more devices

This function takes a list of possible addresses and an optional detection
function. It only scans addresses in the possible addresses list to avoid
disturbing unrelated I2C devices.

If a detection function is not passed in, a default one that performs a
simple read and checks whether it succeeds is used. If the desired device has
an ID register or other means of identification, the optional function should
try to query that. If passing a custom function, be sure to return `false`
rather than raise if there are errors.

A list of bus name and address tuples is returned. The list may be empty.

See also `discover_one/2`.

# `discover_one`

```elixir
@spec discover_one([address()], present?()) ::
  {:ok, {binary(), address()}}
  | {:error, :not_found | :multiple_possible_matches}
```

Scans all I2C buses for one specific device

This function and `discover_one!/2` are convenience functions for the use
case of helping a user find a specific device. They both call `discover/2` with
a list of possible I2C addresses and an optional function for checking whether
the device is present.

This function returns an `:ok` or `:error` tuple depending on whether one and
only one device was found. See `discover_one!/2` for the raising version.

# `discover_one!`

```elixir
@spec discover_one!([address()], present?()) :: {binary(), address()}
```

Same as `discover_one/2` but raises on error

# `info`

```elixir
@spec info(backend() | nil) :: map()
```

Return info about the low level I2C interface

This may be helpful when debugging I2C issues.

# `open`

```elixir
@spec open(String.t(), open_options()) ::
  {:ok, Circuits.I2C.Bus.t()} | {:error, term()}
```

Open an I2C bus

I2C bus names depend on the platform. Names are of the form "i2c-n" where the
"n" is the bus number.  The correct bus number can be found in the
documentation for the device or on a schematic. Another option is to call
`Circuits.I2C.bus_names/0` to list them for you.

The same I2C bus may be opened more than once. There is no need to share
it between modules.

On success, this returns a `Circuits.I2C.Bus.t()` struct for accessing the
I2C bus. Use this in subsequent calls to read and write I2C devices.

Options depend on the backend. The following are for the I2CDev (default)
backend:

* `:retries` - the number of times to retry a transaction. I.e. 2 retries means
  the transaction is attempted at most 3 times. Defaults to 0 retries.
* `:timeout` - the time in milliseconds to wait for a transaction to complete
  or <0 to avoid setting it. Defaults to -1.

# `read`

```elixir
@spec read(Circuits.I2C.Bus.t(), address(), pos_integer(), transfer_options()) ::
  {:ok, binary()} | {:error, term()}
```

Initiate a read transaction to the I2C device at the specified `address`

See `t:transfer_options/0` for options, but backend may provide more.

# `read!`

```elixir
@spec read!(Circuits.I2C.Bus.t(), address(), pos_integer(), transfer_options()) ::
  binary()
```

Initiate a read transaction and raise on error

# `write`

```elixir
@spec write(Circuits.I2C.Bus.t(), address(), iodata(), transfer_options()) ::
  :ok | {:error, term()}
```

Write `data` to the I2C device at `address`.

See `t:transfer_options/0` for options, but backend may provide more.

# `write!`

```elixir
@spec write!(Circuits.I2C.Bus.t(), address(), iodata(), transfer_options()) :: :ok
```

Write `data` to the I2C device at `address` and raise on error

See `t:transfer_options/0` for options, but backend may provide more.

# `write_read`

```elixir
@spec write_read(
  Circuits.I2C.Bus.t(),
  address(),
  iodata(),
  pos_integer(),
  transfer_options()
) ::
  {:ok, binary()} | {:error, term()}
```

Write `data` to an I2C device and then immediately issue a read.

This function is useful for devices that want you to write the "register"
location to them first and then issue a read to get its contents. Many
devices operate this way and this function will issue the commands
back-to-back on the I2C bus. Some I2C devices actually require that the read
immediately follows the write. If the target supports this, the I2C
transaction will be issued that way. On the Raspberry Pi, this can be enabled
globally with `File.write!("/sys/module/i2c_bcm2708/parameters/combined", "1")`

See `t:transfer_options/0` for options, but backend may provide more.

# `write_read!`

```elixir
@spec write_read!(
  Circuits.I2C.Bus.t(),
  address(),
  iodata(),
  pos_integer(),
  transfer_options()
) ::
  binary()
```

Write `data` to an I2C device and then immediately issue a read. Raise on errors.

See `t:transfer_options/0` for options, but backend may provide more.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
