OpenOCD + ST-LinkでFirmware書き込み
OpenOCDを使ってSTM32F401 Nucleo-64にST-Link経由でFirmwareを書き込む。
OpenOCDとST-Linkドライバのインストール
Arch Linuxなら以下のコマンドでインストールする。
$ pacman -S openocd stlink
Firmwareを書き込む
OpenOCDで指定できるinterface, target, boardの設定ファイルは/usr/share/openocd/scripts
に配置されている。
OpenOCDで接続する
STM32F401 Nucleo-64 boardのUSB接続の場合
$ openocd -f board/st_nucleo_f4.cfg
もしくは、
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f4x.cfg
STM32F401 Chip + 中華ST-Linkの場合
Nucleoボードを使っているのなら中華ST-Linkを使う必要はないが、試した結果を書き残しておく。
$ openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg
なお、Nucleoボード上のSWDコネクタ(CN4)は以下のピンアサインとなっている。
Pin | CN4 |
---|---|
1 | VDD_TARGET |
2 | SWCLK |
3 | GND |
4 | SWDIO |
5 | NRST |
6 | SWO |
※中華ST-Linkでは、一度ST-LinkのFirmwareをアップデートした後に書き込みに成功するようになった。 (書き込みに成功している中華ST-LinkのFW versionはV2J28S7)
telnetで書き込む
上記手順でOpenOCDで接続後、別のterminalからtelnet
を起動する。
$ telnet localhost 4444
telnet
上で以下のコマンドを実行することでFirmwareを書き込む。
> reset halt > flash write_image erase ${elf_file_absolute_path}
telnet無しでFirmwareを書き込む
上記の方法だと、OpenOCDとは別にtelnet
を起動する必要があり、若干煩わしい。
そこで、Firmwareを書き込む手順を記載したOpenOCDのconfigファイルを用意し、OpenOCDだけで書き込みを行えるようにする。
任意の名前で以下の内容のconfigファイルを作成する。 (今回はopenocd.cfgという名前にした)
telnet_port 4444 gdb_port 3333 source [find board/st_nucleo_f4.cfg] init proc flash_elf {elf_file} { reset halt flash write_image erase $elf_file verify_image $elf_file echo "flash write_image ($elf_file) complete" reset exit }
configファイルを作成したら、以下のコマンドで書き込みを実行する。
$ openocd -f openocd.cfg -c "flash_elf ${elf_file_relative_path}"
※OpenOCDのproc
の名前はOpenOCDの既存コマンド名にあるものを使うとエラーになるようだ。
(最初、proc flash {elf_file}
としていたところ、以下のエラーが出て小一時間ほどハマってしまった)
Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 2000 kHz adapter_nsrst_delay: 100 none separate srst_only separate srst_nogate srst_open_drain connect_deassert_srst Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : clock speed 1800 kHz Info : STLINK v2 JTAG v28 API v2 SWIM v18 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 3.256353 Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints flash Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz adapter speed: 1800 kHz target halted due to debug-request, current mode: Thread xPSR: 0x61000000 pc: 0x1fff1048 msp: 0x20002e40 openocd.cfg:13: Error: wrong # args: should be "flash elf_file" in procedure 'flash' at file "openocd.cfg", line 13
ST-LinkのFirmwareアップデート
こちらで公開されているツールを使ってアップデートする。
参考
Rustでクロスコンパイル
x86_64-unknown-linux-gnu
のホスト環境上で、CHIP向けのバイナリをRustでクロスコンパイルすることを目的とする。
概要
rustup target add ${target_triple}
でターゲットのツールチェインを追加- ターゲットのリンカをインストール
- Cargoのconfigファイルにターゲット用のリンカ設定を記述
cargo build --target ${target_triple}
でクロスコンパイル実行
※Rustのツールチェイン管理を行ってくれるツールのrustup
はこちらを参考にインストール済みとする。
環境
ホストのシステム情報。
$ uname -a Linux hostname 4.13.7-1-ARCH #1 SMP PREEMPT Sat Oct 14 20:13:26 CEST 2017 x86_64 GNU/Linux $ rustup show Default host: x86_64-unknown-linux-gnu 1.21.0-x86_64-unknown-linux-gnu (default) rustc 1.21.0 (3b72af97e 2017-10-09)
ターゲットであるCHIPのシステム情報。
chip@chip:~$ uname -a Linux chip 4.4.13-ntc-mlc #1 SMP Thu Nov 3 01:28:54 UTC 2016 armv7l GNU/Linux
ターゲットのツールチェインを追加
rustup target list
で、Rustがサポートするターゲットのリストを確認する。
$ rustup target list | pr -w 90 --columns=2 aarch64-apple-ios mips-unknown-linux-gnu aarch64-linux-android mips-unknown-linux-musl aarch64-unknown-fuchsia mips64-unknown-linux-gnuabi64 aarch64-unknown-linux-gnu mips64el-unknown-linux-gnuabi64 arm-linux-androideabi mipsel-unknown-linux-gnu arm-unknown-linux-gnueabi mipsel-unknown-linux-musl arm-unknown-linux-gnueabihf powerpc-unknown-linux-gnu arm-unknown-linux-musleabi powerpc64-unknown-linux-gnu arm-unknown-linux-musleabihf powerpc64le-unknown-linux-gnu armv7-apple-ios s390x-unknown-linux-gnu armv7-linux-androideabi sparc64-unknown-linux-gnu armv7-unknown-linux-gnueabihf wasm32-unknown-emscripten armv7-unknown-linux-musleabihf x86_64-apple-darwin armv7s-apple-ios x86_64-apple-ios asmjs-unknown-emscripten x86_64-linux-android i386-apple-ios x86_64-pc-windows-gnu i586-pc-windows-msvc x86_64-pc-windows-msvc i586-unknown-linux-gnu x86_64-rumprun-netbsd i686-apple-darwin x86_64-unknown-freebsd i686-linux-android x86_64-unknown-fuchsia i686-pc-windows-gnu x86_64-unknown-linux-gnu (default) i686-pc-windows-msvc x86_64-unknown-linux-musl i686-unknown-freebsd x86_64-unknown-netbsd i686-unknown-linux-gnu x86_64-unknown-redox i686-unknown-linux-musl
armv7-unknown-linux-gnueabihf
が見つかり、RustはCHIPのターゲットをサポートしていることを確認できたため、以下のコマンドでCHIP用のツールチェインを追加する。
$ rustup target add armv7-unknown-linux-gnueabihf
rustup target add
後にrustup show
やrustup target list
を実行してRustのツールチェインの状態を確認すると、armv7-unknown-linux-gnueabihf
が(installed)
になっているのがわかる。
$ rustup show Default host: x86_64-unknown-linux-gnu installed targets for active toolchain -------------------------------------- armv7-unknown-linux-gnueabihf x86_64-unknown-linux-gnu active toolchain ---------------- 1.21.0-x86_64-unknown-linux-gnu (default) rustc 1.21.0 (3b72af97e 2017-10-09) $ rustup target list | pr -w 90 --columns=2 aarch64-apple-ios i686-unknown-linux-musl aarch64-linux-android mips-unknown-linux-gnu aarch64-unknown-fuchsia mips-unknown-linux-musl aarch64-unknown-linux-gnu mips64-unknown-linux-gnuabi64 arm-linux-androideabi mips64el-unknown-linux-gnuabi64 arm-unknown-linux-gnueabi mipsel-unknown-linux-gnu arm-unknown-linux-gnueabihf mipsel-unknown-linux-musl arm-unknown-linux-musleabi powerpc-unknown-linux-gnu arm-unknown-linux-musleabihf powerpc64-unknown-linux-gnu armv7-apple-ios powerpc64le-unknown-linux-gnu armv7-linux-androideabi s390x-unknown-linux-gnu armv7-unknown-linux-gnueabihf (installed) sparc64-unknown-linux-gnu armv7-unknown-linux-musleabihf wasm32-unknown-emscripten armv7s-apple-ios x86_64-apple-darwin asmjs-unknown-emscripten x86_64-apple-ios i386-apple-ios x86_64-linux-android i586-pc-windows-msvc x86_64-pc-windows-gnu i586-unknown-linux-gnu x86_64-pc-windows-msvc i686-apple-darwin x86_64-rumprun-netbsd i686-linux-android x86_64-unknown-freebsd i686-pc-windows-gnu x86_64-unknown-fuchsia i686-pc-windows-msvc x86_64-unknown-linux-gnu (default) i686-unknown-freebsd x86_64-unknown-linux-musl i686-unknown-linux-gnu x86_64-unknown-netbsd
ターゲットのリンカをインストール
Rustのツールチェインではターゲットのリンカはサポートしていないため、別途用意する。
$ apt-get install gcc-arm-linux-gnueabihf
Cargoのconfigにターゲットのリンカ設定を記述
クロスコンパイルする対象とするプロジェクトを生成する。
$ cargo new --bin hello
Cargoが生成したスケルトンコードのままで実行すると、Hello, world!
が標準出力に出力される。
$ cargo run Compiling hello v0.1.0 (file:///host_shared/hello) Finished dev [unoptimized + debuginfo] target(s) in 0.44 secs Running `target/debug/hello` Hello, world!
これをそのままターゲット(CHIP)上で動作するようにするために、プロジェクトのconfigファイルを作成し、ターゲットのリンカの設定を記述する。
$ mkdir .cargo $ cat > .cargo/config << EOF > [target.armv7-unknown-linux-gnueabihf] > linker = "arm-linux-gnueabihf-gcc" > EOF
クロスコンパイル実行
$ cargo build --target armv7-unknown-linux-gnueabihf
ビルドされたバイナリの情報を確認すると、ターゲット(CHIP)向けのバイナリになっていることがわかる。
$ file target/armv7-unknown-linux-gnueabihf/debug/hello target/armv7-unknown-linux-gnueabihf/debug/hello: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=70dfb01aa67d797fc64005ac8cff1dba94a48a34, not stripped $ readelf -A target/armv7-unknown-linux-gnueabihf/debug/hello Attribute Section: aeabi File Attributes Tag_CPU_name: "7-A" Tag_CPU_arch: v7 Tag_CPU_arch_profile: Application Tag_ARM_ISA_use: Yes Tag_THUMB_ISA_use: Thumb-2 Tag_FP_arch: VFPv3-D16 Tag_ABI_PCS_GOT_use: GOT-indirect Tag_ABI_PCS_wchar_t: 4 Tag_ABI_FP_rounding: Needed Tag_ABI_FP_denormal: Needed Tag_ABI_FP_exceptions: Needed Tag_ABI_FP_number_model: IEEE 754 Tag_ABI_align_needed: 8-byte Tag_ABI_enum_size: int Tag_ABI_VFP_args: VFP registers Tag_CPU_unaligned_access: v6 Tag_ABI_FP_16bit_format: IEEE 754
クロスコンパイルしたバイナリをターゲット上で実行
chip@chip:~$ ./hello Hello, world!
ターゲット(CHIP)上で実行できることが確認できた。
参考
Rustでのクロスコンパイルに必要な情報が、以下のページに非常にわかりやすく説明されている。
japaric/rust-cross: Everything you need to know about cross compiling Rust programs!
環境構築の検証用にDockerを使う
Rustのクロスコンパイル環境構築の検証にDockerを使い始めた。
開発環境を構築する際、最初は試行錯誤しながら行なうため、さぁ環境が構築ができた、となった時に行なってきた手順のどれが最低限必要なものだったのかがわからなくなることが多い。 必要だと思ってインストールしたものが実は必要なかったり、必要ないと思ったものに実は依存していたりするため、手順に再現性があるのかどうかを検証したくなる。
このようなケースにおいて、いつでもクリーンな環境から手順の確認ができるDockerが非常に便利だったので、以下にRustの開発環境をDockerで立ち上げるまでにやったことをメモとして残しておく。
$ docker --version Docker version 17.10.0-ce, build f4ffd2511c
Docker HubでRustがインストールされたDockerイメージが公開されているのでpullする。
$ docker pull rust
Rustのイメージが取得できたことを確認する。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE rust latest 9578919665db 7 days ago 1.33GB
RustのDockerイメージからコンテナを起動する。
$ docker run -i -t -v ${host_dir_path}:${container_dir_path} --rm rust
docker run
のオプションの意味は以下を参照。
-i
: 標準入力を有効にする-t
: 疑似ターミナルを割り当てる-v ${host_dir_path}:${container_dir_path}
: ホストとコンテナの共有ディレクトリを指定する--rm
: コンテナからExitした時に自動的にコンテナを削除する
共有ディレクトリを指定しているのは、ホストで書いたコードをコンテナ内でビルドし、コンテナでビルドしたファイルをホストから参照するのを容易にするため。
Target Triple
Rustのコンパイラのソースコードの中で使用されていた"Triple"という言葉の意味がわからなかったので調べた。
Target Triplets describe a platform on which code runs and are a core concept in the GNU build system. They contain three fields: the name of the CPU family/model, the vendor, and the operating system name.
サポートするターゲットを表す表現方法を Target Triple
と呼んでいる。
ターゲットの指定が以下の3つのフィールドから成っていることが、Tripleと呼ぶ理由らしい。
- CPU family/model
- Vendor
- OS
具体例としては、以下のようなターゲット指定が挙げられる。(よく見るやつ)
なお、clangのドキュメントでは以下のようにフィールド指定が定義されている。
Cross-compilation using Clang
The triple has the general format
<arch><sub>-<vendor>-<sys>-<abi>
, where:
Arch Linux上にRe:VIEWをインストールする
書籍執筆支援システムRe:VIEWの環境構築のメモ。
依存パッケージのインストール
Re:VIEWを使うために必要なパッケージをインストールする。
$ sudo pacman -S ruby ruby-rubyzip texlive-most texlive-langjapanese poppler-data
dvipdfmxのフォントのエラー対策
Re:VIEWからpdfを生成する際(後述のreview-pdfmaker
実行時)にデータに日本語を含んでいると、以下のエラーが出る場合がある。
kpathsea: Running mktexpk --mfmode / --bdpi 600 --mag 2+180/600 --dpi 1380 uphgothr-h mktexpk: don't know how to create bitmap font for uphgothr-h. mktexpk: perhaps uphgothr-h is missing from the map file. kpathsea: Appending font creation commands to missfont.log. dvipdfmx:warning: Could not locate a virtual/physical font for TFM "uphgothr-h". dvipdfmx:warning: >> There are no valid font mapping entry for this font. dvipdfmx:warning: >> Font file name "uphgothr-h" was assumed but failed to locate that font. dvipdfmx:fatal: Cannot proceed without .vf or "physical" font for PDF output...
対策として、/etc/texmf/dvipdfmx/dvipdfmx.cfg
を編集する。
%% Put additional fontmap files here (usually for Type0 fonts) f cid-x.map
上記変更を反映するために以下を実行する。
$ sudo updmap-sys $ sudo texconfig rehash $ updmap $ texconfig rehash
Re:VIEWのインストール
AURにあるRe:VIEWパッケージは若干古いようなので、gitからインストールする。
$ git clone https://github.com/kmuto/review.git
clone後、展開されたreview/bin/
にPATHを通す。
始め方
$ review-init ${document_name}
${document_name}/
以下に${document_name}.re
が生成されているので、これを編集する。
各フォーマットで出力する
- PDF出力
$ review-pdfmaker config.yml
- EPUB出力
$ review-epubmaker config.yml
- HTML出力
$ review-epubmaker config.yml