-
Notifications
You must be signed in to change notification settings - Fork 0
I2C
This document describes the I2C (Inter-Integrated Circuit) implementation in Gopper, which provides compatibility with Klipper's I2C protocol.
The I2C implementation allows Gopper to communicate with I2C peripheral devices such as:
- Temperature sensors (e.g., BME280, SHT3x)
- Accelerometers (e.g., ADXL345 for input shaping)
- Display controllers (e.g., SSD1306 OLED)
- I/O expanders (e.g., MCP23017)
- Other I2C-compatible sensors and actuators
The I2C implementation follows Gopper's standard three-layer architecture:
Implements Klipper protocol command handlers:
- config_i2c: Allocates an I2C device object
- i2c_set_bus: Configures the I2C bus, frequency, and device address
- i2c_write: Writes data to an I2C device
- i2c_read: Reads data from an I2C device (with optional register addressing)
Defines the platform-independent I2C interface:
type I2CDriver interface {
ConfigureBus(bus I2CBusID, frequencyHz uint32) error
Write(bus I2CBusID, addr I2CAddress, data []byte) error
Read(bus I2CBusID, addr I2CAddress, regData []byte, readLen uint8) ([]byte, error)
}Implements the HAL interface using TinyGo's machine.I2C API for RP2040/RP2350.
The RP2040 and RP2350 microcontrollers have two I2C controllers:
-
I2C0 (Bus ID 0)
- Default SDA: GPIO4
- Default SCL: GPIO5
-
I2C1 (Bus ID 1)
- Default SDA: GPIO6
- Default SCL: GPIO7
Both controllers support standard I2C frequencies:
- 100 kHz (standard mode)
- 400 kHz (fast mode)
- Up to 1 MHz (fast mode plus)
Allocates an I2C device object.
Format: config_i2c oid=%c
Parameters:
-
oid: Object ID for this I2C device
Configures the I2C bus, frequency, and device address.
Format: i2c_set_bus oid=%c i2c_bus=%u rate=%u address=%u
Parameters:
-
oid: Object ID of the I2C device -
i2c_bus: Bus number (0 or 1 for RP2040) -
rate: I2C frequency in Hz (e.g., 100000 for 100 kHz, 400000 for 400 kHz) -
address: 7-bit I2C device address (automatically masked to 7 bits)
Writes data to an I2C device.
Format: i2c_write oid=%c data=%*s
Parameters:
-
oid: Object ID of the I2C device -
data: Buffer of bytes to write
Error Handling: Triggers firmware shutdown on I2C NACK or timeout errors.
Reads data from an I2C device, optionally writing a register address first.
Format: i2c_read oid=%c reg=%*s read_len=%u
Parameters:
-
oid: Object ID of the I2C device -
reg: Optional register address to write before reading (can be empty for simple reads) -
read_len: Number of bytes to read
Response: i2c_read_response oid=%c response=%*s
Error Handling: Triggers firmware shutdown on I2C NACK or timeout errors.
Here's how Klipper's Python code typically uses I2C:
# Configure I2C device
oid = self.mcu.create_oid()
self.mcu.add_config_cmd("config_i2c oid=%d" % oid)
self.mcu.add_config_cmd("i2c_set_bus oid=%d i2c_bus=%d rate=%d address=%d"
% (oid, 0, 400000, 0x76))
# Write data
data = [0x01, 0x02, 0x03]
self.mcu.send_cmd("i2c_write oid=%d data=%s" % (oid, data))
# Read from register
reg = [0xF7] # Register address
read_len = 3
response = self.mcu.send_with_response("i2c_read oid=%d reg=%s read_len=%d"
% (oid, reg, read_len),
"i2c_read_response oid=%c response=%*s")The RP2040 I2C driver uses a mutex (sync.Mutex) to serialize I2C operations, preventing concurrent access to the same bus.
I2C errors (NACK, timeout, bus errors) trigger a firmware shutdown via TryShutdown(), matching Klipper's behavior. This ensures that communication failures are detected and handled safely.
The i2c_read command supports writing a register address before reading:
- If
regis non-empty, it's transmitted first, followed by a restart condition and the read operation - If
regis empty, a simple read transaction is performed - This matches the behavior of TinyGo's
Tx()method
I2C buses are configured on-demand when i2c_set_bus is called:
- The first call to
i2c_set_busfor a given bus initializes it with the specified frequency - Subsequent calls can update the baud rate via
SetBaudRate() - Each I2C device object maintains its own address and bus assignment
- Address: 0x53 (default) or 0x1D (alternate)
- Frequency: 400 kHz
- Usage: Measures printer vibrations for input shaping calibration
- Address: 0x76 (default) or 0x77 (alternate)
- Frequency: 100-400 kHz
- Usage: Measures temperature, humidity, and barometric pressure
- Address: 0x3C or 0x3D
- Frequency: 400 kHz
- Usage: Status display for printer information
If you encounter I2C communication problems:
-
Check wiring:
- Verify SDA and SCL connections
- Ensure pull-up resistors are present (typically 4.7kΩ for 100kHz, 2.2kΩ for 400kHz)
- Check power supply to the I2C device
-
Verify address:
- Use an I2C scanner to detect devices
- Some devices have configurable addresses (check device datasheet)
- Addresses are 7-bit (0x00 to 0x7F)
-
Check bus speed:
- Start with 100 kHz for testing
- Some devices may not support 400 kHz or faster speeds
- Long wires may require lower speeds
-
Monitor firmware logs:
- I2C errors trigger firmware shutdown
- Check Klipper logs for "I2C write error" or "I2C read error" messages
Potential improvements for the I2C implementation:
- Support for 10-bit I2C addresses
- Configurable pin assignments (currently uses default pins)
- I2C bus scanning utility
- Support for clock stretching and other advanced features
- Multi-master I2C support
- Configurable timeout values