Kinematrix provides three I2C-related modules for device scanning, bus expansion, and I/O expansion capabilities.
Available Modules
I2C Scanner Detect and identify I2C devices on the bus
I2C Expander TCA9548A multiplexer for multiple I2C buses
I/O Expander PCF8574 chip for GPIO expansion
I2C Scanner
The I2C Scanner module detects all connected I2C devices and reports their addresses.
Module Definition
lib/modules/communication/wired/i2c/i2c-scanner.h
class I2CScanner {
public:
I2CScanner ();
virtual ~I2CScanner ();
void beginTransmission ();
void scanI2CAddress ();
void endTransmission ();
private:
int n_address_ [ 8 ];
int n_devices_;
};
Basic Usage
#define ENABLE_MODULE_I2C_SCANNER
#include "Kinematrix.h"
I2CScanner scanner;
void setup () {
Serial . begin ( 115200 );
// Start scanning process
scanner . beginTransmission ();
scanner . scanI2CAddress ();
scanner . endTransmission ();
}
void loop () {
// Scanning is typically done once in setup
}
Output Example
==============================
| START SCANNING I2C
==============================
| WIRE BEGIN
| Scanning...
| Done Scanning
| I2C devices found at address :
| 0x0027
| 0x003C
| Total devices found : | 2
| WIRE END
Common I2C Addresses
Device Type Typical Address(es) Notes PCF8574 I/O Expander 0x20-0x27, 0x38-0x3F Configurable via A0-A2 pins LCD with I2C 0x27, 0x3F Common LCD backpack addresses OLED SSD1306 0x3C, 0x3D 128x64 displays BMP280 Pressure 0x76, 0x77 Barometric pressure sensor BME280 0x76, 0x77 Temperature/humidity/pressure MPU6050 IMU 0x68, 0x69 Accelerometer/gyroscope ADS1115 ADC 0x48-0x4B 16-bit analog-to-digital TCA9548A Multiplexer 0x70-0x77 I2C bus expander DS3231 RTC 0x68 Real-time clock AT24C EEPROM 0x50-0x57 External EEPROM
Error Detection
The scanner detects and reports unknown errors:
void I2CScanner :: scanI2CAddress () {
byte error;
for (address = 1 ; address < 127 ; address ++ ) {
Wire . beginTransmission (address);
error = Wire . endTransmission ();
if (error == 0 ) {
// Device found
n_address_ [n_devices_] = address;
n_devices_ ++ ;
} else if (error == 4 ) {
Serial . print ( "Unknown error at address 0x" );
Serial . println (address, HEX);
}
}
}
I2C Expander (TCA9548A)
The I2C Expander module provides access to the TCA9548A I2C multiplexer, allowing up to 8 separate I2C buses from a single master.
Module Definition
lib/modules/communication/wired/i2c/i2c-expander.h
#include "TCA9548A.h"
class I2CExpander : public TCA9548A {
private:
uint8_t addr;
public:
using TCA9548A ::TCA9548A;
};
Why Use an I2C Expander?
Multiple devices with the same I2C address can coexist on different channels: // Two OLED displays at 0x3C
expander . selectChannel ( 0 );
oled1 . display (); // First OLED
expander . selectChannel ( 1 );
oled2 . display (); // Second OLED
Reduce total bus capacitance by splitting devices across multiple channels, improving signal integrity and allowing longer cable runs.
Isolate problematic devices that may hang the bus, allowing the rest of the system to continue operating.
Basic Usage
#define ENABLE_MODULE_I2C_EXPANDER
#include "Kinematrix.h"
I2CExpander expander ( 0x 70 ); // TCA9548A default address
void setup () {
Wire . begin ();
// Select channel 0
expander . selectChannel ( 0 );
// Initialize device on channel 0
sensor1 . begin ();
// Select channel 1
expander . selectChannel ( 1 );
// Initialize device on channel 1
sensor2 . begin ();
}
void loop () {
// Read from channel 0
expander . selectChannel ( 0 );
float value1 = sensor1 . read ();
// Read from channel 1
expander . selectChannel ( 1 );
float value2 = sensor2 . read ();
delay ( 1000 );
}
Advanced Channel Management
// Enable multiple channels simultaneously (bitwise OR)
expander . enableChannels ( 0b 00000011 ); // Channels 0 and 1
// Disable all channels
expander . disableAllChannels ();
// Check which channels are active
uint8_t activeChannels = expander . getActiveChannels ();
TCA9548A Specifications
Parameter Value Notes Supply Voltage 1.65V - 5.5V Compatible with 3.3V and 5V systems Number of Channels 8 SC0-SC7 I2C Address Range 0x70-0x77 Configurable via A0-A2 pins Max Frequency 400 kHz Fast mode I2C Channel Selection Register-based Write to control register
I/O Expander (PCF8574)
The I/O Expander module provides access to the PCF8574 8-bit I/O expander chip.
Module Definition
lib/modules/communication/wired/i2c/io-expander.h
#include "PCF8574.h"
class IOExpander : public PCF8574 {
private:
uint8_t addr;
public:
using PCF8574 ::PCF8574;
};
Basic GPIO Control
#define ENABLE_MODULE_IO_EXPANDER
#include "Kinematrix.h"
IOExpander expander ( 0x 20 ); // PCF8574 address
void setup () {
expander . begin ();
// Set pins 0-3 as outputs, 4-7 as inputs
expander . pinMode ( 0 , OUTPUT);
expander . pinMode ( 1 , OUTPUT);
expander . pinMode ( 2 , OUTPUT);
expander . pinMode ( 3 , OUTPUT);
expander . pinMode ( 4 , INPUT);
expander . pinMode ( 5 , INPUT);
expander . pinMode ( 6 , INPUT);
expander . pinMode ( 7 , INPUT);
}
void loop () {
// Control outputs
expander . digitalWrite ( 0 , HIGH);
expander . digitalWrite ( 1 , LOW);
// Read inputs
bool button1 = expander . digitalRead ( 4 );
bool button2 = expander . digitalRead ( 5 );
delay ( 100 );
}
LED Control Example
IOExpander leds ( 0x 20 );
void setup () {
leds . begin ();
// Set all pins as outputs
for ( int i = 0 ; i < 8 ; i ++ ) {
leds . pinMode (i, OUTPUT);
}
}
void loop () {
// LED chaser effect
for ( int i = 0 ; i < 8 ; i ++ ) {
leds . digitalWrite (i, HIGH);
delay ( 100 );
leds . digitalWrite (i, LOW);
}
}
IOExpander buttons ( 0x 21 );
void setup () {
Serial . begin ( 115200 );
buttons . begin ();
// Set all pins as inputs with pull-ups
for ( int i = 0 ; i < 8 ; i ++ ) {
buttons . pinMode (i, INPUT_PULLUP);
}
}
void loop () {
// Read all button states
uint8_t buttonStates = buttons . read8 ();
// Check individual buttons (active LOW)
for ( int i = 0 ; i < 8 ; i ++ ) {
if ( ! (buttonStates & ( 1 << i))) {
Serial . print ( "Button " );
Serial . print (i);
Serial . println ( " pressed" );
}
}
delay ( 50 ); // Debounce delay
}
PCF8574 Specifications
Parameter Value Notes Supply Voltage 2.5V - 6V Typically 5V I/O Pins 8 P0-P7 Current per Pin 25 mA Maximum sink/source I2C Address (PCF8574) 0x20-0x27 A0-A2 configurable I2C Address (PCF8574A) 0x38-0x3F Different variant Interrupt Support Yes INT pin goes LOW on input change
Multiple Expander Configuration
Combine multiple I/O expanders for large systems:
#define ENABLE_MODULE_IO_EXPANDER
#include "Kinematrix.h"
IOExpander outputs1 ( 0x 20 ); // 8 outputs
IOExpander outputs2 ( 0x 21 ); // 8 more outputs
IOExpander inputs ( 0x 22 ); // 8 inputs
void setup () {
outputs1 . begin ();
outputs2 . begin ();
inputs . begin ();
// Configure first 16 pins as outputs
for ( int i = 0 ; i < 8 ; i ++ ) {
outputs1 . pinMode (i, OUTPUT);
outputs2 . pinMode (i, OUTPUT);
}
// Configure 8 pins as inputs
for ( int i = 0 ; i < 8 ; i ++ ) {
inputs . pinMode (i, INPUT_PULLUP);
}
}
void loop () {
// Control 16 LEDs
uint8_t inputState = inputs . read8 ();
outputs1 . write8 (inputState);
outputs2 . write8 ( ~ inputState);
delay ( 10 );
}
I2C Best Practices
Pull-up Resistors : I2C requires pull-up resistors on SDA and SCL lines. Typical values are 4.7kΩ for short distances or 2.2kΩ for longer cables.
Bus Speed : Start with 100kHz (standard mode) for debugging, then increase to 400kHz (fast mode) for better performance once the system is stable.
Address Conflicts : Always scan the I2C bus before adding new devices to avoid address conflicts.
Common I2C Issues
Possible causes:
Missing or incorrect pull-up resistors
Incorrect wiring (SDA/SCL swapped)
Power supply issues
Wrong I2C pins on ESP32 (use Wire.begin(SDA, SCL))
Solution: // ESP32: Specify I2C pins
Wire . begin ( 21 , 22 ); // SDA=21, SCL=22
// Check pull-ups with multimeter
// SDA and SCL should read VCC when idle
Intermittent Communication
Possible causes:
Bus capacitance too high (long wires)
Insufficient pull-up current
Electrical noise
Solution:
Use stronger pull-ups (2.2kΩ instead of 4.7kΩ)
Reduce wire length
Add capacitors near devices (100nF)
Shield cables for long runs
Possible causes:
Device holding SDA low
Power glitch during communication
Solution: // Software I2C reset
Wire . end ();
delay ( 100 );
Wire . begin ();
// Or clock out stuck device
pinMode (SDA_PIN, OUTPUT);
for ( int i = 0 ; i < 9 ; i ++ ) {
digitalWrite (SCL_PIN, HIGH);
delayMicroseconds ( 5 );
digitalWrite (SCL_PIN, LOW);
delayMicroseconds ( 5 );
}
Wire . begin ();
// Default pins: SDA=21, SCL=22
Wire . begin ();
// Custom pins
Wire . begin (SDA_PIN, SCL_PIN);
// Clock speed
Wire . setClock ( 400000 ); // 400kHz
// Default pins: SDA=4(D2), SCL=5(D1)
Wire . begin ();
// Custom pins
Wire . begin (SDA_PIN, SCL_PIN);
// Clock speed
Wire . setClock ( 100000 ); // 100kHz recommended
// Fixed pins: SDA=A4, SCL=A5 (Uno/Nano)
// Fixed pins: SDA=20, SCL=21 (Mega)
Wire . begin ();
// Clock speed
Wire . setClock ( 100000 ); // 100kHz
Serial Communication Alternative communication protocols
SPI Interface Higher-speed serial communication