User Tools

Site Tools


chumbyhackerboard:i2c

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
chumbyhackerboard:i2c [2010/08/28 22:14]
ladyada
chumbyhackerboard:i2c [2016/01/28 18:05] (current)
Line 1: Line 1:
-====== ​i2c twiddler ​======+====== ​Moved! ​======
  
-First, you'll need to have a toolchain installed so make sure you go back and install it! +This tutorial has moved to [[http://learn.adafruit.com/chumby-hacker-board/i2c-sensor|http://learn.adafruit.com/chumby-hacker-board/i2c-sensor]]
- +
-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** +
- +
-{{:​chumbyhackerboard:​i2ccopy.gif|}} +
- +
-Then compile the code with **gcc** by typing in **gcc -o i2c i2c.c** to create the **i2c** executable. Then run it and make sure you get the response below +
- +
-{{:​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 58 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! +
- +
- +
-====== Basic i2c twiddler Code ====== +
- +
-<​file>​ +
-/* +
- This software uses a BSD license. +
- +
-Copyright (c) 2010, Sean Cross / chumby industries +
-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>​ +
- +
- +
-#define I2C_FILE_NAME "/​dev/​i2c-0"​ +
-#define USAGE_MESSAGE \ +
-    "​Usage:​\n"​ \ +
-    " ​ %s r [addr] [register] ​  "​ \ +
-        "to read value from [register]\n"​ \ +
-    " ​ %s w [addr] [register] [value] ​  "​ \ +
-        "to write a value [value] to register [register]\n"​ \ +
-    ""​ +
- +
-static int set_i2c_register(int file, +
-                            unsigned char addr, +
-                            unsigned char reg, +
-                            unsigned char value) { +
- +
-    unsigned char outbuf[2];​ +
-    struct i2c_rdwr_ioctl_data packets; +
-    struct i2c_msg messages[1];​ +
- +
-    messages[0].addr ​ = addr; +
-    messages[0].flags = 0; +
-    messages[0].len ​  = sizeof(outbuf);​ +
-    messages[0].buf ​  = outbuf; +
- +
-    /* The first byte indicates which register we'll write */ +
-    outbuf[0] = reg; +
- +
-    /*  +
-     * The second byte indicates the value to write. ​ Note that for many +
-     * devices, we can write multiple, sequential registers at once by +
-     * simply making outbuf bigger. +
-     */ +
-    outbuf[1] = value; +
- +
-    /* Transfer the i2c packets to the kernel and verify it worked */ +
-    packets.msgs ​ = messages; +
-    packets.nmsgs = 1; +
-    if(ioctl(file,​ I2C_RDWR, &​packets) < 0) { +
-        perror("​Unable to send data"​);​ +
-        return 1; +
-    } +
- +
-    return 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; +
- +
-    // 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); +
-    } +
- +
- +
-    if(argc > 3 && !strcmp(argv[1],​ "​r"​)) { +
-        int addr = strtol(argv[2],​ NULL, 0); +
-        int reg = strtol(argv[3],​ NULL, 0); +
-        unsigned char value; +
-        if(get_i2c_register(i2c_file,​ addr, reg, &​value)) { +
-            printf("​Unable to get register!\n"​);​ +
-        } +
-        else { +
-            printf("​Register %d: %d (%x)\n",​ reg, (int)value, (int)value);​ +
-        } +
-    } +
-    else if(argc > 4 && !strcmp(argv[1],​ "​w"​)) { +
-        int addr = strtol(argv[2],​ NULL, 0); +
-        int reg = strtol(argv[3],​ NULL, 0); +
-        int value = strtol(argv[4],​ NULL, 0); +
-        if(set_i2c_register(i2c_file,​ addr, reg, value)) { +
-            printf("​Unable to get register!\n"​);​ +
-        } +
-        else { +
-            printf("​Set register %x: %d (%x)\n",​ reg, value, value); +
-        } +
-    } +
-    else { +
-        fprintf(stderr,​ USAGE_MESSAGE,​ argv[0], argv[0]); +
-    } +
- +
- +
-    close(i2c_file);​ +
- +
- +
-    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; +
-+
-</​file>​+
/home/ladyada/public_html/wiki/data/attic/chumbyhackerboard/i2c.1283033680.txt.gz · Last modified: 2016/01/28 18:05 (external edit)