Raspberry Pi > C > RPi_i2c_comm_180227: v1.1 > clock stretching対応 (ソフトウェアI2C)

```txt:動作環境
Raspberry Pi 2 Model B (以下RPi)
Raspbian Jessie
gcc (Raspbian 4.9.2-10) 4.9.2
とあるI2Cセンサー (clock strecthingがある通信)
Analog Discovery 2 (以下AD2)
```

### 前回

- [Raspberry Pi > C > RPi_i2c_comm_180227: v1.0 > センサーからのデータ読取まで | RPi以外への移植と動作](https://qiita.com/7of9/items/09e3c4627cd030da0276)

I2C通信のセンサーとの通信をRPiでc実装した。

### 今回

とあるI2Cセンサー (clock strecthingがある通信)対応のため、clock strecthingを考慮したACK受付に変更。

Clock stretchingのタイミングダイアグラムは下記など参照。
https://learn.sparkfun.com/tutorials/i2c

### GitHubリポジトリ

[v1.1 @ GitHub](https://github.com/yasokada/RPi_i2c_comm_180227/releases/tag/v1.1)

### 処理概要

`RPi_i2c_comm_CLKSTR_180712.c`というファイルにおいてClock stretchingを考慮したI2C通信をしている。

具体的には`send_stopContinuousMeasurement()`の中身となる。

`i2c_clockStretching_IsACK()`を今回追加して、この関数内でSCL=Low状態を確認するようにしている。

```RPi_i2c_comm_CLKSTR_180712.c
...
static void send_stopContinuousMeasurement(int slvAdr)
{
    // write header
    i2c_SendStartCondition(/* withInit=*/true);
    i2c_SendSlaveAddress(slvAdr, /*bfRead=*/false);
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };
    // send command
    i2c_SendData(0x06); // Function Code
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0x00); // Address MSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0x37); // Address LSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0x00); // Content MSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0x01); // Content LSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0xF0); // CRC LSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendData(0x64); // CRC MSB
    if (i2c_clockStretching_IsACK(kMaxloop_SCL_stretch)) {
        printf("ACK\n");
    };

    i2c_SendStopCondition();
}
...
```

### i2c_clockStretching_IsACK()

```i2c_comm_180302.c
...
bool i2c_clockStretching_IsACK(int maxloop)
{
    bool pinIsH;
    int cnt=0;

    i2c_gpio_setSCL_level(GPIO_LOW);
    i2c_gpio_setSDA_direction(GPIO_IN);
    myDelay();
    i2c_gpio_setSCL_level(GPIO_HIGH);

	// { clock streching
    i2c_gpio_setSCL_direction(GPIO_IN);
	myDelay();
	while(true) {
		if(i2c_gpio_isSCL_high()) {
			break;
		}
		if(cnt > maxloop) {
			i2c_gpio_setSCL_direction(GPIO_OUT);  // end clock stretching
			return false;
		}
		myDelay();
		cnt++;
	}
	// } clock streching
    
    pinIsH = i2c_gpio_isSDA_high();
    myDelay();

    // set after reading SDA
    // (will fail to get ACK when set before reading SDA)
    i2c_gpio_setSCL_direction(GPIO_OUT);  // end clock stretching

    return (pinIsH == BOOL_ACK);	
}
...
```

備考: 上記において`i2c_gpio_setSCL_direction(GPIO_OUT);`はSDA読取り後にしている。SDA読取り前にSCLの方向を変更する実装ではACKを受信できなかった。

### ロジックの確認

上記のコマンド発行時の波形をAnalog Discovery 2 (以下AD2)で確認した。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/8279af58-9156-8815-a6ea-48d603a12f26.png)

コマンド送信後のACKを受けることができている。