動作環境
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リポジトリ
処理概要
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)で確認した。
コマンド送信後のACKを受けることができている。