kplindegaard / smbus2

A drop-in replacement for smbus-cffi/smbus-python in pure Python
MIT License
243 stars 68 forks source link

read_i2c_block_data very slow #108

Open arcadeperfect opened 7 months ago

arcadeperfect commented 7 months ago

I am trying to send data from an rp2040 to a raspberry pi via i2c. I am using Arduino on the rpi2040 and python on the raspberry pi.

The use case is similar to that of a midi controller; the data bandwidth doesn't need to be particularly high but the latency and frequency need to be fast.

The following, in which I request one byte at a time works well, with very fast throughput, meaning it is printing hundreds of bytes per second. I suspect the bottleneck is actually the print, even though it's inducing the overhead of a new request for every single byte:

Aruino:

#include <Wire.h>

const int ADDRESS = 0x08;      // I2C address
volatile int tenBitValue = 0;  // 10-bit value
volatile byte val = 0;         // 8-bit value to be transmitted

void setup() {
  Serial.begin(115200);
  Wire.begin(ADDRESS);
  Wire.setClock(400000);  // Set I2C clock speed to 400kHz
  Wire.onRequest(sendData);
}

void loop() {
  tenBitValue = analogRead(A0);  // Example: read value from analog pin A0
  val = map(tenBitValue, 0, 1023, 0, 255);
  Serial.println(val);
}

void sendData() {
  Wire.write(val);  // Send the 8-bit value
}

Python:

import smbus

device_address = 0x08

while True:
    print(bus.read_byte(device_address))

However I need more than one byte. The following, in which I use the block_data function and specify 2 bytes, and send 2 bytes from the arduino, is sending maybe 5 - 10 bytes a second which orders of magnitude slower than 1 byte at a time and won't work for my use case:

Arduino:

#include <Wire.h>

const int ADDRESS = 0x08;      // I2C address
volatile int tenBitValue = 0;  // 10-bit value
volatile byte val = 0;         // 8-bit value to be transmitted

void setup() {
  Serial.begin(115200);
  Wire.begin(ADDRESS);
  Wire.setClock(400000);  // Set I2C clock speed to 400kHz
  Wire.onRequest(sendData);
}

void loop() {
  tenBitValue = analogRead(A0);  // Example: read value from analog pin A0
  val = map(tenBitValue, 0, 1023, 0, 255);
  Serial.println(val);
}

void sendData() {
  Wire.write(val);  // Send the 8-bit value
  Wire.write(234);  // Send dummy data
}

Python:

import smbus

device_address = 0x08

while True:
    print(bus.read_i2c_block_data(device_address, 0, 2))