質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

3回答

2497閲覧

ラズベリーパイで赤外線距離センサVL6180xを動作させる

man_

総合スコア45

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

0クリップ

投稿2019/09/03 07:42

編集2019/09/06 16:23

前提・実現したいこと

 ラズベリーパイでC言語を用いて赤外線距離センサvl6180xを動作させたいのですが、出力が0となってしまい上手く動作できていない状況です。
データシートを確認しながらコーディングしていたのですがデータシートA4545の7ページ目の"Wait for range measurement to complete.a) Poll RESULT__INTERRUPT_STATUS_GPIO {0x4f} register till bit 2 is set to 1.(New Sample Ready threshold event)."の部分をどうコーディングしたら良いのか分かりません。

試行錯誤中でコードが読みにくかったら申し訳ございません。
有識者の方ご協力お願いします。

下記のサイトを参考にしました。
URL:https://www.codelab.jp/blog/?p=706

発生している問題・エラーメッセージ

・データシートの"Wait for range measurement to complete.a) Poll RESULT__INTERRUPT_STATUS_GPIO {0x4f} register till bit 2 is set to 1.(New Sample Ready threshold event)."の部分のコーディングが不明。

・センサの出力が常に0となる。

該当のソースコード

C言語

1#include <stdio.h> 2#include <string.h> 3#include <errno.h> 4#include <unistd.h> 5#include <time.h> 6#include <wiringPi.h> 7#include <wiringPiI2C.h> 8#include <fcntl.h> 9#include <sys/ioctl.h> 10#include <linux/i2c-dev.h> 11 12#define BH1750_ADDRESS 0x29 // SECOND ADDRESS 0x53 13 14 15#define BH1750_WAIT_TIME 100 // ms 16 17int main(void) { 18 19 int fd; 20 int ret; 21 char wait; 22 23 unsigned char set_value[1]; 24 int result[3]; 25 26 int lData; 27 28 fd = wiringPiI2CSetup(BH1750_ADDRESS); 29 printf("0x%x\n",fd); 30 31 32 wiringPiI2CWriteReg8(fd, 0x16,0x00); 33 34while(1){ 35 36 // Power On 37 if((wiringPiI2CWriteReg8(fd, 0x18,0x03)) < 0) { 38 printf("error: power on\n"); 39 } 40 41 usleep(500*1000); 42 43 /*while(1){ 44 ret = wiringPiI2CReadReg8(fd, 0x4F); 45 printf("%02x\n",ret); 46 if(ret && 0x01){ 47 printf("start\n"); 48 break; 49 } 50 }*/ 51 52 // Set Configuration 53 /* set_value[0] = VL61_RANG_MODE; 54 ret = write(fd, set_value, 1); 55 if (ret < 0) { 56 printf("error: set configuration value\n"); 57 return 1; 58 } 59 */ 60 usleep(BH1750_WAIT_TIME * 1000); 61 62 63 // Get Value 64 result[0] = wiringPiI2CReadReg8(fd, 0x62); 65 //result[1] = wiringPiI2CReadReg8(fd, 0x65); 66 if (ret < 0) { 67 printf("error: read value\n"); 68 return 1; 69 } 70 71 wiringPiI2CWriteReg8(fd, 0x15,0x07); 72 printf("distanc: %d \r\n",result[0]); 73 74 } 75 return 0; 76} 77

###現在のコード

#include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #ifndef I2C_M_RD #include <linux/i2c.h> #endif #define vl6180x_addr 0x29 //vl6180xのI2Cアドレス typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; int i2c_fd = -1; const char *i2c_fname = "/dev/i2c-1"; int i2c_init(void) { if ((i2c_fd = open(i2c_fname, O_RDWR)) < 0) { char err[200]; sprintf(err, "open('%s') in i2c_init", i2c_fname); perror(err); return -1; } return i2c_fd; } void i2c_close(void) { close(i2c_fd); i2c_fd = -1; } int i2c_rw(u8 slave_addr, u8 *out, u32 out_len, u8 *in, u32 in_len) { int retval; struct i2c_msg msgs[2]; struct i2c_rdwr_ioctl_data msgset; msgset.msgs = msgs; msgset.nmsgs = 1; msgs[0].addr = slave_addr; msgs[0].flags = 0; msgs[0].len = out_len; msgs[0].buf = out; if(in_len > 0U){ msgs[1].addr = slave_addr; msgs[1].flags = I2C_M_RD; msgs[1].len = in_len; msgs[1].buf = in; msgset.nmsgs = 2; } if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) { perror("ioctl(I2C_RDWR) in i2c_rw"); return -1; } return 0; } int i2c_write16_8(u8 slave_addr, u16 reg, u8 data) { u8 out[3] = { (u8)(reg >> 8), (u8)reg, data }; return i2c_rw(slave_addr, out, sizeof(out), NULL, 0); } int i2c_write16_16(u8 slave_addr, u16 reg, u16 data) { u8 out[4] = { (u8)(reg >> 8), (u8)reg, (u8)(data >> 8), (u8)data }; return i2c_rw(slave_addr, out, sizeof(out), NULL, 0); } int i2c_read16_8(u8 slave_addr, u16 reg, u8 *data) { u8 out[2] = { (u8)(reg >> 8), (u8)reg}; return i2c_rw(slave_addr, out, sizeof(out), data, 1); } int i2c_read16_16(u8 slave_addr, u16 reg, u16 *data) { u8 out[2] = { (u8)(reg >> 8), (u8)reg}; u8 in[2]; int retval = i2c_rw(slave_addr, out, sizeof(out), in, sizeof(in)); if(retval >= 0){ *data = (((u16)in[0]) << 8) | in[1]; } return retval; } int i2c_dump16(u8 slave_addr, u16 reg, u32 in_len) { u8 out[2] = { (u8)(reg >> 8), (u8)reg}; u8 in[256]; u32 i; int retval; if(in_len > sizeof(in)) { in_len = sizeof(in); } for(i = 0;i < in_len;i++) { in[i] = 0xaa; } retval = i2c_rw(slave_addr, out, sizeof(out), in , in_len); if(retval >= 0){ for(i = 0;i < in_len;i++){ if ((i & 0xf) ==0) { printf("%04x:", reg + i); } printf("%02x%c", in[i], ((i & 0xf) == 0xf) ? '\n' : ' '); } if ((i & 0xf) !=0) { printf("\n"); } } return retval; } int vl6180x_initialisation(void){ //センサの初期化 i2c_write16_8(vl6180x_addr, 0x0207, 0x01); i2c_write16_8(vl6180x_addr, 0x0208, 0x01); i2c_write16_8(vl6180x_addr, 0x0096, 0x00); i2c_write16_8(vl6180x_addr, 0x0097, 0xfd); i2c_write16_8(vl6180x_addr, 0x00e3, 0x00); i2c_write16_8(vl6180x_addr, 0x00e4, 0x04); i2c_write16_8(vl6180x_addr, 0x00e5, 0x02); i2c_write16_8(vl6180x_addr, 0x00e6, 0x01); i2c_write16_8(vl6180x_addr, 0x00e7, 0x03); i2c_write16_8(vl6180x_addr, 0x00f5, 0x02); i2c_write16_8(vl6180x_addr, 0x00d9, 0x05); i2c_write16_8(vl6180x_addr, 0x00db, 0xce); i2c_write16_8(vl6180x_addr, 0x00dc, 0x03); i2c_write16_8(vl6180x_addr, 0x00dd, 0xf8); i2c_write16_8(vl6180x_addr, 0x009f, 0x00); i2c_write16_8(vl6180x_addr, 0x00a3, 0x3c); i2c_write16_8(vl6180x_addr, 0x00b7, 0x00); i2c_write16_8(vl6180x_addr, 0x00bb, 0x3c); i2c_write16_8(vl6180x_addr, 0x00b2, 0x09); i2c_write16_8(vl6180x_addr, 0x00ca, 0x09); i2c_write16_8(vl6180x_addr, 0x0198, 0x01); i2c_write16_8(vl6180x_addr, 0x01b0, 0x17); i2c_write16_8(vl6180x_addr, 0x01ad, 0x00); i2c_write16_8(vl6180x_addr, 0x00ff, 0x05); i2c_write16_8(vl6180x_addr, 0x0100, 0x05); i2c_write16_8(vl6180x_addr, 0x0199, 0x05); i2c_write16_8(vl6180x_addr, 0x01a6, 0x1b); i2c_write16_8(vl6180x_addr, 0x01ac, 0x3e); i2c_write16_8(vl6180x_addr, 0x01a7, 0x1f); i2c_write16_8(vl6180x_addr, 0x0030, 0x00); i2c_write16_8(vl6180x_addr, 0x0011, 0x10); i2c_write16_8(vl6180x_addr, 0x010a, 0x30); i2c_write16_8(vl6180x_addr, 0x003f, 0x46); i2c_write16_8(vl6180x_addr, 0x0031, 0xFF); i2c_write16_8(vl6180x_addr, 0x0040, 0x63); i2c_write16_8(vl6180x_addr, 0x002e, 0x01); i2c_write16_8(vl6180x_addr, 0x001b, 0x09); i2c_write16_8(vl6180x_addr, 0x003e, 0x31); i2c_write16_8(vl6180x_addr, 0x0014, 0x24); i2c_write16_8(vl6180x_addr, 0x16, 0x00); } int main(){ int ret, result; u8 data; i2c_init(); if (ioctl(i2c_fd, I2C_SLAVE, vl6180x_addr) < 0) { perror("ioctl(I2C_SLAVE) in i2c_rw"); return -1; } ret = i2c_read16_8(vl6180x_addr, 0x000, &data); printf("data:0x%02x\n",data); i2c_dump16(vl6180x_addr,0,256); vl6180x_initialisation(); // repeat rang mesurement while(1){ //start single-shot mode if((i2c_write16_8(vl6180x_addr, 0x018,0x001)) < 0) { printf("error: power on\n"); } // wait to {0x4f} register till bit 2 is set to 1 while(1){ ret = i2c_read16_8(vl6180x_addr, 0x04f, &data); usleep(500*1000); printf("data:%02x\n",data); if(data == 0x04){ printf("mesurement start\n"); break; } } // get value ret = i2c_read16_8(vl6180x_addr, 0x62, &data); // clear interruput status i2c_write16_8(vl6180x_addr, 0x15, 0x07); printf("distance:%d\n", result); } i2c_close(); }

修正済み
・(現在のコードではmain関数のiotclの部分で"ioctl(I2C_RDWR) in i2c_rw: Bad address"というエラーが出ている状態です。)
・(i2c_rw()関数の部分で "ioctl(I2C_RDWR) in i2c_rw: Remote I/O error"というエラーが出ています。)
・(main()関数の" wait to {0x4f} register till bit 2 is set to 1"の部分で常に"data:00"と出力され、計測が開始されない状態です。改定のアドバイスよろしくお願いいたします。)

現在
{0x62}の値が0と出力されてしまいます。

こちらのサイトとデータシートを参考に作成しました。
サイト:https://qiita.com/shigeru-yokochi/items/ac2138feb74a7ef7ffc6

データシート:https://cdn.sparkfun.com/datasheets/Sensors/Proximity/VL6180_ApplicationNote.pdf

###現段階での出力

data:0xb4 0000:b4 01 03 01 02 72 4c b1 84 b5 56 10 00 00 00 00 0010:60 20 00 00 00 00 00 00 00 ff 00 ff 31 00 00 00 0020:00 14 00 00 0a 00 00 cb 03 fb 32 8f a0 11 00 74 0030:00 00 0a 28 00 00 00 ff 00 00 ff ff 00 00 ff 06 0040:00 00 00 00 00 00 00 00 00 00 00 00 00 73 01 00 0050:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0060:00 00 ff ff ff 00 00 0c 28 fa 00 00 00 00 12 c2 0070:00 3d 40 9d 00 00 04 ec 00 00 0a 57 00 00 bf 52 0080:00 00 bf 52 00 01 02 09 0d 0b 00 00 00 00 00 00 0090:00 00 00 00 00 00 00 fd 00 00 00 00 00 00 00 00 00a0:00 00 00 3c 00 00 0a 57 00 3d 7e a7 00 3d 40 9d 00b0:09 0f 09 06 00 00 00 00 00 00 00 3c 00 00 04 ec 00c0:00 00 30 4a 00 00 12 c2 09 0f 09 06 03 01 0b 00 00d0:01 03 01 01 00 00 00 00 00 05 00 ce 03 f8 06 00 00e0:00 00 03 00 04 02 01 03 00 00 00 00 00 00 06 00 00f0:00 00 01 01 00 02 01 03 00 00 00 00 00 00 02 05 data:00 data:04 mesurement start distance:0 data:00 data:04 mesurement start distance:0 data:00 data:04

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ラズベリーパイ3
コンパイラ:gcc

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

wiringPiI2C*のAPIを使用したI2C通信はできないと思います。

VL6180X データシート(pdf)

の "4. I2C control interface"を見たところ、このデバイスにアクセスするには
16bitのレジスタインデックスを送信しなければならないとしています。

そしてwiringPiI2C*の実装を見たのですがLinux KernelのSMBusインタフェースを使用して実装されています。

SMBusインタフェースはI2C利用方法を限定したもので8bitのインデックスしか送れません。
そのため、デバイスとの通信が成立していないと考えられます。

これを解決するにはLinuxのI2Cインタフェースを直接使うことです。

これを参考に実装します。

レジスタインデックスを16bitに拡張します。

C

1#include <stdio.h> 2#include <string.h> 3#include <fcntl.h> 4#include <unistd.h> 5#include <sys/ioctl.h> 6 7#include <linux/i2c-dev.h> 8#ifndef I2C_M_RD 9#include <linux/i2c.h> 10#endif 11 12typedef unsigned char u8; 13typedef unsigned short u16; 14typedef unsigned int u32; 15 16int i2c_fd = -1; 17const char *i2c_fname = "/dev/i2c-1"; 18 19int i2c_init(void) 20{ 21 if ((i2c_fd = open(i2c_fname, O_RDWR)) < 0) { 22 char err[200]; 23 sprintf(err, "open('%s') in i2c_init", i2c_fname); 24 perror(err); 25 return -1; 26 } 27 28 return i2c_fd; 29} 30 31void i2c_close(void) 32{ 33 close(i2c_fd); 34 i2c_fd = -1; 35} 36 37int i2c_rw(u8 slave_addr, u8 *out, u32 out_len, u8 *in, u32 in_len) 38{ 39 int retval; 40 struct i2c_msg msgs[2]; 41 struct i2c_rdwr_ioctl_data msgset; 42 43 msgset.msgs = msgs; 44 msgset.nmsgs = 1; 45 46 msgs[0].addr = slave_addr; 47 msgs[0].flags = 0; 48 msgs[0].len = out_len; 49 msgs[0].buf = out; 50 51 if(in_len > 0U){ 52 msgs[1].addr = slave_addr; 53 msgs[1].flags = I2C_M_RD | I2C_M_NOSTART; 54 msgs[1].len = in_len; 55 msgs[1].buf = in; 56 57 msgset.nmsgs = 2; 58 } 59 60 if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) { 61 perror("ioctl(I2C_RDWR) in i2c_rw"); 62 return -1; 63 } 64 65 return 0; 66} 67 68int i2c_write16_8(u8 slave_addr, u16 reg, u8 data) 69{ 70 u8 out[3] = { (u8)(reg >> 8), (u8)reg, data }; 71 return i2c_rw(slave_addr, out, sizeof(out), NULL, 0); 72} 73 74int i2c_write16_16(u8 slave_addr, u16 reg, u16 data) 75{ 76 u8 out[4] = { (u8)(reg >> 8), (u8)reg, (u8)(data >> 8), (u8)data }; 77 return i2c_rw(slave_addr, out, sizeof(out), NULL, 0); 78} 79 80int i2c_read16_8(u8 slave_addr, u16 reg, u8 *data) 81{ 82 u8 out[2] = { (u8)(reg >> 8), (u8)reg}; 83 return i2c_rw(slave_addr, out, sizeof(out), data, 1); 84} 85 86int i2c_read16_16(u8 slave_addr, u16 reg, u16 *data) 87{ 88 u8 out[2] = { (u8)(reg >> 8), (u8)reg}; 89 u8 in[2]; 90 int retval = i2c_rw(slave_addr, out, sizeof(out), in, sizeof(in)); 91 if(retval >= 0){ 92 *data = (((u16)in[0]) << 8) | in[1]; 93 } 94 return retval; 95} 96 97int i2c_dump16(u8 slave_addr, u16 reg, u32 in_len) 98{ 99 u8 out[2] = { (u8)(reg >> 8), (u8)reg}; 100 u8 in[256]; 101 u32 i; 102 int retval; 103 if(in_len > sizeof(in)) { in_len = sizeof(in); } 104 for(i = 0;i < in_len;i++) { in[i] = 0xaa; } 105 retval = i2c_rw(slave_addr, out, sizeof(out), in , in_len); 106 if(retval >= 0){ 107 for(i = 0;i < in_len;i++){ 108 if ((i & 0xf) ==0) { printf("%04x:", reg + i); } 109 printf("%02x%c", in[i], ((i & 0xf) == 0xf) ? '\n' : ' '); 110 } 111 if ((i & 0xf) !=0) { printf("\n"); } 112 } 113 return retval; 114}

好きに使ってください。

使用例

C

1// For 8bit registers 2{ 3 int retval; 4 u8 data8; 5 retval = i2c_read16_8(BH1750_ADDRESS, /*RESULT__INTERRUPT_STATUS_GPIO*/0x4f, &data8); 6 if(retval < 0){ 7 /* エラー処理:適切な処理を入れてください */ 8 } 9 else { 10 /* 正常時処理 */ 11 printf("register value = %02x\n", data8); 12 } 13} 14 15// for 16bit registers 16{ 17 int retval; 18 u16 data16; 19 retval = i2c_read16_16(BH1750_ADDRESS, /*RESULT__ALS_VAL*/0x50, &data16); 20 if(retval < 0){ 21 /* エラー処理:適切な処理を入れてください */ 22 } 23 else { 24 /* 正常時処理 */ 25 printf("register value = %04x\n", data16); 26 } 27}

投稿2019/09/04 13:20

編集2019/09/06 10:43
nomuken

総合スコア1627

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

man_

2019/09/04 16:05

nomukenさん回答ありがとうございます。 wiringPiI2Cの"wiringPiI2CWriteReg16"等を用いることで、16ビットの通信が行えるものだと考えていました。 ご指摘ありがとうございます。 お聞きしたいのですが、センサに8ビットと16ビットのレジスタがあるのですが、linuxのI2Cインターフェースを直接使う場合、レジスタのビット数によって通信を行う関数をが違うのでしょうか? 自分でも調べてみますが、ご教授していただければ幸いです。
nomuken

2019/09/04 16:34

wiringPiI2CWriteReg16関数は8bitのインデックスを送信した後16bitのデータを送る関数ですね。送信ビット数が合計24なのでうまく使えば通信できなくはないですがReadでは通用しないので混乱するのでやめたほうがいいです。 16bitレジスタの場合、次のアドレスが空いているはずです。データシートのFigure 34. Multiple location write や Figure 35. Multiple location read でやり取りできるはずです。おそらく先に受信したバイトが上位8bit、次が下位8bitだと思います。この辺りは実機で確認してください。 16bitアクセスする場合は送受信バイト数のパラメーター、バッファサイズを変えることで対応できます。今の関数をカスタマイズして8/16ビット両対応するか、別々に関数を定義するかはお好みです。(私が作るなら後者。)
man_

2019/09/04 21:00 編集

nomukenさん回答ありがとうございます。 とても丁寧に説明して下さり、大変ありがたく存じます。 現在教えていただいたgithubのリンク先のi2c.cに書き足す形でコーディングをしております。 そこで、いくつかお聞きしたいのですが、 1. i2c.c内の関数”i2c_write”と”i2c_read”はそれぞれ8bitのi2c通信用で、最初の回答で提示していただいたコードで16bit 用のi2c通信用の関数をコーディングする形で間違いないでしょうか? 2. 先ほどの回答で”データシートのFigure 34. Multiple location write や Figure 35. Multiple location read でやり取りできるはずです。”と教えていただいたのですが、下記のURLのデータシートの7ページにあるような、{0x18}に0x01を書き込むというような操作を行うコードと、Figure34やFigure35でやり取りを行うコードの違いや、書き方がいまいちよく分からない状態です。 初歩的な質問で申し訳ないですが、それらについて詳しく教えていただけると幸いです。 URL:https://cdn.sparkfun.com/datasheets/Sensors/Proximity/VL6180_ApplicationNote.pdf よろしくお願いします。
nomuken

2019/09/04 22:02

ソースコードを改定しました。アクセス対象レジスタに合わせて関数を使い分けてください。
man_

2019/09/05 16:15 編集

nomukenさん回答ありがとうございます。 現在いただいたソースコードをもとにコーディングを行ているのですが、質問があります。 関数i2c_read16_8()とi2c_read16_16()の引数の*dataには何を渡したら良いのでしょうか? 例えばレジスタ{0x4f}の値を読み取りたい場合どのような記述になるのでしょうか? よろしくお願いします。 また、現在のコードを質問の方に追加しましたので、誤っている部分などのアドバイス宜しくお願い致します。
nomuken

2019/09/05 17:25 編集

使用例を回答欄に追加しました。
jimbe

2019/09/05 18:16

> "ioctl(I2C_RDWR) in i2c_rw: Remote I/O error" i2c_read/write の各関数の第一引数は slave_addr です. i2c_fd ではなく vl6180x_addr を指定するのではないでしょうか.
man_

2019/09/05 18:30

nomukenさん、jimbeさん回答ありがとうございます。 ソースコードを直し追記しました。 しかし、” wait to {0x4f} register till bit 2 is set to 1”の部分で永久ループしてしまい、測定の計測が完了しない状態です。"wiringPiI2C"を使用した際も、同じ部分でループしてしまい、センサを動作出来ない状態でした。 その他にはエラーは特に出ていません。センサの配線も見直しましたが誤りはありませんでした。 改訂のアドバイス等よろしくお願い致します。
nomuken

2019/09/05 18:41

vl6180x_initialisationの手前あたりで0x000 (IDENTIFICATION__MODEL_ID)をread16_8でReadしてみてください。デバイスと通信できていれば0xB4が読めるはずです。通信できていない場合は0xFFが読めると思います。
jimbe

2019/09/05 18:41

vl6180x_initialisation に Recommended の分も入れては如何でしょう. 最初のコメントに何やら怪しげな文言が見えるのですが….
man_

2019/09/05 19:14

nomukenさん、jimbeさん回答ありがとうございます。 修正したソースコードを追記しました。 {0x000}をReadしてみましたが、0x00と読まれました。 ラズパイのターミナルで"i2cdetect"を行うと0x29とアドレスが出力されセンサは認識されています。 改訂のアドバイス等宜しくお願い致します。
nomuken

2019/09/05 19:51 編集

I2Cバスのクロック周波数が適切か確認してみましょう。 https://gist.github.com/ribasco/c22ab6b791e681800df47dd0a46c7c3a#file-howtochangei2cspeed-md の手順5以降で現在のバスクロックを確認してみてください。400000以下になっていないなら手順1からを試してみてください。 VL6180xのデータシートの"4.1 I2C interface - timing characteristics"によると"Operating frequency"の行で400KHz以下でなければならないとなっています。
man_

2019/09/05 20:05

nomukenさん回答ありがとうございます。 クロック周波数を確認したところ、100KHzでした。
nomuken

2019/09/05 22:43

i2c_rw関数の中の msgs[1].flags = I2C_M_RD | I2C_M_NOSTART; の行を msgs[1].flags = I2C_M_RD; に変えてみてもらえますか?
man_

2019/09/06 06:49 編集

nomukenさん回答ありがとうございます。 変更してみましたがdataは0x00のままでした。 現在コンパイル方法としてgcc vl61x.c ←プログラム名 実行方法として./a.out ファイルのディレクトリは/home/pi/Downloads/vl61x.cとなっています。 コンパイル方法などに誤りはないでしょうか? 改訂等のアドバイスよろしくお願いいたします
nomuken

2019/09/06 10:45

i2c_dump16関数を増やしました。vl6180x_initialisation関数呼び出しの手前あたりで i2c_dump16(vl6180x_addr, 0, 256); を実行してみてください。
nomuken

2019/09/06 10:48

> コンパイル方法などに誤りはないでしょうか? 大丈夫だと思います。 不安だったらi2c_init関数を呼ぶ前に printf("Build date time is " __DATE__ " "__TIME__ "\n"); とでも書いておいてください。
man_

2019/09/06 13:13

nomukenさん回答ありがとうございます。 "i2c_dump16"を入れて実行してみましたが、dataは00のままでした。 また、質問の部分にターミナルでの出力結果を載せました。 改訂等のアドバイスよろしくお願いいたします。
nomuken

2019/09/06 14:46 編集

一度システムをシャットダウン、電源をOFFし、起動後、1回目の結果を取得してみてください。張り付けてある内容がそれであれば不要です。VL6180xをリセットすることが目的です。
man_

2019/09/06 15:09

nomukenさん回答ありがとうございます。 シャットダウンし、再度プログラムを実行したところ、{0x000}のレジスタが0xb4と読むことが出来ました。しかしmain関数内の"wait to {0x4f} register till bit 2 is set to 1"の部分がdata:00のままで、センサの計測が完了していない状態です。 改訂等のアドバイスよろしくお願いいたします。
nomuken

2019/09/06 16:20

I2C通信が確立していることは確認できました。アドレス0x000が0x00になっていたのは試行錯誤しているうちに書き換わってしまったのでしょう。リセットによって元に戻ったと思います。 InitialisationをApplication Noteとまったく同じようになるようにコードを修正してみてください。 1. Check device has powered up (Optional) → アドレス0x016の値が0x01であることを確認する。違う場合は手順2~4は飛ばし、手順5へすすむ。 2. Load settings onto VL6180X i2c_dump16(vl6180x_addr,0,256);でレジスタダンプを取ってください。 修正後、一旦リセットしてから試してください。
man_

2019/09/06 16:29

nomukenさん回答ありがとうございます。 データシートを確認したところ、initialisationで見逃していたレジスタがあったため、vl6810x_initialisation関数に追加したところ、{0x4f}のレジスタが0x04と読み取ることが出来ました。 しかし、distanceの部分が0と出力されてしまいます。 今頂いたアドバイスを参考に引き続きコーディングしていきます。
man_

2019/09/06 17:06

nomukenさん回答ありがとうございます。 おかげさまでセンサの動作を確認することが出来ました。 毎回丁寧に回答していただきありがとうございました。 深夜帯でも回答していただき、とても感謝しています。 今後ともよろしくお願いいたします。
guest

0

Google の翻訳によりますと

2.1 Performing a range measurement in single-shot mode

  1. Check device is ready to start a range measurement. (Optional)

a) Check bit 0 of RESULT__RANGE_STATUS {0x4d} is set.
2. Start a range measurement.
a) Write 0x01 to SYSRANGE__START {0x18}.
3. Wait for range measurement to complete.
a) Poll RESULT__INTERRUPT_STATUS_GPIO {0x4f} register till bit 2 is set to 1.
(New Sample Ready threshold event).
4. Reading range result.
a) Read RESULT__RANGE_VAL {0x62}.
b) This is the range measurement between the VL6180X and target in mm
5. Clear the Interrupt status.
a) Write 0x07 to SYSTEM__INTERRUPT_CLEAR {0x15}.
6. Repeat the previous steps 1 to 4 for more range measurements.

2.1 シングルショットモードでの距離測定の実行

  1. デバイスが範囲測定を開始する準備ができていることを確認します。 (オプション)

a)RESULT__RANGE_STATUS {0x4d}のビット0が設定されていることを確認します。
2. 範囲測定を開始します。
a)0x01をSYSRANGE__START {0x18}に書き込みます。
3. 範囲の測定が完了するまで待ちます。
a)ビット2が1に設定されるまで、RESULT__INTERRUPT_STATUS_GPIO {0x4f}レジスタをポーリングします。
(新しいサンプル準備完了しきい値イベント)。
4. 読み取り範囲の結果。
a)RESULT__RANGE_VAL {0x62}を読み取ります。
b)これは、VL6180Xとターゲット間の距離測定(mm)です
5. 割り込みステータスをクリアします。
a)SYSTEM__INTERRUPT_CLEAR {0x15}に0x07を書き込みます。
6. さらに範囲を測定するには、前の手順1〜4を繰り返します。

だそうです.

投稿2019/09/03 18:00

編集2019/09/03 18:09
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2019/09/03 18:15

すいません, 最初 2.2 を翻訳してしまい「コピペ間違った」と思いまして 2.1 に書き換えましたが, 2.2 で良かったのでしょうか. (RESULT__INTERRUPT_STATUS_GPIO の箇所は同じようですが.)
man_

2019/09/03 18:25

jimbeさん回答ありがとうございます。 丁寧に翻訳していただきありがとうございます。 このシングルショットモードをC言語で動作させたいのですが、3のポーリングの部分でレジスタ{0x4f}のビット2が1に設定されず、悩んでいます。 測定完了まで待つというのは、何かプログラム側で操作が必要なのでしょうか? ご教授よろしくお願いします。
man_

2019/09/03 18:28

2.1と2.2両方試している状態です。修正していただきありがとうございます。
jimbe

2019/09/04 00:51

ご提示されているコードではポーリング箇所がコメントになっていますが, これを生かしても抜けないということでしょうか. オプションの 1. をご確認されては如何でしょう.
man_

2019/09/04 06:29

jimbeさん回答ありがとうございます。 回答の通り、ポーリングの部分でレジスタ{0x4f}の2ビット目に1がセットさせず、常に00の状態です。 オプション1のレジスタ{0x4d}の0ビット目はデータシートを見ると、result__range_device_ready: Device Ready. When set to 1, indicates the device mode and configuration can be changed and a new start command will be accepted. When 0, indicates the device is busy"と記載されており、プログラムで確認してみると0ビット目には0がセットされていました。 このレジスタ{0x4d}は読み込み専用で、0ビット目に1や0を設定する方法がいまいちよく分からない状態です。
jimbe

2019/09/04 12:16

AN4545 の set-up (特に 1.3 Initialisation )はされていますでしょうか.
man_

2019/09/04 15:09

jimbeさん回答ありがとうございます。 1.3のセットアップを行っていなかったため、プログラムに追加しました。しかし、センサの値は0のままです。 現在のコードは下記のような状態になっております。 ``` #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <time.h> #include <wiringPi.h> #include <wiringPiI2C.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #define BH1750_ADDRESS 0x29 // SECOND ADDRESS 0x53 #define BH1750_WAIT_TIME 100 // ms int main(void) { int fd; int ret; int wait; unsigned char set_value[1]; int result[2]; int lData; fd = wiringPiI2CSetup(BH1750_ADDRESS); printf("0x%x\n",fd); wiringPiI2CWriteReg8(fd, 0x16,0x01); wiringPiI2CWriteReg16(fd, 0x0207, 0x01); wiringPiI2CWriteReg16(fd, 0x0208, 0x01); wiringPiI2CWriteReg16(fd, 0x0096, 0x00); wiringPiI2CWriteReg16(fd, 0x0097, 0xfd); wiringPiI2CWriteReg16(fd, 0x00e3, 0x00); wiringPiI2CWriteReg16(fd, 0x00e4, 0x04); wiringPiI2CWriteReg16(fd, 0x00e5, 0x02); wiringPiI2CWriteReg16(fd, 0x00e6, 0x01); wiringPiI2CWriteReg16(fd, 0x00e7, 0x03); wiringPiI2CWriteReg16(fd, 0x00f5, 0x02); wiringPiI2CWriteReg16(fd, 0x00d9, 0x05); wiringPiI2CWriteReg16(fd, 0x00db, 0xce); wiringPiI2CWriteReg16(fd, 0x00dc, 0x03); wiringPiI2CWriteReg16(fd, 0x00dd, 0xf8); wiringPiI2CWriteReg16(fd, 0x009f, 0x00); wiringPiI2CWriteReg16(fd, 0x00a3, 0x3c); wiringPiI2CWriteReg16(fd, 0x00b7, 0x00); wiringPiI2CWriteReg16(fd, 0x00bb, 0x3c); wiringPiI2CWriteReg16(fd, 0x00b2, 0x09); wiringPiI2CWriteReg16(fd, 0x00ca, 0x09); wiringPiI2CWriteReg16(fd, 0x0198, 0x01); wiringPiI2CWriteReg16(fd, 0x01b0, 0x17); wiringPiI2CWriteReg16(fd, 0x01ad, 0x00); wiringPiI2CWriteReg16(fd, 0x00ff, 0x05); wiringPiI2CWriteReg16(fd, 0x0100, 0x05); wiringPiI2CWriteReg16(fd, 0x0199, 0x05); wiringPiI2CWriteReg16(fd, 0x01a6, 0x1b); wiringPiI2CWriteReg16(fd, 0x01ac, 0x3e); wiringPiI2CWriteReg16(fd, 0x01a7, 0x1f); wiringPiI2CWriteReg16(fd, 0x0030, 0x00); wiringPiI2CWriteReg16(fd, 0x0011, 0x10); wiringPiI2CWriteReg16(fd, 0x010a, 0x30); wiringPiI2CWriteReg16(fd, 0x003f, 0x46); wiringPiI2CWriteReg16(fd, 0x0031, 0xFF); wiringPiI2CWriteReg16(fd, 0x0040, 0x63); wiringPiI2CWriteReg16(fd, 0x002e, 0x01); wiringPiI2CWriteReg16(fd, 0x001b, 0x09); wiringPiI2CWriteReg16(fd, 0x003e, 0x31); wiringPiI2CWriteReg16(fd, 0x0014, 0x24); wiringPiI2CWriteReg8(fd, 0x16,0x00); /*wait = 4; printf("wait = 0x%02x\n",wait); printf("wait = %d\n",wait); */ //wiringPiI2CWriteReg8(fd, 0x16,0x00); //ret=wiringPiI2CReadReg8(fd, 0x4d); //printf("%02x\n",ret); while(1){ //wiringPiI2CWriteReg8(fd, 0x4d,0x01); // Power On if((wiringPiI2CWriteReg8(fd, 0x18,0x03)) < 0) { printf("error: power on\n"); } usleep(500*1000); /*while(1){ ret = wiringPiI2CReadReg8(fd, 0x4f); printf("%02x\n",ret); usleep(500*1000); if(ret == 0x04){ printf("%d\n",ret); break; } }*/ // Set Configuration /* set_value[0] = VL61_RANG_MODE; ret = write(fd, set_value, 1); if (ret < 0) { printf("error: set configuration value\n"); return 1; } */ usleep(BH1750_WAIT_TIME * 1000); // Get Value result[0] = wiringPiI2CReadReg8(fd, 0x62); result[1] = wiringPiI2CReadReg8(fd, 0x62 >> 8); //read(fd ,result,2); if (ret < 0) { printf("error: read value\n"); return 1; } wiringPiI2CWriteReg8(fd, 0x15,0x07); printf("distanc1: %d \r\n",result[0]); printf("distanc2: %d \r\n",result[1]); //printf("distance: %.2f\n", lData / 1.2 * (69 / BH1750_MTREG) / BH1750_MODE_DIV); } return 0; } ```
jimbe

2019/09/05 04:08

現在のコードはご質問に追加編集して戴いた方が, 他の方にも分かって良いかと思います。 nomuken さんの回答で「レジスタへの書き込みが出来ていないのでは」と言うことで更に直されていると思いますので, 直された折には是非またコードのご提示を(ご質問に追記で)お願いします.
man_

2019/09/05 17:27

jimbeさん回答ありございます。 直したコードは質問部分に追記していきたいと思います。
guest

0

if(ret && 0x01)

なってますが、

  1. &&は論理積なので、これは
if(ret)

と同じ意味です。
ビット同士のANDである&を使いましょう。

... bit 2 is set to 1

「ビット2が1になるまで」
となっているのに0x01となっています。
これでは最初のビットを見ています。

ret & (1<<1)ret & (1<<2)になるはずです。
どっちなのかはデータシートで最初のビットが1ビット目と表現するか0ビット目と表現しているかによります。

投稿2019/09/03 08:02

ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

man_

2019/09/03 15:09

ozwkさん回答ありがとうございます。 プログラムを変更してみましたが、出力が0のままでした。 データシートの"Wait for range measurement to complete."のwait とは何を意味しているのでしょうか? このレジスタ{0x4f}は読み込み専用のレジスタで、Wait とあるので待ってみましたが、時間経過では変更されませんでした。 私が初心者で知識も少ないため、このような初歩的な質問ですが、何卒ご教授お願いします。
ozwk

2019/09/03 23:37 編集

1. センサに測定開始の指示を送る 2. (センサがすぐ測定を終えるわけじゃないので)測定終了と答えるまでセンサに終わった?と訪ね続ける という使用方法っぽいので、例えば1.の時点で間違ってると 測定が開始されてないので終わりもしないことになっても不思議じゃないです
man_

2019/09/04 06:44

ozwkさん回答ありがとうございます。 他の回答者さんと同じ返答になってしまうのですが、センサに測定開始の指示を送ると思われるレジスタが{0x18}と{0x4d}です。{0x18}には”wiringPiI2CwriteReg8()”を用いて書き込みを行っているのですが、{0x4d}のレジスタの設定方法が不明な状態です。 データシートよりレジスタ{0x4d}の0ビット目は"result__range_device_ready: Device Ready. When set to 1, indicates the device mode and configuration can be changed and a new start command will be accepted. When 0, indicates the device is busy." の設定を行うビットで常に0がセットされています。”wiringPiI2CwriteReg8()”で書き込みが出来ないか試してみましたが、動作しませんでした。このレジスタは読み込み専用で0ビット目に1を設定する方法が分からない状態です。 センサの配線は何度も確認しましたが間違いは無いようで、プログラム側の問題だと考えられます。 I2C初心者のため、お力添えお願いします。
ozwk

2019/09/04 08:23

0x4dはセットされているかを確認するだけです。書くものじゃないです。 (そう書いてありますよね?)
man_

2019/09/04 09:59

ozwkさん回答ありがとうございます。 {0x4d}は確認するだけとういことは理解しております。ただ、0x4dの0ビット目が0の状態ではビジーで使用できないのではと考え、1に設定するためには何をしたら良いのかわからず、試行錯誤しておりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問