ORANGE-ESPerで、MicroPython + FabGLを実現 ~ FabGLのESP-IDFへのポーティング
2021.04.30
①ESP-IDFの"hello_world_main.c"にAnsi-Terminalを追加
まず、FabGLライブラリの配置です。ESP-IDFでは、ソースツリーに"components"というサブディレクトリを配置すると、自動的に"CMakeLists.txt"をスキャンしてビルドの対象にしてくれます。
+hello_world
+components
| +fabgl
| +arduino ESP32用Arduinoライブラリ
| +cores Arduinoコアライブラリ
| +libraries Arduinoオプションライブラリ
| +variants ボード依存ヘッダー
| +src FabGLライブラリ
| +CMakeLists.txt ビルド用スクリプト
+main メインプログラム

次に、CMakeLists.txtの記述です。
Ansi-Terminalが必要とする最低限のモジュールを順番にビルド対象にしていきます。コンパイルン時にヘッダーファイルが見つからない場合は、ヘッダーパスを追加し、エラーを解消していきます。ただ、ESP-IDFのバージョンが異なるため、ヘッダーファイルの内容が変更されている部分があるため、未定義の型・マクロの定義部分を見つけてソースコードを変更していきます。

コンパイルエラーを解消後、リンカーで未定義変数・関数が出てきますので、対象ライブラリを追加すると、CMakeLists.txtが完成します。この段階で、必要に応じコンパイラ・リンカーのオプションを追加します。

リンクが完了し、バイナリイメージをESP32に焼いて実行できるようになりました。Arduinoと同じVGA画面が表示でき、ホットしたのもつかの間、設定変更のダイアログを終了させると、"Guru Meditation Error"で落ちてしまいます。Arduinoでは、何ら問題ありませんでした。

Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400eb927 PS : 0x00060f30 A0 : 0x800ea9a2 A1 : 0x3ffebd90
A2 : 0xfefefefe A3 : 0x3ffebdc5 A4 : 0x00000000 A5 : 0x00000000
A6 : 0xffffffff A7 : 0x3ffed290 A8 : 0x80082d08 A9 : 0x3ffebd50
A10 : 0x3ffe3efc A11 : 0x00000000 A12 : 0x3ffb7028 A13 : 0x00000000
A14 : 0x00000000 A15 : 0x00060023 SAR : 0x00000008 EXCCAUSE: 0x0000001c
EXCVADDR: 0xfefeff3a LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000

ELF file SHA256: 1e6c549e1a65be00

Backtrace: 0x400eb927:0x3ffebd90 0x400ea99f:0x3ffebdc0 0x400d3492:0x3ffebdf0
0x400d3616:0x3ffebe10 0x401163e9:0x3ffebe30 0x400f5b99:0x3ffebe50 0x40088bb6:0x3ffebe90

バックトレースアドレス・リンカーマップの確認、ログ追加で問題個所を特定はできました。通常問題なく通過していますが、問題がある場合、途中で落ちてしまいます。ESP32マイクロコントローラでは、命令RAMは、書き込み保護が掛かっているので、プログラムの破壊がなくても落ちてしまったわけです。

ESP32について調べていくと、例外が発生した場合には、対象アドレスが、EXCVADDRに表示される仕組みになっているので、NULLポインター・未確保ヒープ・解放済ヒープなのか切り分けができるようです。下記のオプションで有効になります。

Heap memory debugging --->
Heap corruption detection (Comprehensive) --->

前記の例では、"EXCVADDR: 0xfefeff3a"でしたので、解放済ヒープでの値"0xfefefefe"に近い値で、このアドレスに対するオフセットで変数をアクセスしていることが想定できました。

ソースコードから、問題となったクラス変数ポインターが特定できました。そのクラスの生成・消滅を追っかけると、ダイアログの消去処理中に消滅が起こりえる部分を見つけました。わずかなタスク実行タイミングの差で発生する潜在バグでると考えられます。完全な修正ではないですが、回避できるタイミングで対象クラスの消滅を行うように変更しました。

これで、FabGLライブラリをESP-IDF上に移植できました。

②MicroPythonのソースツリーへの組込みとビルド
"hello_world"の場合と同様に、micropython/portの配下にFabGLライブラリを移行します。MicroPpythonのメインプログラム"main.c'から、MicroPpythonを開始する前にFabGLを初期化しておくようしました。MicroPpythonは、最大確保可能なヒープをMicroPpythonのヒープに割り当てますので、起動前に一時的なヒープの使用を終わらせておきます。"AnsiTerminal.ino.cpp"を変更し"fabgl_setup.cpp"を作成します。Ansi-Terminalの設定ダイアログを閉じると、MicroPpythonを起動させるシーケンスにします。
+esp32
+components
| +fabgl
| +arduino ESP32用Arduinoライブラリ
| +cores Arduinoコアライブラリ
| +libraries Arduinoオプションライブラリ
| +variants ボード依存ヘッダー
| +src FabGLライブラリ
| +CMakeLists.txt ビルド用スクリプト
+main メインプログラム
 +modules 追加のMicroPythonモジュール

MicroPythonとFabGLの統合に合わせて"CMakeLists.txt"を変更して、ビルドしたところ、partitionのサイズが足らなくなったので、"partitions.csv"変更して、なんとか動作させることができました。但し、この段階では、MicroPpythonは、USBシリアル経由のみの動作です。

③MicroPythonの入出力をFabGL Ansi-Terminalに接続
MicroPythonにUSB-Serial(RX)とAnsi-Terminal(Keyboard)のどちらからでも入力できるようにします。MicroPythonからは、USB-Serial(TX)とAnsi-Terminal(VGA Display)へ出力させます。これで、マルチターミナルになり、どちらからも透過的に使用できます。TeraTermがなくても、Ansi-Terminalで、Micropythonパソコンになります。

USB-Serial(RX) -+-> MicroPython -+-> USB-Serial(TX)
| |
Ansi-Terminal(Keyboard) +-> Ansi-Terminal(VGA Display)

"mphalport.c"を変更して、上記を実現しました。ただ1点、スクリーンエディタなどで、Ansi-Terminalからのレポート情報を取得する"ESC [ 5 n"と"ESC [ 6 n"のエスケープシーケンスがあることがわかりました。両方にこのシーケンスを送ると、双方からレスポンスがあり、混信してしまいます。そのため、このエスケープシーケンスをUSB-Serial(TX)へ送らないようにブロックする機能を追加しました。

以上、全体をビルドしました。下記は起動画面です。FabGL Ansi-Terminalの設定ダイアログが出ますが、変更が無ければ、"Enter"でMicroPythonが起動します。


MicroPythonが起動した画面です。


かんぱぱさんのasciiartを動かしてみました。PC上のTeraTermとVGAモニタが同じ表示になります。

2021.04.30 23:26 | 固定リンク | MicroPython + FabGL
ORANGE-ESPerで、MicroPython + FabGLを実現 ~ 準備編
2021.04.29
①MicroPythonとFabGL
MicroPythonは、幅広い組込みマイコンで手軽にプログラミング可能な言語処理系です。今回ターゲットにしたESP32は、上海のEspressif Systems社から販売されている、米国のTensilica社の240MHz Xtensa LX6 dual CPUを搭載した普及価格のIoT用マイクロコントローラです。IoT用ですので、Bluetooth、WiFiなど機能も搭載されて、Micropythonから利用できます。

一方、ORANGE-ESPerは、ESP32-WROOM-32モジュールを搭載したESP32-DevKitC開発ボードを利用してVGAモニタ・キーボード・マウス・SDカードを接続でき、ESP32用Arudino上のFabGLライブラリを利用したライブラリ付属の懐かしいアプリケーションが楽しめます。
このFabGLライブラリは、イタリアのFabrizio Di Vittorioさんが開発し、SPI+DMAでVGAビデオ信号を生成させ、IoT用マイクロコントローラをパソコンのように使えるようにした点が光ります。

また、ORANGE-ESPer発売元のピコソフト社からORANGE-OSも公開されていますが、アプリケーションは、限られています。そこで、今回は、ORANGE-ESPerで、Micropythonパソコンにチャレンジすることにしました。PCのTeraTermとORANGE-ESPerのキーボード+VGAモニタ双方からMicroPythonを使えるようにしたいと考えています。

②Windows10上でMicroPythonのビルド
MicroPythonのビルドには、ESP-IDF開発環境が必要になります。まず ESP-IDF Tools Installer for Windows(V2.5)をインストール後、適当なディレクトリにMicroPythonをgithubからcloneします。ESP-IDFは、V4.2がインストールされ、MicroPythonは、V1.14でした。
早速、esp32用のビルドを行うと、Linuxのcatコマンドが無いため、ビルドエラーで先に進めることができませんでした。みなさん、Linuxでビルドしているみたいです。(涙)

Windows10で、VM上にLinuxをインストールしたことはありますが、今回のビルドのためにLinux全体の機能を管理するのも大変ですので、今回は、Linuxをお手軽なWindows Subsystem for LinuxのUbuntuを選択しました。利点は、Windows配下のファイルシステムを共用できるので、慣れたWindows用のツールが利用できる点が優れています。ただし、Windowsからファイルを書き込むと、Linuxのパーミッションがリセットされる点がありますので、注意が必要になります。

下記が、Windows Subsystem for LinuxのUbuntuインストール後の手順です。

sudo apt update && sudo apt upgrade
sudo apt update
sudo apt install \
gcc git wget make libncurses-dev flex bison gperf \
libffi-dev libssl-dev

cd
mkdir esp32
cd esp32
git clone --recursive https://github.com/micropython/micropython
git clone -b v4.2 --recursive https://github.com/espressif/esp-idf.git
git submodule update --init --recursive

cd /usr/bin
sudo ln -s /usr/bin/python3 python

cd
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
python get-pip.py
sudo apt install cmake

cd ~/esp32/esp-idf
./install.sh

. ~/esp32/esp-idf/export.sh

cd ~/esp32/micropython/mpy-cross
make mpy-cross

cd ~/esp32/micropython/port/esp32
idf.py build

無事、MicroPythonのビルドに成功しました。WSLでは、CPUコアの割り当てが少ないようで、Windows上のESP-IDFに比べると遅い点が気になりますが、仕方がありません。

ORANGE-ESPerで、無事にMicroPythonのプロンプトが表示できました。ちなみに、MicroPythonの空きヒープサイズは、99KB程度でした。

③ESP32用のAruduino上で、FabGLのAnsi-Terminalサンプルプログラムをビルド
Arduino V1.8.10にesp32 V1.0.6ボードマネージャと、FabGL V1.0.2ライブラリを追加し、FabGL付属のAnsiTerminalサンプルプログラムをビルド後、無事、VGA画面が立ち上がりました。



次に、ESP-IDF V4.2上で、Ansi-Terminalサンプルプログラムをビルドできる必要があります。esp32 V1.0.6ボードマネージャは、ESP-IDF V3.3.5ベースのようですので、V4.2に適合させることができれば、FabGLライブラリをMicroPythonのソースコードと統合できるはずです。
2021.04.29 15:11 | 固定リンク | MicroPython + FabGL

- CafeNote -