问题
I am trying to use python-smbus on a Raspberry Pi to communicate with an MMA7660 accelerometer chip using I2C.
In the code below, I am reading registers 0x00, 0x01, 0x02 and 0x03 of the chip, and I am getting the exact same values for all. Looking at the values, and tilting the chip, I can see that they all correspond to register 0x00, the X value register.
Output:
...
1 1 1 2
3 3 3 3
1 1 1 1
59 60 60 60
51 51 51 51
58 58 58 58
3 3 3 3
62 62 62 62
58 58 58 58
62 62 62 62
...
Code:
import smbus
import time
bus = smbus.SMBus(1)
# I2C address for MMA7660
addr = 0x4C
try:
bus.write_byte_data(addr, 0x07, 0x00)
bus.write_byte_data(addr, 0x06, 0x10)
bus.write_byte_data(addr, 0x08, 0x00)
bus.write_byte_data(addr, 0x07, 0x01)
except IOError, err:
print err
while True:
try:
x = bus.read_byte_data(addr,0x00)
y = bus.read_byte_data(addr,0x01)
z = bus.read_byte_data(addr,0x02)
tr = bus.read_byte_data(addr,0x03)
print x, y, z, tr
time.sleep(0.25)
except:
print 'exiting...'
break
Am I doing something wrong with the smbus syntax? I did look at the documentation here.
I have verified that the chip works - I can communicate fine with it using an Arduino and setting the registers in the same order as above.
Update #1 (28 Jun 2013):
As per Sylvain's comment, I am attaching oscilloscope output for SDA/SCL lines for the following code:
bus.write_byte(addr, 0x01)
print bus.read_byte(addr)

Update #2:
I guess there is a known problem with I2C on Raspberry Pi - there is no "Repeated Start".
https://raspberrypi.stackexchange.com/questions/7138/mma8452-i2c-module
According to the Linux SMBus spec:
SMBus Read Byte: i2c_smbus_read_byte_data()
============================================
This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.
S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
But when I tried it, the osciiloscope clearly shows a STOP (P) before the Repeated Start (S).
So I guess I am out of luck for using I2C hardware on the Pi to talk to the MMA7760.
回答1:
if you read all the needed registers at once, it works fine:
import smbus
bus = smbus.SMBus(1)
Register = bus.read_i2c_block_data(0x4c, 0x99,4)
acc_x = Register[0]*1.0
acc_y = Register[1]*1.0
acc_z = Register[2]*1.0
acc_tilt = Register[3]
回答2:
I'm absolutly not sure this is the problem, but according to the specs p22:
MMA7660FC is read using it’s internally stored register address as address pointer, the same way the stored register address is used as address pointer for a write. The pointer generally auto-increments after each data byte is read using the same rules as for a write (Table 5). Thus, a read is initiated by first configuring the device’s register address by performing a write (Figure 11) followed by a repeated start. The master can now read 'n' consecutive bytes from it, with the first data byte being read from the register addressed by the initialized register address.
As far as I understand, to "read" from a register, you have to start by writing the register address, and then blindly read a byte. I don't know if SMBus.read_byte_data
take care of that for you, but you could try it manually:
bus.write_byte(addr,0x00)
x = bus.read_byte(addr)
bus.write_byte(addr,0x01)
y = bus.read_byte_data(addr)
bus.write_byte(addr,0x02)
z = bus.read_byte(addr)
bus.write_byte(addr,0x03)
tr = bus.read_byte(addr)
Maybe that would even work:
bus.write_byte(addr,0x00)
x = bus.read_byte(addr)
y = bus.read_byte_data(addr)
z = bus.read_byte(addr)
tr = bus.read_byte(addr)
回答3:
After viewing your example, as well as class written for the MMA7455, I was able to write the following:
import smbus
import time
import os
import math
# Define a class for the accelerometer readings
class MMA7660():
bus = smbus.SMBus(1)
def __init__(self):
self.bus.write_byte_data(0x4c, 0x07, 0x00) # Setup the Mode
self.bus.write_byte_data(0x4c, 0x06, 0x10) # Calibrate
self.bus.write_byte_data(0x4c, 0x08, 0x00) # Calibrate
self.bus.write_byte_data(0x4c, 0x07, 0x01) # Calibrate
def getValueX(self):
return self.bus.read_byte_data(0x4c, 0x00)
def getValueY(self):
return self.bus.read_byte_data(0x4c, 0x01)
def getValueZ(self):
return self.bus.read_byte_data(0x4c, 0x02)
mma = MMA7660()
for a in range(1000):
x = mma.getValueX()
y = mma.getValueY()
z = mma.getValueZ()
print("X=", x)
print("Y=", y)
print("Z=", z)
time.sleep(0.2)
os.system("clear")
That should do the trick.
回答4:
The Raspberry PI I2C Kernel Driver did not support repeated starts for a specific time. However, the I2C Kernel Driver has been updated and now supports the repeated start, though this functionality must be activated explicitly.
To set combined transfers 'on'
sudo sh -c '/bin/echo Y > /sys/module/i2c_bcm2708/parameters/combined'
To set combined transfers 'off'
sudo sh -c '/bin/echo N > /sys/module/i2c_bcm2708/parameters/combined'
Information found here: http://raspberrypi.znix.com/hipidocs/topic_i2c_rs_and_cs.htm
来源:https://stackoverflow.com/questions/17317317/using-python-smbus-on-a-raspberry-pi-confused-with-syntax