Metadata-Version: 2.4
Name: tca9548a
Version: 0.1.0
Summary: Python Library to interface with Texas Instruments TCA9548A 8-channel I2C multiplexer.
Author-email: Jonathan Oxer <jon@oxer.com.au>
Maintainer-email: Jonathan Oxer <jon@oxer.com.au>
License: MIT
Project-URL: bugs, https://github.com/SuperHouse/tca9548a/issues
Project-URL: homepage, https://github.com/SuperHouse/tca9548a
Classifier: Topic :: Software Development :: Embedded Systems
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: smbus2>=0.4.0
Dynamic: license-file

# TCA9548A Python Library

The Texas Instruments TCA9548A is an 8-channel I2C multiplexer: it lets up
to 8 downstream I2C buses share the same upstream bus and controller, each
addressable independently, even if devices on different channels share the
same I2C address.

This library was created for use with the
[Testomatic PCB test jig system](https://github.com/superhouse/testomatic),
which uses a TCA9548A to address multiple identical IOMOD modules from one
I2C bus, but it is designed to be a self-contained driver that can be used
in other projects.

It follows the same injectable-transport design as this project's sibling
[`ad5593r`](https://github.com/SuperHouse/ad5593r) and
[`mcp23008`](https://github.com/SuperHouse/mcp23008) libraries, with one
addition: a channel object exposes that exact same `writeto`/`readfrom`/
`scan` shape, so it can be handed straight to another chip's driver as its
`i2c_bus`. See the "Behind the Mux" example below, which is this
library's main reason to exist.

## Installation

Install the required dependency:

```bash
pip install -r requirements.txt
```

Or install directly:

```bash
pip install smbus2
```

## Usage

### Basic Setup

```python
from tca9548a import TCA9548A, TCA9548A_DEFAULT_ADDRESS

# Create instance with I2C address 0x70 (the default, set by the A0-A2 pins)
# bus_number defaults to 1 (for Raspberry Pi)
tca = TCA9548A(TCA9548A_DEFAULT_ADDRESS, bus_number=1)

# Check connection
print(f"Connected: {tca.is_connected()}")
print(f"Address: 0x{tca.get_address():02X}")
```

### Selecting Channels Directly

```python
# Connect only channel 3
tca.select_channel(3)
print(tca.get_selected_channels())  # [3]

# Disconnect everything
tca.deselect_all()
print(tca.get_selected_channels())  # []
```

### Scanning a Channel

```python
# tca[n] returns a TCA9548AChannel for channel n, which selects itself
# automatically before each operation
addresses = tca[3].scan()
print(f"Devices on channel 3: {[hex(a) for a in addresses]}")
```

### Behind the Mux: Driving Another Chip Through a Channel

You can use this library as a simple driver for the TCA9548A, but it
can perform a very handy trick because `tca[n]` behaves like an
I2C bus of its own and can be passed directly as another chip driver's
`i2c_bus`. For example:

```python
from tca9548a import TCA9548A, TCA9548A_DEFAULT_ADDRESS
from mcp23008 import MCP23008, PinMode

tca = TCA9548A(TCA9548A_DEFAULT_ADDRESS, bus_number=1)

# An MCP23008 at 0x20 on channel 1, addressed through the mux
mcp = MCP23008(0x20, i2c_bus=tca[1])
mcp.pin_mode(0, PinMode.OUTPUT)
mcp.digital_write(0, 1)
```

Every `writeto`/`readfrom`/`scan` call that `mcp` makes will then 
reselect channel 1 first automagically, so other channels' devices 
(which may share the same I2C address but be connected to a different 
channel) are never accidentally addressed.

### Cleanup

```python
# Close I2C bus when done
tca.close()
```

## Examples

See the `examples/` directory:

- `examples/example_scan_all_channels.py`: select each of the 8 channels in turn and scan for devices behind it
- `examples/example_behind_the_mux.py`: drive an MCP23008 that sits behind channel 1, using `tca[1]` as its `i2c_bus`
- `examples/example_tca9548a_passed_i2c.py`: the same channel-scanning example, but with the I2C connection set up externally and passed in

`example_scan_all_channels.py` and `example_tca9548a_passed_i2c.py` cover the same operations but show the two ways to set up the I2C connection, so you can compare them directly:

- **Let TCA9548A manage it** (`bus_number=1`, the default) -- the simplest option. TCA9548A lazily opens its own `smbus2.SMBus` on first use, and `close()` closes it. This is enough for the common case of a single upstream bus on the Raspberry Pi.
- **Set it up yourself and pass it in** (`i2c_bus=...`) -- needed whenever something else has to control the connection: for example, several devices sharing one bus. TCA9548A only needs an object exposing `writeto(address, buffer)`/`readfrom(address, length)`/`scan()`; since you own the connection's lifecycle, TCA9548A won't open or close it for you.

## Multiple Channels At Once

The control register is a plain 8-bit mask, not a one-hot selector -- more
than one channel can be connected simultaneously if the devices behind
them have distinct addresses. `TCA9548AChannel` (via `tca[n]`) always
selects exactly one channel, which is what this project needs and is the
safest default. For multiple channels at once, use `write_control()`
directly with a combined bitmask (e.g. `tca.write_control(0b00000101)`
for channels 0 and 2).

## Scope

This library only supports the genuine 8-channel TCA9548A. It does not
support the 4-channel TCA9546A/PCA9546A variant, which has a smaller
channel range (0-3) and would need its own bounds checking.

## Error Codes

- `TCA9548A_OK` (0x0000): Success
- `TCA9548A_CHANNEL_ERROR` (0xFF81): Invalid channel number
- `TCA9548A_I2C_ERROR` (0xFF82): I2C communication error

## Notes

- Make sure I2C is enabled on your system! On Raspberry Pi this is done using
  `sudo raspi-config` -> `Interface Options` -> `I2C`
- Uses `smbus2` for I2C communication
- Default I2C bus is 1 for Raspberry Pi. Modern Raspberry Pi models reserve bus 0
  for Pi Hat EEPROMs that are read at startup. Use `bus_number=0` for older
  Raspberry Pi models
- The device supports I2C addresses 0x70-0x77, set by the A0-A2 pins
- The default transport's `scan()` uses an SMBus quick-write probe on
  every address from 0x03-0x77. `i2cdetect` avoids quick-write specifically
  on 0x30-0x37 and 0x50-0x5F by default, since a write-type probe can
  disturb some devices in those ranges (e.g. triggering an EEPROM write
  cycle). Worth checking before relying on `scan()` on a system with
  devices in those ranges.

## License

Released under the MIT licence.
