User Tools

Site Tools


chumbyhackerboard:i2c

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Next revision Both sides next revision
chumbyhackerboard:i2c [2010/08/28 21:37]
ladyada created
chumbyhackerboard:i2c [2010/09/02 20:29]
binkl Change address 58 to 29 so that the wiki text matches the i2cfail.gif
Line 1: Line 1:
-**THIS TUTORIAL IS STILL IN PROGRESS** +====== i2c twiddler ​======
- +
-====== i2c ======+
  
 First, you'll need to have a toolchain installed so make sure you go back and install it! First, you'll need to have a toolchain installed so make sure you go back and install it!
  
-Next, scroll ​down and copy the i2c C code board. Open up your terminal to the CHB and type in **mkdir /​mnt/​storage/​devcd /​mnt/​storage/​devcat > i2c.c** into the terminal and hit return.+Sean Cross wrote a great i2c twiddler-tool. This allows you to poke and peek at i2c chips right from the command line. Nice! 
 + 
 +Scroll ​down and copy his i2c C code. Open up your terminal to the CHB and type in **mkdir /​mnt/​storage/​dev** (or whatever place you want to store your code), then **cd /​mnt/​storage/​dev** and finally **cat > i2c.c** into the terminal and hit return.
 Then paste in the code and finish by typing **Control-D** Then paste in the code and finish by typing **Control-D**
  
Line 13: Line 13:
  
 {{:​chumbyhackerboard:​i2ccompile.gif|}} {{:​chumbyhackerboard:​i2ccompile.gif|}}
 +
 +====== Reading the MMA7455L accelerometer ======
 +
 +There'​s a Freescale +-2G to +-8G 3-access accelerometer on the CHB for you to play with, lets get some readings. First off, we need to know what the i2c address is. [[http://​www.freescale.com/​files/​sensors/​doc/​data_sheet/​MMA7455L.pdf|Open up the datasheet]] and look for the section called "i2c Slave Address"​
 +
 +{{:​chumbyhackerboard:​mma7455addr.gif|}}
 +
 +**$1D** means hexadecimal 0x1D which is the same as decimal 29. Great! Lets read byte #0 from the accelerometer by typing in **./i2c r 29 0**
 +
 +{{:​chumbyhackerboard:​i2cfail.gif|}}
 +
 +?? We got an error that the register was not readable. This means the chip could not be found on the i2c bus. :( But then we rememer that i2c addresses are 7 bits long and are transmitted in the upper bits of an 8-bit byte. So we actually need to shift the address up by 1 bit. That's easy to do, though, just multiply by 2 to get i2c address **58**
 +
 +{{:​chumbyhackerboard:​i2cok.gif|}}
 +
 +Rock! Now we need to figure out what registers we can read, looking at the datasheet we see:
 +
 +{{:​chumbyhackerboard:​mma7455reg.gif|}}
 +
 +There'​s a lot of stuff! Lets start with one we know is going to work, like **$0D** (hex 0x0D = dec 13)
 +
 +{{:​chumbyhackerboard:​mmareg13.gif|}}
 +
 +It in fact returns the value 0x1D which we know is the i2c address
 +
 +====== Acceleromate! ======
 +
 +OK so now we want to get that XYZ data, right? Looking at the register file it seems like the first 6 bytes are used for 10-bit readings, but we can get single 8 bit readings from registers number 6, 7 and 8
 +
 +If you're careful you can read those registers while having a friend gently shake the board, you'll see different values returned
 +
 +{{:​chumbyhackerboard:​mmai2ctest.gif|}}
 +
 +However, wouldn'​t it be great if you didn't need a friend to shake the board while you pressed Up-arrow & Return? Lets edit Sean's code. To begin we will put **#​define**'​s in for the address and registers
 +
 +<​code>​
 +// The '​raw'​ 7 bit address shifted up 
 +#define MMA7455_I2CADDR (0x1D * 2)
 +
 +// The registers to read!
 +#define MMA7455_XOUT8 6
 +#define MMA7455_YOUT8 7
 +#define MMA7455_ZOUT8 8
 +</​code>​
 +
 +Then replace the **main()** function with our own which is shorter and only reads those registers to print out the values
 +
 +<​code>​
 +int main(int argc, char **argv) {
 +    int i2c_file;
 +    int8_t x, y, z;  // the readings are 8 bits and signed!
 +
 +    // Open a connection to the I2C userspace control file.
 +    if ((i2c_file = open(I2C_FILE_NAME,​ O_RDWR)) < 0) {
 +        perror("​Unable to open i2c control file"​);​
 +        exit(1);
 +    }
 +
 +    // ignore arguments!
 +
 +    while (1) {
 +      ​
 +      // read X and Y and Z from the register
 +      if( get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_XOUT8,​ &x) ||
 +   get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_YOUT8,​ &y) ||
 +   get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_ZOUT8,​ &z) ) {
 +
 + printf("​Unable to read register!\n"​);​
 + return -1;
 +      }
 +
 +      printf("​X = %d\tY = %d\tZ = %d\n", x, y, z); 
 +    }
 +
 +    close(i2c_file);​
 +    return 0;
 +}
 +</​code>​
 +
 +Note the while() loop, and that we read all three registers and stick the results into 8-bit signed variables. Then we printf() 'em all and loop again.
 +
 +You can grab all of the code below
 +
 +Stick the code in a new file called **mma7455.c** by copying and pasting as before. Then compile by running **gcc -o mma7455 mma7455.c** and run with **./​mma7455**. ​ Now shake it!
 +
 +{{:​chumbyhackerboard:​shaken.gif|}}
 +
 +There you go! Now you can talk to the accelerometer to get motion data, and this code is easily adaptable for any i2c chip you may want to use. Enjoy!
  
  
-====== Code ======+====== ​Basic i2c twiddler ​Code ======
  
 <​file>​ <​file>​
Line 187: Line 275:
  
  
 +    return 0;
 +}
 +</​file>​
 +
 +====== MMA7455L reader ======
 +<​file>​
 +/*
 + This software uses a BSD license.
 +
 +Copyright (c) 2010, Sean Cross / chumby industries &  Limor Fried / adafruit industries (we are both industrious people, eh?)
 +
 +All rights reserved.
 + 
 + ​Redistribution and use in source and binary forms, with or without
 + ​modification,​ are permitted provided that the following conditions
 + are met:
 +
 + * Redistributions of source code must retain the above copyright
 +   ​notice,​ this list of conditions and the following disclaimer.
 + * Redistributions in binary form must reproduce the above copyright
 +   ​notice,​ this list of conditions and the following disclaimer in the
 +   ​documentation and/or other materials provided with the
 +   ​distribution.  ​
 + * Neither the name of Sean Cross / chumby industries nor the names
 +   of its contributors may be used to endorse or promote products
 +   ​derived from this software without specific prior written
 +   ​permission.
 +
 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + "​AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + ​LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + ​HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 + ​INCIDENTAL,​ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + ​LIABILITY,​ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 + ​POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include <​stdio.h>​
 +#include <​linux/​i2c.h>​
 +#include <​linux/​i2c-dev.h>​
 +#include <​fcntl.h>​
 +#include <​stdlib.h>​
 +#include <​unistd.h>​
 +#include <​sys/​ioctl.h>​
 +#include <​string.h>​
 +
 +// The '​raw'​ 7 bit address shifted up 
 +#define MMA7455_I2CADDR (0x1D * 2)
 +
 +// The registers to read!
 +#define MMA7455_XOUT8 6
 +#define MMA7455_YOUT8 7
 +#define MMA7455_ZOUT8 8
 +
 +
 +#define I2C_FILE_NAME "/​dev/​i2c-0"​
 +
 +static int get_i2c_register(int file,
 +                            unsigned char addr,
 +                            unsigned char reg,
 +                            unsigned char *val) {
 +    unsigned char inbuf, outbuf;
 +    struct i2c_rdwr_ioctl_data packets;
 +    struct i2c_msg messages[2];​
 +
 +    /*
 +     * In order to read a register, we first do a "dummy write" by writing
 +     * 0 bytes to the register we want to read from.  This is similar to
 +     * the packet in set_i2c_register,​ except it's 1 byte rather than 2.
 +     */
 +    outbuf = reg;
 +    messages[0].addr ​ = addr;
 +    messages[0].flags = 0;
 +    messages[0].len ​  = sizeof(outbuf);​
 +    messages[0].buf ​  = &​outbuf;​
 +
 +    /* The data will get returned in this structure */
 +    messages[1].addr ​ = addr;
 +    messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;​
 +    messages[1].len ​  = sizeof(inbuf);​
 +    messages[1].buf ​  = &inbuf;
 +
 +    /* Send the request to the kernel and get the result back */
 +    packets.msgs ​     = messages;
 +    packets.nmsgs ​    = 2;
 +    if(ioctl(file,​ I2C_RDWR, &​packets) < 0) {
 +        perror("​Unable to send data"​);​
 +        return 1;
 +    }
 +    *val = inbuf;
 +
 +    return 0;
 +}
 +
 +
 +int main(int argc, char **argv) {
 +    int i2c_file;
 +    int8_t x, y, z;  // the readings are 8 bits and signed!
 +
 +    // Open a connection to the I2C userspace control file.
 +    if ((i2c_file = open(I2C_FILE_NAME,​ O_RDWR)) < 0) {
 +        perror("​Unable to open i2c control file"​);​
 +        exit(1);
 +    }
 +
 +    // ignore arguments!
 +
 +    while (1) {
 +      ​
 +      // read X and Y and Z from the register
 +      if( get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_XOUT8,​ &x) ||
 +   get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_YOUT8,​ &y) ||
 +   get_i2c_register(i2c_file,​ MMA7455_I2CADDR,​ MMA7455_ZOUT8,​ &z) ) {
 +
 + printf("​Unable to read register!\n"​);​
 + return -1;
 +      }
 +
 +      printf("​X = %d\tY = %d\tZ = %d\n", x, y, z); 
 +    }
 +
 +    close(i2c_file);​
     return 0;     return 0;
 } }
 </​file>​ </​file>​
/home/ladyada/public_html/wiki/data/pages/chumbyhackerboard/i2c.txt · Last modified: 2016/01/28 18:05 (external edit)