Page 1 of 1

'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 6:49 pm
by krisss
I've been frustrated with my efforts to read a temp/humidity sensor, so I connected my board to a scope and read the data being transferred. When I use the command read_i2c_block_data(addr, 0, 4), I noticed that the raspberry pi first writes a '0' to the device, then immediately reads 4 bytes in succession. It's not supposed to write a 0 first. That screws up my chip big time. Why is it doing this and how can I fix it/work around it?

I'm using python (a tkinter interface) on a raspberry pi zero. Here's a section of relevant code:

Code: Select all

try:
    from Tkinter import *
except ImportError:
    from tkinter import *
try:
    import tkinter.messagebox
except ImportError:
        import tkMessageBox
import smbus
import csv
import time
from datetime import datetime
import subprocess, sys

sens_addr = 0x28

def csv_write (self):
        global directory
        global file_name
        logFile = open(directory+file_name, 'a')
        with logFile:
            
            block = bus.read_i2c_block_data(sens_addr, 0, 4) #read 4 bytes
            print(block)

Re: 'smbus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 6:56 pm
by DirkS
Yes, maybe, 42...

Any answer is possible with so little to go on...
Minimum you have to give us is some more code, and which programming language you're using...

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 7:07 pm
by krisss
Edited the top post. Is that enough?

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 7:30 pm
by stevend
http://www.raspberry-projects.com/pi/pr ... nterface-2 suggests that the read syntax is:

Code: Select all

long[] read_i2c_block_data(int addr,char cmd)
If I've found the right reference, your line should be:

Code: Select all

block = bus.read_i2c_block_data(sens_addr,  4) #read 4 bytes

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 7:33 pm
by joan
The initial 0 will be the register to read on the device.

See my pigpio equivalent.

http://abyz.me.uk/rpi/pigpio/python.htm ... block_data

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 7:37 pm
by joan
stevend wrote:
Wed Aug 22, 2018 7:30 pm
http://www.raspberry-projects.com/pi/pr ... nterface-2 suggests that the read syntax is:

Code: Select all

long[] read_i2c_block_data(int addr,char cmd)
If I've found the right reference, your line should be:

Code: Select all

block = bus.read_i2c_block_data(sens_addr,  4) #read 4 bytes
The example was C (using the Linux I2C interface) whereas the OP is using the Python SMBus module.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 7:46 pm
by krisss
stevend wrote:
Wed Aug 22, 2018 7:30 pm
If I've found the right reference, your line should be:

Code: Select all

block = bus.read_i2c_block_data(sens_addr,  4) #read 4 bytes
This causes it to read 32 bytes now. I don't have it connected to the scope anymore but I'm getting the same nonsense numbers indicating it's writing a 0 first.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Wed Aug 22, 2018 8:19 pm
by 6by9
Don't use an smbus library when you want an i2c one. They may have a lot in common, but they are not the same (smbus is really a subset of i2c).

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 3:21 pm
by krisss
I think this is a really simple problem: I just need to read four bytes using a repeated start condition. Can I do that with smbus or is there a python library that can do this? I'm sure I'm not the first person with this problem.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 3:47 pm
by 6by9
Talk I2C then, not SMBus.
https://github.com/quick2wire/quick2wir ... ith-i2c.md appears to be talking to the I2C functions of the kernel rather than smbus. It's using the ioctl I2C_RDWR to allow multiple read and/or write transactions as a single entity. The lengths of those transactions is entirely up to you and what your device requires.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 5:22 pm
by joan
What device are you trying to read?

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 5:26 pm
by krisss

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 5:42 pm
by joan
https://github.com/tonyastolfi/chipcap2 ... hipcap2.py uses the Python smbus module. I presume it is meant to work.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 6:08 pm
by krisss
Thanks for finding that. It's very similar to my own code. Unfortunately I tried it and it spits out the same numbers as before. The code again reads 32 bytes from the device, all garbage.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Thu Aug 23, 2018 11:17 pm
by Paeryn
As 6by9 pointed out earlier, you are trying to use SMBus to talk to an I2C device, the chip you linked to doesn't use SMBus so it shouldn't be expected that it follows the SMBus protocol.

From a quick look at what read_i2c_block_data(address, comm, count) involves :-

Code: Select all

Key to symbols
==============

S     (1 bit) : Start bit
P     (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit. 
Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to 
                get a 10 bit I2C address.
Comm  (8 bits): Command byte, a data byte which often selects a register on
                the device.
Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
                for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.

SMBus Block Read:  i2c_smbus_read_block_data()
==============================================

This command reads a block of up to 32 bytes from a device, from a 
designated register that is specified through the Comm byte. The amount
of data is specified by the device in the Count byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
From that it says that the comm byte is first written to the device to tell the device which register it wants to read from, then the first byte received is how many more bytes the device is going to send, followed by the data.

According to the docs for your chip, when you send a command byte it expects to be sent two more bytes of data (and that 0 is not a valid command) and any responses to a command are either 1, 2 or 3 bytes (and it doesn't send a count byte first).

To just read the humidity and temperature you don't send a command each time, you just issue data fetches and by the looks of it SMBus only has one function that can read without sending a command and that only allows reading one byte.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Fri Aug 24, 2018 5:47 pm
by krisss
That's what I figured. Is there a way for me to edit the smbus code? I searched on my Pi but couldn't find anything.

EDIT: Thanks everyone, I'm going to take your advice and abandon smbus and use quick2wire. I'll start a new thread as well.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Fri Aug 24, 2018 7:52 pm
by Paeryn
The version installed is likely to be the C version pre-compiled as a shared object file which Python can use. There is a pure Python version but probably not in the repos so either a pip or a manual download may be needed.

Either way you don't want to go modifying libraries to do something they aren't supposed to do as it could have a negative effect on other libraries / programs that use them, unless you make a new library using the source library as a template.

Hopefully the quick2wire library does what you need, it looked as though it does when I checked 6by9's link.

Re: 'bus.read_i2c_block_data' writes a 0 first then reads data

Posted: Fri Aug 24, 2018 8:00 pm
by joan
What I don't understand is how the github I linked worked (presumably). Perhaps the chipcap2 has changed or smbus has changed or the github author didn't actually check the data.