The I2C communications bus uses 7-bit or 10-bit addressing to address slave devices. Taking the more common 7-bit addresses, each packet sent on the bus by the master starts with an 7-bit address followed by a 1-bit read or write indicator (\$\text{R}/\overline{\text{W}}\$).
7-bit communication from the I2C Bus Specification

Most datasheets only give the I2C address for their device either in binary notation or as bits on timing diagrams (with notes for configurable address bits), which are both unambiguous as they either display seven or eight bits so you can tell if the \$\text{R}/\overline{\text{W}}\$ bit is included. This seems to follow the official NXP I2C specification.

The problem comes when trying to write down the address in hex. Different sources convert the address in different ways:

  1. Convert the 7-bit address to a hexadecimal value in the range 0x00 to 0x7F
  2. Include the \$\text{R}/\overline{\text{W}}\$ bit as the LSB and give two addresses, one for reading and one for writing in the range 0x00 to 0xFF

These two options are not always distinguishable.

Clearly using binary notation is better as it gives you an unambiguous address, however this is not always possible. One notable case is on C/C++ where there is not a particularly standard way of writing binary numbers. This leads to the problem I'm having where specifying constants for devices in the circuit is ambiguous.

So in choosing a standard for our schematics, documentation and code (C++) we have to pick one way or the other. That leads to my question:

Is there a dominant way of displaying an I2C address in hexadecimal notation, or are both used commonly?

  • 4
    \$\begingroup\$ +1 for the question, I too have faced this problem when defining the interface to I2C libraries. I always used the 7-bit address (with some pain in the hart, because it means an extra shift left somewhere in the implementation) because that is how the original Philips document put down addresses. PS: the new C++ 0x14 has binary literals and ' as allowed noise, so you could write the literal 0b'110'1100 \$\endgroup\$ Jan 28, 2015 at 22:31

3 Answers 3


I know what you mean. I have seen these ambiguities in documentation too. That doesn't make it right, though.

I personally only communicate the address as a 7 bit value, whether in binary (0-1111111), hex (0-7F), decimal (0-127) or some other scheme. The R/W bit is NOT part of the address. It and the address are two separate fields that happen to be crammed into the same byte.

Unfortunately, even though the 7-bit address interpretation is correct and does seem to be the more common, there is a lot of bad documentation out there. This means you can't count on the next datasheet you read to do it one way or the other. When reading documentation, this is a issue you just have to be aware of and be extra careful to see how exactly the address is being presented. So far I haven't come across a datasheet where this couldn't eventually be figured out.

When writing your own documentation, please do the rest of the world a favor and express the "address" as a 7 bit value. If you want to show it with the R/W bit, call it the "address byte" or something to make this clear.

  • \$\begingroup\$ My starting point was that 7-bit value was the only way to go. It's just a pity that the STM32 HAL library which my colleagues are targeting at the moment doesn't agree! \$\endgroup\$
    – Xcodo
    Jan 28, 2015 at 23:38

In my experience, the most common way of expressing an I2C address is to use the 7-bit form in hexadecimal.

To ensure no ambiguity, be consistent:

  • In your I2C code, make sure every I2C function takes the 7-bit address as an argument and not the 8-bit address.

  • In your documentation always refer to the address as the 7-bit address.

Note: I was wondering what you meant by binary being less ambiguous and I realised it was because with binary you can choose to pad with zeros to give a number with either 7 or 8 digits, and thus distinguish between them. Clever! I wonder if people will even notice one less digit though, so probably best to be explicit.

  • 3
    \$\begingroup\$ I come from a strongly typed, flexible array-width VHDL world. My I2C address constants will always be 6 downto 0! I guess you learn to check binary literal widths match otherwise the synthesiser complains at you loudly... \$\endgroup\$
    – Xcodo
    Jan 28, 2015 at 23:35

There isn't a standard, and it is an endless source of grief. Linux i2cset and i2cget use the 7-bit notation, so that's the closest to 'standard' as there is. There exist other tools / platforms that use 8-bit. Datasheets aren't consistent. Chaos!

Anyway, when I make a document notation about I2C, I'll represent it as both a binary and hex (7-bit) value as follows:

periph_i2c addr: {1 1 0 0 1 0 1 r/w} (0x65 hex)

This makes clear which one I mean.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.