6

I am working on Raspberry Pi Model B.

I am trying to interface this device over the I2C Bus on the Rpi.

My hardware Connections are:

RPi                    Accelerometer
Vcc P1_1 ------------------Vcc
Gnd P1_9 ------------------Gnd
SDA P1_3 ------------------SDA
SCL P1_5 ------------------SCL

I am using the wiring Pi Library.

I compile the code by the command:

pi@raspberrypi ~/acc $gcc main.c acc.c -lwiringPi

and run it with the command:

pi@raspberrypi ~/acc $ sudo  ./a.out

I do the following before executing my code:

pi@raspberrypi ~/acc $ gpio load i2c
pi@raspberrypi ~/acc $ i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- 1d -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Here I am getting the correct slave address, but when I try to read anything from the device I always a 00 from the device.

Here is my code.

Anything that I am missing out.

I would appreciate the help

EDIT:

pi@raspberrypi ~/acc $ i2cget 1 0x1D 0x0D

WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will read from device file /dev/i2c-1, chip address 0x1d, data address
0x0d, using read byte data.
Continue? [Y/n] Y

0x00

pi@raspberrypi ~/acc $ sudo strace -e open 2>&1 | grep dev

pi@raspberrypi ~/acc $sudo ./a.out

Return Value is 0

Success setting up i2c device with the fd = 4

The value of the WHO_AM_I register is 0

Coudnot connect to the device

X : Y : Z : 0, 0, 0
X : Y : Z : 0, 0, 0
X : Y : Z : 0, 0, 0
Krzysztof Adamski
  • 9,615
  • 1
  • 37
  • 53
Jay K
  • 248
  • 2
  • 8
  • Can you check that the device is working correctly when using i2cget command? Also, could you check if proper /dev/i2c-X device is being opened on your device by running sudo strace -e open 2>&1 | grep dev ? – Krzysztof Adamski Apr 22 '13 at 07:03
  • @KrzysztofAdamski--- I tried doing i2cget 0x1D 0x0D, where 0x1D is the slave address and 0x0D is a internal register in the slave, it returned 0x00, but it should have returned 0x2A I will check if the device is getting opened or not and update you – Jay K Apr 22 '13 at 07:11
  • Note that first argument to i2cget should be the i2c bus number which should be 1 for you. Please check i2cget 1 0x1D 0x0D. Please also check the strace command I gave you and update your question with the results. – Krzysztof Adamski Apr 22 '13 at 07:42
  • @KrzysztofAdamski--I have added the result to the question. Doing the sudo strace -e open 2>&1 | grep dev did not print anything on the terminal. – Jay K Apr 22 '13 at 08:49
  • It should be strace -e open ./a.out 2>&1 | grep dev, actually. The most important information is that i2cget gives you 0x00 so it's not your program that is wrong. Unfortunately I don't know this device and I don't have enough time to read the datasheet so I can't help you any more. You have to double check all your wiring and read datasheet carefully. Make i2cget/i2cset working before you start debugging the C program. – Krzysztof Adamski Apr 22 '13 at 08:49
  • @KrzysztofAdamski--- strace -e open ./a.out 2>&1 | grep dev also does not print anything on the screen. – Jay K Apr 22 '13 at 08:53
  • @KrzysztofAdamski The fact that i2cdetect -y 1 correctly prints the slave address (0x1D), can be used to infer that my connections are correct? – Jay K Apr 22 '13 at 08:57
  • strace command is to check that proper i2c port is used but maybe wiringpi does not use /dev/i2c-X files so lets leave it for now. About your other question - it does means that your I²C connection is kind of OK. Note that MMA8452 has internal pull-up resistors so does RaspberryPi. I'm not sure if it's not a problem. I have also found some people over Internet mentioning that this modules is (for some reason) not compatible with RaspberryPi. You could try using software I²C bus instead of hardware one also using pins without pull-ups but that requires kernel module compilation. – Krzysztof Adamski Apr 22 '13 at 09:17

2 Answers2

4

From your module datasheet (5.10.1):

The MMA8452Q expects repeated STARTs to be used to randomly read from specific registers.

Unfortunately it seems that BCM2835 (RaspberryPi's SoC) does not support repeated START sequence. This means that your module is not compatible with the I²C bus on RaspberryPi.

There are two workarounds, none of them is easy to do, however.

Bitbanged I²C

You can use software (bitbanged) I²C bus on your RaspberryPi. I can't test this but reading the driver code it seems that repeated start sequence is supported by i2c-gpio driver. My tests with logic analyzer confirm (although I only tested this with pfc8574 which is very stupid device) that i2c_bcm2708 sends stop+start bit after data address while i2c_gpio only sends start bit.

It so happens that I recently wrote a Linux kernel module that let you create such bus without manually changing Kernel code. It's not (yet?) a part of the RaspberryPi kernel so you would have to compile this yourself. Here's the code and some instructions (but you need to know how to compile your own kernel to use it).

Since WiringPi uses i2c_smbus_read_byte_data function, it should "just work".

HiPi commandline utility

You could use HiPi utility (here are installation instructions) and check that it works from the provided commandline utilities. If it does, you could use them instead of WiringPi to do the communication. I know that it is not pretty solution but it may work.

Krzysztof Adamski
  • 9,615
  • 1
  • 37
  • 53
  • Alternatively, I could make my own precompiled kernel version with my module installed available if you can't follow my instructions on github and want to test this. This is not a long-run solution since it will prevent you from updating your kernel. If you test that it works, I might be able to integrate this to the official kernel, though. – Krzysztof Adamski Apr 22 '13 at 10:54
  • @KrzysztofAdamkski Yes, I can test if that works. – Jay K Apr 22 '13 at 20:24
  • @JayK: Here's precompiled kernel, if you didn't compile one yourself yet. – Krzysztof Adamski Apr 22 '13 at 21:53
  • ---Meanwhile I started working on HiPi, and I was able to read the WHO_AM_I register. You were correct with the Repeated Start Problem. Thanks..I will test the kernel too.. – Jay K Apr 23 '13 at 00:43
  • @KrzysztofAdamski--I need some more pointers on using the modules.tar.gz file in your kernel link. Could you add a little more info. I am a newbie to Linux – Jay K Apr 25 '13 at 05:43
  • @JayK: Please check README.txt file now. – Krzysztof Adamski Apr 25 '13 at 06:38
  • @KrzysztofAdamski--I understood the way to add your kernel module. But can you tell me what function calls should I make to read and write registers from my device? – Jay K Apr 27 '13 at 01:27
  • @JayK: My module creates bus number 7 by default and uses pins 0 and 1 after loading it. Those are pins used by hardware i²c bus on RaspberryPi so you have to either remove i2c_bcm2708 module or change the pins using kernel parameters. For example modprobe i2c_gpio_param busid=7 sda=22 scl=23 will use pins 22 and 23 (note that you may need external pull-up resistors when using those pins). Now when you have i2c bus with number 7, you should pass this number to wiringPiI2CSetup() function when initializing i2c in wiringPi. And this should be the only change in your code. – Krzysztof Adamski Apr 27 '13 at 07:32
  • @KrzysztofAdamski--I did modprobe i2c_gpio_param. When I do a lsmod, I can see that this kernel module is loaded. The i2c_bcm2708 is not loaded in my kernel. Now I also pass bus number 7 to wiringPiI2CSetup() function. But I was wondering, how will the i2c_gpio_param module know the address of the device (In my case 0x1D) where it has to send the data? My code is in this link. Also now when I call the wiringPiI2CReadReg8(fd, 0x03), it will generate a Repeated Start Signal? – Jay K Apr 28 '13 at 01:20
  • @JayK: I was wrong, did not read the documentation careful enough, sorry for that - you should pass your device I²C address (0x1D) to wiringPiI2CSetup. Unfortunately there is no way you can tell wiringPi which I²C bus it should use. It guesses that according to your board revision. This means that in your case wiringPi is only able to work on bus number 1. So you have to tell i2c_gpio_param to use this bus number instead of default 7 - modprobe i2c_gpio_param busid=1 sda=22 scl=23 (if the module is already loaded just remove it with rmmod i2c_gpio_param. – Krzysztof Adamski Apr 28 '13 at 10:40
  • A patch adding support for combined transactions was recently proposed on github – Krzysztof Adamski Jun 28 '13 at 10:31
  • Can you tell me in little more detail about this? – Jay K Jun 29 '13 at 14:39
  • @JayK: This patch adds support for using repeated starts in situations it is possible. This is exactly what is needed for your sensor to work correctly out of the box. The patch was not yet merged to the raspberryPi kernel as there is a need for more testing. You can either compile kernel with this patch and test or just watch this thread if you don't feel like you can test it. – Krzysztof Adamski Jun 29 '13 at 20:17
1

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
  • 49
  • 1
  • 5