LoginSignup
9
4

More than 1 year has passed since last update.

仮想 IoT デバイスを Athrill で作る!

Last updated at Posted at 2020-12-18

仮想環境で IoT 組込み開発

組込みマイコン開発では実機を使ってドライバ/アプリのデバッグをするのが普通のスタイルだと思います.PoCであれば,ラズパイやWio LTE等を使えばそんなに苦労なく開発ができることでしょう.

たぶん,この記事をチラ見された方は,「IoTで仮想環境なにそれ?おいしいの?」と感じておられるのではないかと思いますが,あえて仮想環境で IoT 開発の話をさせていただきます!

デモ

まずは,この動画をご覧ください.
demo1.gif

画面左は,GPS位置情報を Google Map と紐づけてリアルタイムに位置表示する Unity アプリです(自作).画面右は,TOPPERS/箱庭 単体ロボット向けシミュレータです.

デモの内容としては,「ロボットの位置情報をGPSアプリに通知して表示する」という単純なものなのですが,その作りは結構奥深いです.

プログラム構成

プログラム構成はこんな感じです.

image.png

ご覧の通り,クラウド/サーバー介さずに1個のパソコン(Windows/WSL)上で,GPS位置情報の動作確認テストができています.さらに注目すべきポイントは,マイコン側のプログラムは,マイコン・シミュレータ(Athrill)上で動作しており,マイコン上で動作するアプリケーションおよびドライバ開発がこの仮想環境上で出来てしまうのです!

つまり,クラウド側のアプリとマイコン側のアプリ/ドライバが同じ仮想環境上で開発できてしまうのですよ.

Athrill

ここから本題です.こんな素敵な開発を実現してくれる仮想化技術の紹介です.
Athrill は,TOPPERS から一般公開されているオープンソースベースのマイコン・シミュレータです.どなたでも自由に利用いただけますし,ソース改修も自由です.

また,Athrill は,マイコン単体のシミュレーションに留まらず,様々な要素技術(UnityRDBOXmROS等)と連携したシミュレーションもできます.

余談ですが,「IoT/クラウド時代に求められるシミュレーションとは何か?」の問いに応えてくれた有志が集まって,箱庭というTOPPERSワーキンググループができました.箱庭という次世代シミュレーション構想の中で,Athrill はその要素技術の一つでもあります.

デバイスプラットフォーム Athrill

そんな Athrill ですが,次世代シミュレーション環境として求められるであろう機能を検討したところ,IoT のような開発で求められるのは様々な周辺デバイス(温度センサ, 加速度センサ,GPS, LTE,...)を手軽に試せるシミュレーション環境ではないか?と思い至りました.

そのために必要な Athrill 機能とは何かというと,様々なデバイスを手軽に開発できて,デバッグ/実行できるようなプラットフォームだと気づきました.つまり,こんなプラットフォームです.

image.png

今回のデモで作成したデバイスは,GPSとLTEです.GPSデバイスについては,以下で一般公開しております.

なお,プラグインとして開発できるようにするために,一般的なデバイスが求める共通機能は Athrill 側でデバイス共通機能として利用できるようにしています.デバイス側は,これらの共通機能を利用しながら,開発対象デバイス側で必要な機能実装をするというわけです.

サンプルデバイスで Hello World

具体的なデバイス作成方法の理解を深めるために,Hollo World やってみましょう.

準備

まず,以下のリポジトリをクローンしましょう.

$ cd <work_dir※作業フォルダを作ってください>
$ git clone https://github.com/toppers/athrill.git
$ git clone https://github.com/toppers/athrill-target-v850e2m.git
$ git clone https://github.com/toppers/athrill-device.git

次に,athrillをビルドします.

$ cd athrill-target-v850e2m/build_linux
$ make timer32=true serial_fifo_enable=true

ビルド成功すると,athrill2 というバイナリができていますので,以下のコマンドで確認してください.

$ ls -l ../../athrill/bin/linux/athrill2

デバイス作成方法

さて,ここから athrill に追加するデバイスの作成方法です.
以下に,単純なサンプルデバイスを用意していますので,そのプログラムを見ながら説明します(100行程度です).

athrill-device/device/sample/sample_device.c

このファイルの中で,athrill のプラグインとしてデバイス登録するためのデータが以下です.athrill は,athrill_ex_device というシンボル名を検索し,そのデータの妥当性チェック後,問題なければ,デバイス初期化関数の呼び出しおよび定期的なクロック供給を行います.

/**************************************
 * START: external symbols
 **************************************/
AthrillExDeviceType athrill_ex_device = {
                .header.magicno = ATHRILL_EXTERNAL_DEVICE_MAGICNO,
                .header.version = ATHRILL_EXTERNAL_DEVICE_VERSION,
                .header.memory_size = EX_DEVICE_MEMORY_SIZE, /* KB */
                .datap = ex_device_memory_data,
                .ops = &ex_device_memory_operation,
                .devinit = ex_device_init,
                .supply_clock = ex_device_supply_clock,
};
/**************************************
 * END: external symbols
 **************************************/

初期化関数は,devinit メンバに登録します.
クロック供給関数は,supply_clock メンバに登録します.
また,デバイスレジスタの I/O ですが,datap でアクセス領域のメモリ割り当てし,I/O用のフック関数を ops メンバに登録します.

サンプルデバイス実装例

では,それぞれの登録関数の実装例を見ていきましょう.

devinit 関数

まず,初期化関数 devinit の実装例です.
本初期化関数は,athrill 起動時に1回だけ呼び出されます.このとき,athrill が提供する共通機能を athrill_ops で渡していますので,デバイス処理実装時に利用できるように,グローバル変数(athrill_ex_devop )にアドレスコピーしています.

static void ex_device_init(MpuAddressRegionType *region, AthrillExDevOperationType *athrill_ops)
{
        athrill_ex_devop = athrill_ops;
        printf("SAMPLE_DEVICE: init\n");
        return;
}

supply_clock 関数

次に supply_clock の実装例です.
本関数は,athrill のシミュレーション時間が 1 clock 進むたびに呼び出されるものです.本実装例では,10,000 クロック後に,Hello World を出力していますね.

static void ex_device_supply_clock(DeviceClockType *dev_clock)
{
        if (dev_clock->clock == 10000) {
                printf("SAMPLE_DEVICE: Hello World!\n");
        }
        return;
}

デバイスレジスタ I/O 関数

デバイスレジスタへの I/O 関数には,サイズ(1byte, 2byte, 4byte)毎に read関数/write関数を登録します.

この例では,1byte のwrite 関数の実装例です.本デバイスレジスタへの書き込みがあった場合,そのアドレスと書き込みしたデータの値を表示するようにしています.

static Std_ReturnType ex_sampledev_put_data8(MpuAddressRegionType *region, CoreIdType core_id, uint32 addr, uint8 data)
{
        uint32 off = (addr - region->start);
        *((uint8*)(&region->data[off])) = data;
        printf("SAMPLE_DEVICE: put8() addr=0x%x data=0x%x(%c)\n", addr, data, data);
        return STD_E_OK;
}

サンプルデバイスのビルド

このサンプルデバイスのビルドは make を叩くだけです.
成功すると devsample.so ファイルができます.

$ make clean;make
rm -f sample_device.o devsample.so
gcc -O3 -c -g -Wall -Wunknown-pragmas -Wimplicit-int -Wtrigraphs -std=gnu99 -mtune=native -march=native -mfpmath=both  -I../../../athrill/src/inc -I../../../athrill/src/cpu -I../../../athrill/src/bus -I../../../athrill/src/device/mpu -I../../../athrill/src/device/peripheral/serial/fifo -I../../../athrill/src/lib -fPIC -DOS_LINUX -DATHRILL_EXT_DEVICE sample_device.c
gcc -shared -fPIC  -o devsample.so sample_device.o

サンプルプログラム作成

さて,デバイスができましたので,そのデバイスを動かすマイコン側のプログラムを作成しましょう.場所は,以下にあります.

athrill-device/demo/sample/v850/main.c

サンプルプログラムの内容は以下の通りです.デバイスレジスタアドレスに,"Hello World" を書き込み,その書いたアドレスの内容をシリアルで出力させています.

#define SAMPLE_DEV_ADDR ((volatile char*)0xFF100000)
int main(void)
{
        volatile char *p = SAMPLE_DEV_ADDR;

        p[0] = 'H';
        p[1] = 'e';
        p[2] = 'l';
        p[3] = 'l';
        p[4] = 'o';
        p[5] = ' ';
        p[6] = 'W';
        p[7] = 'o';
        p[8] = 'r';
        p[9] = 'l';
        p[10] = 'd';
        p[11] = '\n';
        while (TRUE) {
                test_print((const char*)SAMPLE_DEV_ADDR);
                do_halt();
        }
        return 0;
}

このプログラムのビルドは make 実行するだけす.成功すると,test_main.elf ファイルが作成されます.

サンプルプログラム実行

では,サンプログラムを実行してみましょう.
その前に,athrill に渡すメモリ配置構成定義ファイル(memory.txt)に,サンプルデバイスのレジスタアドレス先頭番地(0xFF100000)と,先ほど作成したサンプルデバイス(devsample.so)のパスを追加しておきます.

DEV,  0xFF100000, ../../../device/sample/devsample.so

athrill 実行コマンドは以下の通りです.

$ ../../../../athrill/bin/linux/athrill2 -t -1 -c1 -m memory.txt -d device_config.txt test_main.elf

実行すると以下のような起動ログが出力されます.

:
RAM : START=0x5ff7000 SIZE=512
DEV : START=0xff100000 SIZE=2
:
SAMPLE_DEVICE: init

上記の通り,デバイスのアドレスが認識され,サンプルデバイスの初期化が行われていることがわかります.

そして,サンプルデバイスの Hello World が出力されました.

SAMPLE_DEVICE: Hello World!

また,サンプルプログラムの実行した Hello World のレジスタ書き込みは,以下のようにサンプルデバイス内でフック検出できています.

SAMPLE_DEVICE: put8() addr=0xff100000 data=0x48(H)
SAMPLE_DEVICE: put8() addr=0xff100001 data=0x65(e)
SAMPLE_DEVICE: put8() addr=0xff100002 data=0x6c(l)
SAMPLE_DEVICE: put8() addr=0xff100003 data=0x6c(l)
SAMPLE_DEVICE: put8() addr=0xff100004 data=0x6f(o)
SAMPLE_DEVICE: put8() addr=0xff100005 data=0x20( )
SAMPLE_DEVICE: put8() addr=0xff100006 data=0x57(W)
SAMPLE_DEVICE: put8() addr=0xff100007 data=0x6f(o)
SAMPLE_DEVICE: put8() addr=0xff100008 data=0x72(r)
SAMPLE_DEVICE: put8() addr=0xff100009 data=0x6c(l)
SAMPLE_DEVICE: put8() addr=0xff10000a data=0x64(d)
SAMPLE_DEVICE: put8() addr=0xff10000b data=0xa(
)

ここで書き込みした値を,参照⇒シリアル出力した結果は以下の通りで,期待したものです!

Hello World

今後について

様々なIoTデバイスを手軽に追加できるデバイスプラットフォームとしてのマイコンシミュレータ Athrill の紹介をさせていただきました.

今後は,これらのデバイスの数を増やしていくと共に,Athrill として備えるべき共通機能の拡充を図りたいと考えています.乞うご期待ください!

9
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4