element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Single-Board Computers
  • Products
  • Dev Tools
  • Single-Board Computers
  • More
  • Cancel
Single-Board Computers
Forum BBB - I2C notes
  • Blog
  • Forum
  • Documents
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Single-Board Computers to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 33 replies
  • Subscribers 60 subscribers
  • Views 6693 views
  • Users 0 members are here
  • beaglebone_black
  • beagle_black
  • bb_black
  • beagle_bone_black
Related

BBB - I2C notes

shabaz
shabaz over 12 years ago

Note: 15th August 2019: The I2C library described here has been wrapped up into a single general-purpose I/O library which includes I2C and SPI. See here:

BeagleBone Black (BBB) and PocketBeagle I/O (GPIO), SPI and I2C Library for C – 2019 Edition

 

I2C turns out to be fairly easy and straightforward on the BBB.

There are three I2C busses (I2C0, I2C1, I2C2), of which I2C2 is easily usable (Expansion port P9, see table 11 in the SRM).

 

I2C0: used for some on-board components (HDMI, EEPROM, power mgmt). Not brought out to any connector/header

I2C1: entirely free to use, but doesn't seem to be enabled

I2C2: entirely free to use, and works

 

NOTE: In software, the busses are numbered differently; I2C2 is identified as 1. I2C0 is identified as 0.

 

The C code in the zip file attached worked for me on I2C2 bus (it's just a tidied version of various other peoples code, with some wrapper

functions to make life easier).

 

 

// bus=1 for interface I2C2 on BBB

// returns handle to be used in remainder functions

// addr is a 7-bit value (so, for example the BMP085-0330SBO008BMP085-0330SBO008 datasheet specifies

// 0xEE, so we need to right-shift by 1 and use 0x77 for this function)

int i2c_open(unsigned char bus, unsigned char addr);

// These functions return -1 on error, otherwise return the number of bytes read/written:

int i2c_write(int handle, unsigned char* buf, unsigned char length);

int i2c_read(int handle, unsigned char* buf, unsigned char length);

int i2c_write_read(int handle,

                   unsigned char addr_w, unsigned char *buf_w, unsigned int len_w,

                   unsigned char addr_r, unsigned char *buf_r, unsigned int len_r);

int i2c_write_ignore_nack(int handle,

                          unsigned char addr_w, unsigned char* buf, unsigned int length);

int i2c_read_no_ack(int handle,

                    unsigned char addr_r, unsigned char* buf, unsigned int length);

int i2c_write_byte(int handle, unsigned char val);

int i2c_read_byte(int handle, unsigned char* val);

// These functions return -1 on error, otherwise return 0 on success

int i2c_close(int handle);

// Provides an inaccurate delay (may be useful for waiting for ADC etc).

// The maximum delay is 999msec

int delay_ms(unsigned int msec);

 

 

By default the bus appears to run at 100kbps approx.

I created a test program using the nearest I2C device at hand (which happened to be a BMP085 temperature and pressure sensor),

it is part of the zip contents.

 

 

root@beaglebone:~# ./a.out

Temperature is 23.6 degrees C

Pressure is 101.027 kPa

 

 

I noticed it is not possible to control the power mgmt ic using the code, since presumably it is a protected resource.

 

I2C2 on Expansion header P9:

pin 19: SCL

pin 20: SDA

pin 1: 0V

pin 3: 3.3V

 

 

image

 

Message was edited by: Shabaz  - added more recent v3 which adds a couple more functions, and added a precompiled library (put it in /usr/lib and put the header in /usr/include)

Attachments:
i2c_code_v3.zip
precompiledv3.zip
  • Sign in to reply
  • Cancel

Top Replies

  • Former Member
    Former Member over 12 years ago +1
    shabaz wrote: NOTE: In software, the busses are numbered differently; I2C 2 is identified as 1 . I2C0 is identified as 0. That will be due to the order of registration with the kernels i2c subsystem. I…
  • shabaz
    shabaz over 12 years ago in reply to Former Member +1
    That's good to know! So we'll be able to enumerate at the start of code. Hopefully a build will appear with the full 400kHz speed too. I had to update the code a little bit (attached) with a new function…
  • shabaz
    shabaz over 12 years ago +1
    The code is updated to v3 (I've left the older version there for now, I'll delete it in a few days), to add a couple more functions for I2C-like devices that don't actually ack at all (which is technically…
Parents
  • jrychter
    jrychter over 11 years ago

    Hi — for those who find this post and might be looking for a way to send longer I2C that include restarts, I've written a tiny Linux library that allows you to send arbitrary sequences with restarts and reads, using the Bus Pirate convention/notation. See Lsquaredc (L²C) for details.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • jrychter
    jrychter over 11 years ago

    Hi — for those who find this post and might be looking for a way to send longer I2C that include restarts, I've written a tiny Linux library that allows you to send arbitrary sequences with restarts and reads, using the Bus Pirate convention/notation. See Lsquaredc (L²C) for details.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Children
  • shabaz
    shabaz over 11 years ago in reply to jrychter

    Hi Jan,

     

    The code above supports restarts too, I've been using this code for close to a year. Not sure what bus pirate convention is, but the code above (in my opinion) follows closely what the I2C bus is doing, in it's naming of functions and parameters, i.e. how chip manufacturers may specify behavior.

     

    Anyway, choice is good.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jrychter
    jrychter over 11 years ago in reply to shabaz

    I'm sorry, I should have been clearer in my description. Your code is OK and works fine, as long as all you need is a single restart in a transaction.


    The main difference is that lsquaredc has a *single* API call to perform any kind of I2C sequence, including multiple writes, reads and restarts. Sequences are specified like this:


    {0x38, 0x16, I2C_RESTART, 0x39, I2C_READ, I2C_READ, I2C_READ};

     

    you then call i2c_send_sequence() providing a buffer that can store 3 bytes, and you get your data back. The sequence may include many restarts (up to 42).

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to jrychter

    Any kind of I2C sequence?  Ok, I need to have a sequence length of 1, how do I do that with your code ?

     

    This is on real hardware where an I2C transaction needs to be exactly one byte on the wire.

     

    Ten bit addressing? PEC?  You seem to fall quite a way short of your 'any' claim.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • jrychter
    jrychter over 11 years ago in reply to Former Member

    Guys, chill down. I am not here to compete, and my code has a proud price tag of 0. If you like it, use it. If you don't, don't use it. I just thought it would be useful to people.

     

    I have better things to do than pursue arguments of this kind.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to jrychter

    Nobody is arguing.  The choice you made of how to answer what should have been a straightforward question is perhaps more interesting than any real answer.

     

    FWIW, I'm unlikely to ever use either piece of code, neither meet my needs.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • shabaz
    shabaz over 11 years ago in reply to jrychter

    Hi Jan,

     

    Your original post did seem to imply that restarts were missing from the above code - not great when I want people to incrementally improve the code over time. I did not go through the NXP spec and implement all, I took the approach that I would test with the devices I use, and add over time, since this is not a rocket-science thing. As it is, I've used it with "I2C-like' devices too, like cameras.

     

    I really don't understand what you're saying, the code above is free too - and has no restrictions to do with acknowledgement either, unlike your code (not saying it is a bad thing though) - so to be fair it is "more free".

     

    I hope people do use your code (Especially if they are familiar with this bus pirate convention which I really didn't think was a convention - I2C has been around before Bus Pirate was even conceived). Just you could have expressed it in a better way.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 11 years ago in reply to shabaz

    Hi,

    I have written the c code for I2C for interfacing the SHT11(temp sensor) and PIC24F16KA102. but i m not getting the acknowledge from the SHT11 when i m writing through pic.  i m pasting my code here. plz let me know where i m doing wrong if possible. thanks

     

    #include <stdint.h>

    #include <xc.h>

    #include "main.h"

     

    #include <p24Fxxxx.h>

    // ICD Pin Placement Select (EMUC/EMUD share PGC3/PGD3)

    //_FICD(ICS_PGx1)

    /*

    * File:   main.c

    * Author: jalpa

    *

    * Created on 7 February, 2014, 10:11 AM

    */

    /*******************************************************************************************************************/

    //Include section

     

    /*******************************************************************************************************************/

    #include "p24F16KA102.h"

     

    #include "spi.h"

    #include "i2c.h"

    #include <timer.h>

     

     

     

    /*******************************************************************************************************************/

    //Define section

    /*******************************************************************************************************************/

    // for input use  PORTBbits.RB7  notation and for output pin use LATBbits.LATB2.

    //#define CE LATBbits.LATB2    //pin-6  // CE output pin, PORTB bit 2

     

     

    //#define SDA_pin LATBbits.LATB9    //pin-22// Clock output pin, PORTB bit 11

    //#define SCL_pin LATBbits.LATB8

    //

    //#define SDA_dir TRISBbits.TRISB9

    //#define SCL_dir TRISBbits.TRISB8

     

    /*******************************************************************************************************************/

     

    //Declaration of variable

    /*******************************************************************************************************************/

    unsigned char msb;

    unsigned char lsb;

    unsigned char status;

     

    /*******************************************************************************************************************/

    //Declaration of functions

     

    /*******************************************************************************************************************/

    void i2c_init();

    void reset_i2c_bus();

    void delay_us(unsigned short us);

    void i2c_start();

    void i2c_restart();

    char i2c_send_byte(int data);

    char i2c_read_byte();

     

     

    //#define SCK_dir TRISBbits.TRISB8

     

     

     

    /*******************************************************************************************************************/

    //Main function

    /*******************************************************************************************************************/

     

    void main(void)

    {

     

     

     

       // AD1PCFGbits.PCFG0=1;

       // AD1PCFGbits.PCFG1=1;

     

       AD1PCFG =0XFF;

       //SCK_dir=0;

      

       i2c_init();

       i2c_start();

       delay_us(2000);

       status = i2c_send_byte(0x03);

       delay_us(10000);

       msb= i2c_read_byte();

       lsb= i2c_read_byte();

       reset_i2c_bus();

     

     

     

       

     

    }

     

     

     

     

     

    void i2c_init()

    {

        int temp;

        I2C1BRG = 157;

        I2C1CONbits.I2CEN = 0;

        I2C1CONbits.DISSLW = 1;

        I2C1CONbits.I2CEN= 1;

        temp = I2C1RCV;

        reset_i2c_bus();

     

    }

     

    void reset_i2c_bus()  // reset is used before and after a packet i sent through the bus (release both sda and scl)

    {

     

        int x=0;

     

        I2C1CONbits.PEN= 1;

     

        while(I2C1CONbits.PEN)

        {

     

            delay_us(1);

            x++;

            if(x>20) break;

     

        }

     

        I2C1CONbits.RCEN=0;

        IFS1bits.MI2C1IF=0;

        I2C1STATbits.IWCOL=0;

        I2C1STATbits.BCL=0;

     

        delay_us(10);

       

    }

     

    void i2c_start(void)

    {

       int x = 0;

       I2C1CONbits.ACKDT = 0;    //Reset any previous Ack

       delay_us(10);

       I2C1CONbits.SEN = 1;    //Initiate Start condition

       Nop();

     

       //the hardware will automatically clear Start Bit

       //wait for automatic clear before proceding

       while (I2C1CONbits.SEN)

       {

          delay_us(1);

          x++;

          if (x > 20)

          break;

       }

        delay_us(2);

    }

     

     

    void i2c_restart(void)

    {

       int x = 0;

     

       I2C1CONbits.RSEN = 1;    //Initiate restart condition

       Nop();

     

       //the hardware will automatically clear restart bit

       //wait for automatic clear before proceding

       while (I2C1CONbits.RSEN)

       {

          delay_us(1);

          x++;

          if (x > 20)    break;

       }

     

       delay_us(2);

    }

     

     

    char i2c_send_byte(int data)

    {

       int i;

     

       while (I2C1STATbits.TBF) { }

       IFS1bits.MI2C1IF = 0; // Clear Interrupt

       I2C1TRN = data; // load the outgoing data byte

     

       // wait for transmission

       for (i=0; i<500; i++)

       {

          if (!I2C1STATbits.TRSTAT) break;

          delay_us(1);

     

          }

          if (i == 500) {

          return(1);

       }

     

       // Check for NO_ACK from slave, abort if not found

       if (I2C1STATbits.ACKSTAT == 1)

       {

          reset_i2c_bus();   //error

          return(1);

       }

     

       delay_us(2);

       return(0);

    }

     

    char i2c_read_byte(void)    //does not reset bus!!!

    {

       int i = 0;

       char data = 0;

     

       //set I2C module to receive

       I2C1CONbits.RCEN = 1;

     

       //if no response, break

       while (!I2C1STATbits.RBF)

       {

          i++;

          if (i > 2000) break;

       }

     

       //get data from I2CRCV register

       data = I2C1RCV;

     

       //set ACK to high

       I2C1CONbits.ACKEN = 1;

     

       //wait before exiting

       delay_us(10);

     

       //return data

       return data;

    }

     

     

     

    void delay_us(unsigned short us)

    {

      unsigned short i;

     

      // TIMER1 Period = PR1 x 2 x Tosc x Prescale second

      // TIMER1 Period = 145 x 2 x 1/32000000 x 1 = 9 us // practically coming 12us

     

      PR1=145;                      // Maximum Counter

      T1CON=0x0000;            // TIMER1 Off, Prescale 1:1 using the internal clock

      for (i=0; i < us;i++) {

        TMR1=0;                     // Reset TIMER1 Counter

        IFS0bits.T1IF=0;            // Clear TIMER1 Interrupt Flag

        T1CONbits.TON=1;            // Turn On TIMER1

        while(IFS0bits.T1IF != 1);  // Wait until TMR1 > PR1 (Overflow)

        T1CONbits.TON=0;            // Turn Off TIMER1

      }

     

    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • shabaz
    shabaz over 11 years ago in reply to Former Member

    Hi Jalpa,

     

    This post is about the BeagleBone Black (BBB) and is unrelated to your question, and will confuse. For better visibility (I know nothing about the PIC and sensor you mention), please can you open a separate discussion?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube