Home / Tutorials / BeagleBone Tutorial / Beaglebone Black I2C Tutorial
beaglebone black i2c

Beaglebone Black I2C Tutorial

I2C is a popular communications protocol and is used by a lot of sensors and devices. This is why most microcontrollers, including Arduino, PICs and STM32 have I2C support. In this tutorial, we will look at how to use the I2C protocol on the BBB and create a simple Beaglebone Black I2C application.

Beaglebone Black I2C Bus

There are three I2C buses on the Beaglebone Black according to the AM335X Technical Reference Manual and their memory addresses are:

  • i2c-0: 0x44E0_B000
  • i2c-1: 0x4802_A000
  • i2c-2: 0x4819_C000

The i2c-0 bus is not accessible on the header pins while the i2c-1 bus is utilized for reading EEPROMS on cape add-on boards and may interfere with that function when used for other digital I/O operations.

beaglebone black i2c pinouts

The i2c-2 bus is the one that is free for use so we'll be using that in this tutorial.

Linux I2C Tools

Thankfully, Linux has built-in i2c tools that make our life easier (unlike with BBB PWM). To check which of the three buses are enabled we can use i2cdetect:

Mine's showing two i2c devices. But again we can't use i2c-0 so we'll go with i2c-2.

 

 

To detect the devices connected to i2c-2:

Those addresses with UU are reserved address. Noticed there is a 68. That's because I connected a device with an I2C address of 68 to my Beaglebone Black.

Writing and Reading from the I2C Bus

Now, to write to the I2C bus, we can use:

The first hex number is the I2C device address followed by the specific data address and the byte to be written. You can read more about the i2cset at https://linux.die.net/man/8/i2cset.

To read the registers from the device connected to the I2C bus, the i2cdump command can be used:

Read more about i2cdump here: https://linux.die.net/man/8/i2cdump

Finally, we can acquire the data from a specific register on the I2C device using i2cget:

Here's more information for i2cget: https://linux.die.net/man/8/i2cget.

On the next part of this tutorial, we'll be reading data from the MPU6050 gyroscope + accelerometer and display it on the Beaglebone Black terminal. Follow this blog for updates!

Check Also

beaglebone black adc

Controlling a Servo Motor with BoneScript

Using the Beaglebone Black's PWM Bonescript also includes an analogWrite function which utilizes the 8 …

24 comments

  1. Hi,

    I am facing one problem while doing i2cset and i2cget.But in different board.
    I am using AMD MF bettong DDR4 board.
    kernel version is : 4.4.11-158-amd+

    I am doing i2cset works fine.
    But i2cget reads 0xff all the time.

    commands used is:
    sudo i2cset -y 6 0x50 0x6c 00
    sudo i2cget -y 6 0x50 0x6c

    i2cdump also reads 0xff all the time irrespective of the value written!!!

    [email protected]:~$ sudo i2cdump 6 0x50
    No size specified (using byte-data access)
    WARNING! This program can confuse your I2C bus, cause data loss and worse!
    I will probe file /dev/i2c-6, address 0x50, mode byte
    Continue? [Y/n] y
    0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
    00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
    [email protected]:~$

    Please let me know why i am not able to write to EEPROM?

    I am using one i2c test application to receive i2c 1 or 2 bytes.After running which only i2c slave will be attached to i2c bus!

    And also running the application changes the register values,which is read using printk() in the driver.

    That time also i2cdump or i2cget reads 0xff !!!!

    Why is this happening?? can anyone please let me know?

    Thanks & Regards,
    Kripashree

    • Hello

      You're device and board is quite different to what I'm presenting here but normally, a 0xFF reading indicate a timing mismatch between the master and the slave device. Maybe there is something wrong with the wiring because one reason for mismatches are voltage spikes or not reaching voltage thresholds for both low and high pulses.

  2. hello, im trying to scan the registry of for i2c address ("KSZ9897R" 7-Port Gigabit Ethernet Switch with Two RGMII/MII/RMII Interfaces) , on the schematic it's writing that the address is :0xBE which i didnt find it, and there is another address for the poe+ which is: 0x20 i already found it.

    i use this commande i2cdetect -r 2 and its ok, but the issue that the range of this commande is " 0x03-0x77."

    and the address that im looking for is 0xBE, which is obviously outside of this range, what i can do to have a bigger range to scan so i can catch the address im looking for.

    thx you

  3. [email protected]:~$ i2cdetect -r 2
    WARNING! This program can confuse your I2C bus, cause data loss and worse!
    I will probe file /dev/i2c-2 using read byte commands.
    I will probe address range 0x03-0x77.
    Continue? [Y/n] y
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: 50 -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --

  4. hello. how i can enlarge the rang in the beagle bone to scan the registry from 0x03-0x77, to more than that till i reach the address 0xBE, because the address i'm searching for is 0xBE it's for an Ethernet switch "KSZ9897R"

    • Hello Mahmoud,

      You can specify the first and last address of i2cget using this command:

      i2cdetect -r 2 0x00 0xBE

      This scans from 0x00 to 0xBE.

      • hello,, thx for your reply, i tried this command but it seems that the beaglebone doesnt support this range, it says out of rang, this is the result of the commande

        Last login: Mon Feb 5 15:33:33 UTC 2018 on ttyGS0
        Linux beaglebone 4.4.9-ti-r25 #1 SMP Thu May 5 23:08:13 UTC 2016 armv7l

        The programs included with the Debian GNU/Linux system are free software;
        the exact distribution terms for each program are described in the
        individual files in /usr/share/doc/*/copyright.

        Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
        permitted by applicable law.
        [email protected]:~$ i2cdetect -r 2 0x00 0xBE
        Error: FIRST argument out of range (0x03-0x77)!
        Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
        i2cdetect -F I2CBUS
        i2cdetect -l
        I2CBUS is an integer or an I2C bus name
        If provided, FIRST and LAST limit the probing range.
        [email protected]:~$

        • Ah yes, it is expected. Sorry I thought you are using a device other than BBB. 0x77 is the maximum address because addresses beyond that are used for 10-bit I2C mode. Also, I don't think the address of your device is 0xBE. You must convert it to 7-bit by dropping the 7th bit and OR'ing the 0th bit to the write/flag bit (which is done automatically by the kernel, btw). So 0xBE should be 0x5F which is within range.

          0xBE = 101111100

          remove 0th bit and shift bits to the right

          01011111 = 0x5F

          you can now read the data from your device using:

          i2cdetect -r 2 0x03 0x5F

          I hope this answers your problem

  5. What a great tutorial.
    Did you have to pull up the I2C connection to be able to detect the device?

    • I used MPU6050 for this example so there was no need for a pull-up resistor

      • Thanks for that Roland, It seems as though my device isn't being picked up with i2cdetect and I was suspecting that it would require a pull up resistor but unsure at this stage. What would you do to test that?

        • Hi Yasir

          May I know what device you are using?

          • Hi Roland,

            I seem to have got the address successfully.

            I am driving an LED array using an ISSI IS31FL3741 LED driver which is apart of their Evaluation Board. I am trying to hook up the BeagleBone to be able to send i2c commands to the uC onboard the evaluation board and toggle the LED's.

          • Hi Roland,

            It still seems confusing as to how one can write a program to write to an I2C slave device and control. Command line is great but writing a script that could be run and looped is something that I am still looking into. Any advice?

          • Hi Yasir,

            You can always use shell scripts to run bash commands like i2cget, i2cset, etc. I assume you are not familiar with this so let me share a bit.

            A typical script contains these:

            #!/bin/bash

            command1
            sudo command2
            command3
            sudo command4

            this is normally a .sh file that you can make executable using

            chmod +x script.sh

            to run it:

            ./script.sh

            you can also use conditional statements, loops, etc in shell scripts. I would recommend this site: https://www.shellscript.sh/

          • Thanks for that Roland, I was not aware of that possibility and will start experimenting with it immediately.
            How would you set the clock frequency with those commands? Since the slave would only operate at either 400kHz or 1Mhz. I assume real-time communication is not possible with this method on the BBB?

          • For changing speeds, you have to update the I2C device tree overlay of the BBB. I have written articles about device tree overlays here.

            For real-time communication, you can use the BBB's PRU (programmable real-time unit) which is like a separate microcontroller. Using it isn't easy though and I haven't tried using it with I2C. Maybe I'll write about that in the future.

          • PRU's are definitly what caught my attention when selecting the beaglebone for their realtime capabilities and potential of using processor heavy tasks with linux to control the PRUSS is really promising. I hope it gets clearer as to how one could tap into the PRUSS as it does not seem to be similar to programming an AVR microcontroller at all.

  6. hello, thank you for answering me, im using beagle bean green, does that make any difference?

    i tried what you've told me to do, but it didnt work too.

    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    [email protected]:~$ i2cdetect -r 2 0x03 0x5F
    WARNING! This program can confuse your I2C bus, cause data loss and worse!
    I will probe file /dev/i2c-2 using read byte commands.
    I will probe address range 0x03-0x5f.
    Continue? [Y/n]
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- 0c -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: 50 -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
    60:
    70:
    [email protected]:~$ i2cdetect -r 2 0x03 0x5F
    WARNING! This program can confuse your I2C bus, cause data loss and worse!
    I will probe file /dev/i2c-2 using read byte commands.
    I will probe address range 0x03-0x5f.
    Continue? [Y/n]
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: 50 -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
    60:
    70:

    about the address of the ship as u said i found this in the datasheet of the device:

    The management interface may be configured to be an I2C slave. In this mode, an I2C master has complete programming
    access to the device's internal control and status registers, including all MIB counters, address lookup tables,
    VLAN table and ACL table.
    The 7-bit device address is fixed as 1011_111. Because of the fixed address, only one KSZ9897R may be on the I2C
    bus at a time. The R/W control bit is then appended as the least significant bit to form these 8-bit address/control words:
    1011_1110
    1011_1111

    • Hello Mahmoud,'

      Yes, it confirms that 0x5F is indeed the I2c address of that device and not 0xBE. I2C specifications states that there is only 7-bit or 10-bit addresses.

      There is a reason why the I2C address range is 0x03 to 0x77. For 7-bit addressing, you have 128 possible numbers, (0-127 or 0x00 to 0x7F). Out of those 128, there are 8 reserved addresses:
      000 0000 0 General call address
      000 0000 1 START byte
      000 0001 X CBUS address
      000 0010 X Reserved for different bus format
      000 0011 X Reserved for future purposes
      000 01XX X Hs-mode master code
      111 10XX X 10-bit slave addressing
      111 11XX X Reserved for future purposes

      Thus, the valid i2c address for devices is from 0x03 (CBUS 0x11 is allowed) to 0x77 (0x78 to 0x7F are used for 10-bit addressing or "Reserved for future purposes" above).

      So I think the i2cdetect command I just gave might be correct but there are other problems involved. Did you follow this diagram for wiring the device with your Beaglebone Green? https://i.imgur.com/KOCwYaG.jpg

  7. hello Roland,

    i have an evaluation board for this ship ( EVB-KSZ9897) i run the i2cdetect command and it gives me the address 0x5f.

    on my board i have some different values for the resistors like 1k ohms for both scla and sda, and for the led3_1 i tested on the oscilloscope it give logic output 1 but i put already 10k to the vddio, and the led4-1 the resistor was 220 ohms i changed to 1k, than i ran the order again but nothing happen always the same result as before.

  8. hello Rolland,

    thx for you help, i found the problem last week, it was a crystal issue, but now i have another issue that the internet is intermittent when i want to use it as PoE, but when i use the data only it's good, im investigating about that, thx for your help 🙂

  9. can anyone post c++ code for i2c. i am working with battery fuel gauge. my c++ does not work on it.

Leave a Reply

Your email address will not be published. Required fields are marked *