M5Stack Core２+ Zephyr OSでSlintを動かしたい

# はじめに
　メリークリスマスイブ、ごきげんよう。[スリントアドベントカレンダー](https://qiita.com/advent-calendar/2024/slint)も残り2日になりましたね。
　昨日は、@rarirure さんによる「[RustとSlintで作る動的棒グラフ・ゲージチャート](https://qiita.com/rarirure/items/f1559f5d2ec3ccd98b04)」でした。no_stdな環境とか、softwareレンダラーな環境だとPATHも使えないのですよね。記事ではsoftwareレンダラーを使って苦労されたようですが、それでもちゃんとあるものの組み合わせできちんと実現されています。素晴らしいです。
　はやく下回りが完備されて、もっと手軽に実現できるようになるといいのですが、Rustの勉強をもっとしてSlint開発も手伝えるようになりたいものですねぇ。来年はライフワークとして頑張って下回り追いかけるか‥。Zephyrも勉強したいのだけど、やりたいことの多さに比べて自由な時間が少ないこと。困ったものです。

## 本日のお題
　SlintはZephyr OSでの動作実績もあります。というわけで、Zephyrでも動かして展示したいよねって先月急遽手を出したのですが、M5Stack Core2上でZephyrを動かすまではすんなりでしたが、PSRAMを認識させてスタックとして割り振るのがうまく行かずに悩んでまして。まぁ、終わったあともESP32のドキュメントを斜め読みしたりとか時間のあるときに見てたのですが、うまく行かなかったので、うまく行かなかった挫折日記です。誰か詳しい人ヘルプミー。まぁ、僕はクリスマスに挫折続きな人生なのでちょうど良い記事とも言えるのですが。
 　
# Slintとは
　[Slint-スリント](https://slint.dev/)は、ドイツのSixtyFPS GmbH社が開発しているRust製のクロスプラットフォーム向けGUIフレームワークです。
　独自のGUI向け宣言型言語を提供しており、GUI開発言語としてRust, C++, JavaScript, Python用に提供されたランタイムとコンパイラ（一部はインタプリタ）とともに利用することでGUIアプリケーションを作成できます。
　ベアメタルでならRaspberry Pi PicoのようなMCU(CPU: ARM Cortex M0+ 133MHz, SRAM:256KB)でも動作できるほど軽量なフレームワークとなっています。

　詳しい説明は、@task_jpさんの「[GUI フレームワーク Slint の紹介](https://qiita.com/task_jp/items/5e76f66366673d46afcd)」を参照してください。

# Zephyr OSとは
　[Zephyr OS](https://zephyrproject.org/)は、世界的にはかなり注目度の上がっているMCU向けの軽量RTOSです。mixi2でzephyr osコミュニティを立ち上げた[Katsuhiro Suzukiさん](https://x.com/ksattkb?lang=ja)の[ZephyrOSで遊ぼう](https://www.katsuster.net/index.php?arg_act=cmd_show_diary&arg_date=20200222)あたりは、実際色々手をうごかされていて非常に参考になります。[CRSさん](https://x.com/crs)もあちこちで布教されている[^1][^2][^3][^4]ようですし、日本でも少しずつ注目が集まってきておりQiitaのタグだけでも92件の記事が確認できました。カワサキバイク好き[^5]以外の日本人にはスペルが難しすぎる[^6]からかなかなか話題にあがらないものの、これから先が期待されているRTOSです。
　元はWindRiver Rocketの名前で知られたWindRiver社のMCU向けRTOS kernelがベースになっています。組込業界にいないと馴染みが薄いかもしれませんが、[WindRiver社](https://www.windriver.com/)はVxWorksというRTOSで著名な会社です。VxWorksは航空・自動運転・衛生・ロケット関係など特にリアルタイム性が重要な部分でよく利用されています。Linux Foundationのメンバーでもあり、Linuxカーネル開発や特にYoctoへの貢献が高い会社です。 
　そんなWindRiver社ですがIntel社に買収されていた時期があり、当時のIntel IoT戦略の一環でRocket Kernelの開発が開始されました。当時のVxWorksフットプリントが200KB程度に対し、Rocketは4KB程度と非常に小さくまとまったカーネルでしたが、Linux FoundationによるIoTのためのプロジェクトであるZephyrプロジェクト立ち上げに際してLinux Foundationへと寄贈され現在に至っています。
　ZephyrはマクロとPythonスクリプトが多用され賛否の声はあるものの、非常に柔軟なビルドシステムを備えており、IPv4/IPv6, BLE, CANを始めとするIoTに必要な各種プロトコルをサポートし、不揮発性ストレージ用の複数のフラッシュファイルシステムもサポートしています。
　LinuxのKConfigやDeviceTreeフォーマットを流用したビルド構成システム、gitやCMake, Ninjaといった実績のあるツールをバックエンドとして、手順を簡略化するために用意したメタツールのwestなど、Yocto Linuxあたりを触れていれば知っているであろう知識をベースに、サポートされているボードなら、簡単に「Lチカしてみる」程度はできるようになっています[^7]。
　まぁ、知ったふりして書いてますが、WindRiver Rocketは知ってたけどZephyr Projectは最近まで知らなかった（YAPFかなんかでちらっと耳にした気はするけど）ニワカです。昔の仕事仲間が数人WindRiver社に在籍していたころ買収があって、当時動向は気にしていたのでRocketまでは知ってたのですが。

  
[^1]: あすもの研 - [いまどきの組込みOSの​ ZephyrRTOSと​ OpenThreadを​ Arduino環境で遊んでみる](https://www.slideshare.net/slideshow/os-zephyrrtos-openthread-arduino/146554712) 
[^2]: Risc-V勉強会 - [ZephyrRTOSのLongan Nanoへの移植](https://speakerdeck.com/tokitahiroshi/zephyrrtosfalselongan-nanohefalseyi-zhi)
[^3]: Japan Technical Jamboree EP2 [ZephyrRTOSで遊ぼう!](https://speakerdeck.com/tokitahiroshi/zephyrrtosdeyou-bou)
[^4]: SWEST26 - [ZephyrRTOSの概要、特色とそのOSSプロジェクト運営](https://swest.toppers.jp/SWEST26/lecture/data/s3c_public.pdf)
[^5]:[ZR400](https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AF%E3%82%B5%E3%82%AD%E3%83%BB%E3%82%BC%E3%83%95%E3%82%A1%E3%83%BC)　通称ゼファーさん。弟が昔カワサキ派バイク乗りでしたので。
[^6]: @task_jpさん曰く「z4rとかにしてほしい」とのことで「ほんとそれ」
[^7]: [Getting Started](https://docs.zephyrproject.org/latest/develop/getting_started/index.html)‥まぁ、ちょっとその先に踏み出すと罠にハマりそうな印象も


# Slint on Zephyr OS
## 公式のZephyr OSサポート状況
　Slintは公式デモのprinter demoを[NXP MIMXRT1170-EVKB](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html) + [RK055HDMIPI4MA0 MIPI Display](https://docs.zephyrproject.org/latest/boards/shields/rk055hdmipi4ma0/doc/index.html)上のZephyr OSに組み入れて動かした実績があります。
 
 <blockquote class="twitter-tweet" data-media-max-width="560"><p lang="en" dir="ltr">🚀Now you can also run a <a href="https://twitter.com/hashtag/Slint?src=hash&amp;ref_src=twsrc%5Etfw">#Slint</a> app on Zephyr OS 🚀<br>photo: Slint printer demo on <a href="https://twitter.com/NXP?ref_src=twsrc%5Etfw">@NXP</a> <a href="https://t.co/ux1QDCYQnX">https://t.co/ux1QDCYQnX</a> RT1170 and <a href="https://twitter.com/ZephyrIoT?ref_src=twsrc%5Etfw">@ZephyrIoT</a> OS<a href="https://twitter.com/hashtag/rustlang?src=hash&amp;ref_src=twsrc%5Etfw">#rustlang</a> <a href="https://twitter.com/hashtag/embedded?src=hash&amp;ref_src=twsrc%5Etfw">#embedded</a> <a href="https://twitter.com/hashtag/zephyros?src=hash&amp;ref_src=twsrc%5Etfw">#zephyros</a> <a href="https://twitter.com/hashtag/NXPpartner?src=hash&amp;ref_src=twsrc%5Etfw">#NXPpartner</a> <a href="https://t.co/Sy7aHcpVYG">pic.twitter.com/Sy7aHcpVYG</a></p>&mdash; Slint (@slint_ui) <a href="https://twitter.com/slint_ui/status/1826590023749120504?ref_src=twsrc%5Etfw">August 22, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
 
　その際の[West Manifestファイル](https://github.com/slint-ui/slint/blob/master/demos/printerdemo/zephyr/west.yaml)と[手順](https://github.com/slint-ui/slint/blob/master/demos/printerdemo/zephyr/README.md)がgithubに入っています。Zephyrは2024/04/26の特定バージョン、SDKも少し古いバージョン指定になっていますが。
 
## Native Simulatorで動かしてみる
　Slint公式の[手順](https://github.com/slint-ui/slint/blob/master/demos/printerdemo/zephyr/README.md)をみていただければわかるように、Simulatorの手順が用意されています。

### 環境構築
WindowsやmacOSでも利用できるのですが、手間なので今回もKUbuntu 24.04上での手順だけ記載しておきます。

```bash:/etc/os-release
PRETTY_NAME="Ubuntu 24.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.1 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
```

なお、このあとの実機も踏まえて環境構築するので、QEMUのみの場合より余計なものを色々入れているのでご承知おきください。

#### 1. OS package追加と設定

いらない手順が入っているかもですが

```bash:
wget https://apt.kitware.com/kitware-archive.sh
sudo bash kitware-archive.sh
sudo apt update
sudo apt upgrade
sudo apt install build-essential cmake ninja-build \
    gperf ccache dfu-util device-tree-compiler \
    python3-venv gcc-multilib g++-multilib \
    libsdl2-dev libmagic1t64 gawk diffstat \
    texinfo chrpath python3-pip python3-pexpect \
    libsdl1.2-dev xterm lz4 gettext autopoint \
    libssl-dev curl
sudo usermod -a -G dialout $USER
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
git config --global http.postBuffer 524288000
git config --global http.maxRequestBuffer 1048576000
reboot
```

　rebootは、dialoutへの登録を反映する必要もあり（ログインし直すだけで十分なのだけど）、カーネルアップデートとか入っていると起動できるのか確かめて置くほうが無難なためrebootにしています。

#### 2. Rustのセットアップ
```bash:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. $HOME/.cargo/env
```
プロンプトはデフォルトのまま(Enter入力）で進めて指示の通りパスを有効にしています。

#### 3. Rust環境セットアップ
　Rust単体で遊ぶには必要。ZephyrでSDKを入れてslint+zephyrではそちらを使うようなのでesp関連は不要かもしれない。
```bash:
cargo install cargo-generate ldproxy espup espflash cargo-espflash
espup install
rustup install nightly
rustup default nightly
```


#### 4. westのインストール
　westはPythonの仮想環境にインストールします。
```bash:
python3 -m venv $HOME/slint-zephyr/.venv
source $HOME/slint-zephyr/.venv/bin/activate
pip install west
```

#### 5. slint+zephyerソースのセットアップ
　手順が少し古いのは、slintのwest.yamlのzephyrが古いため。最新と異なるので注意が必要

```bash:
west init -m https://github.com/slint-ui/slint --mf demos/printerdemo/zephyr/west.yaml $HOME/slint-zephyr
cd ~/slint-zephyr
west update
west zephyr-export
pip3 install -r zephyr/scripts/requirements.txt
```

#### 6. SDKのセットアップ
```bash:
cd $HOME
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.8/zephyr-sdk-0.16.8_linux-x86_64.tar.xz
mkdir sdk
tar -xvf zephyr-sdk-0.16.8_linux-x86_64.tar.xz -C sdk
./sdk/zephyr-sdk-0.16.8/setup.sh
```



### Slimulatorのビルドと起動
```bash:
cd $HOME/slint-zephyr
west build -b native_sim/native/64 -p always slint/demos/printerdemo/zephyr
./build/zephyr/zephyr.exe
```

　これで、シミュレータが起動しzephyr os上でprinter demoが実行されます。

# M5 Stack Core2上で動かしたい
## M5 Stackとは
　中国深圳に拠点を持つスタートアップ企業の開発した小型のマイコンモジュールです。無線、ディスプレー、操作ボタンなどのプロトタイプ開発に必要な機能をあらかじめ備えた小型コンピュータとなっています。

## M5 Stack Core2について
<img width="30%" alt="M5 Stack Core2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58828/c5757a84-d9b9-91b0-f3de-e7f72e2e24b8.png"><br/>

　M5Core2は、M5Stack開発キットシリーズの第2世代のコアデバイスで、オリジナル世代のコアの機能をさらに強化したものです。MCUは ESP32モデルD0WDQ6-V3で、デュアルコアのXtensa® 32-bit 240Mhz LX6プロセッサを搭載。Wi-Fiを標準サポートし、オンボードで16MB Flashと8MB PSRAM、充電やプログラムのダウンロード、シリアル通信が可能なUSB TYPE-Cインターフェース、2.0インチ内蔵静電容量式タッチパネル、内蔵振動モーターを搭載しています。

## Zephyrのサポート
https://docs.zephyrproject.org/latest/boards/m5stack/m5stack_core2/doc/index.html

　Zephyrについては、一部の機能を除き対応済みです。

## Slintを動かすために
m5stack_core2/esp32/procpu bord 設定を生やしていきます。
```cmake:slint/demos/printerdemo/zephyr/CMakeLists.txt
if(BOARD STREQUAL "native_sim/native/64")
    set(Rust_CARGO_TARGET "x86_64-unknown-linux-gnu")
    set(SLINT_LIBRARY_CARGO_FLAGS "-Zbuild-std=core,alloc")
elseif(BOARD STREQUAL "mimxrt1170_evk@B/mimxrt1176/cm7")
    set(Rust_CARGO_TARGET "thumbv7em-none-eabi")
elseif(BOARD STREQUAL "m5stack_core2/esp32/procpu")
    set(Rust_TOOLCHAIN "esp")
    set(Rust_CARGO_TARGET "xtensa-esp32-espidf")
    set(SLINT_LIBRARY_CARGO_FLAGS "-Zbuild-std=core,alloc")
else()
    # See rustc --print target-list for available targets. Match that up with you supported board
    # https://docs.zephyrproject.org/latest/boards
    message(FATAL_ERROR "Unsupported BOARD option specified: ${BOARD}")
endif()
```

```cmake:slint/demos/printerdemo/zephyr/boards/m5stack_core2_procpu.conf
CONFIG_NEWLIB_LIBC=y
CONFIG_ESP_SPIRAM=y
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_POSIX_API=y
CONFIG_ESP_HEAP_MIN_EXTRAM_THRESHOLD=2048
CONFIG_SHELL=y
```
　stack sizeは、STM32の設定を見る限りだいぶ足りないのですが、とりあえずprinter demoを諦めてhello worldレベルを表示するということで、まずは減らしています。

```:slint/demos/printerdemo/zephyr/boards/m5stack_core2_procpu.overlay
/delete-node/ &slot0_partition;
/delete-node/ &slot1_partition;
/delete-node/ &scratch_partition;
/delete-node/ &storage_partition;

&flash0 {
    partitions {
        slot0_partition: partition@10000 {
            label = "image-0";
            reg = <0x00010000 0x00a00000>;
        };
    };
};

/{
    aliases {
        slint-input = &ft5336_touch;
    };
};
```
　M5 Stack Core2ボードの設定は、なぜかmcubootを使わなくてもMCU boot向けのパーティション設定になっており、slint入で入れるには容量が少ないのでパーティションを変更します。

```qml:slint/demos/printerdemo/ui/my_application_ui.slint
export component HelloWorld inherits Window {
    width: 320px;
    height: 240px;
    in property my_label <=> label.text;
    label := Text {
       text: "Hello, world";
       font-size: 24px;
       horizontal-alignment: center;
       vertical-alignment: center;
       color: blue;
    }
}
```
　Printer demo を動かすにはPSRAMなどを有効にする必要があるので、まずは文字を表示だけするだけのアプリを用意します。

```cmake:slint/demos/printerdemo/zephyr/CMakeLists.txt
#slint_target_sources(app ../ui/printerdemo.slint)
slint_target_sources(app ../ui/my_application_ui.slint)
```

　Slintのターゲットソースを変更します。

```cpp:slint/demos/printerdemo/zephyr/src/main.cpp
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(zephyrPrinterDemo, LOG_LEVEL_INF);

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <soc/soc_memory_layout.h>

#ifdef CONFIG_ARCH_POSIX
#    include "posix_board_if.h"
#    include <sys/time.h>
#endif

#include <app_version.h>
#include "slint-zephyr.h"
#include "my_application_ui.h"

int main(void)
{
    const struct device *display_dev = nullptr;

    display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
    if (!device_is_ready(display_dev)) {
        LOG_ERR("Device %s not found. Aborting.", display_dev->name);
#ifdef CONFIG_ARCH_POSIX
        posix_exit(1);
#else
        return 0;
#endif
    }
    slint_zephyr_init(display_dev);
    auto hello_world = HelloWorld::create();
    hello_world->set_my_label("Hello from C++");
    hello_world->run();
    return 0;
}
```

```bash:
west build -b m5stack_core2/esp32/procpu -p always slint/demos/printerdemo/zephyr -- -DCMAKE_BUILD_TYPE=Release
west flash --esp-device /dev/ttyACM0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58828/6a5322b9-c205-e158-bcb5-bc206280cc43.png)

　これで、M5Stack Core2 の上でZephyr+Slintが動作するところまでは来ました。単純な画面表示までなら簡単なのですが、実はPrinter Demoどころか、Slint TemplateのボタンのあるHello Worldを動かすと、ボタンを押したところで画面が壊れたりします。
　PSRAMなしだと圧倒的にメモリ不足なのと、たぶんですがメモリマップがだめです。

## まずは現状確認
### メモリレイアウト

ビルド中に生成されたリンカースクリプトは以下の通りです。
```: build/zephyr/linker.cmd
user_iram_end = (0x20000 - ((0x3ffe8000) - 0x3ffe0000) + 0x400a0000);
user_iram_seg_org = (0x40070000 + 0x10000);
user_iram_seg_len = user_iram_end - user_iram_seg_org;
user_dram_seg_org = 0x3ffb0000;
user_dram_seg_len = (0x3ffe0000 - 0x3ffb0000);
user_dram_2_seg_org = 0x3ffe8000;
user_dram_2_seg_len = (0x40000000 - 0x3ffe8000);

MEMORY
{
  FLASH (R): org = 0x0, len = 16777216 - 0x100
  iram0_0_seg(RX): org = user_iram_seg_org, len = user_iram_seg_len
  dram0_0_seg(RW): org = user_dram_seg_org + 0x0,
                   len = user_dram_seg_len - 0x0
  dram0_shm0_seg(RW): org = 0x3ffe5230, len = 2K
  dram0_sem0_seg(RW): org = 0x3ffe5a30, len = 8
  dram0_1_seg(RW): org = 0x3ffe5a38, len = 0K
  irom0_0_seg(RX): org = 0x400d0000, len = (16777216 - 0x1000)
  drom0_0_seg(R): org = 0x3f400000, len = (16777216 - 0x1000)
  rtc_iram_seg(RWX): org = 0x400c0000, len = 0x2000
  rtc_slow_seg(RW): org = 0x50000000, len = 0x1000
  ext_ram_seg(RW): org = 0x3f800000, len = 2097152
  IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000
}
```

　ESP32はハーバード・アーキテクチャを採用しています。またマルチコアに対応するためセグメントを分けたりと複雑なメモリマップになります。

```:build/zephyr/zephyr.map
Memory Configuration

Name             Origin             Length             Attributes
FLASH            0x0000000000000000 0x0000000000ffff00 r
iram0_0_seg      0x0000000040080000 0x0000000000038000 xr
dram0_0_seg      0x000000003ffb0000 0x0000000000030000 rw
dram0_shm0_seg   0x000000003ffe5230 0x0000000000000800 rw
dram0_sem0_seg   0x000000003ffe5a30 0x0000000000000008 rw
dram0_1_seg      0x000000003ffe5a38 0x0000000000000000 rw
irom0_0_seg      0x00000000400d0000 0x0000000000fff000 xr
drom0_0_seg      0x000000003f400000 0x0000000000fff000 r
rtc_iram_seg     0x00000000400c0000 0x0000000000002000 xrw
rtc_slow_seg     0x0000000050000000 0x0000000000001000 rw
ext_ram_seg      0x000000003f800000 0x0000000000200000 rw
IDT_LIST         0x000000003ebfe010 0x0000000000002000 rw
*default*        0x0000000000000000 0xffffffffffffffff
```
　並べ替えると以下の通りです。
|Name            | Origin     | Length            | Attributes|
|:---------------|:-----------|:------------------|:----------|
| FLASH          | 0x00000000 | 0xffff00(15.99 MB) | r         |
| IDT_LIST       | 0x3ebfe010 | 0x002000(    8 KB) | rw        |
| drom0_0_seg    | 0x3f400000 | 0xfff000(15.99 MB) | r         |
| ext_ram_seg    | 0x3f800000 | 0x200000(    2 MB) | rw        |
| dram0_0_seg    | 0x3ffb0000 | 0x030000(  192 KB) | rw        |
| dram0_shm0_seg | 0x3ffe5230 | 0x000800(    2 KB) | rw        |
| dram0_sem0_seg | 0x3ffe5a30 | 0x000008(  8 Byte) | rw        |
| dram0_1_seg    | 0x3ffe5a38 | 0x000000(  0 Byte) | rw        |
| iram0_0_seg    | 0x40080000 | 0x038000(  224 KB) | xr        |
| rtc_iram_seg   | 0x400c0000 | 0x002000(    8 KB) | xrw       |
| irom0_0_seg    | 0x400d0000 | 0xfff000(15.99 MB) | xr        |
| rtc_slow_seg   | 0x50000000 | 0x001000(    4 KB) | rw        |

　まぁ、ただこのマップなんだかおかしいのですよね。ESP32公式ドキュメントのマップだと以下の通りです。

<table>
<tr>
  <th colspan="2">Boundary Address</th>
  <th rowspan="2">size</th>
  <th rowspan="2">Target</th>
  <th rowspan="2">Attribute</th>
</tr>
<tr>
  <th>Low Addreess</th>
  <th>High Addreess</th>
</tr>
<tr>
    <td>0x3F400000</td>
    <td>0x3F7FFFFF</td>
    <td>0x00400000<br/>(    4 MB)</td>
    <td>外部フラッシュ</td>
    <td>D-Cache<br/>(Read Only)</td>    
</tr>

<tr>
    <td>0x3F800000</td>
    <td>0x3FBFFFFF</td>
    <td>0x00400000<br/>(    4 MB)</td>
    <td>PSRAM</td>
    <td>R</td>    
</tr>

<tr>
    <td>0x3FF00000</td>
    <td>0x3FF7FFFF</td>
    <td>0x00080000<br/>(   512 KB)</td>
    <td>ペリフェラル</td>
    <td></td>    
</tr>

<tr>
    <td>0x3FF80000</td>
    <td>0x3FF81FFF</td>
    <td>0x00002000<br/>(    8 KB)</td>
    <td>RTC Fast Memory</td>
    <td>D</td>    
</tr>

<tr>
    <td>0x3FF82000</td>
    <td>0x3FF8FFFF</td>
    <td>0x0000E000<br/>(   56 KB)</td>
    <td>Reserved</td>
    <td>N/A</td>    
</tr>

<tr>
    <td>0x3FF90000</td>
    <td>0x3FF9FFFF</td>
    <td>0x00010000<br/>(   64 KB)</td>
    <td>Internal ROM1</td>
    <td>D</td>    
</tr>

<tr>
    <td>0x3FFA0000</td>
    <td>0x3FFADFFF</td>
    <td>0x0000E000<br/>(   56 KB)</td>
    <td>Reserved</td>
    <td>N/A</td>    
</tr>

<tr>
    <td>0x3FFAE000</td>
    <td>0x3FFDFFFF</td>
    <td>0x00032000<br/>(  200 KB)</td>
    <td>Internal SRAM2<br/>(Data only)</td>
    <td>D</td>    
</tr>

<tr>
    <td>0x3FFE0000</td>
    <td>0x3FFFFFFF</td>
    <td>0x00020000<br/>(  128 KB)</td>
    <td>Internal SRAM1<br/>(I/D共用)</td>
    <td>D</td>    
</tr>

<tr>
    <td>0x40000000</td>
    <td>0x40007FFF</td>
    <td>0x00008000<br/>(  32 KB)</td>
    <td>Internal ROM0<br/>(I/D共用)</td>
    <td>I(Remap)</td>    
</tr>

<tr>
    <td>0x40008000</td>
    <td>0x4005FFFF</td>
    <td>0x00058000<br/>( 352 KB)</td>
    <td>Internal ROM0<br/>(I/D共用)</td>
    <td>I</td>    
</tr>

<tr>
    <td>0x40060000</td>
    <td>0x4006FFFF</td>
    <td>0x00010000<br/>(   64 KB)</td>
    <td>Reserved</td>
    <td>N/A</td>    
</tr>

<tr>
    <td>0x40060000</td>
    <td>0x4006FFFF</td>
    <td>0x00010000<br/>(   64 KB)</td>
    <td>Reserved</td>
    <td>N/A</td>    
</tr>

<tr>
    <td>0x40070000</td>
    <td>0x4007FFFF</td>
    <td>0x00010000<br/>(   64 KB)</td>
    <td>Internal SRAM0</td>
    <td>I(cache)</td>    
</tr>

<tr>
    <td>0x40080000</td>
    <td>0x4009FFFF</td>
    <td>0x00020000<br/>(  128 KB)</td>
    <td>Internal SRAM0</td>
    <td>I</td>    
</tr>

<tr>
    <td>0x400A0000</td>
    <td>0x400AFFFF</td>
    <td>0x00010000<br/>(   64 KB)</td>
    <td>Internal SRAM1</td>
    <td>I</td>    
</tr>

<tr>
    <td>0x400B0000</td>
    <td>0x400B7FFF</td>
    <td>0x00008000<br/>(   32 KB)</td>
    <td>Internal SRAM1</td>
    <td>I(remap)</td>    
</tr>

<tr>
    <td>0x400B8000</td>
    <td>0x400BFFFF</td>
    <td>0x00008000<br/>(   32 KB)</td>
    <td>Internal SRAM1</td>
    <td>I</td>    
</tr>

<tr>
    <td>0x400C0000</td>
    <td>0x4001FFFF</td>
    <td>0x00002000<br/>(    8 KB)</td>
    <td>RTC Fast Memory</td>
    <td>I</td>    
</tr>

<tr>
    <td>0x400C2000</td>
    <td>0x40BFFFFF</td>
    <td>0x00B3E000<br/>( 11.24 MB)</td>
    <td>外部フラッシュ</td>
    <td>I-cache</td>    
</tr>
<tr>
    <td>0x50000000</td>
    <td>0x50001FFF</td>
    <td>0x00002000<br/>(    8 KB)</td>
    <td>RTC Slow Memory</td>
    <td>D/I</td>    
</tr>
</table>

 - もともとMMU周りの制御を用意しないとSPIRAMは4MBまでしか使えない
 - FLASH, IDL_LISTはドキュメントのマップの範囲外
 - drom0_0_segは内蔵ROMではなくFlashを指している（ただし領域範囲外まで含んでいる）
 - ext_ram_seg（SPIRAM)のAddressは正しいもののサイズが半分
 - dram0_0_segは、SRAN2上の IPC buffer等shared buffer用領域を省く領域
 - dram0_shm0_seg, dram0_sem0_segは現状用途不明
 - dram0_1_seg はAPP CPU向けでsize　0なのでシンボルだけ残っている？
 - irom0_0_segは外部フラッシュの途中から？
 - rtc_slow_segはサイズ設定が半分？

## 機能追加
　UIにボタンを追加します。

```qml:slint/demos/printerdemo/ui/my_application_ui.slint
import { Button, VerticalBox } from "std-widgets.slint";

export component HelloWorld inherits Window {
    width: 320px;
    height: 240px;
    in-out property<int> counter: 42;
    callback request-increase-value();
    VerticalBox {
        Text {
           text: "Counter : \{root.counter}";
           font-size: 24px;
           color: blue;
        }
        Button {
            text: "Increase value";
        }
    }
}
```

```cpp:slint/demos/printerdemo/zephyr/src/main.cpp
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(zephyrPrinterDemo, LOG_LEVEL_INF);

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <soc/soc_memory_layout.h>

#ifdef CONFIG_ARCH_POSIX
#    include "posix_board_if.h"
#    include <sys/time.h>
#endif

#include <app_version.h>
#include "slint-zephyr.h"
#include "my_application_ui.h"

int main(void)
{
    const struct device *display_dev = nullptr;

    display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
    if (!device_is_ready(display_dev)) {
        LOG_ERR("Device %s not found. Aborting.", display_dev->name);
#ifdef CONFIG_ARCH_POSIX
        posix_exit(1);
#else
        return 0;
#endif
    }
    slint_zephyr_init(display_dev);
    auto ui = HelloWorld::create();
    ui->on_request_increase_value([&]{
        ui->set_counter(ui->get_counter() + 1);
    });
    ui->run();
    return 0;
}
```
　これで何事もなく動けば成功だったのですが‥。

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">ぬーん。コールバックなしにしても画面壊れるし、入力周りに何かあるのかなぁ。まぁ、挫折日記行きだな。 <a href="https://t.co/gveJB5Cl8j">pic.twitter.com/gveJB5Cl8j</a></p>&mdash; 緑野翁 (@hermit4) <a href="https://twitter.com/hermit4/status/1871517569959821726?ref_src=twsrc%5Etfw">December 24, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

　とりあえず、モニターを起動して眺めてみましょう。

```bash:
west espressif monitor -p /dev/ttyACM0
```

```bash:log
--- idf_monitor on /dev/ttyACM0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3ffb0000,len:12556
ho 0 tail 12 room 4
load:0x3ffb310c,len:996
load:0x40080000,len:90112
0x40080000: _WindowOverflow4 at /home/hermit4/slint-zephyr/zephyr/arch/xtensa/core/window_vectors.S:56

1150 mmu set 00010000, pos 00010000
entry 0x4008a3fc
0x4008a3fc: __start at /home/hermit4/slint-zephyr/zephyr/soc/espressif/common/loader.c:227

I (60) boot: ESP Simple boot
I (60) boot: compile time Dec 24 2024 20:06:55
W (60) boot: Unicore bootloader
I (60) spi_flash: detected chip: generic
I (63) spi_flash: flash io: dio
I (66) boot: chip revision: v3.1
I (69) boot.esp32: SPI Speed      : 40MHz
I (72) boot.esp32: SPI Mode       : DIO
I (76) boot.esp32: SPI Flash Size : 16MB
I (80) boot: Enabling RNG early entropy source...
[esp32] [INF] DRAM: lma 0x00001020 vma 0x3ffb0000 len 0x310c   (12556)
[esp32] [INF] DRAM: lma 0x00004134 vma 0x3ffb310c len 0x3e4    (996)
[esp32] [INF] IRAM: lma 0x00004520 vma 0x40080000 len 0x16000  (90112)
0x40080000: _WindowOverflow4 at /home/hermit4/slint-zephyr/zephyr/arch/xtensa/core/window_vectors.S:56

[esp32] [INF] padd: lma 0x0001a538 vma 0x00000000 len 0x5ac0   (23232)
[esp32] [INF] IMAP: lma 0x00020000 vma 0x400d0000 len 0x58fe8  (364520)
0x400d0000: _stext at ??:?

[esp32] [INF] padd: lma 0x00078ff0 vma 0x00000000 len 0x7008   (28680)
[esp32] [INF] DMAP: lma 0x00080000 vma 0x3f410000 len 0x16eb8  (93880)
[esp32] [INF] padd: lma 0x00096ec0 vma 0x00000000 len 0x9138   (37176)
[esp32] [INF] DMAP: lma 0x000a0000 vma 0x3f400000 len 0x114    (276)
[esp32] [INF] Image with 9 segments
[esp32] [INF] DROM segment: paddr=00080000h, vaddr=3f410000h, size=16EB4h ( 93876) map
[esp32] [INF] IROM segment: paddr=00020000h, vaddr=400d0000h, size=58FE8h (364520) map
I (177) quad_psram: This chip is ESP32-D0WD
I (178) esp_psram: Found 8MB PSRAM device
I (178) esp_psram: Speed: 40MHz
I (178) esp_psram: PSRAM initialized, cache is in normal (1-core) mode.
W (183) esp_psram: Virtual address not enough for PSRAM, map as much as we can. 4MB is mapped
I (1026) esp_psram: SPI SRAM memory test OK

[00:00:06.186,000] <err> gpio_hogs: GPIO port axp192_gpio not ready
*** Booting Zephyr OS build v3.6.0-3234-gacc2b51959b6 ***
[00:00:06.324,000] <inf> zephyrSlint: Screen size: 320 x 240
[00:00:06.324,000] <inf> zephyrSlint: Double buffering: 0
[00:00:06.324,000] <inf> zephyrSlint: Has framebuffer: 0
[00:00:06.324,000] <inf> zephyrSlint: Pixel format: RGB_565
[00:00:06.324,000] <inf> zephyrSlint: Supports RGB_888: 1
[00:00:06.324,000] <inf> zephyrSlint: Supports MONO01: 0
[00:00:06.324,000] <inf> zephyrSlint: Supports MONO10: 0
[00:00:06.324,000] <inf> zephyrSlint: Supports ARGB_8888: 0
[00:00:06.324,000] <inf> zephyrSlint: Supports RGB_565: 1
[00:00:06.324,000] <inf> zephyrSlint: Supports BGR_565: 0
[00:00:06.325,000] <inf> zephyrSlint: Rotated screen size: 320 x 240
[00:00:06.328,000] <dbg> zephyrSlint: run_event_loop: Start
[00:00:06.328,000] <dbg> zephyrSlint: run_event_loop: Loop
[00:00:06.352,000] <dbg> zephyrSlint: maybe_redraw: Rendering 1 dirty regions:
[00:00:06.360,000] <dbg> zephyrSlint: maybe_redraw:    - converted pixel data for x: 0 y: 0 w: 320 h: 240
[00:00:06.406,000] <dbg> zephyrSlint: maybe_redraw:    - rendered x: 0 y: 0 w: 320 h: 240
[00:00:06.406,000] <dbg> zephyrSlint: maybe_redraw:  - total: 77 ms, slint: 23 ms, write: 54 ms
[00:00:06.407,000] <dbg> zephyrSlint: run_event_loop: Sleeping for forever
uart:~$ kernel stacks
0x3ffb5580 input                            (real size 1024):   unused  696     usage  328 / 1024 (32 %)
0x3ffb4fe0 shell_uart                       (real size 2048):   unused  440     usage 1608 / 2048 (78 %)
0x3ffb5768 sysworkq                         (real size 1024):   unused  696     usage  328 / 1024 (32 %)
0x3ffb4f08 logging                          (real size 1024):   unused  552     usage  472 / 1024 (46 %)
0x3ffb5618 idle                             (real size 1024):   unused  824     usage  200 / 1024 (19 %)
0x3ffb56b0 main                             (real size 8192):   unused 2352     usage 5840 / 8192 (71 %)
0x3ffb71c0 IRQ 00                           (real size 2048):   unused 1792     usage  256 / 2048 (12 %)

```

　mainのスタックがかなりいっぱいですが、画面が壊れた状態でもスタックはまだ空いてる様にみえるのですよね。　とりあえず、年末はつらつらとタッチパネルが押されたときの挙動周りを調べて行くことになりそうです。
 
　このコンフィグ立てて追いかけてみたら？とか、このあたり見てみたほうがというようなアドバイスがあればどんどんコメントでもXやmixi2のDMでもご連絡ください。

# まとめ
　というわけで、M5 Stack Core2にZephyrを入れたうえでSlintを動かして見ましたが、まだ道半ばです。PRAMの認識も怪しいし、メモリマップも若干あやしいし、ボタン押すと画面崩れるしで、色々見直すべき場所がいっぱい。残念な挫折日記となりましたが、先に解決してやるぜって方は、ぜひお試しください。

　最終日の明日は、@task_jpさんが、何か書いてくださる予定です。