Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add no addr reads #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions qwiic_i2c/circuitpy_i2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ def readWord(self, address, commandCode):
buffer = bytearray(2)

try:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
if (commandCode == None):
self._i2cbus.readfrom_into(address, buffer) # TODO: not yet validated...
else:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
except Exception as e:
self._i2cbus.unlock()
raise e
Expand All @@ -176,14 +179,17 @@ def read_word(self, address, commandCode):
return self.readWord(address, commandCode)

#----------------------------------------------------------
def readByte(self, address, commandCode):
def readByte(self, address, commandCode = None):
if not self._i2cbus.try_lock():
raise Exception("Unable to lock I2C bus")

buffer = bytearray(1)

try:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
if (commandCode == None):
self._i2cbus.readfrom_into(address, buffer) # TODO: not yet validated...
else:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
except Exception as e:
self._i2cbus.unlock()
raise e
Expand All @@ -203,7 +209,10 @@ def readBlock(self, address, commandCode, nBytes):
buffer = bytearray(nBytes)

try:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
if (commandCode == None):
self._i2cbus.readfrom_into(address, buffer) # TODO: not yet validated...
else:
self._i2cbus.writeto_then_readfrom(address, bytes([commandCode]), buffer)
except Exception as e:
self._i2cbus.unlock()
raise e
Expand Down Expand Up @@ -332,3 +341,20 @@ def scan(self):
self._i2cbus.unlock()

return devices

#-----------------------------------------------------------------------
# Custom method for reading +8-bit register using `i2c_msg` from `smbus2`
#
# Designed to have same operation as the __i2c_rdwr method in linux_i2c.py
def __i2c_rdwr__(self, address, write_message, read_nbytes):
"""
Custom method used for 16-bit (or greater) register reads
:param address: 7-bit address
:param write_message: list with register(s) to read
:param read_nbytes: number of bytes to be read

:return: response of read transaction
:rtype: list
"""
self._i2cbus.readBlock(address, write_message, read_nbytes)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not work in CircuitPython


35 changes: 33 additions & 2 deletions qwiic_i2c/micropython_i2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,29 @@ def __setattr__(self, name, value):

# read commands ----------------------------------------------------------
def readWord(self, address, commandCode):
buffer = self._i2cbus.readfrom_mem(address, commandCode, 2)
if (commandCode == None):
buffer = self._i2cbus.readfrom(address, 2)
else:
buffer = self._i2cbus.readfrom_mem(address, commandCode, 2)

return (buffer[1] << 8 ) | buffer[0]

def read_word(self, address, commandCode):
return self.readWord(address, commandCode)

def readByte(self, address, commandCode):
def readByte(self, address, commandCode = None):
if (commandCode == None):
return self._i2cbus.readfrom(address, 1)[0]

return self._i2cbus.readfrom_mem(address, commandCode, 1)[0]

def read_byte(self, address, commandCode = None):
return self.readByte(address, commandCode)

def readBlock(self, address, commandCode, nBytes):
if (commandCode == None):
return self._i2cbus.readfrom(address, nBytes)

return self._i2cbus.readfrom_mem(address, commandCode, nBytes)

def read_block(self, address, commandCode, nBytes):
Expand Down Expand Up @@ -182,3 +192,24 @@ def ping(self, devAddress):
def scan(self):
""" Returns a list of addresses for the devices connected to the I2C bus."""
return self._i2cbus.scan()

#-----------------------------------------------------------------------
# Custom method for reading +8-bit register using `i2c_msg` from `smbus2`
#
# Designed to have same operation as the __i2c_rdwr method in linux_i2c.py
def __i2c_rdwr__(self, address, write_message, read_nbytes):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be changed. I know this is what was used elsewhere, but it's not a great name. Should match the conventions of the other methods in this driver, and get added to i2c_driver.py and linux_i2c.py. Then any device drivers that use it (I think just the VL53?) should be changed to use this new method. Does that make sense?

Copy link
Contributor

@santaimpersonator santaimpersonator Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming convention was based off the original i2c_rdwr() method from the smbus2 Python package that this package utilizes as the driver on Linux platforms:

def i2c_rdwr(self, *i2c_msgs):

When we added this method, I included the double underscores (__) to give it a private attribute. This keeps the method hidden (in a way), since we were only using it for the VL53L1x. Additionally, the method wasn't considered a feature of the package, as noted in the README.md file of the smbus2 GitHub repository, :

Note

Starting with v0.2, the smbus2 library also has support for combined read and write transactions. i2c_rdwr is not really a SMBus feature but comes in handy when the master needs to:

  1. read or write bulks of data larger than SMBus' 32 bytes limit.
  2. write some data and then read from the slave with a repeated start and no stop bit between.

Each operation is represented by a i2c_msg message object.


As a recommendation... I'd keep the __i2c_rdwr__()method for backwards compatibility. Since it is technically private, we could create a new public method with the naming convention that you prefer. To keep the functionality, you could:

  • Call on the __i2c_rdwr__()method
  • Reuse the same code

"""
Custom method used for 16-bit (or greater) register reads
:param address: 7-bit address
:param write_message: list with register(s) to read
:param read_nbytes: number of bytes to be read

:return: response of read transaction
:rtype: list
"""

# micropython I2C doesn't have a corresponding "i2c_rdwr" function like smbus2, so we will make our own by passing stop=False to not send stop bits between repeated transfers
self._i2cbus.writeto(address, bytes(write_message), False)
return self._i2cbus.readfrom(address, read_nbytes)