juhasch / pyBusPirateLite

Python library for BusPirate
https://pybuspiratelite.readthedocs.io/en/latest/
Other
59 stars 32 forks source link

Invalid read implementation for write_then_read method #27

Open horror-vacui opened 4 years ago

horror-vacui commented 4 years ago

The write_then_read method, which according to my understanding supposed to be the general I2C read/write function implements the I2C wrong. The read supposed to be as follows:

The example in the README does not tell anything about how to issue a repeated start. I've written a code in the spirit of the example in the README:

>>> import pyBusPirateLite
>>> i2c = pyBusPirateLite.I2C()
>>> i2c.speed = '5kHz'
>>> i2c.configure(power=True)
>>> i2c.write_then_read(4,0, [ 0x3e, 0x82, 0xf0, 0xf0 ]  )
b''
>>> i2c.write_then_read(2,2, [ 0x3f, 0x01]  )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/dist-packages/pyBusPirateLite/I2C.py", line 308, in write_then_read
    raise ProtocolError('Error in transmission')
pyBusPirateLite.base.ProtocolError: Error in transmission

Note to the code: The 0x82 command sets among others the 0x01 register, what I want to read out.

The signal waveforms shows that the first part of the transmission is missing (R/Wb=0 & reg address = 0x01) scope_3

I could get around with this if I could force a repeated start in the read_then_write's txdata. In its form either the implementation of the code is bad, or something is missing from the description.

julianvilas commented 5 months ago

Hi @horror-vacui,

The Bus Pirate Write then read command works exactly as you said it should work, you can check it on the Bus Pirate firmware. The pyBusPirateLite.I2C.write_then_read just implements the bitbang mode call for the firmware method.

According to the firmware code you should provide the write address if you are not going to read anything or you are going to read and write more data than just the single byte of the device address. Because in the second case as you can see the firmware itself will issue the i2c restart and set the read bit in the device address. The only case where you would need to send the read device address is when you are just reading.

I don't know the details of the peripheral you are communicating with through I2C, but here you can see some examples for reading/writing an AT24C128/256 EEPROM using the write_then_read, with the particularities of that specific device.