はじめに
M5NanoC6、小さいのに高機能でとても魅力的なパッケージですよね!M5社製品あるあるですが、使い道が決まる前に反射神経でスイッチサイエンスさんで購入していました(笑)。久しぶりにArduino IDEと格闘するか~と思っていたのですが、ふとCircuitPythonのサイトを見るとesp32c6_devkitのファームウェアがあったので、これで動くかどうか試したところうまく動いたので紹介しておきます。
M5NanoC6のIRからNEC IR信号をM5AtomS3+IRに送信して表示するの図
方針
まずesp32c6のUSBはJTAGのみで、USB Storageにできません。また、Bluetoothは搭載しているもののCircuitPython側がesp32c6のBLEに対応していません。よって接続方法は、WIFI接続によるWebワークフロー一択となります。WIFI接続は多少不安定なところがあり、最初は心配になりますが、慣れるとリトライのタイミングとかが分かってきてむしろ超絶便利なので頑張って設定していきましょう(といっても大した手間ではないです)。
CircuitPythonのダウンロード
ESP32-C6のフラッシュ4MBなので、以下をダウンロードします
https://circuitpython.org/board/espressif_esp32c6_devkitm_1_n4/
9.0.xでも動いていましたが、より新しいESP-IDFに対応している9.1.x系で試しています。
ファームウェア書き込み
ファームウェア書き込みモードとして起動するには、ボタンを押しながらUSB-Cを接続します。esptoolを使ってダウンロードした.binファイルを書き込みます。
.\esptool.exe --chip esp32c6 --port COM6 --baud 115200 --before default_reset --after hard_reset --no-stub write_flash --flash_mode dio 0x0 .\adafruit-circuitpython-espressif_esp32c6_devkitm_1_n4-en_US-9.1.0-beta0.bin
ちなみにブラウザからの書き込みツールはChip ID未登録でできないようです。
WIFI APの設定
基本となるドキュメントはこちらになります。
USBシリアルで接続します。もし見つからなかったら、Arduino IDE でUSB CDC on BootをOnにしてみてください。接続できたらREPLから以下のようにPythonでsettings.tomlというファイルを作成するスクリプトを実行します(複数行まとめてコピペして大丈夫です)。
f = open('settings.toml', 'w')
f.write('CIRCUITPY_WIFI_SSID = "ssid"\n')
f.write('CIRCUITPY_WIFI_PASSWORD = "password"\n')
f.write('CIRCUITPY_WEB_API_PASSWORD = "webpassword"\n')
f.close()
無事書き込んだらリセット(抜き差し)して、APに接続されるか確認しましょう。
オンラインエディタの起動
http://circuitpython.local/code/ をブラウザで表示すると、ローカルネットワークからマイコンを探し出して接続できます。
ESP32-C6特有の現象かは分かりませんが、以下のケースで何回かリトライが必要なことがあります。
- マイコン検出しない: ブラウザのタブ閉じてリロード
- ファイル保存でヘビぐるぐるのままになる: ブラウザのタブ閉じてリロード(実際は保存が完了していることが多いです)
- ファイル保存後、プログラムの実行が止まったように見える: エディタで止まっているように見えるのか、本当に止まっているのかは切り分けられませんでしたが、このようになったらSave+Runを押してみてください
また、他のマイコンよりコンパイルの時間が少し長い(10秒弱)気がしますので、保存後すぐ動作しなくても、少し待ってみてください。
PIN定義
espressif_esp32c6_devkitm_1_n4 のピン定義は以下のようになります。M5NanoC6で引っ張られていない端子もありますので、仕様を確認し、使用できる端子をアサインします。
GROVEを使う場合はIO1/IO2になります。
BUTTON IO0 IO1 IO10
IO18 IO19 IO2 IO20
IO21 IO3 IO4 IO5
IO6 IO7 IO8 IO9
MTCK MTDI MTDO MTMS
NEOPIXEL RX TX UART
__dict__ board_id
※上記はimport boardして "board."→"タブ"で表示されます。
エイリアスがついている端子は以下のような関係になります。
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO8) },
Lチカ
ボタンでLチカです。単純なIO7のLEDを使用しています。
import time
import board
import digitalio
button = digitalio.DigitalInOut(board.IO9) # デフォルトでは入力
button.pull = digitalio.Pull.UP # 内部のプルアップ抵抗を有効化する
led = DigitalInOut(board.IO7)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = not (button.value) # False == ボタンが押された
time.sleep(0.2)
Neopixelチカ
neopixel_writeの点灯です。
import time
import board
import neopixel_write
import digitalio
ledpwr = digitalio.DigitalInOut(board.IO19)
ledpwr.direction = digitalio.Direction.OUTPUT
ledpwr.value = True
led = digitalio.DigitalInOut(board.IO20)
led.direction = digitalio.Direction.OUTPUT
neopixel_write.neopixel_write(led, bytearray([0, 0, 0])) #消灯初期化
time.sleep(0.1)
neopixel_write.neopixel_write(led, bytearray([0, 128, 128])) #紫
time.sleep(1)
neopixel_write.neopixel_write(led, bytearray([0, 0, 0])) #消灯
Lチカ+IR送信
ボタンを押すとLEDが光ったのち東芝のテレビの電源ボタンのIR送信をするコードも試してみました。実はIR送信周りは盛大にハマっていて、Adafruit_CircuitPython_IRRemoteライブラリに色々修正のPRをmergeしてもらいました。
動作を試してみましたが、カタログ値通り(直線で5m)M5Atomの時より圧倒的に遠くまで信号が届くようで、SmartHome向けにはかなり良い選択になりそうです!
import time
import board
import gc
import digitalio
import pulseio
import adafruit_irremote
button = digitalio.DigitalInOut(board.IO9) # Default in
button.pull = digitalio.Pull.UP # enable pull up resistor
led = digitalio.DigitalInOut(board.IO7)
led.direction = digitalio.Direction.OUTPUT
# Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz
pulseout = pulseio.PulseOut(board.IO3, frequency=38000, duty_cycle=22000)
# Create an encoder that will take numbers and turn them into NEC IR pulses
low = 560
high = 1700
encoder = adafruit_irremote.GenericTransmit(
header=[9000, 4500], one=[low, high], zero=[low, low], trail=low
)
while True:
if not button.value:
led.value = True
print(f"{button.value} {gc.mem_free()}")
encoder.transmit(pulseout, [0x02, 0xFD, 0x48, 0xB7])
time.sleep(0.5)
led.value = False
time.sleep(0.25)
メモリが気になっていたので残メモリ出していますが、特にこのコードレベルなら厳しくはなさそうでした。
さいごに
超小型サイズなのに必要な機能を備えOTAでファームウェア更新できるM5NanoC6は、マイコン選定時に有力なオプションになりそうです。すこしづつCircuitPythonのいろいろな機能をM5NanoC6上で試していきたいと思います。