WebAssembly Micro Runtimeお試し①
はじめに
少し前に、組込みで使えるWebAssembly Micro Runtimeが公開されました。 また、いつの間にかSTMでのデモアプリが公開されています。
リファレンスが普段触っているZephyrなので、少し動かしてみます。
準備
ライブラリをインストールします。
sudo apt install lib32gcc-5-dev g++-multilib
ソースコードをビルドします。
git clone https://github.com/intel/wasm-micro-runtime.git cd wasm-micro-runtime/core/iwasm/products/linux/ cmake make
iwasm
というバイナリができました。
$ ls CMakeCache.txt cmake_install.cmake libiwasm.so Makefile CMakeFiles iwasm libvmlib.a
Zephyrで起動してみましょう。
cd core/iwasm/products/zephyr/simple source <zephyr>/zephyr-env.sh ln -s ../../../ iwasm ln -s ../../../../shared-lib shared-lib mkdir build && cd $_ cmake -GNinja -DBOARD=qemu_x86 ..
<iwasm_dir>
はcore/iwasm
ディレクトリです。
<shared_lib_dir>
はwasm-micro-runtime/core/shared-lib
ディレクトリです。
実行します。
$ ninja run SeaBIOS (version rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org) Booting from ROM..***** Booting Zephyr OS zephyr-v1.14.0 ***** Hello world! buf ptr: 0x40000180 buf: 1234
動くやん!お手軽ですねー。
次に、試しにqemu_cortex_m3にターゲットを移してみましょう。
$ cmake -GNinja -DBOARD=qemu_cortex_m3 .. $ ninja run Memory region Used Size Region Size %age Used FLASH: 69112 B 256 KB 26.36% SRAM: 535984 B 64 KB 817.85% IDT_LIST: 120 B 2 KB 5.86/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/8.3.0/../../../../arm-zephyr-eabi/bin/ld: zephyr/zephyr_prebuilt.elf section `bss' will not fit in region `SRAM' /opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/8.3.0/../../../../arm-zephyr-eabi/bin/ld: section .intList VMA [0000000020010000,0000000020010077] overlaps section bss VMA [0000000020000000,0000000020080354] /opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/8.3.0/../../../../arm-zephyr-eabi/bin/ld: region `SRAM' overflowed by 470448 bytes collect2: error: ld returned 1 exit status % ninja: build stopped: subcommand failed.
SRAMのサイズが足りずにリンクで死んだ!!! なんでしょうこのSRAM使用量…。500KB超えてますが…。
STMのデモ
じゃあSTMで動いているデモは一体何なのでしょうか? ということで、デモアプリのREADMEを読んでみます。
|> wasm-micro-runtime/samples/littlevgl/README.md
Since ui_app incorporated LittlevGL source code, so it needs more RAM on the device to install the application. It is recommended that RAM SIZE greater than 512KB.
512KB以上のRAMが推奨環境! かなり高性能なマイコンを要求していますね…。
デモで使用しているマイコンもNUCLEO-F767ZI
という512KB RAMを搭載しているものですね…。
simple
デモアプリのソースコードを見る
希望を捨てずに、デモアプリで何をしているか、少し覗いてみましょう。 アプリで使うRAMサイズが減れば、動くかもしれないですし!
|> wasm-micro-runtime/core/iwasm/products/zephyr/simple/src/main.c
static char global_heap_buf[512 * 1024] = { 0 };
ん?きみぃ?何だいこの有無を言わさず512KB確保するstatic変数の定義は!
static char global_heap_buf[16 * 1024] = { 0 };
とりあえず、16KBくらいにしたろ。
$ ninja run [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-m3 qemu-system-arm: warning: nic stellaris_enet.0 has no peer ***** Booting Zephyr OS zephyr-v1.14.0 ***** Instantiate memory failed: allocate memory failed.
うん。QEMU起動まではいきましたが、ランタイムで落ちてます。
|> wasm-micro-runtime/core/iwasm/products/zephyr/simple/iwasm/runtime/vmcore-wasm/wasm_runtime.c
static WASMMemoryInstance* memory_instantiate(uint32 init_page_count, uint32 max_page_count, uint32 addr_data_size, uint32 global_data_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { WASMMemoryInstance *memory; uint32 total_size = offsetof(WASMMemoryInstance, base_addr) + NumBytesPerPage * init_page_count + addr_data_size + global_data_size; /* Allocate memory space, addr data and global data */ if (!(memory = wasm_malloc(total_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: allocate memory failed."); return NULL; }
この辺りかな? 少しデバッガで見ていますが、サクッと解決できなさそうなので、また次回。
ZephyrのI2C scannerサンプルを動かしてみる
はじめに
I2Cデバイスを使いたいので、手始めにZephyrのI2C scannerサンプルを動かしてみます。 ターゲットSoCはnRF52840です。
サンプルプロジェクトを確認
|> zephyr/samples/drivers/i2c_scanner
nRF52x系は、overlayする設定ファイルが用意されています。
|> overlay-nrf52.nrf
CONFIG_I2C_NRFX=y CONFIG_I2C_0=y
今回は、I2C1を使うので、I2C1に変更しておきます。
CONFIG_I2C_NRFX=y CONFIG_I2C_1=y
ソースコードをざっと確認します。
#include <errno.h> #include <zephyr.h> #include <misc/printk.h> #include <device.h> #include <i2c.h> #ifdef ARDUINO_I2C_LABEL #define I2C_DEV ARDUINO_I2C_LABEL #else #define I2C_DEV "I2C_1" #endif /** * @file This app scans I2C bus for any devices present */ void main(void) { struct device *i2c_dev; printk("Starting i2c scanner...\n"); i2c_dev = device_get_binding(I2C_DEV); if (!i2c_dev) { printk("I2C: Device driver not found.\n"); return; } for (u8_t i = 4; i <= 0x77; i++) { struct i2c_msg msgs[1]; u8_t dst; /* Send the address to read from */ msgs[0].buf = &dst; msgs[0].len = 0U; msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; if (i2c_transfer(i2c_dev, &msgs[0], 1, i) == 0) { printk("0x%2x FOUND\n", i); } } }
全アドレス順番にreadしていって、値が読めたら、見つかった判定しています。 まぁこんなもんでしょう。
動作確認
動かしてみましょう。
Starting i2c scanner... [00:00:10.125,366] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 [00:00:22.562,713] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 [00:00:25.425,384] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 [00:00:29.490,722] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 [00:00:31.948,394] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 [00:00:33.013,885] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 ... [00:01:22.722,534] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 --- 18 messages dropped --- [00:01:22.725,891] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 ...
ありゃ、途中でRTTのメッセージがdropしていますね。 I2Cのアドレスを一通り舐めていて、デバイスが見つからなかった時のエラーが多すぎる、ということなのでしょう。
一応見落としがないようにするため、GDBを使って手動でループを回します。
... [00:00:14.157,165] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 0x51 FOUND [00:00:14.360,198] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 ... [00:00:16.207,885] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 0x64 FOUND [00:00:16.414,978] <err> i2c_nrfx_twi: Error 195952641 occurred for message 0 ...
今、繋がっているI2Cデバイスのアドレスは、0x51と0x64なので、OKですね!
ZephyrでPWM
はじめに
ZephyrでPWMしてみます。 ターゲットSoCはnRF52840です。
Zephyrプロジェクト設定
Zephyr PWM driver
CONFIG_PWMを有効にします。
nRF52840のPWM0を利用するので、CONFIG_PWM_0
を有効にします。
|> prj.conf
# PWM CONFIG_PWM=y CONFIG_PWM_0=y
device tree
nRF5xシリーズでは、ハードウェアPWMとソフトウェアPWMが利用できます。 今回は、ハードウェアPWMを利用します。
ハードウェアPWMでは、割り当てたGPIOにPWM信号を出力します。 今回、GPIO0の27番ピンにPWMオーディオデバイスが搭載されているので、device treeを次のようにします。
&pwm0 { status = "ok"; ch0-pin = <27>; };
参考までに、大本のdevice treeノードを掲載します。
|> zephyr/soc/arm/nordic/nrf52840.dtsi
pwm0: pwm@4001c000 { compatible = "nordic,nrf-pwm"; reg = <0x4001c000 0x1000>; interrupts = <28 1>; status = "disabled"; label = "PWM_0"; };
nRFの仕様書を見ると、PWMペリフェラルが4つ搭載されており、1つのPWMペリフェラルにつき4チャネル利用できます。
chx-inverted
を設定すると、負論理になります。
&pwm0 { status = "ok"; ch0-pin = <13>; ch0-inverted; };
アプリケーション
適当に4kHz出力すれば鳴るでしょう、という安易な考えでアプリケーションを作ります。
#include <zephyr.h> #include <misc/printk.h> #include <device.h> #include <pwm.h> #define PWM_DRIVER DT_NORDIC_NRF_PWM_PWM_0_LABEL #define PWM_CHANNEL DT_NORDIC_NRF_PWM_PWM0_CH0_PIN /* in milli second */ #define PWM_4000_HZ (MSEC_PER_SEC / 4U) void main(void) { struct device *pwm_dev; u32_t period = PWM_4000_HZ; printk("Start PWM buzzer.\n"); pwm_dev = device_get_binding(PWM_DRIVER); if (!pwm_dev) { printk("Cannot find %s!\n", PWM_DRIVER); return; } if (pwm_pin_set_usec(pwm_dev, PWM_CHANNEL, period, period / 2U)) { printk("pwm pin set fails\n"); return; } k_sleep(MSEC_PER_SEC); printk("Stop PWM buzzer.\n"); if (pwm_pin_set_usec(pwm_dev, PWM_CHANNEL, period, 0)) { printk("pwm pin set fails\n"); return; } }
これでピーっと鳴ります。
PWM出力を開始するAPIは下記です。
pwm_pin_set_usec(pwm_dev, PWM_CHANNEL, period, period / 2U)
Driverオブジェクト、channel、period_cycles
、pulse_cycles
を引数に与えます。
pulse_cycles / period_cycles
がデューティ比になります。
次は、PWM出力を停止する方法です。 ZephyrのPWM Driver APIは、PWMを停止する方法を提供していません。
Driverの実装を見ていると、デューティ比を0%
にすると、GPIOピンをclearしてくれるようになっています。
(上記issueにもそう書いてあります)
ということで、次のpwm_pin_set_usec
の呼び出しでPWM出力が停止します。
pwm_pin_set_usec(pwm_dev, PWM_CHANNEL, period, 0)
westを使ったZephyrプロジェクトの管理
はじめに
Zephyr 1.14からwestというメタツールが公式なツールになりました。
面倒ですがさらっと使っておきましょう。
ソースコードやドキュメントは、できるだけ1.14を参照するようにします。 Zephyr 1.14はLTSという位置づけで、2年間はセキュリティアップデートが保証されます。
Getting Started
SDKのバージョンが更新されており、古いSDKではビルドできないので、新しいものをインストールします。
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.10.0/zephyr-sdk-0.10.0-setup.run cd <sdk download directory> sh zephyr-sdk-0.10.0-setup.run
$ cat ~/.zephyrrc export ZEPHYR_TOOLCHAIN_VARIANT=zephyr export ZEPHYR_SDK_INSTALL_DIR="/opt/zephyr-sdk"
次に、westのインストールです。
pip3 install --user west
westを使ってZephyr(と関連ツール)レポジトリを取得します。
west init zephyrproject cd zephyrproject west update $ ls modules net-tools zephyr
Zephyrのversionを指定する場合は、init時に指定します。
west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.14.0 zephyrproject cd zephyrproject west update
ビルド
westを使ってビルドしてみます。
$ west -v build -b nrf52840_pca10056 samples/hello_world $ ls build/ app CMakeFiles rules.ninja zephyr_modules.txt build.ninja cmake_install.cmake tinycbor CMakeCache.txt Kconfig.modules zephyr
なるほど、これでビルドできるようです。
デフォルトのターゲットを設定することもできます。
west config build.board nrf52840_pca10056
$ west build samples/hello_world/ ERROR: this looks like a new or clean build, please provide --board FATAL ERROR: refusing to proceed without --force due to above error
あれぇ〜、ダメじゃん?
デバッグ
JLinkデバッガのラッパーコマンドもあります。
west debug --runner jlink west debugserver --runner jlink
ZephyrでRTTコンソール
はじめに
久々のZephyrです。
JLinkには、JTAG/SWD経由でシリアル入出力をする機能があります。 UARTを使ったコンソールも良いのですが、物理配線が増えたり、簡単にUARTを引き出せない場合、RTTが便利です。
Zephyrコンフィグ
NordicのZephyrフォークを参考に、必要そうなコンフィグを有効化していきます。
- CONFIG_USE_SEGGER_RTT=y
- CONFIG_SHELL_BACKEND_RTT=y
上の2つあたりが必須そうです。 次の内容で設定ファイルを作成します。
|> zephyr/samples/subsys/shell/shell_module/prj_minimal_rtt.conf
CONFIG_SHELL=y CONFIG_KERNEL_SHELL=n CONFIG_SHELL_BACKEND_SERIAL=n CONFIG_OBJECT_TRACING=y CONFIG_THREAD_MONITOR=y CONFIG_INIT_STACKS=y CONFIG_BOOT_BANNER=n CONFIG_THREAD_NAME=y CONFIG_LOG=n CONFIG_SHELL_HISTORY=n CONFIG_SHELL_STACK_SIZE=1024 CONFIG_SHELL_CMD_BUFF_SIZE=128 CONFIG_SHELL_WILDCARD=n CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT=n CONFIG_SHELL_STATS=n CONFIG_SHELL_CMDS=n CONFIG_CONSOLE=y #enable RTT shell CONFIG_USE_SEGGER_RTT=y CONFIG_SHELL_BACKEND_RTT=y
ビルドしてターゲットボードに書き込みます。
mkdir build && cd $_ cmake -GNinja -DBOARD=nrf52840_pca10056 -DCONF_FILE="prj.conf prj_minimal_rtt.conf" .. ninja flash
RTTクライアントを立ち上げます。 まず、JLinkの接続から。
JLinkExe -device nrf52840_xxaa -speed 4000 -if SWD J-Link>connect
RTTクライアントを起動します。
$ JLinkRTTClient ###RTT Client: ************************************************************ ###RTT Client: * SEGGER Microcontroller GmbH * ###RTT Client: * Solutions for real time microcontroller applications * ###RTT Client: ************************************************************ ###RTT Client: * * ###RTT Client: * (c) 2012 - 2016 SEGGER Microcontroller GmbH * ###RTT Client: * * ###RTT Client: * www.segger.com Support: support@segger.com * ###RTT Client: * * ###RTT Client: ************************************************************ ###RTT Client: * * ###RTT Client: * SEGGER J-Link RTT Client Compiled Mar 27 2019 17:12:05 * ###RTT Client: * * ###RTT Client: ************************************************************ ###RTT Client: ----------------------------------------------- ###RTT Client: Connecting to J-Link RTT Server via localhost:19021 Connected. llss^?^?###RTT Client: Connection lost. Going to reconnect. ###RTT Client: Connecting to J-Link RTT Server via localhost:19021 .. Connected. SEGGER J-Link V6.44d - Real time terminal output J-Link OB-SAM3U128-V2-NordicSemi compiled Jan 7 2019 14:07:15 V1.0, SN=683516743 Process: JLinkExe rtt:~$
Zephyrのshell rtt:~$
が立ち上がっています。
Tabでの補完も効きます。
rtt:~$ demo device dynamic gpio log_test version
version情報を見てみましょう。
rtt:~$ vvveeerrrsssiiiooonnn Zephyr version 1.13.99
あん?何故かキー入力に対して、3回文字が出力されます。 Zephyr側はコマンドを受け付けているので、RTTClientの問題っぽいですね…。
どうもどこかのバージョンからバグったみたいですね…。
Zephyrのブートログが出力されていません。 上記設定では、printkが出力されていません。
UARTコンソールが有効になっているせいかと思いきや、そうでもないようです。
LOG_PRINTK
を設定しないとダメ?
お試して、LOG機能を有効化して、バックエンドをRTTにします。
ダメですね…。
1.14のリリースノートで解決済みになっているようですが、1.14でもprintkでの出力は出ていないような…?
下のサンプルだと、printkが出力されることがわかりました。
|> zephyr/samples/subsys/logging/logger
Process: JLinkExe ***** Booting Zephyr OS zephyr-v1.14.0-1039-gc3ccbbbdc3ca ***** Module logging showcase. [00:00:00.125,030] <inf> sample_module: log in test_module 11 [00:00:00.125,061] <inf> sample_module: Inline function. Disabling logging in the sample_module module Function called again but with logging disabled. Instance level logging showcase. [00:00:00.125,213] <inf> sample_instance.inst1: Inline call. [00:00:00.125,213] <inf> sample_instance.inst1: counter_value: 0 [00:00:00.125,213] <wrn> sample_instance.inst1: Example of hexdump: 01 02 03 04 |.... [00:00:00.125,213] <inf> sample_instance.inst2: Inline call. [00:00:00.125,213] <inf> sample_instance.inst2: counter_value: 0 [00:00:00.125,244] <wrn> sample_instance.inst2: Example of hexdump: 01 02 03 04 |.... Changing filter to warning on sample_instance.inst1 instance. [00:00:00.125,305] <wrn> sample_instance.inst1: Example of hexdump: 01 0m
設定ファイルを見てみます。
$ cat prj_rtt.conf CONFIG_LOG=y CONFIG_LOG_RUNTIME_FILTERING=y CONFIG_LOG_BUFFER_SIZE=2048 CONFIG_LOG_PRINTK=y CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0 CONFIG_LOG_BACKEND_RTT=y CONFIG_USE_SEGGER_RTT=y CONFIG_COVERAGE=n
ふむふむ。LOG_BACKEND_RTT
を有効にするようですね。
では、これをshellの方の設定に継ぎ足して…
$ ninja zephyr/subsys/shell/shell_rtt.c:7: ../../../../../include/toolchain/gcc.h:28:37: error: static assertion failed: "Conflicting log RTT backend enabled on the same channel" #define BUILD_ASSERT_MSG(EXPR, MSG) _Static_assert(EXPR, MSG) ^~~~~~~~~~~~~~ zephyr/subsys/shell/shell_rtt.c:12:1: note: in expansion of macro 'BUILD_ASSERT_MSG' BUILD_ASSERT_MSG(!(IS_ENABLED(CONFIG_LOG_BACKEND_RTT) && ^~~~~~~~~~~~~~~~ [64/130] Building C object zephyr/CMak...phyr.dir/subsys/logging/log_core.c.obj ninja: build stopped: subcommand failed.
ああん? まさか、shellとログ、どちらかしか使えないってこと…?
Rust製組込みOSのTockを触ってみる②
はじめに
諸事情によりまとまった時間を取るのが難しいので、入門系やります。
今回は、Rust製のRTOSであるTockを触ってみます。 githubのTock organizationはこちらです。
前回はC言語で書かれたサンプルアプリケーションを動かしたので、今回はRustで書かれたサンプルアプリケーションを動かしてみます。
libtock-rs
Rustでアプリケーションを書くためのライブラリレポジトリは、libtock-rsです。 examplesは、nRF52-DKでなら動作するようです。 nRF52840-DKとは別物ですが、まぁ動くでしょう。やってみましょう。
rustup target add thumbv7em-none-eabi git clone https://github.com/tock/libtock-rs.git cd libtock-rs ./run_example.sh blink
無事書き込めて、動いています。
+ elf_file_name=target/tab/blink/cortex-m4.elf + tab_file_name=target/tab/blink.tab + tockloader_flags='--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000' + hail_defined= + '[' -n '' ']' + mkdir -p target/tab/blink + cp target/thumbv7em-none-eabi/release/examples/blink target/tab/blink/cortex-m4.elf + elf2tab -n blink -o target/tab/blink.tab target/tab/blink/cortex-m4.elf --stack 2048 --app-heap 1024 --kernel-heap 1024 --protected-region-size=64 + '[' 1 -ge 2 ']' + tockloader uninstall --jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000 Preparing to uninstall apps... Using known arch and jtag-device for known board nrf52dk No apps are installed on the board + true + tockloader install --jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000 target/tab/blink.tab Installing apps on the board... Using known arch and jtag-device for known board nrf52dk Finished in 1.961 seconds
なにやら色々やっていますね。 事前にアプリケーションがインストールされていると、アンインストールするみたいです。
examplesチラ見
BLEのサンプルがあって気になります。
|> exmaples/ble_scanning.rs
#![no_std] use libtock::ble_parser; use libtock::led; use libtock::simple_ble; use libtock::simple_ble::BleCallback; use libtock::simple_ble::BleDriver; use libtock::syscalls; use serde::Deserialize; #[derive(Deserialize)] struct LedCommand { pub nr: u8, pub st: bool, } // Prevents the compiler from dropping the subscription too early. #[allow(unreachable_code)] fn main() { let mut shared_buffer = BleDriver::create_scan_buffer(); let mut my_buffer = BleDriver::create_scan_buffer(); let shared_memory = BleDriver::share_memory(&mut shared_buffer).unwrap(); let mut callback = BleCallback::new(|_: usize, _: usize| { shared_memory.read_bytes(&mut my_buffer[..]); ble_parser::find(&my_buffer, simple_ble::gap_data::SERVICE_DATA as u8) .and_then(|service_data| ble_parser::extract_for_service([91, 79], service_data)) .and_then(|payload| corepack::from_bytes::<LedCommand>(&payload).ok()) .and_then(|msg| led::get(msg.nr as isize).map(|led| led.set_state(msg.st))); }); let _subscription = BleDriver::start(&mut callback).unwrap(); loop { syscalls::yieldk(); } }
あー、serdeビルドしているの、なぜだろうと思ってましたが、ここで使っていたのですね…。 割とビルド時間長いのは、気になりますね。
BLE Advertising driverもkernel側に実装されています。
libtock-rsにBleAdvertisingDriver
の実装がありますが、基本はシステムコールを呼ぶだけで、実態はkernel側のようですね。
おもむろにDRIVER_NUMBER
が使用されていますが、これはkernel側のシステムコールで定義されています。
|> libtock-rs/src/simple_ble.rs
const DRIVER_NUMBER: usize = 0x30000; pub const MAX_PAYLOAD_SIZE: usize = 9; pub const BUFFER_SIZE_ADVERTISE: usize = 39; pub const BUFFER_SIZE_SCAN: usize = 39; mod ble_commands { pub const START_ADVERTISING: usize = 0; pub const ALLOW_ADVERTISMENT_BUFFER: usize = 0; pub const BLE_PASSIVE_SCAN_SUB: usize = 0; pub const ALLOW_SCAN_BUFFER: usize = 1; pub const PASSIVE_SCAN: usize = 5; }
|> tock/doc/syscalls/README.md
Radio
1.0 | Driver Number | Driver | Description |
---|---|---|---|
0x30000 | BLE | Bluetooth Low Energy | |
0x30001 | 802.15.4 | IEEE 802.15.4 | |
0x30002 | UDP | UDP / 6LoWPAN Interface |
なるほどね〜。
Rust製組込みOSのTockを触ってみる①
はじめに
諸事情によりまとまった時間を取るのが難しいので、入門系やります。
今回は、Rust製のRTOSであるTockを触ってみます。 githubのTock organizationはこちらです。
Getting started
Getting startedを参考に、何か動かしてみます。
Requirements
- nightly Rust (開発グループは
nightly-2019-04-11
を使用) - make
- tockloader
Rustとmakeはインストールされているので、tockloaderをインストールします。
pip3 install --upgrade tockloader --user
ttyUSBを管理者権限なしで使えるようにします。
grep -q dialout <(groups $(whoami)) || sudo usermod -a -G dialout $(whoami)
Compile kernel
git clone https://github.com/tock/tock.git cd tock/
kernelをビルドする前に、まずボードを選びます。 手元にnRF52840-DKがあるので、それにします。
kernelをビルドして、ボードに書き込みます。
cd boards/nordic/nrf52840dk/ make flash
JLinkで何やら書き込んでいるようです。
Finished release [optimized + debuginfo] target(s) in 2.36s text data bss dec hex filename 71676 1940 260204 333820 517fc target/thumbv7em-none-eabi/release/nrf52840dk tockloader flash --address 0x00000 --jlink --board nrf52dk target/thumbv7em-none-eabi/release/nrf52840dk.bin Flashing binar(y|ies) to board... Using known arch and jtag-device for known board nrf52dk Finished in 5.365 seconds
build example application
C言語のユーザーアプリケーションを実行してみましょう。
git clone https://github.com/tock/libtock-c.git cd libtock-c/ cd examples/blink/ make DIR ../../libtock/build/cortex-m0 CC ../../libtock/internal/alarm_internal.c /bin/sh: 1: arm-none-eabi-gcc: not found ../../TockLibrary.mk:149: recipe for target '../../libtock/build/cortex-m0/alarm_internal.o' failed make: *** [../../libtock/build/cortex-m0/alarm_internal.o] Error 127
む?C言語のアプリケーション実行には、GCCが必要みたいです。 (そういえばPC新しくしてからインストールしてなかったな)
sudo apt install gcc-arm-none-eabi
改めて、今度はビルドが通ります。
make
アプリケーションを書き込みます。
tockloader install --jlink --board nrf52dk
無事、Lチカできました!