STM32におけるI²C通信のソフトウェア実装

I²C(Inter-Integrated Circuit)は、シリアルデータ線(SDA)とシリアルクロック線(SCL)の2本で構成される同期式シリアルバスです。標準モードでは最大100 kbps、高速モードでは400 kbpsまでの通信が可能です。SDAおよびSCLはオープンドレイン出力で、外部プルアップ抵抗が必要です。通信はマスタがスレーブアドレスを送信し、対応するスレーブがACKを返すことで確立されます。

基本的な通信シーケンス

I²Cのデータ転送は、スタートコンディション(START)、スレーブアドレス+R/Wビット、ACK/NACK、データバイト(複数可)、ストップコンディション(STOP)で構成されます。

遅延関数の定義

タイミング調整のため、マイクロ秒単位の遅延を挿入します:

#define I2C_DELAY()  delay_us(10)

スタートおよびストップコンディション

START:SCLがHIGHの状態でSDAをHIGH→LOWに遷移。
STOP:SCLがHIGHの状態でSDAをLOW→HIGHに遷移。

void i2c_start(void) {
    sda_set(1);
    I2C_DELAY();
    scl_set(1);
    I2C_DELAY();
    sda_set(0);
    I2C_DELAY();
    scl_set(0);  // 次の操作に備えてSCLをLOWに保持
    I2C_DELAY();
}

void i2c_stop(void) {
    sda_set(0);
    I2C_DELAY();
    scl_set(1);
    I2C_DELAY();
    sda_set(1);
    I2C_DELAY();
}

ACK/NACKの送信

マスタがACK(0)またはNACK(1)を送信する際、SCLがHIGHの間にSDAのレベルを固定します。

void i2c_send_ack(uint8_t nack) {
    sda_set(nack);  // 0=ACK, 1=NACK
    I2C_DELAY();
    scl_set(1);
    I2C_DELAY();
    scl_set(0);
    I2C_DELAY();
}

ACKの受信

スレーブからのACKを確認するため、SDAを入力モードにしてSCL HIGH中に値を読み取ります。

uint8_t i2c_wait_ack(void) {
    uint8_t ack;
    sda_input();      // SDAを入力に設定
    I2C_DELAY();
    scl_set(1);
    I2C_DELAY();
    ack = sda_read(); // 0ならACK、1ならNACK
    scl_set(0);
    I2C_DELAY();
    sda_output();     // 再び出力モードに戻す
    return ack;
}

1バイトの送信

MSBから順に8ビットをクロック同期で送信します。

void i2c_write_byte(uint8_t byte) {
    uint8_t i;
    for (i = 0; i < 8; i++) {
        sda_set((byte & (0x80U >> i)) ? 1 : 0);
        I2C_DELAY();
        scl_set(1);
        I2C_DELAY();
        scl_set(0);
        I2C_DELAY();
    }
}

1バイトの受信

SDAをHIGHにプルアップした状態で、SCLの立ち上がり時にビットをサンプリングします。

uint8_t i2c_read_byte(void) {
    uint8_t i, data = 0;
    sda_input();  // 受信用に設定
    I2C_DELAY();

    for (i = 0; i < 8; i++) {
        scl_set(1);
        I2C_DELAY();
        if (sda_read()) {
            data |= (0x80U >> i);
        }
        scl_set(0);
        I2C_DELAY();
    }

    sda_output(); // 復帰
    return data;
}

タグ: STM32 I2C Embedded C GPIO bit-banging serial communication

6月3日 16:15 投稿