5

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)

enter image description here

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.

Community
  • 1
  • 1
M-V
  • 5,167
  • 7
  • 52
  • 55

4 Answers4

2

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] 
ThomGob
  • 21
  • 2
  • Tried this with the MMA8452 and it didn't help. I'm guessing whatever chip you were using was tolerant of improper START/STOP/REPEATED-START – Dan Sandberg Jan 18 '14 at 02:07
1

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)
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • Unfortunately neither worked, but I think your are on the right track. It's a matter of figuring out how to do this using smbus. I wish they had lower level calls for I2C start/stop/restart, etc. I could do the same exactly in C and and an ATmega168 and it all works. – M-V Jun 26 '13 at 11:34
  • @M-V Have you an oscilloscope or logical analyzer to examine the bus? – Sylvain Leroux Jun 26 '13 at 11:35
  • I have an oscilloscope - but not a very capable one. Honestly, I haven't figured out how to use it for analyzing digital waveforms - the data goes off in a blip. – M-V Jun 26 '13 at 11:41
  • @M-V You probably need a [DSO](http://en.wikipedia.org/wiki/Oscilloscope_types#Digital_storage_oscilloscope) to investigate that kind of signal. – Sylvain Leroux Jun 26 '13 at 11:46
  • Thanks @Sylvain - I spent some time on how to use my scope to catch these signals. I've posted the signals - please share any insights. – M-V Jun 28 '13 at 08:15
0

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.

Ravi L
  • 1,142
  • 9
  • 17
  • Why should this "do the trick" when it basically does the same as the code in the question? – Daniel K. Aug 24 '20 at 08:18
  • 1
    @DanielK. - sorry, it's been 5 years, so I lost the context on this answer. I believe it might might have had something to do with the - os.system("clear") – Ravi L Aug 25 '20 at 05:44
  • os.system("clear") just clears the displayed output; it wouldn't do anything with the sensor – Chris Combs Jul 24 '23 at 19:21
0

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

a.Dippel
  • 93
  • 1
  • 7
  • Once this is done, what governs how many repeated start commands are issued? If I try to use smbus's read_i2c_block_data method, what controls how many times it issues a repeat start before it issues a stop? – temporary_user_name Feb 24 '17 at 00:45
  • @Aerovistae The repeated start is issued once after the Master has transmitted its data to the slave (slave in receiver mode) in order to read data back from the slave (slave in transmitter mode). The repeated start is used to avoid another master on the bus to gain control over the bus too early. The Master requests data as long as it doesn't issue a _Stop Condition_ or the Slave doesn't signal a _Not Acknowledge_ after the previous transmitted Byte. – a.Dippel Mar 22 '17 at 09:15
  • the link appears to be dead – Tooniis Nov 18 '22 at 08:20