正直に言うと、XIAO ESP32C6でのI2C通信にここまで悩まされるとは思っていませんでした。
これまでRP2040やESP32などでは、I2C(0)を使い、指定のSDA/SCLピンをつなげば簡単にI2Cデバイスが認識されていたのです。
しかし今回は i2c.scan() を実行しても、返ってくるのは空リスト []。
「配線ミスか?」「LCDが壊れたか?」と何度もチェックしましたが、同じAQM1602がRP2040では正常に動作するので、そうではなさそう。
ESP32C6にはハードウェアI2Cとして使用できるピンが限られていたり、正確な情報がまだ少ない、という背景もあり、「実際には動くのかもしれないが、正しいピン指定や初期化方法が把握しづらい」という状況だったのかもしれません。
結果として、「SoftI2Cを使ってみたらすんなり動いた」が情報不足でしたというのが今回の教訓でした。
なぜハードI2Cがうまくいかなかったのか?
i2c通信を良く理解していない
machine.I2C を使ったハードウェアI2Cの場合でも、どのGPIOピンをSDAとSCLにするかは自由に設定できます。これは、多くのMicroPythonが動作するマイコン(ESP32シリーズやRaspberry Pi Picoなど)が持つI2Cコントローラの柔軟な機能の一つなのだそうです。
正しいコード
import machine
sda=machine.Pin(0)
scl=machine.Pin(1)
i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000)
print(i2c.scan())>>> %Run -c $EDITOR_CONTENT
[62]
>>>正しく表示されました
ESP32-C6の持つハードウェアI2Cコントローラを使い、そのSDAとSCLピンとしてGPIO0とGPIO1を割り当てたという設定で、私はこれをよく理解していませんでした。
GPIOピンの選択肢が広いことは、開発者にとって非常に便利な機能になります。
失敗例(一部のチップでは使える)
from machine import Pin, I2C
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100000)
print(i2c.scan())i2c.scan()が常に空リスト [] を返す状態に
SoftI2Cを使ってみた
SoftI2C()でGPIO0(scl)とGPIO1(sda)を任意で指定
今回はscl=Pin(1), sda=Pin(0)に設定しました。
freq=は100000から400000の設定が可能で、こちらを省いた場合デフォルトで100000になるそうです。
from machine import Pin, SoftI2C
import time
i2c = SoftI2C(scl=Pin(1), sda=Pin(0), freq=100000)
print(i2c.scan())上記のプログラムを実行した場合[62]が表示されます
>>> %Run -c $EDITOR_CONTENT
[62]
>>>C6ピンレイアウト

接続図

実際にLCDへ表示する例
from machine import Pin, SoftI2C
import time
LCD_ADDR = 0x3E
i2c = SoftI2C(scl=Pin(1), sda=Pin(0), freq=200000)
print(i2c.scan())
# コマンド送信
def lcd_command(cmd):
i2c.writeto(LCD_ADDR, bytearray([0x00, cmd])) # 0x00 はコマンド送信
# データ送信
def lcd_data(data):
i2c.writeto(LCD_ADDR, bytearray([0x40, data])) # 0x40 はデータ送信
# LCD 初期化
def lcd_init():
time.sleep(0.05) # 電源投入後の待機
for cmd in [0x38, 0x39, 0x14, 0x70, 0x56, 0x6C]:
lcd_command(cmd)
time.sleep_ms(2)
time.sleep_ms(200)
for cmd in [0x38, 0x0C, 0x01]:
lcd_command(cmd)
time.sleep_ms(2)
# LCD に文字列を表示
def lcd_print(text):
for char in text:
lcd_data(ord(char)) # 1文字ずつ送信
# LCD 文字表示位置指定 col row
def set_cursor(col, row):
if row == 0:
address = 0x00 + col
elif row == 1:
address = 0x40 + col
else:
print("error")
lcd_command(0x80 | address) # Set DDRAM addre
time.sleep_ms(2)
# 実行 set_cursor(col,row) row は 0 か 1 です
lcd_init()
set_cursor(0,0)
lcd_print("Hello AQM1602")
set_cursor(0,1)
lcd_print("Hello ESC32-C6")
SoftI2Cのメリットと注意点
- 任意のGPIOが使える → ピン配置の自由度が高い
SoftI2Cはfreq=で通信速度を自由に指定可能- 通常は
100_000で十分ですが、表示が遅いと感じる場合は400_000を試す価値あり - 安定性と信号品質に注意しつつ調整を!
🟪 まとめ
XIAO ESP32C6は小型で高性能なマイコンですが、I2Cに関しては情報が少なく、
ハードI2Cではうまく動かせないという現実に直面しました。
今回のように、SoftI2Cを使うことも出来ますが、import machine でのESP32-C6の持つハードウェアI2Cコントローラを使うのがいいと思います。



