This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
chumbyhackerboard:i2c [2010/08/28 21:54] ladyada |
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 twiddler ====== | ||
Line 22: | Line 20: | ||
{{:chumbyhackerboard:mma7455addr.gif|}} | {{: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** | + | **$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|}} | {{:chumbyhackerboard:i2cfail.gif|}} | ||
Line 42: | Line 40: | ||
====== Acceleromate! ====== | ====== 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 | ||
- | ====== Code ====== | + | 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> | <file> | ||
Line 215: | 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> |