Raspberry Pi で３つのi2cデバイスを同時に動かしてみた

#概要
3つのi2cデバイス
１．距離センサ([VL53L0X](http://www.st.com/ja/imaging-and-photonics-solutions/vl53l0x.html))
２．ジャイロ加速度センサ([MPU-6050](https://www.invensense.com/products/motion-tracking/6-axis/mpu-6050/))
３．PWMドライバ([PCA9685](http://www.nxp.com/ja/products/power-management/lighting-driver-and-controller-ics/i2c-led-display-control/16-channel-12-bit-pwm-fm-plus-ic-bus-led-controller:PCA9685))
が同時動作することを確認しました。

#使用プログラミング言語言語
c
c++

#接続図
![aaa_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/146154/5facccd8-467c-60d0-a35a-32a0a0c05a04.png)

#動作確認画面
![キャプチャ2.png](https://qiita-image-store.s3.amazonaws.com/0/146154/668e1efb-4760-b0ec-a5d6-11fd9ebf8a52.png)
VL53L0X:距離センサ
MPU-6050:ジャイロ加速度センサ
PCA9685:PWMドライバ

binファイルはそれぞれi2cデバイス毎に用意して3プロセスを同時に実行した。
上の画像では静止画ですが、実際は３つとも同時に動作しました。

#プログラムソースコード
##距離センサ(VL53L0X)
https://github.com/cassou/VL53L0X_rasp を利用させていただきました。
http://www.st.com/content/st_com/en/products/embedded-software/proximity-sensors-software/stsw-img005.html のVL53L0X APIを利用するためダウンロードと、MakeFieへのAPIパス設定が必要です。



##ジャイロ加速度センサ(MPU-6050)
https://www.raspberrypi.org/forums/viewtopic.php?t=22266 を利用させていただきました。

##PWMドライバ(PCA9685)
http://junkroom2cyberrobotics.blogspot.jp/2013/06/raspberry-pi-adafruit-i2c-16-channel.html を参考させていただきc++からcへ変更しました。

```c:PCA9685.c
//gcc -Wall -O2 -lm PCA9685.c -o PCA9685
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <math.h>

#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4

#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE

#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9

#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD



//PCA9685
int m_nI2c;
void PCA9685_init(float freq);
uint8_t PCA9685_read(uint8_t adr);
void PCA9685_write(uint8_t adr, uint8_t dat);
void PCA9685_pwmWrite(uint8_t ch, double pulseWidth_usec);
void PCA9685_setPWM(uint8_t ch, uint16_t onTime, uint16_t offTime);

#define PWM_FREQUENCY 60					//60Hz 16.7ms
#define PWM_PULSE_WIDTH_MAX	12000			//12ms

/**********************************************************************
*
**********************************************************************/
int main(int argc, char *argv[])
{
	char *i2cFileName = "/dev/i2c-1";
	int driverAddress = 0x40;
	int i;
	double dfVal;

	if((m_nI2c = open(i2cFileName, O_RDWR)) < 0){
		printf("m_nI2c open err\n");
		return -1;
	}
 
	if(ioctl(m_nI2c, I2C_SLAVE, driverAddress) < 0){
		printf("ioctl err\n");
		return -1;
	}

	PCA9685_init(PWM_FREQUENCY);

	for(i=0;i<100;i++){
        dfVal = i*200+1000;
		if(PWM_PULSE_WIDTH_MAX < dfVal)break;
		printf("%0.1lfms\n",dfVal/1000);
		PCA9685_pwmWrite(0, dfVal);
		PCA9685_pwmWrite(1, PWM_PULSE_WIDTH_MAX - dfVal);
		sleep(1);
	}

	printf("stop\n");
	sleep(5);
	PCA9685_pwmWrite(0, 0);


	return 0;
}


/**********************************************************************
*	PCA9685_init
**********************************************************************/
void PCA9685_init(float freq)
{
	float prescaleval = 25000000;

	PCA9685_write(PCA9685_MODE1, 0x0);
	usleep(100000);//100ms

	prescaleval /= 4096;
	prescaleval /= freq;
	prescaleval -= 1;
	printf("Estimated pre-scale: %f\n", prescaleval);

	uint8_t prescale = floor(prescaleval + 0.5);
	printf("Final pre-scale: %d\n", prescale); 

	uint8_t oldmode = PCA9685_read(PCA9685_MODE1);
	uint8_t newmode = (oldmode&0x7F) | 0x10; 
	PCA9685_write(PCA9685_MODE1, newmode); 
	PCA9685_write(PCA9685_PRESCALE, prescale);
	PCA9685_write(PCA9685_MODE1, oldmode);
	sleep(5);
	PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);  

}


/**********************************************************************
*	PCA9685_pwmWrite
**********************************************************************/
void PCA9685_pwmWrite(uint8_t ch, double pulseWidth_usec)
{
	double pulselength;
	double pulseWidth;
	// 1秒=1000000usを60Hzで割ってパルス長を算出。
	pulselength = 1000000 / PWM_FREQUENCY;
	// 12bit(2^12=4096)分解能相当へ。1分解能当たりの時間算出。
	pulselength /= 4096;
	// PWMのパルス設定値を算出。
	pulseWidth = pulseWidth_usec / pulselength;

	// PWM値設定。
	//  setPWM(channel, on_timing, off_timing)
	//  channelで指定したチャネルのPWM出力のon(0→1）になるタイミングと
	//  off(1→0)になるタイミングを0～4095で設定する。
	PCA9685_setPWM(ch, 0, pulseWidth);
}
/**********************************************************************
*	PCA9685_setPWM
**********************************************************************/
void PCA9685_setPWM(uint8_t ch, uint16_t onTime, uint16_t offTime)
{
	uint8_t sendData[5];

	sendData[0] = LED0_ON_L + 4 * ch;
	sendData[1] = (uint8_t)(0x00ff & onTime);
	sendData[2] = (uint8_t)((0xff00 & onTime) >> 8);
	sendData[3] = (uint8_t)(0x00ff & offTime);
	sendData[4] = (uint8_t)((0xff00 & offTime) >> 8);
 
	if(write(m_nI2c, sendData, 5) != 5){
		printf("PCA9685_setPWM() err\n");
	}
}


/**********************************************************************
*	PCA9685_read
**********************************************************************/
uint8_t PCA9685_read(uint8_t adr)
{
	uint8_t sendData;
	uint8_t readData;

	sendData = adr;
	if(write(m_nI2c, &sendData, 1) != 1){
		printf("PCA9685_read() err1\n");
	}
	else{
		if(read(m_nI2c, &readData, 1) != 1){
			printf("PCA9685_read() err2\n");
		}
	 }

	return readData;
}
/**********************************************************************
*	PCA9685_write
**********************************************************************/
void PCA9685_write(uint8_t adr, uint8_t dat)
{
	uint8_t buf[2];

	buf[0] = adr;
	buf[1] = dat;
	if(write(m_nI2c, buf, 2) != 2){
		printf("PCA9685_write() err\n");
	}
}


```