or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

apidiff.mdconstraints.mdebnf.mderrors.mdevent.mdgorelease.mdindex.mdio-i2c.mdio-spi.mdjsonrpc2.mdmaps.mdmmap.mdmodgraphviz.mdrand.mdshiny.mdslices.mdslog.mdstats.mdsumdb.mdtrace.mdtxtar.mdtypeparams.mdutf8string.md
tile.json

io-i2c.mddocs/

I2C Communication Library

I2C (Inter-Integrated Circuit) is a synchronous serial communication protocol that allows multiple devices to communicate over just two wires. The golang.org/x/exp/io/i2c package provides a Go implementation for reading from and writing to I2C slave devices, along with a driver interface for various I2C hardware implementations.

Package Information

  • Package Name: golang.org/x/exp/io/i2c
  • Package Type: Go (golang.org/x)
  • Language: Go
  • Installation: go get golang.org/x/exp/io/i2c
  • Status: Deprecated - Not actively maintained. Use https://periph.io/ as an actively supported cross-platform alternative.

Core Imports

import "golang.org/x/exp/io/i2c"
import "golang.org/x/exp/io/i2c/driver"

Basic Usage

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
	"golang.org/x/exp/io/i2c/driver"
)

func main() {
	// Open a connection to an I2C device at address 0x48
	opener := &i2c.Devfs{Dev: "/dev/i2c-1"}
	device, err := i2c.Open(opener, 0x48)
	if err != nil {
		log.Fatal(err)
	}
	defer device.Close()

	// Read 10 bytes from the device
	buf := make([]byte, 10)
	if err := device.Read(buf); err != nil {
		log.Fatal(err)
	}

	// Write to a register
	data := []byte{0x01, 0x02, 0x03}
	if err := device.WriteReg(0x10, data); err != nil {
		log.Fatal(err)
	}
}

Architecture

The I2C package consists of two main components:

Main Package (golang.org/x/exp/io/i2c)

Provides high-level device abstraction for communicating with I2C slave devices:

  • Device: The main interface for I2C communication, representing an open connection to an I2C device
  • Devfs: A concrete implementation that uses the Linux devfs interface (/dev/i2c-*)
  • Address Helper: TenBit() function for marking addresses as 10-bit

Driver Package (golang.org/x/exp/io/i2c/driver)

Defines the low-level interfaces that hardware implementations must satisfy:

  • Conn: Low-level connection interface for raw I2C transactions
  • Opener: Interface for opening connections to I2C devices

Capabilities

Device Operations

Manage connections to I2C devices.

// Open opens a connection to an I2C device.
// All devices must be closed once they are no longer in use.
// For devices that use 10-bit I2C addresses, addr can be marked as a 10-bit address with TenBit.
func Open(o driver.Opener, addr int) (*Device, error)
// Close closes the device and releases the underlying resources.
func (d *Device) Close() error

Reading Data

Read data from I2C devices.

// Read reads len(buf) bytes from the device.
func (d *Device) Read(buf []byte) error
// ReadReg is similar to Read but it reads from a register.
func (d *Device) ReadReg(reg byte, buf []byte) error

Writing Data

Write data to I2C devices.

// Write writes the buffer to the device.
// If it is required to write to a specific register, the register should be passed
// as the first byte in the given buffer.
func (d *Device) Write(buf []byte) error
// WriteReg is similar to Write but writes to a register.
func (d *Device) WriteReg(reg byte, buf []byte) error

Address Handling

Handle I2C address formats.

// TenBit marks an I2C address as a 10-bit address.
func TenBit(addr int) int

Types

Device

type Device struct {
	// Has unexported fields
}

Device represents an I2C device. Devices must be closed once they are no longer in use.

Devfs

type Devfs struct {
	// Dev is the I2C bus device, e.g. /dev/i2c-1. Required.
	Dev string
}

Devfs is an I2C driver that works against the devfs. You need to load the "i2c-dev" kernel module to use this driver.

Methods:

func (d *Devfs) Open(addr int, tenbit bool) (driver.Conn, error)

Driver Package Types

Conn Interface

type Conn interface {
	// Tx first writes w (if not nil), then reads len(r)
	// bytes from device into r (if not nil) in a single
	// I2C transaction.
	Tx(w, r []byte) error

	// Close closes the connection.
	Close() error
}

Conn represents an active connection to an I2C device. This is the low-level interface that hardware implementations must satisfy.

Opener Interface

type Opener interface {
	Open(addr int, tenbit bool) (Conn, error)
}

Opener opens a connection to an I2C device to communicate with the I2C address given. If the address is a 10-bit I2C address, tenbit is true. This interface should be implemented by hardware-specific drivers.

Usage Examples

Example: Reading from a Sensor

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
)

func main() {
	// Open connection to a temperature sensor at address 0x48 on bus /dev/i2c-1
	opener := &i2c.Devfs{Dev: "/dev/i2c-1"}
	device, err := i2c.Open(opener, 0x48)
	if err != nil {
		log.Fatalf("Failed to open I2C device: %v", err)
	}
	defer device.Close()

	// Read temperature from register 0x05
	tempBuf := make([]byte, 2)
	if err := device.ReadReg(0x05, tempBuf); err != nil {
		log.Fatalf("Failed to read temperature: %v", err)
	}

	// Convert bytes to temperature value (example conversion)
	temperature := (int(tempBuf[0]) << 8) | int(tempBuf[1])
	log.Printf("Temperature: %d", temperature)
}

Example: Writing Configuration to a Device

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
)

func main() {
	opener := &i2c.Devfs{Dev: "/dev/i2c-1"}
	device, err := i2c.Open(opener, 0x62)
	if err != nil {
		log.Fatal(err)
	}
	defer device.Close()

	// Write configuration to register 0x00
	config := []byte{0x00, 0x10, 0x20}
	if err := device.WriteReg(0x00, config); err != nil {
		log.Fatalf("Failed to write configuration: %v", err)
	}

	log.Println("Configuration written successfully")
}

Example: Using 10-bit I2C Addresses

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
)

func main() {
	opener := &i2c.Devfs{Dev: "/dev/i2c-1"}

	// Open a device at a 10-bit address (0x380 as example)
	addr := i2c.TenBit(0x380)
	device, err := i2c.Open(opener, addr)
	if err != nil {
		log.Fatalf("Failed to open I2C device with 10-bit address: %v", err)
	}
	defer device.Close()

	// Perform I2C operations as normal
	buf := make([]byte, 10)
	if err := device.Read(buf); err != nil {
		log.Fatal(err)
	}
}

Example: Implementing a Custom I2C Driver

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
	"golang.org/x/exp/io/i2c/driver"
)

// CustomDriver implements the driver.Opener interface
type CustomDriver struct {
	// Custom driver fields
}

// Open implements the driver.Opener interface
func (c *CustomDriver) Open(addr int, tenbit bool) (driver.Conn, error) {
	// Custom implementation for opening a connection
	// Return a connection that implements the driver.Conn interface
	return &CustomConn{}, nil
}

// CustomConn implements the driver.Conn interface
type CustomConn struct {
	// Connection state
}

// Tx implements the driver.Conn interface
func (cc *CustomConn) Tx(w, r []byte) error {
	// Custom transaction logic
	return nil
}

// Close implements the driver.Conn interface
func (cc *CustomConn) Close() error {
	// Clean up resources
	return nil
}

func main() {
	// Use the custom driver
	customDriver := &CustomDriver{}
	device, err := i2c.Open(customDriver, 0x48)
	if err != nil {
		log.Fatal(err)
	}
	defer device.Close()
}

Example: Bit-level I2C Transactions

package main

import (
	"log"
	"golang.org/x/exp/io/i2c"
	"golang.org/x/exp/io/i2c/driver"
)

func sendAndReceive(conn driver.Conn, sendData []byte, receiveLength int) ([]byte, error) {
	receiveBuf := make([]byte, receiveLength)
	if err := conn.Tx(sendData, receiveBuf); err != nil {
		return nil, err
	}
	return receiveBuf, nil
}

func main() {
	opener := &i2c.Devfs{Dev: "/dev/i2c-1"}
	device, err := i2c.Open(opener, 0x48)
	if err != nil {
		log.Fatal(err)
	}
	defer device.Close()

	// Example: Send command and receive response in single transaction
	command := []byte{0x40} // Example command byte
	response, err := sendAndReceive(device, command, 8)
	if err != nil {
		log.Fatalf("Transaction failed: %v", err)
	}

	log.Printf("Received: %v", response)
}

Error Handling

The I2C package returns errors in the following scenarios:

  • Device Open Failures: When the I2C device cannot be opened (e.g., device not found, permission denied)
  • Read/Write Errors: When I2C communication fails during read or write operations
  • Close Errors: When the device cannot be properly closed

Example error handling:

device, err := i2c.Open(opener, 0x48)
if err != nil {
	log.Fatalf("Failed to open device: %v", err)
}

buf := make([]byte, 10)
if err := device.Read(buf); err != nil {
	log.Fatalf("Read operation failed: %v", err)
}

if err := device.Close(); err != nil {
	log.Fatalf("Failed to close device: %v", err)
}

Platform Requirements

  • Linux: Requires the i2c-dev kernel module to be loaded for Devfs driver
  • I2C Bus: Device must be connected to an accessible I2C bus (e.g., /dev/i2c-0, /dev/i2c-1)
  • Permissions: User must have appropriate permissions to access the I2C device file

Deprecation Notice

The golang.org/x/exp/io/i2c package is no longer actively maintained. For new projects, use the actively supported cross-platform alternative at https://periph.io/. The Periph library provides similar functionality with continued maintenance and support across multiple platforms.