Need help communicating with a "primitive" I2C device
I have a Onion Omega2+ plugged into a CE PR32-3 (adapter), thence into a MCP23008 / PEIO4R4G5LE (4-relay "shield" with I2C interface).
Using a simple Python script, I was controlling the relays quickly. So far, so good.
I plugged a SI7020-A20 (temperature / humidity sensor) into the I2C bus. The LED lights up.
This device has no addressable registers, so has a different programming interface than what the onionI2C Python library provides. There is i2c.readBytes(), but no i2c.read(). I suspect this is the root of my problem, but I tried this Python script:
from OmegaExpansion import onionI2C
i2c = onionI2C.OnionI2C()
i2c.write(0x40, [0xF5]) # 0x40 is the I2C address, 0xF5 is the command to start a conversion
data = i2c .readBytes(0x40, 0x00, 2) # This device has no addressable registers, so this readBytes() call is suspect, but there is no i2c .read()
print "%x" %data
print "%x" %data
Specced conversion gives RH of -5.88%. I've never heard of negative humidity!
I'm sure it's something really silly, but I have fiddled around a lot with the write(), writeBytes(), and readBytes() calls and not gotten anywhere.
It could be that I need to abandon Python and try to use more primitive functions that might be available in the C libraries, but I was sorta trying to avoid that. I haven't gotten anywhere with the cloud C compiler at all! All I get is an inert Web page that doesn't do anything.
Indeed, I2C devices that do not have internal registers do break a number of I2C wrapper APIs.
It looks like the Linux i2c-dev interface should itself be able to do the kinds of raw byte access you want
That is mostly simple file operations, but you will need to use an ioctl() call to set the target chip's address.
You get a working cross compiler as a result of a build of the system from source
There appear to be ways to perform an ioctl() from python, for example there's an "fcntl" module that has this capability, you could see if that or something similar is available.
Update: looks like all the pieces you need are available
in pythonC code in the onion i2c library, you just need to refactor them somewhat.
_i2c_writeBuffer appears to operate without the assumption that the first byte sent is an internal register address, it is then used by higher level functions that do enforce that assumption that is problematic for your case.
I'm not immediately seeing a corresponding raw buffer read, but you should be able to make one from the piece there, perhaps just by making a copy that doesn't do a write to send a register address, but instead goes right to the read.
Needless to say i2c debugging is a lot easier with the aid of a storage scope or a simple USB-based logic analyzer - you can figure it all out from what should be happening but it goes a lot faster when you can see what is happening.
2nd Update: realizing the above is C code, not python that you could use without the cross compiler. But that C code includes the ability to do the necessary ioctl() call, so perhaps you can use the built library to open the i2c device "file", perform the ioctl() call to set the peripheral address, but then do the actual byte writing/reading using file operations on that file descriptor directly from python.
@Chris-Stratton I previously wrote a suite of libraries and programs for the Omega1 (see https://github.com/KitBishop/Omega-GPIO-I2C-Arduino) and amongst this is some code for I2C that includes
rawaccess (i.e. without specifying a register) because I had some devices that required this.
Unfortunately, my code is currently only for the Omega1, it will not work as is for the Omega2. I need to make some changes for the Omega2 - I intend to do this but can't at the moment say when I will have time to do so (paid work getting in the way :-( )
I have compiled libsoc and its python2- and python3-bindings ( https://github.com/jackmitch/libsoc ) for the Omega2. libsoc allows you to read or write without specifying the register, so go nuts with it, if you please. A python-example is available at https://github.com/jackmitch/libsoc/blob/master/test/i2c_test.py
libsoc itself: https://dl.dropboxusercontent.com/u/11811685/omega2-stuff/libsoc_0.8.2-230117-1_mipsel_24kc.ipk
EDIT: Thought to add the LEDE-package Makefile for libsoc that I made: https://dl.dropboxusercontent.com/u/11811685/omega2-stuff/lede-libsoc-Makefile -- this is only useful for those who wish to build their own LEDE-packages, so everyone else can just ignore this.
Finally getting a chance to look at this again.
I want to thank everyone for their thoughtful responses.
I'm afraid I have a IoT noob question. How do I go about installing an .ipk file? I'd like to have a go with WereCatf's libsoc. Seems like the path of least resistance.
How do I go about installing an .ipk file?
Download the file, then
opkg install package.ipk
Do note that I haven't tested these on the official firmware, so I don't 100% guarantee they work. But they should work just fine.
Wow, I must be a total doof. I tried to use opkg to attempt to install python-libsoc_xxxxxxxxxx and I just got an error:
Installing python-libsoc (0.8.2-230117-1) to root...
- satisfy_dependencies_for: Cannot satisfy the following dependencies for python-libsoc:
pkg-config * libsoc *
- opkg_install_cmd: Cannot install package python-libsoc.
@Art-Milburn Did you download and install libsoc? Also, install pkg-config from repos.
I can't figure out where to get pkg-config
I got it all installed but I get a segmentation fault when I try to import I2C
Ugh I was just trying to get this to work myself. What is annoying is there IS a write function that allows a no address write, but no corresponding read! Not sure why this was part of the kickstarter if its not easy to control, at least via python.
Has anyone found any reasonably straightforward solution here? I appreciate all the suggestions from folks, but am very surprised by the lack of corresponding function to the arduino Wire library for OMega2 + Python for I2C. I'm trying to get a board running that is working on Arduino utilizing the Wire API to get data from the device using Wire.requestFrom(), Wire.available(), and Wire.read(). Is the most straightforward solution to add parameter compatible calls to OmegaExpansion.onionI2c? I might be able to assist in any efforts if this seems like a path Onion would like to take that would be useful to others. Btw, I do love my Omega2. I think it just needs a little more library love!
Original Arduino Source: https://github.com/SparkysWidgets/MinipHBFW/blob/master/MinipH.ino
Python Version: https://github.com/SparkysWidgets/MinipHBFW/blob/master/RaspberryPi - Python3/pHReader.py
Maybe posting here will make them merge the PR: https://github.com/OnionIoT/i2c-exp-driver/pull/15
Compiled packages are available on https://www.dropbox.com/sh/p7mki5nbgyu1tcv/AABPC1HzA848MbEA9RpNiNNva?dl=0
One can install them with opkg install libonioni2c_0.4-2_mipsel_24kc.ipk pyOnionI2C_0.4-2_mipsel_24kc.ipk pyOmegaExpansion_0.4-2_mipsel_24kc.ipk liboniondebug_0.4-2_mipsel_24kc.ipk
Example using modified python library: https://gist.github.com/foxel/a163231293d7cf6f24831b363a91dfe5