YU2TA7KA's BLOG ~take one step at a time~

派生開発、組み込み開発周りのこと。

【組込みRust】RustでM5Stamp C3U MateでHello, world!する

はじめに

インターフェース5月号の特集を写経して、Hello, world!をしました。ターゲット環境は雑誌と同じなのですが、ビルド環境が右往左往し、結局WSL2上でUbuntuを動作させました。構築する環境は、Rustの標準ライブラリstdを使った組込みRust開発環境となります。初手がLチカでなく、コンソールHello, Worldになるあたり、これまでのno_std環境とは一線を画します。

環境

ターゲット M5Stamp C3U Mate
OS Ubuntu 22.04.2 LTS

Ubuntu はWindows11のWSL2上で動作させています。

M5Stamp C3U Mate

ターゲットとなるM5Stamp C3U Mateの仕様は以下の通りです。なお、Stamp は大きさが切手サイズということに由来します。
M5Stamp C3U Mate — スイッチサイエンス

機能 パラメータ
ESP32-C3 32-bit RISC-V シングルコアプロセッサ(動作周波数160 MHz)
ストレージ 384 KB ROM、400 KB SRAM、8 KB RTC SRAM、4 MBフラッシュ
Wi-Fi 2.4 GHz(20 MHzおよび40 MHzチャンネル幅に両対応)、IEEE 802.11 b/g/n、最大150 Mbpsデータレート
Bluetooth Bluetooth 5、Bluetooth mesh、対応レート125 Kbps/500 Kbps/1 Mbps/2 Mbps
入力 5 V @ 500 mA
ヒューマンマシンインターフェース(HMI) 1 x プログラマブル物理ボタン、1 x リセットデバッグボタン、1 x プログラマブルRGB LED(SK6812)
USBインターフェース 1 x USB Type-C x1
アンテナタイプ 2.4 GHz 3Dアンテナ
ペリフェラル ADC、GPIO、SPI、UART、I2C、I2S、PWM、RMT、DMA、USBシリアルポート、TWAI
14 x I/O G0、G1、G3、G4、G5、G6、G7、G8、G9、G10、G18、G19、G20、G21
I/Oピッチ 2.54 mm
本体重量(1個) 3.8 g
本体サイズ 34 x 20 x 4.6 mm

環境構築

WSLでのUbuntu環境構築

WSL 開発環境の構築メモ - YU2TA7KA's BLOG ~take one step at a time~を参照ください。

必要なパッケージのインストール

# Cバインディング生成用ツールチェーン
$ sudo apt install llvm-dev libclang-dev clang
# その他必要なパッケージ(FAQより)
$ sudo apt install -y curl gcc ninja-build cmake libudev-dev python3 python3-pip libusb-1.0-0 libssl-dev pkg-config libtinfo5


FAQ記載内容より、パッケージを追加しています。

Rustの環境構築

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ rustup toolchain install nightly-2022-10-01
$ rustup component add rust-src --toolchain nightly-2022-10-01-x86_64-unknown-linux-gnu


クレートの追加

$ cargo install ldproxy
$ cargo install cargo-espflash


WSLでのUSBデバイス接続の環境設定

RustでLチカしてみた – JL1NIE Blog
USB デバイスを接続する | Microsoft Learn
を参考にさせていただきました。

WindowsにUSBIPD-WIN プロジェクトをインストールします

Releases · dorssel/usbipd-win · GitHubより、usbipd-win_2.4.1.msiをダウンロードして、インストールします。

LinuxにUSBIPツールとハードウェアデータベースをインストールします

$ sudo apt install linux-tools-generic hwdata
$ sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/*-generic/usbip 20


udev設定によりパーミッションを設定します

以下2つのファイル(99-esp32c3.rules, wsl.conf)を作成します。

SUBSYSTEM=="tty", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="303a", GROUP="plugdev", MODE="0666"


[boot]
command="service udev start"

ファイルを作成したら、wslを再起動し設定を反映させます。

> wsl --shutdown 
> wsl 


以上でWSLからUSBデバイスを接続する準備ができました。

USB デバイスを接続します

Windwos(PowerShell)側で接続デバイスをWSLへアタッチします。

>usbipd wsl list
BUSID  VID:PID    DEVICE                                                        STATE
1-3    303a:1001  USB Serial Device (COM4), USB JTAG/serial debug unit          Not attached
>usbipd wsl attach --busid 1-3


busidはlistコマンドで確認したものを読み替えて設定してください。
Ubuntu側でデバイスが接続できたことを確認します。

$ lsusb
Bus 001 Device 004: ID 303a:1001 Espressif USB JTAG/serial debug unit

以上でビルドに必要な環境構築が完了しました。

hello_c3のビルド

github.com
上記著者(tomoyuki-nakabayashi さん)のリポジトリより、コードをクローンし、ビルドします。

$ git clone https://github.com/tomoyuki-nakabayashi/interface202305-c3-std-rust.git
$ cd interface202305-c3-std-rust/hello_c3/
$ cargo espflash --release --monitor
New version of cargo-espflash is available: v2.0.0-rc.3

Serial port: /dev/ttyACM0
Connecting...

   Compiling hello_c3 v0.1.0 (/home/yu2ta7ka/Rust/test/interface202305-c3-std-rust/hello_c3)
    Building [=======================> ] 231/232: hello_c3(bin)
  Finished release [optimized] target(s) in 0.10s
Chip type:         ESP32-C3 (revision 3)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi
MAC address:       60:55:f9:57:af:50
App/part. size:    345872/1048576 bytes, 32.98%
[00:00:00] ########################################      12/12      segment 0x0
[00:00:00] ########################################       1/1       segment 0x8000
[00:00:04] ########################################     189/189     segment 0x10000
Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0xc (SPI_FAST_FLASH_BOOT)
Saved PC:0x4004c516
0x4004c516 - chip726_phyrom_version_num
    at ??:??
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x16bc
load:0x403ce000,len:0x930
0x403ce000 - _coredump_iram_end
    at ??:??
load:0x403d0000,len:0x2d28
0x403d0000 - _coredump_iram_end
    at ??:??
SHA-256 comparison failed:
Calculated: e0864179295788a9ce29d422d34452ba10da5c63d9e870f4a384c1a600fd027d
Expected: 67a0f3ec8f4ca3d7aca23d343e272c0c7cdb5e859bb472b6092704e126dac6be
Attempting to boot anyway...
entry 0x403ce000
0x403ce000 - _coredump_iram_end
    at ??:??
I (43) boot: ESP-IDF v4.4.1-dirty 2nd stage bootloader
I (43) boot: compile time 21:31:25
I (43) boot: chip revision: 3
I (45) boot.esp32c3: SPI Speed      : 80MHz
I (50) boot.esp32c3: SPI Mode       : DIO
I (54) boot.esp32c3: SPI Flash Size : 4MB
I (59) boot: Enabling RNG early entropy source...
I (65) boot: Partition Table:
I (68) boot: ## Label            Usage          Type ST Offset   Length
I (75) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (83) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (90) boot:  2 factory          factory app      00 00 00010000 00100000
I (98) boot: End of partition table
I (102) boot_comm: chip revision: 3, min. application chip revision: 0
I (109) esp_image: segment 0: paddr=00010020 vaddr=3c040020 size=0f280h ( 62080) map
I (127) esp_image: segment 1: paddr=0001f2a8 vaddr=3fc89a00 size=00d70h (  3440) load
I (128) esp_image: segment 2: paddr=00020020 vaddr=42000020 size=3a528h (238888) map
I (172) esp_image: segment 3: paddr=0005a550 vaddr=3fc8a770 size=00794h (  1940) load
I (173) esp_image: segment 4: paddr=0005acec vaddr=40380000 size=099e0h ( 39392) load
I (185) esp_image: segment 5: paddr=000646d4 vaddr=50000010 size=00010h (    16) load
I (189) boot: Loaded app from partition at offset 0x10000
I (192) boot: Disabling RNG early entropy source...
I (209) cpu_start: Pro cpu up.
I (217) cpu_start: Pro cpu start user code
I (217) cpu_start: cpu freq: 160000000
I (217) cpu_start: Application information:
I (220) cpu_start: Project name:     libespidf
I (225) cpu_start: App version:      1
I (230) cpu_start: Compile time:     May  3 2023 21:31:15
I (236) cpu_start: ELF file SHA256:  0000000000000000...
I (242) cpu_start: ESP-IDF:          v4.4.1-dirty
I (247) heap_init: Initializing. RAM available for dynamic allocation:
I (254) heap_init: At 3FC8BE30 len 000341D0 (208 KiB): DRAM
I (261) heap_init: At 3FCC0000 len 0001F060 (124 KiB): STACK/DRAM
I (267) heap_init: At 50000020 len 00001FE0 (7 KiB): RTCRAM
I (274) spi_flash: detected chip: generic
I (278) spi_flash: flash io: dio
I (283) sleep: Configure to isolate all GPIO pins in sleep state
I (289) sleep: Enable automatic switching of GPIO sleep configuration
I (296) cpu_start: Starting scheduler.
Hello, world!

無事にHello, world! できました!

トラブルシューティング

ここまでで、エラーなくHello, world! する手順を示しました。しかし、私が行ったときはいろいろトラブルがありましたので、以下参考として記します。

ビルドに時間がかかる。

エラーでは無いのですが、Hello, world! プログラムであっても初回のビルドに時間がかかります。ビルド中はむやみに中断せず、待つようにしましょう。時間がかかる理由は、ESP-IDF(C言語ライブラリ)をインストールしてビルドするなど、stdでHello, world!するためにいろいろやってくれているからです。詳細は特集記事を参照ください。

ラズベリーパイ4だとARMCPUのため、ビルドできない。

ビルドはx86_64のアーキテクチャである必要があります。しかし、ラズパイはarmv7アーキテクチャのため、不一致しており、ビルドができません。ビルド試行結果は以下になります。
ラズベリーパイ4での開発環境構築 · Issue #2 · tomoyuki-nakabayashi/interface202305-c3-std-rust · GitHub

udev設定を正しく行う。

udev設定方法を記述しましたが、これを忘れるとビルド後の実行時に「waiting for download」で停止してしまいます。
WSLでの環境構築 No.2 · Issue #4 · tomoyuki-nakabayashi/interface202305-c3-std-rust · GitHub

正誤表 & FAQ

リポジトリに記載されている、正誤表 & FAQも参考になると思います。
interface202305-c3-std-rust/correct.md at main · tomoyuki-nakabayashi/interface202305-c3-std-rust · GitHub

issues

リポジトリに記載されている、issuesも参考になると思います。
Issues · tomoyuki-nakabayashi/interface202305-c3-std-rust · GitHub

おわりに

以上で、Hello, world!完了です。ここがスタート地点で、std環境のクレート利用しつつデバイス制御などもやっていきたいと思います。また、本記事はHello, world!に必要なコマンドを並べた感じになっています。特集記事では、ビルドの裏側やHello, world!コードの解説などもあるので、そちらもご覧いただけると幸いです。