I2C
The I2C (Inter-Integrated Circuit) interface provides two-wire synchronous serial communication. Supports standard (100 kHz), fast (400 kHz), and fast-plus (1 MHz) modes with configurable voltage levels from 1.6V to 5.0V.
Please note that the AT1000 device only supports master mode for I2C communication. This means that it can initiate communication with slave devices, but it cannot act as a slave itself.
The AT1000 I2C master does not support clock stretching. A slave that holds SCL low to delay a transfer will not be waited for, so devices that rely on clock stretching need their own timing accommodation.
Some interfaces share the same GPIO pins, so only one can be used at a time. Check out the pin alternate functions page for more details.
Quick Start​
The example code below shows how to enable the I2C bus, set the baud rate, and transmit/receive data.
- NodeJS
- Python
- Rust
import { AT1000 } from '@ikalogic/at1000';
let devices = await AT1000.findDevices(); // Find devices (returns host strings)
let tester = await AT1000.open(devices[0]); // Open the first detected device
await tester.reset(); // Reset the device to a known state
let i2c = tester.com.i2c(0); // Select the first I2C bus
await i2c.enable({ vcc: 3.3, baud_rate: 100000 }); // Enable I2C bus with 3.3V and 100kHz
// Define an I2C transaction
let i2c_transaction = {
address: 0x50, // I2C address of the slave device
start: true, // Start condition
stop: true, // Stop condition
nack_last_byte: false, // Don't NACK the last byte; the device default is true
};
// Write request to the slave device, registers 0x10 and 0x20
await i2c.tx({ ...i2c_transaction, data: [0x10, 0x20] });
i2c_transaction.nack_last_byte = true;
// Read 4 bytes from the slave device
let data = await i2c.rx({ ...i2c_transaction, length: 4 });
// Disable I2C bus on AT1000 master
await i2c.disable();
from ikalogic_at1000 import AT1000
devices = AT1000.find_devices() # Find devices (returns host strings)
tester = AT1000.open(devices[0]) # Open the first detected device
tester.reset() # Reset the device to a known state
i2c = tester.com.i2c(0) # Select the first I2C bus
i2c.enable(vcc=3.3, baud_rate=100000) # Enable I2C bus with 3.3V and 100kHz
# Define an I2C transaction
i2c_transaction = {
"address": 0x50, # I2C address of the slave device
"start": True, # Start condition
"stop": True, # Stop condition
"nack_last_byte": False, # Don't NACK the last byte; the device default is true
}
# Write request to the slave device, registers 0x10 and 0x20
i2c.tx({ **i2c_transaction, "data": [0x10, 0x20] })
i2c_transaction["nack_last_byte"] = True
# Read 4 bytes from the slave device
data = i2c.rx({ **i2c_transaction, "length": 4 })
# Disable I2C bus on AT1000 master
i2c.disable()
use ikalogic_at1000::{AT1000, I2cAddress, I2cEnableConfig, I2cTransactionRead, I2cTransactionWrite};
use std::time::Duration;
let devices = AT1000::find_devices(Duration::from_millis(500))?; // Find devices (returns host strings)
let tester = AT1000::open(&devices[0])?; // Open the first detected device
tester.reset()?; // Reset the device to a known state
let i2c = tester.com.i2c(0)?; // Select the first I2C bus
i2c.enable(&I2cEnableConfig { vcc: Some(3.3), baud_rate: Some(100_000) })?; // Enable I2C bus with 3.3V and 100kHz
// I2C address of the slave device, validated once and reused
let address = I2cAddress::try_from(0x50)?;
// Write request to the slave device, registers 0x10 and 0x20
i2c.tx(&I2cTransactionWrite {
address,
start: Some(true), // Start condition
stop: Some(true), // Stop condition
nack_last_byte: Some(false), // Don't NACK the last byte; the device default is true
data: &[0x10, 0x20],
})?;
// Read 4 bytes from the slave device
let data = i2c.rx(&I2cTransactionRead {
address,
start: Some(true),
stop: Some(true),
nack_last_byte: Some(true),
length: 4,
})?;
// Disable I2C bus on AT1000 master
i2c.disable()?;
API Reference​
Accessing I2C​
- NodeJS
- Python
- Rust
const i2c = tester.com.i2c(id);
i2c = tester.com.i2c(id)
let id: u32 = 0;
let i2c = tester.com.i2c(id)?;
Parameters:
id(number/int/u32): The I2C interface identifier (0-based index)
Returns: I2c instance / Result<I2c, At1000Error> in Rust
Methods​
configure(config)​
Configures the I2C interface parameters without changing the enabled state.
- NodeJS
- Python
- Rust
await i2c.configure({
baud_rate: 400000,
vcc: 3.3
});
i2c.configure(
baud_rate=400000,
vcc=3.3
)
use ikalogic_at1000::I2cConfigPatch;
let i2c = tester.com.i2c(0)?;
i2c.configure(&I2cConfigPatch {
baud_rate: Some(400_000),
vcc: Some(3.3),
..Default::default()
})?;
Parameters:
config(I2cConfigPatch,&I2cConfigPatchin Rust): Configuration object with optional properties:enabled(boolean/bool/Option<bool>, optional): Enable or disable the interfacebaud_rate(number/int/Option<u32>, optional): I2C clock frequency - 100000, 400000, or 1000000vcc(number/float/Option<f64>, optional): Logic level voltage in volts (1.6 to 5.0)
Valid baud rates:
- 100000 (100 kHz): Standard mode
- 400000 (400 kHz): Fast mode
- 1000000 (1 MHz): Fast-plus mode
Returns: Promise<I2cConfig> / I2cConfig / Result<I2cConfig, At1000Error> - The updated configuration
Exceptions:
- Throws validation error if
baud_rateis not one of the valid values - Throws validation error if
vccis outside the range [1.6, 5.0]
enable([config])​
Enables the I2C interface and optionally applies configuration.
- NodeJS
- Python
- Rust
await i2c.enable({
baud_rate: 400000,
vcc: 3.3
});
i2c.enable(
baud_rate=400000,
vcc=3.3
)
use ikalogic_at1000::I2cEnableConfig;
let i2c = tester.com.i2c(0)?;
i2c.enable(&I2cEnableConfig {
baud_rate: Some(400_000),
vcc: Some(3.3),
})?;
Parameters:
config(I2cEnableConfig, optional;&I2cEnableConfigin Rust, always passed): Optional configuration to apply:baud_rate(number/int/Option<u32>, optional): I2C clock frequency (100000, 400000, or 1000000)vcc(number/float/Option<f64>, optional): Logic level voltage (1.6 to 5.0)
Returns: Promise<I2cConfig> / I2cConfig / Result<I2cConfig, At1000Error> - The updated configuration with enabled: true
Exceptions:
- Throws validation error if parameters are outside valid ranges
disable()​
Disables the I2C interface.
- NodeJS
- Python
- Rust
await i2c.disable();
i2c.disable()
let i2c = tester.com.i2c(0)?;
i2c.disable()?;
Returns: Promise<I2cConfig> / I2cConfig / Result<I2cConfig, At1000Error> - The updated configuration with enabled: false
tx(transaction)​
Writes data to an I2C device.
- NodeJS
- Python
- Rust
// Write to device at address 0x50
await i2c.tx({
address: 0x50,
data: [0x00, 0x10, 0xAA, 0xBB]
});
// Write with custom start/stop conditions
await i2c.tx({
address: 0x3C,
start: true,
stop: false, // No stop - for repeated start
data: [0x40, 0xFF]
});
# Write to device at address 0x50
i2c.tx({
'address': 0x50,
'data': [0x00, 0x10, 0xAA, 0xBB]
})
# Write with custom start/stop conditions
i2c.tx({
'address': 0x3C,
'start': True,
'stop': False, # No stop - for repeated start
'data': [0x40, 0xFF]
})
use ikalogic_at1000::{I2cAddress, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
// Write to device at address 0x50
i2c.tx(&I2cTransactionWrite {
address: I2cAddress::try_from(0x50)?,
start: None,
stop: None,
nack_last_byte: None,
data: &[0x00, 0x10, 0xAA, 0xBB],
})?;
// Write with custom start/stop conditions
i2c.tx(&I2cTransactionWrite {
address: I2cAddress::try_from(0x3C)?,
start: Some(true),
stop: Some(false), // No stop - for repeated start
nack_last_byte: None,
data: &[0x40, 0xFF],
})?;
Parameters:
transaction(I2cTransactionWrite,&I2cTransactionWritein Rust): Write transaction configuration:address(number/int/I2cAddress, required): 7-bit I2C device addressdata(string | number[]/str | list[int]/&[u8], required): Data to write (max 65536 bytes)start(boolean/bool/Option<bool>, optional, default:true): Generate START conditionstop(boolean/bool/Option<bool>, optional, default:true): Generate STOP conditionnack_last_byte(boolean/bool/Option<bool>, optional, default:true): Send NACK on last byte (ignored on writes)
Returns: Promise<number> / int / Result<usize, At1000Error> - Number of bytes written
Exceptions:
- Throws validation error if data exceeds 65536 bytes
- Throws error if device doesn't acknowledge (NACK)
- In Rust a NACK is not an error:
txreturns the number of bytes the slave acknowledged, which is0when it never acknowledged its address
rx(transaction)​
Reads data from an I2C device.
- NodeJS
- Python
- Rust
// Read 16 bytes from device at address 0x50
const data = await i2c.rx({
address: 0x50,
length: 16
});
// Read with custom conditions
const data2 = await i2c.rx({
address: 0x3C,
length: 8,
start: true,
stop: true,
nack_last_byte: true
});
# Read 16 bytes from device at address 0x50
data = i2c.rx({
'address': 0x50,
'length': 16
})
# Read with custom conditions
data2 = i2c.rx({
'address': 0x3C,
'length': 8,
'start': True,
'stop': True,
'nack_last_byte': True
})
use ikalogic_at1000::{I2cAddress, I2cTransactionRead};
let i2c = tester.com.i2c(0)?;
// Read 16 bytes from device at address 0x50
let data = i2c.rx(&I2cTransactionRead {
address: I2cAddress::try_from(0x50)?,
start: None,
stop: None,
nack_last_byte: None,
length: 16,
})?;
// Read with custom conditions
let data2 = i2c.rx(&I2cTransactionRead {
address: I2cAddress::try_from(0x3C)?,
start: Some(true),
stop: Some(true),
nack_last_byte: Some(true),
length: 8,
})?;
Parameters:
transaction(I2cTransactionRead,&I2cTransactionReadin Rust): Read transaction configuration:address(number/int/I2cAddress, required): 7-bit I2C device addresslength(number/int/usize, required): Number of bytes to read (1 to 1024)start(boolean/bool/Option<bool>, optional, default:true): Generate START conditionstop(boolean/bool/Option<bool>, optional, default:true): Generate STOP conditionnack_last_byte(boolean/bool/Option<bool>, optional, default:true): Send NACK on last byte
Returns: Promise<SerialData> / SerialData / Result<SerialData, At1000Error> - Received data as byte array (number[], Vec<u8> in Rust)
Exceptions:
- Throws validation error if
lengthis outside the range [1, 1024] - Throws error if device doesn't acknowledge (NACK)
- In Rust a NACK is not an error:
rxreturns the bytes actually received, which is an empty vector when the slave never acknowledged its address
Types​
I2cConfig​
Complete configuration object returned by configuration methods.
{
enabled: boolean,
baud_rate: number, // 100000, 400000, or 1000000
vcc: number // 1.6 to 5.0
}
Rust: ikalogic_at1000::I2cConfig
pub struct I2cConfig {
pub enabled: bool,
pub baud_rate: u32,
pub vcc: f64,
}
I2cConfigPatch​
Partial configuration for the configure() method. All properties are optional.
{
enabled?: boolean,
baud_rate?: number, // 100000, 400000, or 1000000
vcc?: number // 1.6 to 5.0
}
Rust: ikalogic_at1000::I2cConfigPatch
pub struct I2cConfigPatch {
pub enabled: Option<bool>,
pub baud_rate: Option<u32>,
pub vcc: Option<f64>,
}
I2cEnableConfig​
Optional configuration for the enable() method.
{
baud_rate?: number, // 100000, 400000, or 1000000
vcc?: number // 1.6 to 5.0
}
Rust: ikalogic_at1000::I2cEnableConfig
pub struct I2cEnableConfig {
pub baud_rate: Option<u32>,
pub vcc: Option<f64>,
}
I2cTransactionWrite​
Write transaction parameters.
{
address: number, // 7-bit I2C address
data: string | number[], // Data to write (max 65536 bytes)
start?: boolean, // Generate START (default: true)
stop?: boolean, // Generate STOP (default: true)
nack_last_byte?: boolean // NACK last byte (default: true; ignored on writes)
}
Rust: ikalogic_at1000::I2cTransactionWrite. The payload is borrowed for the duration of the call, and the address is a validated I2cAddress built with I2cAddress::try_from(0x50)?, which rejects anything above 0x7f.
pub struct I2cTransactionWrite<'a> {
pub address: I2cAddress,
pub start: Option<bool>,
pub stop: Option<bool>,
pub nack_last_byte: Option<bool>,
pub data: &'a [u8],
}
I2cTransactionRead​
Read transaction parameters.
{
address: number, // 7-bit I2C address
length: number, // Number of bytes to read (1-1024)
start?: boolean, // Generate START (default: true)
stop?: boolean, // Generate STOP (default: true)
nack_last_byte?: boolean // NACK last byte (default: true)
}
Rust: ikalogic_at1000::I2cTransactionRead
pub struct I2cTransactionRead {
pub address: I2cAddress,
pub start: Option<bool>,
pub stop: Option<bool>,
pub nack_last_byte: Option<bool>,
pub length: usize,
}
SerialData​
Output data type, always returned as a byte array.
number[] // Array of bytes (0-255)
Rust: ikalogic_at1000::SerialData
pub type SerialData = Vec<u8>;
Usage Example​
- NodeJS
- Python
- Rust
import { AT1000 } from '@ikalogic/at1000';
// Find and connect to device
const devices = await AT1000.findDevices();
const tester = await AT1000.open(devices[0]);
await tester.reset(); // Reset the device to a known state
// Access I2C interface 0
const i2c = tester.com.i2c(0);
// Enable with 400 kHz clock and 3.3V logic
await i2c.enable({
baud_rate: 400000,
vcc: 3.3
});
// Write to EEPROM at address 0x50
await i2c.tx({
address: 0x50,
data: [0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F] // "Hello" at address 0x0000
});
// Wait for write cycle to complete
await new Promise(resolve => setTimeout(resolve, 10));
// Read back from EEPROM
// First, set read address
await i2c.tx({
address: 0x50,
data: [0x00, 0x00],
stop: false // No stop for repeated start
});
// Then read data
const data = await i2c.rx({
address: 0x50,
length: 5
});
console.log("Read:", Buffer.from(data).toString()); // "Hello"
// Disable interface
await i2c.disable();
from ikalogic_at1000 import AT1000
import time
# Find and connect to device
devices = AT1000.find_devices()
tester = AT1000.open(devices[0])
tester.reset() # Reset the device to a known state
# Access I2C interface 0
i2c = tester.com.i2c(0)
# Enable with 400 kHz clock and 3.3V logic
i2c.enable(
baud_rate=400000,
vcc=3.3
)
# Write to EEPROM at address 0x50
i2c.tx({
'address': 0x50,
'data': [0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F] # "Hello" at address 0x0000
})
# Wait for write cycle to complete
time.sleep(0.01)
# Read back from EEPROM
# First, set read address
i2c.tx({
'address': 0x50,
'data': [0x00, 0x00],
'stop': False # No stop for repeated start
})
# Then read data
data = i2c.rx({
'address': 0x50,
'length': 5
})
print(f"Read: {bytes(data).decode()}") # "Hello"
# Disable interface
i2c.disable()
use ikalogic_at1000::{AT1000, I2cAddress, I2cEnableConfig, I2cTransactionRead, I2cTransactionWrite};
use std::time::Duration;
// Find and connect to device
let devices = AT1000::find_devices(Duration::from_millis(500))?;
let tester = AT1000::open(&devices[0])?;
tester.reset()?; // Reset the device to a known state
// Access I2C interface 0
let i2c = tester.com.i2c(0)?;
// Enable with 400 kHz clock and 3.3V logic
i2c.enable(&I2cEnableConfig {
baud_rate: Some(400_000),
vcc: Some(3.3),
})?;
let eeprom = I2cAddress::try_from(0x50)?;
// Write to EEPROM at address 0x50
i2c.tx(&I2cTransactionWrite {
address: eeprom,
start: None,
stop: None,
nack_last_byte: None,
data: &[0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F], // "Hello" at address 0x0000
})?;
// Wait for write cycle to complete
std::thread::sleep(Duration::from_millis(10));
// Read back from EEPROM
// First, set read address
i2c.tx(&I2cTransactionWrite {
address: eeprom,
start: None,
stop: Some(false), // No stop for repeated start
nack_last_byte: None,
data: &[0x00, 0x00],
})?;
// Then read data
let data = i2c.rx(&I2cTransactionRead {
address: eeprom,
start: None,
stop: None,
nack_last_byte: None,
length: 5,
})?;
println!("Read: {}", String::from_utf8_lossy(&data)); // "Hello"
// Disable interface
i2c.disable()?;
Common Patterns​
Register Read (Single Byte)​
- NodeJS
- Python
- Rust
// Read register 0x75 from device at 0x68 (e.g., IMU WHO_AM_I register)
await i2c.tx({
address: 0x68,
data: [0x75],
stop: false
});
const whoAmI = await i2c.rx({
address: 0x68,
length: 1
});
console.log("WHO_AM_I:", whoAmI[0].toString(16));
# Read register 0x75 from device at 0x68 (e.g., IMU WHO_AM_I register)
i2c.tx({
'address': 0x68,
'data': [0x75],
'stop': False
})
who_am_i = i2c.rx({
'address': 0x68,
'length': 1
})
print(f"WHO_AM_I: {who_am_i[0]:02x}")
use ikalogic_at1000::{I2cAddress, I2cTransactionRead, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
let imu = I2cAddress::try_from(0x68)?;
// Read register 0x75 from device at 0x68 (e.g., IMU WHO_AM_I register)
i2c.tx(&I2cTransactionWrite {
address: imu,
start: None,
stop: Some(false),
nack_last_byte: None,
data: &[0x75],
})?;
let who_am_i = i2c.rx(&I2cTransactionRead {
address: imu,
start: None,
stop: None,
nack_last_byte: None,
length: 1,
})?;
println!("WHO_AM_I: {:02x}", who_am_i[0]);
Register Write​
- NodeJS
- Python
- Rust
// Write 0x80 to register 0x6B (e.g., PWR_MGMT_1 register)
await i2c.tx({
address: 0x68,
data: [0x6B, 0x80]
});
# Write 0x80 to register 0x6B (e.g., PWR_MGMT_1 register)
i2c.tx({
'address': 0x68,
'data': [0x6B, 0x80]
})
use ikalogic_at1000::{I2cAddress, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
// Write 0x80 to register 0x6B (e.g., PWR_MGMT_1 register)
i2c.tx(&I2cTransactionWrite {
address: I2cAddress::try_from(0x68)?,
start: None,
stop: None,
nack_last_byte: None,
data: &[0x6B, 0x80],
})?;
Multi-Byte Register Read​
- NodeJS
- Python
- Rust
// Read 6 bytes starting from register 0x3B (e.g., accelerometer data)
await i2c.tx({
address: 0x68,
data: [0x3B],
stop: false
});
const accelData = await i2c.rx({
address: 0x68,
length: 6
});
// Parse as 16-bit signed integers
const accelX = (accelData[0] << 8) | accelData[1];
const accelY = (accelData[2] << 8) | accelData[3];
const accelZ = (accelData[4] << 8) | accelData[5];
# Read 6 bytes starting from register 0x3B (e.g., accelerometer data)
i2c.tx({
'address': 0x68,
'data': [0x3B],
'stop': False
})
accel_data = i2c.rx({
'address': 0x68,
'length': 6
})
# Parse as 16-bit signed integers
accel_x = (accel_data[0] << 8) | accel_data[1]
accel_y = (accel_data[2] << 8) | accel_data[3]
accel_z = (accel_data[4] << 8) | accel_data[5]
use ikalogic_at1000::{I2cAddress, I2cTransactionRead, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
let imu = I2cAddress::try_from(0x68)?;
// Read 6 bytes starting from register 0x3B (e.g., accelerometer data)
i2c.tx(&I2cTransactionWrite {
address: imu,
start: None,
stop: Some(false),
nack_last_byte: None,
data: &[0x3B],
})?;
let accel_data = i2c.rx(&I2cTransactionRead {
address: imu,
start: None,
stop: None,
nack_last_byte: None,
length: 6,
})?;
// Parse as 16-bit signed integers
let accel_x = i16::from_be_bytes([accel_data[0], accel_data[1]]);
let accel_y = i16::from_be_bytes([accel_data[2], accel_data[3]]);
let accel_z = i16::from_be_bytes([accel_data[4], accel_data[5]]);
EEPROM Operations​
- NodeJS
- Python
- Rust
// Write to EEPROM (24C256 example)
const eepromAddr = 0x50;
const memAddr = [0x00, 0x10]; // Address 0x0010
const writeData = [0xAA, 0xBB, 0xCC, 0xDD];
await i2c.tx({
address: eepromAddr,
data: [...memAddr, ...writeData]
});
// Wait for write cycle (5ms typical)
await new Promise(resolve => setTimeout(resolve, 10));
// Read back
await i2c.tx({
address: eepromAddr,
data: memAddr,
stop: false
});
const readData = await i2c.rx({
address: eepromAddr,
length: 4
});
import time
# Write to EEPROM (24C256 example)
eeprom_addr = 0x50
mem_addr = [0x00, 0x10] # Address 0x0010
write_data = [0xAA, 0xBB, 0xCC, 0xDD]
i2c.tx({
'address': eeprom_addr,
'data': mem_addr + write_data
})
# Wait for write cycle (5ms typical)
time.sleep(0.01)
# Read back
i2c.tx({
'address': eeprom_addr,
'data': mem_addr,
'stop': False
})
read_data = i2c.rx({
'address': eeprom_addr,
'length': 4
})
use ikalogic_at1000::{I2cAddress, I2cTransactionRead, I2cTransactionWrite};
use std::time::Duration;
let i2c = tester.com.i2c(0)?;
// Write to EEPROM (24C256 example)
let eeprom_addr = I2cAddress::try_from(0x50)?;
let mem_addr = [0x00u8, 0x10]; // Address 0x0010
let write_data = [0xAAu8, 0xBB, 0xCC, 0xDD];
let payload: Vec<u8> = mem_addr.iter().chain(write_data.iter()).copied().collect();
i2c.tx(&I2cTransactionWrite {
address: eeprom_addr,
start: None,
stop: None,
nack_last_byte: None,
data: &payload,
})?;
// Wait for write cycle (5ms typical)
std::thread::sleep(Duration::from_millis(10));
// Read back
i2c.tx(&I2cTransactionWrite {
address: eeprom_addr,
start: None,
stop: Some(false),
nack_last_byte: None,
data: &mem_addr,
})?;
let read_data = i2c.rx(&I2cTransactionRead {
address: eeprom_addr,
start: None,
stop: None,
nack_last_byte: None,
length: 4,
})?;
Scanning I2C Bus​
- NodeJS
- Python
- Rust
console.log("Scanning I2C bus...");
const foundDevices = [];
for (let addr = 0x08; addr < 0x78; addr++) {
try {
await i2c.tx({
address: addr,
data: []
});
foundDevices.push(addr);
console.log(`Found device at 0x${addr.toString(16).padStart(2, '0')}`);
} catch (e) {
// Device not found at this address
}
}
console.log(`Found ${foundDevices.length} device(s)`);
print("Scanning I2C bus...")
found_devices = []
for addr in range(0x08, 0x78):
try:
i2c.tx({
'address': addr,
'data': []
})
found_devices.append(addr)
print(f"Found device at 0x{addr:02x}")
except:
# Device not found at this address
pass
print(f"Found {len(found_devices)} device(s)")
use ikalogic_at1000::{I2cAddress, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
println!("Scanning I2C bus...");
let mut found_devices = Vec::new();
for addr in 0x08u8..0x78 {
// A NACK is not an error in Rust: `tx` returns the number of acknowledged
// bytes, and an absent slave acknowledges nothing, not even its address.
let acknowledged = i2c.tx(&I2cTransactionWrite {
address: I2cAddress::try_from(addr)?,
start: None,
stop: None,
nack_last_byte: None,
data: &[],
})?;
if acknowledged > 0 {
found_devices.push(addr);
println!("Found device at 0x{addr:02x}");
}
}
println!("Found {} device(s)", found_devices.len());
Repeated Start Transaction​
- NodeJS
- Python
- Rust
// Combined write-read transaction with repeated start
// (More efficient than separate transactions)
// Write register address
await i2c.tx({
address: 0x3C,
data: [0x00],
stop: false // Keep bus active for repeated start
});
// Immediately read without releasing bus
const data = await i2c.rx({
address: 0x3C,
length: 16,
start: true, // Repeated START
stop: true
});
# Combined write-read transaction with repeated start
# (More efficient than separate transactions)
# Write register address
i2c.tx({
'address': 0x3C,
'data': [0x00],
'stop': False # Keep bus active for repeated start
})
# Immediately read without releasing bus
data = i2c.rx({
'address': 0x3C,
'length': 16,
'start': True, # Repeated START
'stop': True
})
use ikalogic_at1000::{I2cAddress, I2cTransactionRead, I2cTransactionWrite};
let i2c = tester.com.i2c(0)?;
let display = I2cAddress::try_from(0x3C)?;
// Combined write-read transaction with repeated start
// (More efficient than separate transactions)
// Write register address
i2c.tx(&I2cTransactionWrite {
address: display,
start: None,
stop: Some(false), // Keep bus active for repeated start
nack_last_byte: None,
data: &[0x00],
})?;
// Immediately read without releasing bus
let data = i2c.rx(&I2cTransactionRead {
address: display,
start: Some(true), // Repeated START
stop: Some(true),
nack_last_byte: None,
length: 16,
})?;
Notes​
- I2C addresses are 7-bit values (0x08 to 0x77)
- Pull-up resistors are typically required on SDA and SCL lines (often integrated)
- Clock stretching is not supported by the underlying hardware
- Use
nack_last_byte: truewhen reading to signal end of transaction - Read transactions are limited to 1024 bytes; write data may be up to 65536 bytes per transaction