2016-09-09 14 views
2

は、私が最近gy-521 boardを買って、私はi2cdetect -y 1を使用して、次の接続アクセスデバイスのレジスタI2C

RPi3  |  GY-521 
--------------------- 
3.3V <-------> Vcc 
GND <-------> GND 
SCL <-------> SCL 
SDA <-------> SDA 

を通じてラズベリーパイ3でそれを使用しようとしている私は、そう、次の

 0 1 2 3 4 5 6 7 8 9 a b c d e f 
00:   -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 

を取得しますデバイスのアドレスは0x68です。 datasheetを読むと、たとえば、X軸の加速度はレジスタ3B(上位ビット)と3C(下位ビット)に格納されています。私の質問はどのようにこれらのレジスタにアクセスできますか?

私は、ファイル記述子として/dev/i2c-1を開いた場合、通常のreadwriteの機能を使用できます。その後、常にデータを取得するのではなく、新しい利用可能なデータの場合はpollを使用することができます。

私はdocumentationで提案されているようread機能を使用しようとしましたが、それは働いていない(私はゼロのみを取得)と私はpollを使用するときに、他の側に誰とタイムアウト(100msのは)ありませんようにそれが期限切れになったようです。私はチップに「3Bレジスタの価値を教えてください」と言わなければならないと思いますが、それをどうやって行うのか分かりません。

CODE

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <stdint.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <linux/i2c-dev.h> 
#include <sys/ioctl.h> 
#include <stdarg.h> 
#include <poll.h> 
#include <errno.h> 

const char *filename = "/dev/i2c-1"; 
int DEBUG = 0; 
int ADDRESS = 0x68; 
struct pollfd pfd; 

void debug(const char* format, ...) 
{ 
    if (DEBUG) 
    { 
     va_list argptr; 
     va_start(argptr, format); 
     fprintf(stdout, "### "); 
     vfprintf(stdout, format, argptr); 
     va_end(argptr); 
    } 
} 

void error_handler(const char *msg) 
{ 
    perror(msg); 
    exit(EXIT_FAILURE); 
} 

void set_debug(const char *deb_lev) 
{ 
    unsigned long num; 
    char *p; 
    errno = 0; 

    num = strtoul(deb_lev, &p, 10); 

    if (errno != 0 || *p != '\0') 
     error_handler("set_debug | strtoul"); 

    DEBUG = (num > 0); 
} 

int open_file(const char *filename) 
{ 
    int fd; 

    if ((fd = open(filename, O_RDWR)) == -1) 
     error_handler("open_file | open"); 

    debug("\"%s\" opened at %d\n", filename, fd); 
    return fd; 
} 

int8_t read_value(int fd) 
{ 
    debug("Reading from %d\n", fd); 

    int8_t num; 
    char *p = (char *)&num; 
    ssize_t size = sizeof(int8_t); 
    ssize_t r = 0; 

    while (size > 0) 
    { 
     if ((r = read(fd, p, size)) == -1) 
      error_handler("read_value | read"); 

     size -= r; 
     p += r; 
    } 

    return num; 
} 

void command(uint16_t reg, int fd) 
{ 
    debug("Writing to %d\n", fd); 

    unsigned char reg_buf[2]; 
    ssize_t w = 0; 
    ssize_t size = sizeof(unsigned char)*2; 

    reg_buf[0] = (reg >> 0) & 0xFF; 
    reg_buf[1] = (reg >> 8) & 0xFF; 

    if ((w = write(fd, reg_buf, size)) == -1) 
     error_handler("command | write"); 
} 

void read_data_from_imu(struct pollfd *pfd) 
{ 
    int8_t val; 
    int p; 

    for (;;) 
    { 
     command(0x3b, pfd->fd); 

     switch (p = poll(pfd, 1, 100)) 
     { 
      case -1: 
       error_handler("read_data_from_imu | poll"); 
      case 0: 
       fprintf(stderr, "Timeout expired\n"); 
       break; 
      default: 
       val = read_value(pfd->fd); 
       printf("Read: %u\n", val); 
       break; 
     } 
    } 
} 

int main(int argc, const char **argv) 
{ 
    if (argc < 2) 
    { 
     fprintf(stderr, "Usage: %s debug_flag\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    set_debug(argv[1]); 

    pfd.fd = open_file(filename); 

    debug("Setting slave address\n"); 
    if (ioctl(pfd.fd, I2C_SLAVE, ADDRESS) == -1) 
     error_handler("main | ioctl"); 

    read_data_from_imu(&pfd); 

    return EXIT_SUCCESS; 
} 

EDIT writeを追加Kennyhyun

おかげで問題を解決しました。

あなたはさらに、この

... 
#define ACCEL_XOUT_H 0x3b 
#define ACCEL_XOUT_L 0x3c 
... 
write_register(ACCEL_XOUT_H, pfd->fd); 
x_data = read_value(pfd->fd); 
write_register(ACCEL_XOUT_L, pfd->fd); 
x_data = (x_data << 8) + read_value(pfd->fd); 
... 

EDIT 2

ような何かを持っているx軸 上加速度計の測定値を読みたいのであれば、あなたはコードを簡素化することができます書き込み後2バイト分直接読み込みます。このようなことが起こります(エラー処理は省略されます)

int8_t buff[2]; 
write_register(ACCEL_XOUT_H, pfd->fd); 
read(pfd->fd, buff, 2); //in this way you'll read both the ACCEL_XOUT_H register and the ACCEL_XOUT_L (the next one). 
+0

[このデータシート、第9章](http://www.dipmicro.com/?datasheet=PS-MPU-6000A-00v3)の通信プロトコルに従ってください。 4.pdf)、I2C(スレーブ・アドレスはリンク先のインターフェースによって提供されます)に1バイト(レジスタ・アドレス)だけを書き込んだ後、1​​バイトを読み取り、各レジ​​スタまたはバーストを複数バイト読み取るようにしてください。 I2Cがアイドル状態のときにレジスタを自由に更新できるため、バースト読み取りのみがマルチバイト値を正しく修正します。あなたは2バイト、レジスタアドレスとゼロバイトを書いていて、次に1バイトを読んでいます。インターフェイスに精通している誰かが私を修正するために自由です。 – sendaran

答えて

1

i2cの基本を理解する必要があるかもしれません。 I2Cレジスタを読み出すためにI2Cバス

enter image description here

上のスレーブからの読み取り

http://www.ti.com/lit/an/slva704/slva704.pdf

3.2、あなたは、スレーブADDRを書くADDRを登録して、再度ADDRをスレーブとし、データを読み取る必要がありますバスから。 これはドライバによって行われます。 スレーブアドレスはioctlによってfdに設定されます。 でもaddrを書く必要があります。

あなたのリンクから

/* Using SMBus commands */ 
    res = i2c_smbus_read_word_data(file, reg); 
    if (res < 0) { 
    /* ERROR HANDLING: i2c transaction failed */ 
    } else { 
    /* res contains the read word */ 
    } 

i2c_smbus_read_word_dataは、レジスタADDRが含まれているregを持っています。 ですが、read()はそうではありません。 write(reg)にしてからread()にする必要があります。

バーストモードなどを使用しない限り、1バイトしか読み取る必要はありません。 sizeが1であるので1バイトを読みますが、意味がないwhileとp ++です。

あなたはcommand(0x3b, pfd->fd);で読む前に3bを書いています。 しかし、それは書き込みのようになります。

68 > 3B , 68 > 00 , 68 < 

と読もうとしています。 (ここでは> 0の場合、<は1になります) commandの代わりにwrite(pfd->fd, 0x3b, 1)が必要なことがあります。

+0

あなたが言ったように、私はちょうど '書き込み'を入れて、今働くようです。どうもありがとうございました。私は現在の解決策で私の質問を編集します。 – igng

0

i2cdetectはi2c-toolsプロジェクトのものです。既にi2cgetもあります。これは、レジスタを読み取るためのコマンドラインプログラムが必要な場合に有効です。 link to Github