0
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-17
動作環境
Raspberry Pi 2 Model B (以下RPi)
Raspbian Jessie
gcc (Raspbian 4.9.2-10) 4.9.2
とあるI2Cセンサー (clock strecthingがある通信)
Analog Discovery 2 (以下AD2)

前回

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

今回

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

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

GitHubリポジトリ

v1.1 @ GitHub

処理概要

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

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

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2