I2C with Raspberry Pi

This is a placeholder topic for “I2C with Raspberry Pi” comments.

Hello there, how’s your day been? Good? Fantastic! Not so good? Don’t worry it’s about to get a lot better, because today we’re going to take a look at how to use the I2C interface on our Raspberry Pi to control I2C devices.

Read more

1 Like

I want to understand the application of the statement
bus.write_byte_data(0x20, 0x00, 0x00)
bus.write_byte_data(0x20, 0x01, 0x00)
I know the first parameter is the address of the particular I2C device.
According to the document I2C addresses produced by Adafruit, 0x20 could be:
FXAS21002 Gyroscope (https://adafru.it/y6c) (0x20 or 0x21)
Chirp! Water sensor (https://adafru.it/dEv) (0x20)
MCP23008 I2C GPIO expander (https://adafru.it/y6f) (0x20 - 0x27)
MCP23017 I2C GPIO expander (https://adafru.it/sCR) (0x20 - 0x27)

I haven’t finished. I must have accidentally hit the reply button. Sorry.
I understand the first parameter must be the address of the particular I2C as exempllifed above.
I would like to know the second and third parameters, please.

The reason for asking this question is that the bus.write_byte_data is not well explained in any random search.

For example in another tutorial, at https://tutorials-raspberrypi.com/measuring-rotation-and-acceleration-raspberry-pi/ the use of the bus.write_byte_data is:
bus.write_byte_data(address, power_mgmt_1, 0)
That is:
bus.write_byte_data(0x6a, 0x6b,0)
That is, initialising the gyroscope at I2C address 0x68, then turning on the gyroscope module, and initializing with 0.

BUT I want to know a general principle of the bus.write_byte_data(arg1, arg2, arg3) please.

Thank you,
Anthony of Sydney

Hi @Anthony12822, I haven’t done a great deal of tinkering with I2C yet (but that is about to change in the near future) but my understanding is that write_byte_data() takes three values: The I2C address of the device you are sending data to; a device-specific command code; and a byte of data. The command code will be specific to the I2C device you are communicating with, so you would need to find documentation for the device to determine what the command and data parameters actually mean.

If I understand the I2C docs correctly, the data parameter is not necessarily needed, so you may sometimes just use the I2C address and a command code. But again, the command code will be specific to the type of device you are communicating with, so a command code sent to a Gyroscope sensor may have a completely different meaning if the same command code was sent to a water sensor.

Does that help? :wink:


Dear arb,
Thank you for your reply. In the interim, I just found this code at https://forum.dexterindustries.com/t/solved-python-library-for-6-axis-accelerometer-and-compass/1043/3 by ben_bd. It is not necessarily the ultimate code, but to get me started.

I may have solved my problem. It’s nerdy, and I understood its purpose by going deeper down the code instead of relying on the Adafruit (higher level code).

When you read the datasheet for the LSM303DHLC, you find that there is the address for the module, using the i2cdetect or by using the list of addresses pdf document produced by Adafruit i2c-addresses.pdf (384.3 KB) from https://learn.adafruit.com/i2c-addresses/overview where the link to the document is https://cdn-learn.adafruit.com/downloads/pdf/i2c-addresses.pdf.

Start again. You have the address of the device. Then the device has specific registers that can be set, that is the 2nd parameter. Then the register is stored with a particular value.

For example during the initialization of the module you come across this:

bus.write_byte_data(LSM303D_ADDR, CTRL_REG1, 0x57)
# where LSM303D_ADDR = 0x1E, CTRL_REG1 = 0x20, and 0x57
# refer to p25 data sheet. 0x57 = 01010111, where 0101 = 100Hz operation table 18, table 19
# 0111 = lpen and enable x,y,z. = normal power, enable x,y,z, table 18 and 20

Don’t worry about WHO_AM_I when reading from the command

 whoami = bus.read_byte_data(LSM303D_ADDR, WHO_AM_I)

This refers to the device LSM303D, where the WHO_AM_I register is 0x0f is supposed to return the value 0x49 as in page 28, table 19 and page 32. So this is irrelevant for the LSM303DHLC. Source document for the LSM303D is at https://www.pololu.com/file/download/LSM303D.pdf?file_id=0J703 . Yes the LSM303D does a similar thing to the LSM303DHLC

Thank you,
Anthony of Sydney

1 Like

“If you’ve wired everything up correctly, …” but never told us anything about how to wire it. Sheesh…

Hi Chris,
Welcome to the forum,

The tutorial does include a wiring diagram with how everything is connected on the protoboard, I’ll include the image below.

Was there a particular part of the wiring process you were unsure about that we could elaborate further?

PS. a super useful tool for wiring anything to a Raspberry Pi board is https://pinout.xyz/


Thanks Trent: I worked it out. Suggestion for future - try not to assume n00bs like me know “obvious (to you) stuff”.
A heading “How to connect” is probably needed, spelling out that (if this is true) that the rPI has only one I2C interface, and to use it, we need to connect “SDA (on the pi) to SDA (on the board)” and “SCL to SCL” - maybe also mentioning that sometimes some boards use different names for those pins, and that we can wire other boards to those same pins at the same time if we want, etc etc: you know - all the stuff you know about that, which we do not.

  • “SDA to SDA” might seem obvious to you, but: “RX to RX” and “TX to TX” … remember that your users have probably already encountered the opposite convention already…

Are the pullups really needed? Te rPI has it’s own already, right? Not sure if the kernel brings them up, but it seems logical it would (or if not, let us know the /boot/config.txt and/or CLI method of pulling them up in software, so we can avoid those redundant resistors?). I worked all this out last night after 5+ hours of google… so I’ve now happily got 4 devices humming along nicely on my PI4’s I2C


Hi Chris,

Thank for the feedback this tutorial is quite old so hasn’t been reviewed in some time. I’ve made a note to have someone review it and integrate your feedback.

As a bit of an aside, a lot of our more recent Raspberry Pi guides feature our PiicoDev range of I2C devices which simplify the connection process greatly for beginners by allowing connection via 4-pin cables. They still can be connected via header pins if you want to breadboard projects, but we find it a lower barrier to entry.


I followed the tutorial which I found useful, however I encountered errors using i2cset etc.
i2cset –y 1 0x20 0x00 0x00
Error: I2C bus name doesn’t match any bus present!

This turned out to be because I copied the command BUT the ‘-y’ option is INCORRECT because it uses an endash rather than an ASCII ‘-’


Hi Ian,

Good catch on the mistake there! I suspect that incorrect character encoding may have happened when the text editor that was used to type the article took some liberties with autoformatting.
I’ve got the character switched over now so it should work properly. Thanks for letting us know about the error.