ESP32-C3 SuperMini 用 オリジナル CircuitPython をビルドする

# はじめに

<img width="300" alt="esp32-c3_super-mini.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/3485b29e-61ff-4db2-9b22-370e66942175.png" />


10個で 2,144円（送料込み）と安価な ESP32-C3 SuperMini を購入した。
[いくつかのタイプがある](https://tamanegi-digick.com/it/smc3/)ようだが、今回購入したものは、裏面に HW-466AB のプリントがあるもの。

```terminal:ボード情報
% esptool.py --chip auto --port /dev/cu.usbmodem1201 flash_id
esptool.py v4.8.1
Serial port /dev/cu.usbmodem1201
Connecting...
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (QFN32) (revision v0.4)
Features: WiFi, BLE, Embedded Flash 4MB (XMC)
Crystal is 40MHz
MAC: aa:bb:cc:xx:yy:zz
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...
```

<br>[`Maker Go ESP32-C3 SuperMini`](https://circuitpython.org/board/makergo_esp32c3_supermini/)向けの [CircuitPython](https://circuitpython.org) が提供されており、ピンアサインが同じため そのままこのボードで使用できます。

今回は、購入した ESP32-C3 SuperMini に 4つのボタンと 1つのフルカラーLEDを 追加した オリジナルボード 向けに CircuitPython をビルドします。


# 0. ビルド 環境準備

CircuitPythonをクローンして、esp-idf環境をセットアップ

```s
cd /path/to/you
git clone https://github.com/adafruit/circuitpython.git
cd circuitpython
git checkout main # or git checkout 9.2.7
cd ports/espressif
make fetch-port-submodules

esp-idf/install.sh
source esp-idf/export.sh
cd ../..
pip install --upgrade -r requirements-dev.txt
pip install --upgrade -r requirements-doc.txt
```



# 1. ピンアサイン

オリジナルボード の ピンアサイン は次のとおり。

✅オリジナル仕様

| Pin | Analog | Peripheral | PWM | Function |
|:-:|:-:|:-:|:-:|:-:|
| 5V  |   |   |   |   |
| GND  |   |   |   |   |
| 3V3  |   |   |   |   |
| 4  | A4  | SCK  | ○  | ✅RGBLED  |
| 3  | A3  |   | ○  | ✅SW2  |
| 2  | A2  |   | ○  | ✅SW4  |
| 1  | A1  |   | ○  | ✅SW1  |
| 0  | A0  |   | ○  | ✅SW3  |
| 5  | A5  | MISO  | ○  |   |
| 6  |   | MOSI  | ○  |   |
| 7  |   | SS  | ○  |   |
| 8  |   | SDA  | ○  | LED  |
| 9  |   | SCL  | ○  | BOOT0 /<br>BUTTON |
| 10  |   |   | ○  |   |
| 20  |   | RXD  | ○  |   |
| 21  |   | TXD  | ○  |   |



# 2. オリジナル ボード を定義

### 2.1 前提

ターミナルを起動し[`circuitpython.git`](https://github.com/adafruit/circuitpython)をクローンしたディレクトリに移動しておく。

```terminal
% cd /path/to/you/circuitpython
```

### 2.2 流用ボードをコピー

`Maker Go ESP32-C3 SuperMini`を流用します。
オリジナルボードの名前を`nak435_esp32c3_supermini`としました。

```terminal
circuitpython % cd ports/espressif/boards

boards % cp -r makergo_esp32c3_supermini nak435_esp32c3_supermini 
```

_ちなみに、`Maker Go ESP32-C3 SuperMini`ボードをサポートしたのは、`CircuitPython 9.1.0-beta.0`からのようです。[#9131](https://github.com/adafruit/circuitpython/pull/9131)_



### 2.3 ファイルの修正

コピーしたディレクトリにある、次の2つのファイルに変更を加えます。

- mpconfigboard.h（ボード名の変更）
- pins.c（ピン定義の追加）
- mpconfigboard.mk（インクルード ライブラリの追加）

```diff_c:nak435_esp32c3_supermini/mpconfigboard.h
- #define MICROPY_HW_BOARD_NAME       "Maker Go ESP32C3 Supermini"
+ #define MICROPY_HW_BOARD_NAME       "nak435 ESP32-C3 Supermini"
  #define MICROPY_HW_MCU_NAME         "ESP32-C3"
```

```diff_c:nak435_esp32c3_supermini/pins.c
    // LED
    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO8) },
+   // RGB
+   { MP_ROM_QSTR(MP_QSTR_RGB), MP_ROM_PTR(&pin_GPIO4) },
    
    // SPI
    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO4) },

 （中略）
    
    // Button
    { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO9) },
    { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO9) },
   
+   { MP_ROM_QSTR(MP_QSTR_SW1), MP_ROM_PTR(&pin_GPIO1) },
+   { MP_ROM_QSTR(MP_QSTR_SW2), MP_ROM_PTR(&pin_GPIO3) },
+   { MP_ROM_QSTR(MP_QSTR_SW3), MP_ROM_PTR(&pin_GPIO0) },
+   { MP_ROM_QSTR(MP_QSTR_SW4), MP_ROM_PTR(&pin_GPIO2) },
```

_`MP_QSTR_XXX`の`XXX`部分がピン名称として定義されます。この文字列定義はビルドプロセスにおいて自動生成されるため、`XXX`部分には任意の識別子を指定することができます。_


```diff_c:nak435_esp32c3_supermini/mpconfigboard.mk
  CIRCUITPY_ESP_USB_SERIAL_JTAG = 1

+ # Include these Python libraries in firmware.
+ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
+ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Ticks
```



### 2.4 ビルド

流用して作成したオリジナルボードの CircuitPython をビルドします。

```terminal
boards % cd ..
espressif % make -j8 BOARD=nak435_esp32c3_supermini 
#数分待つ
espressif % find . -name "firmware.bin" 
./build-nak435_esp32c3_supermini/firmware.bin
```

_初回のビルドにおいては、1000本近いファイルが生成/コンパイルされるため、数分要します。_



# 3. ESP32-C3 SuperMini に焼く

さっそく ビルドできた ファームウェア`firmware.bin`を焼きます。

```terminal
espressif % esptool.py --chip esp32c3 --port /dev/cu.usbmodem1201 write_flash 0 ./build-nak435_esp32c3_supermini/firmware.bin 
esptool.py v4.8.1
Serial port /dev/cu.usbmodem1201
Connecting...
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (QFN32) (revision v0.4)
Features: WiFi, BLE, Embedded Flash 4MB (XMC)
Crystal is 40MHz
MAC: 94:a9:90:52:91:1c
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x0016efff...
Compressed 1501264 bytes to 942459...
Wrote 1501264 bytes (942459 compressed) at 0x00000000 in 11.4 seconds (effective 1057.8 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
```

<br>REPL から バージョン他、諸々を確認します。

```python
espressif % screen /dev/cu.usbmodem1201 115200

>>> (Ctrl+D)
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Hello World!

Code done running.

Press any key to enter the REPL. Use CTRL-D to reload.
(enter)

Adafruit CircuitPython 10.0.0-alpha.4-2-g9819e7a1bf on 2025-05-08; nak435 ESP32-C3 Supermini with ESP32-C3
>>> import board
>>> dir(board)
['__class__', '__name__', 'BOOT0', 'BUTTON', 'I2C', 'IO0', 'IO1', 'IO10', 'IO2', 'IO20', 'IO21', 'IO3', 'IO4', 'IO5', 'IO6', 'IO7', 'IO8', 'IO9', 'LED', 'MISO', 'MOSI', 'RGB', 'RX', 'SCK', 'SCL', 'SDA', 'SPI', 'SW1', 'SW2', 'SW3', 'SW4', 'TX', 'UART', '__dict__', 'board_id']
>>> board.RGB
board.IO4
>>> board.SW1
board.IO10
>>> board.SW2
board.IO6
>>> board.SW3
board.IO7
>>> board.SW4
board.IO3

>>> import os
>>> os.listdir()
['sd', 'settings.toml', 'code.py', 'lib', 'boot_out.txt']

>>> f=open('boot_out.txt','r')
>>> print(f.read())
Adafruit CircuitPython 10.0.0-alpha.4-2-g9819e7a1bf on 2025-05-08; nak435 ESP32-C3 Supermini with ESP32-C3
Board ID:nak435_esp32c3_supermini
UID:499A092519C1
MAC:06:00:00:00:BE:F4

>>> f.close()

>>> import gc
>>> print(gc.mem_free())
120784

>>> (Ctrl+A Ctrl+K) 
Really kill this window [y/n] y

[screen is terminating]
```

期待通り ピンの定義が追加されています。

最新ソースをクローンしたので、バージョンは[プレリリース版の`10.0.0-alpha.4`](https://github.com/adafruit/circuitpython/releases/tag/10.0.0-alpha.4)より新しい `10.0.0-alpha.4-2`でした。

[最終リリース版の`9.2.7`](https://github.com/adafruit/circuitpython/releases/tag/9.2.7)を作るなら、クローン時に`git checkout 9.2.7`すればよいでしょう。<br>　


_空きメモリは 120KB弱。あまり大きなコードは作れないかも。使わないライブラリをバンドルから削除して、空きを増やすしかないか。_


# 4. オリジナルボード

<img width="133" alt="back.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/73017311-27f3-49e4-9a6f-44e09f68cac0.png" />

<img width="161" alt="front.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/f86028e7-3c62-4bbe-bd28-b44a5351ff12.png" />

いい感じに実装できました。

<img width="300" alt="IMG_4541.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b0d5ccb1-4605-49dd-8e09-f36b01ba6de0.png" />

<img width="300" alt="IMG_4543.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/41d4e764-dcd3-4ecb-b5f7-4a40249b5805.png" />



# 5. 本当は、

オリジナル CircuitPython をビルドしたのは、`_bleio`をバンドルライブラリに追加するのが目的でした。 _標準では `ESP32-C3`向けの CircuitPython は、BLE が使用できない設定になっています。_ 
フラッシュが4MBと少ないことが理由だと思いますが、`sdkconfig`に`CIRCUITPY_BLEIO_NATIVE=1`を追加し、パーティションテーブルを変更してビルドすることで、`_bleio`をバンドルできました。しかし、次のエラーとなり CircuitPythonが安定しません。

```
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
```

```text:Thonnyにて実行
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xd (SPI_FAST_FLASH_BOOT)
Saved PC:0x40382be0
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd5820,len:0x78
load:0x403cc710,len:0x848
load:0x403ce710,len:0x20b8
entry 0x403cc710

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
Please file an issue with your program at github.com/adafruit/circuitpython/issues.
Press reset to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.

Adafruit CircuitPython 10.0.0-alpha.4-2-g9819e7a1bf on 2025-05-08; nak435 ESP32-C3 Supermini with ESP32-C3
>>> 
>>> 
PROBLEM IN THONNY'S BACK-END: Internal error (thonny.plugins.micropython.mp_back.ManagementError: Command output was not empty).
See Thonny's backend.log for more info.
You may need to press "Stop/Restart" or hard-reset your CircuitPython device and try again.


Process ended with exit code 0.
```

原因究明には時間がかかりそうです。


```text:circuitpython/ports/espressif/boards/nak435_esp32c3_supermini/sdkconfig
#
# Espressif IoT Development Framework Configuration
#
#
# Component config
#
#
#
# Partition Table
#
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-4MB-no-uf2-2.csv"
CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-uf2-2.csv"
# end of Partition Table
#
# LWIP
#
# end of LWIP

# end of Component config

# end of Espressif IoT Development Framework Configuration
```

```text:circuitpython/ports/espressif/boards/nak435_esp32c3_supermini/mpconfigboard.mk
CIRCUITPY_CREATOR_ID =  0x19981000
CIRCUITPY_CREATION_ID = 0x00BB0001

IDF_TARGET = esp32c3

CIRCUITPY_ESP_FLASH_MODE=dio
CIRCUITPY_ESP_FLASH_FREQ=80m
CIRCUITPY_ESP_FLASH_SIZE=4MB


CIRCUITPY_BLEIO_NATIVE = 1


CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1

CIRCUITPY_ESP_USB_SERIAL_JTAG = 1
```

```csv:circuitpython/ports/espressif/esp-idf-config/partitions-4MB-no-uf2-2.csv
# Name,             Type,   SubType,    Offset,     Size
# bootloader,       app,    boot,       0x1000/0x0, 28/32K
# partition_table,  data,   table,      0x8000,     4K
nvs,                data,   nvs,        0x9000,     20K
otadata,            data,   ota,        0xe000,     8K
ota_0,              app,    ota_0,      0x10000,    1664K
ota_1,              app,    ota_1,      0x1B0000,   1024K
user_fs,            data,   fat,        0x2B0000,   1344K
```

<br>`ESP32-S3`の`4MBフラッシュ版`ではこの方法でBLEが使えるようになったので、`ESP32-C3`は何か別な制約があるのかも??・・・

その後もいろいろ試していたところ、`code.py`を削除すると、ターミナルから`screen`コマンドで接続すると、エラーが起きずにREPLが起動しました。_`Thonny`では相変わらずエラーで動かないが・・・_

```python
% screen /dev/cu.usbmodem1201 115200

Adafruit CircuitPython 10.0.0-alpha.4-2-g9819e7a1bf on 2025-05-08; nak435 ESP32-C3 Supermini with ESP32-C3
>>>
>>>
>>> import microcontroller
>>> microcontroller.reset()
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xd (SPI_FAST_FLASH_BOOT)
Saved PC:0x40382be0
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd5820,len:0x78
load:0x403cc710,len:0x848
load:0x403ce710,len:0x20b8
entry 0x403cc710

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Code done running.

Press any key to enter the REPL. Use CTRL-D to reload.

Adafruit CircuitPython 10.0.0-alpha.4-2-g9819e7a1bf on 2025-05-08; nak435 ESP32-C3 Supermini with ESP32-C3
>>> help('modules')
__future__        codeop            max3421e          synthio
__main__          collections       mdns              sys
_asyncio          digitalio         microcontroller   terminalio
_bleio            displayio         micropython       tilepalettemapper
_pixelmap         dualbank          msgpack           time
adafruit_bus_device                 epaperdisplay     neopixel_write    touchio
adafruit_bus_device.i2c_device      errno             nvm               traceback
adafruit_bus_device.spi_device      espidf            onewireio         ulab
adafruit_pixelbuf espnow            os                ulab.numpy
analogbufio       fontio            ps2io             ulab.numpy.fft
analogio          fourwire          pulseio           ulab.numpy.linalg
array             framebufferio     pwmio             ulab.scipy
atexit            gc                rainbowio         ulab.scipy.linalg
audiobusio        getpass           random            ulab.scipy.optimize
audiocore         gifio             re                ulab.scipy.signal
audiomixer        hashlib           rgbmatrix         ulab.scipy.special
audiomp3          i2cdisplaybus     rtc               ulab.utils
binascii          io                sdcardio          usb
bitbangio         ipaddress         select            usb.core
bitmaptools       jpegio            sharpdisplay      usb.util
board             json              socketpool        vectorio
builtins          keypad            ssl               warnings
busdisplay        locale            storage           watchdog
busio             lvfontio          struct            wifi
canio             math              supervisor        zlib
Plus any modules on the filesystem

>>> import _bleio
>>> 
```

[`WebRepl`](https://learn.adafruit.com/circuitpython-with-esp32-quick-start/setting-up-web-workflow) で接続することもできましたが、やはりエラーになります。

![webrepl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/5170cb6a-3e02-48ec-a370-08984f78eecf.png)



継続調査が必要・・・

---

Micropython や Arduino であれば、普通に BLE が使えるので、とりあえず 困っていませんが。。。

<br><br><br>

**以上**