カーネルコンフィギュレーションの設定
Zephyr RTOS上でI2C機能を有効化するには、プロジェクトの設定ファイル(通常はprj.confまたはKconfig)にて、以下のオプションを追加する必要があります。これにより、I2Cドライバがカーネルに組み込まれます。
CONFIG_I2C=y
デバイスツリーオーバーレイの定義
ハードウェア設定を定義するため、プロジェクトのルートディレクトリにボード名に対応したオーバーレイファイル(例: nrf54l15dk_nrf54l15app.overlay)を作成します。このファイル内でピン機能(ピンコンフィグレーション)とI2Cノードの有効化を行います。
以下の設定例では、TWIM(Two-wire Interface Master)ペリフェラルを使用し、ポート1のピン11(SCL)とピン12(SDA)を割り当てています。また、スリープ時の低消費電力設定も併せて定義しています。
/ {
pinctrl {
/* アクティブ状態のピン設定 */
i2c_cfg_default: i2c_cfg_default {
group1 {
psels = <NRF_PSEL(TWIM_SCL, 1, 11)>,
<NRF_PSEL(TWIM_SDA, 1, 12)>;
bias-pull-up;
};
};
/* スリープ状態のピン設定 */
i2c_cfg_sleep: i2c_cfg_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SCL, 1, 11)>,
<NRF_PSEL(TWIM_SDA, 1, 12)>;
low-power-enable;
};
};
};
};
&i2c22 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>;
/* ピン状態の割り当て */
pinctrl-0 = <&i2c_cfg_default>;
pinctrl-1 = <&i2c_cfg_sleep>;
pinctrl-names = "default", "sleep";
/* 接続するI2Cデバイスの定義 (アドレス 0x58) */
my_peripheral: my_peripheral@58 {
compatible = "i2c-device";
status = "okay";
reg = <0x58>;
};
};
アプリケーションコードの実装
メインアプリケーションコードにて、デバイスツリーで定義したノードを取得し、I2Cバスの準備状況を確認した後、データの送受信を行います。ここでは、ZephyrのI2CデバイスツリーAPI(i2c_dt_spec)を使用して実装します。
以下のコードは、デバイスへの書き込み処理と、レジスタ指定による読み出し処理の例です。
#include <zephyr/kernel.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/printk.h>
/* デバイスツリーのノードラベルを指定 */
#define SENSOR_NODE_ID DT_NODELABEL(my_peripheral)
int main(void)
{
printk("Starting I2C sample on %s\n", CONFIG_BOARD_TARGET);
/* デバイスツリーからI2Cデバイス情報を取得 */
static const struct i2c_dt_spec bus_spec = I2C_DT_SPEC_GET(SENSOR_NODE_ID);
/* I2Cバスの準備完了を確認 */
if (!device_is_ready(bus_spec.bus)) {
printk("Error: I2C bus %s is not ready!\n", bus_spec.bus->name);
return 0;
}
printk("I2C bus %s is ready.\n", bus_spec.bus->name);
/* レジスタ 0x01 にデータ 0xA5 を書き込む */
uint8_t tx_packet[2] = {0x01, 0xA5};
int ret = i2c_write_dt(&bus_spec, tx_packet, sizeof(tx_packet));
if (ret != 0) {
printk("Write failed: addr 0x%x, reg 0x%02x\n", bus_spec.addr, tx_packet[0]);
}
/* レジスタ 0x01 からデータを読み出す */
uint8_t target_reg = 0x01;
uint8_t rx_buffer = 0;
ret = i2c_write_read_dt(&bus_spec, &target_reg, 1, &rx_buffer, 1);
if (ret != 0) {
printk("Read failed: addr 0x%x, reg 0x%02x\n", bus_spec.addr, target_reg);
} else {
printk("Read success: value 0x%02x\n", rx_buffer);
}
return 0;
}