この記事 is 何
これまで断片的に「xxマイコンが動いた」とか記事にしてきましたが、実際にマイコンを動かすために何をしているのかということをご紹介したく本シリーズを始めます。
あくまでも我流なので一部間違いがあるかもしれませんが、これでも一応数多くのマイコンを動かしているのでほぼほぼ合っているはずです。
ゼロから?
この記事のモットーは、「公式の IDE 等がない状態で、どのようにしてマイコン開発を行っていくのか」ということを明らかにすることです。ここでいう「ゼロから」というのはプロジェクトのテンプレートがないことですとか、ビルド済みコンパイラが無いという状態を指します。
現に僕も去年、一昨年くらいまでは「gcc は作れたんだけど、そこからどうすれば分からない」「リンカスクリプトを配布しているサイトを探さなきゃ」「スタートアップファイルなんて書けないよ」という状態でした。
最終的には「データシート類と gcc さえあれば、なんでもできる」という事をわかっていただけたら嬉しいです。
すみませんが、マイコンへの書き込みソフト作成は省略します。
目標
タイトル通り、Lチカです。しかもただのLチカではなくて、割り込みを使ったLチカを目標とします。そのためには、ゴールまでに以下の知識が必要となります。これは記事で紹介していくので、予め詳細に理解しておく必要はありません(でもある程度は知っておいてね)。
- 基礎的なシェルコマンド(
cd
,ls
,mkdir
,rm
等) - アセンブリ言語
- 割り込み
- データシート
- メモリ空間
対象とするマイコン
ということで早速やっていきましょう。開発環境を Mac としています。
対象のマイコンは需要も考えて ARM Cortex-M マイコンとします。「開発環境あるじゃん」というツッコミが入りそうですが、これ以外にあまり役立ちそうな例が浮かばなかったためです。本記事の目的も鑑みて、とりあえず開発環境が無いという仮定のもとでやっていくつもりです。
具体的な搭載チップは STM32F303K8T6 としましょう。秋月でも買えるチップです。
ツールチェインの準備
それでは取り敢えずコンパイラを用意します。目標として gcc と g++ を作ることにしましょう。これらはそれぞれ C言語 と C++ のコンパイラです。本記事では C++ は使わないのですが、取り敢えずついでに作っておきましょう。
ビルドするツール
- binutils
- バイナリ操作用の基礎ツール群。アセンブラもここに含まれる(つまりアセンブラだけやりたい人はこれだけ用意すれば十分なのです)。
- gcc(筑波大のミラー)
- 言わずと知れた GNU C Compiler。記事執筆時の最新バージョンは 8.3.0 です。
- newlib
- 組込み用のCライブラリ。
stdio.h
やstring.h
等の標準ライブラリはこれがないと使えない。
- 組込み用のCライブラリ。
- newlib-nano
- newlib の軽量版。ARM Cortex-M 向けに存在するライブラリで、浮動小数点数関連が省略されている。
- 現在調査中のため省略。
始める前に
Linux の方は大丈夫だと思いますが、Mac では gcc が必要です。何を言っているかと言うと、コンパイラを作るのにコンパイラが必要であるということです。イチからアセンブリでコンパイラを書くのは無理がありますから、こういうことになります。必要なのは ARM マイコン用コンパイラではなく、普通の PC 用 gcc で構いません。
なお、このような他のアーキテクチャ、他のシステム向けにコンパイルを行うソフトをクロスコンパイラといいます。
Mac で Homebrew を導入している方は以下でインストールできます。
$ brew install gcc
binutilsのビルド
いきなりやってみましょう。最新バージョンをダウンロードして、展開します。そのディレクトリ内に移動してください。勢い余って ./configure
しそうですが、これらのツール群はサブディレクトリを作り、その中でビルドを行うのが普通なので、そうしましょう。
まずは mkdir arm_build
(ディレクトリ名は何でもいい)とします。続いて cd arm_build
で移動します。
言い忘れました。これから何をするかと言うと、当然 binutils に含まれるツールをすべてビルドするのですが、そのために叩くべきコマンドがあります。
configure
: シェルスクリプトで構成。実際のビルドに必要なMakefile
を環境に合うように生成する。- もっと知りたい人は autoconf でググるといいかも。
make
: ビルド用のシステム。Makefile
があるディレクトリでmake
を実行すると、ビルドが開始する。make install
:make
でできた生成物を指定ディレクトリにコピーしインストールする。- 厳密に言えば、
Makefile
にあるinstall
ターゲットを実行するということ。上のmake
オンリーのコマンドではMakefile
内の最上位ターゲットを実行するという意味でしか無い。
- 厳密に言えば、
では configure
を実行すればいいのですが、もちろんツールチェインはあらゆるアーキテクチャに対応できるように作られているので、ARM Cortex-M 用に作れと指定する必要があります。とりあえずどうすればいいかわからないのでヘルプを求めてみましょうか。
$ ../configure --help
`configure' configures this package to adapt to many kinds of systems.
...
Fine tuning of the installation directories:
--bindir=DIR user executables [EPREFIX/bin]
--sbindir=DIR system admin executables [EPREFIX/sbin]
--libexecdir=DIR program executables [EPREFIX/libexec]
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--libdir=DIR object code libraries [EPREFIX/lib]
...
なんかよく分からないですが、以下のような記述が見つかるはずです。実際の実行結果から探してみてください(Mac 以外では異なるかも)。
make install
するとデフォルトで/usr/local/bin
にインストールする- 異なる場所にインストールしたい場合は
--prefix
を指定する
- 異なる場所にインストールしたい場合は
- ターゲットを指定するには
--target
を指定する
あと、help には出てきませんが、--disable-nls
とすると NLS: Native Language Support (多言語対応) が無効化されるのでエラーメッセージがググりやすくなると思います。
さて、取り敢えずやってみましょうか。多分最低限これでできるっぽいです。正しい場所にディレクトリを作成、cd
している場合は ../configure
が実行できるはずです。インストール先(prefix
) は自由に変えてください。この prefix の中に bin ディレクトリ等が展開されます。
$ ../configure --target=arm-none-eabi --prefix=/usr/local/cross/arm-none-eabi --disable-nls
...
checking where to find the target nm... just compiled
checking where to find the target objcopy... just compiled
checking where to find the target objdump... just compiled
checking where to find the target ranlib... just compiled
checking where to find the target readelf... just compiled
checking where to find the target strip... just compiled
checking where to find the target windres... just compiled
checking where to find the target windmc... just compiled
checking whether to enable maintainer-specific portions of Makefiles... no
configure: creating ./config.status
config.status: creating Makefile
お、一瞬で終わりましたね。creating Makefile
とありますが、つまりこれで Makefile
が生成されたようです。
$ ls
Makefile config.log config.status* serdep.tmp
ということで、make
してみましょう!ちょっと時間とバッテリーを食いますので、ご注意。
あとこれはお役立ち情報ですが、make
実行時に -j4
とやると4並列で処理できます。これは自分のマシンに合わせてください。
$ make -j4
画面がぐちゃぐちゃになっていろいろ実行されていますね。どうやら make
の最中でも configure
が行われているっぽいことも分かると思います。
おそらく数分で終わると思いますが(もちろん時間は環境による)、最後にエラーっぽいメッセージが出ていなければ完成です!案外あっけなかったですね。
終わったらインストールです。
$ sudo make install
/usr
ディレクトリをいじるのに root が必要になると思うので、sudo
を付けています。そうしたら、パスを通しましょう。
$ PATH=/usr/local/cross/arm-none-eabi/bin:${PATH}
これで例えばアセンブラを呼び出したらコマンドが実行できると思います。
$ arm-none-eabi-as --version
GNU assembler (GNU Binutils) 2.30
Copyright (C) 2018 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-none-eabi'.
ここまでくれば binutils のインストールは完了です。ビルド時にできたファイルたちは削除して構いません。
gccのビルド(その1)
一番時間がかかり、かつエラーにハマると厄介なところです。慎重に行きましょう。
まずはビルドに必要なツールを導入します。とても簡単にでき、スクリプトを実行するだけです。
$ contrib/download_prerequisites
できたら、binutils 同様に、専用のビルド用ディレクトリを作成します。それでは configure
のヘルプを見てみましょう。中でも必要なオプションを示します。
--target
でターゲット指定--prefix
でインストール指定- stdc++-v3 のプリコンパイルヘッダビルドは
--disable-libstdcxx
で無効化できる(C++ビルド時)- 無用の長物なので常に無効化しておくべき
- このビルド時に内部エラーで失敗することがある
--enable-bootstrap
でブートストラップを有効にする(?)- 複数回ビルドして、ちゃんとファイルができているか検証するもの
- ぶっちゃけ不要なんで無効化しましょう(やってもビルド時間が長くなるだけ)
--enable-libssp
で libssp をビルドできる- SSP: stack smash protector はスタックポインタ由来の攻撃を保護するライブラリです。あってもいいかなと思いましたが(用途不明)、どうやらビルド時にコケるようなので無効化しちゃいましょう。
また、これ以外に先程同様の --disable-nls
、--enable-languages
によってビルドする言語を選べるということも利用します。むしろ --enable-languages
で言語を選ばないと、fortran とか、ada とか、いろいろな言語用のコンパイラをビルドしようとし、失敗してしまいます。
今回の目的は C と C++ のコンパイラをビルドすることですが、C++ はこの後にビルドする newlib が無いとだめなため、取り敢えず C のみビルドしましょう。
では configure
等々をしてみましょう。
$ ../configure --target=arm-none-eabi --prefix=/usr/local/cross/arm-none-eabi --enable-languages=c --disable-nls --disable-bootstrap --disable-libssp
$ make -j4
$ sudo make install
しばらくお茶しながら画面を見てみるのもいいと思います。「いろいろなライブラリをビルドしているなぁ」と分かると思います。僕個人的には少し楽しい時間です。暇ですけど。
インストールができても、生成されたファイルは削除しないでください。C++ のコンパイラ(g++)をビルドするために必要です。
具体的には、これに上書きでビルドをするという形態を取ります。
newlibのビルド
newlib も binutils と同じようにできます。今回もきっちりブートストラップを無効化していきましょう。
$ ../configure --target=arm-none-eabi --prefix=/usr/local/cross/arm-none-eabi --disable-bootstrap
$ make -j4
$ sudo make install
gccのビルド(その2)
続いて、g++ をビルドします。先程の、libstdc++
関連オプションをオンにします。あと、enable-languages
に c++
をカンマ区切りで追加しておきましょう。
$ ../configure --target=arm-none-eabi --prefix=/usr/local/cross/arm-none-eabi --enable-languages=c,c++ --disable-nls --disable-bootstrap --disable-libssp --disable-libstdcxx
$ make -j4
$ sudo make install
これで一応終わりです。お疲れ様でした。
FAQ
ツールチェインビルド時にありそうなミスとかを挙げます。
なんかマクロがないとかで怒られる
あなたが使っている gcc が本物か確かめてみましょう。gcc --version
と打ったときに clang の文字列が出てきたらそれは偽物の gcc です。
もしも Homebrew で入れたのなら、gcc-8
とかいうコマンドになっていると思います。なので gcc
として実行できるようにする必要があります。
例えば、別ディレクトリを作ってそこにパスを通すという方法です。こうすればディレクトリ内に別名のシンボリックリンクを貼ることができます。例えば ~/usr/bin
というディレクトリを作った場合です。
$ mkdir -p ~/usr/bin # ディレクトリ作成
$ ln -s /usr/local/bin/gcc-* ~/usr/bin/gcc # Homebrewでインストールした gcc-なんとか に対して、gcc という名前でリンクを貼る
$ PATH=~/usr/bin:${PATH} # 作成したディレクトリにパスを通す(セッション内のみ有効)
$ gcc -v # clangではないことを確認する
gccビルドの初期段階でコケる
binutils をビルドした後、そこにパスを通してますか?怠らずにきちんと実行しましょう。
$ PATH=/usr/local/cross/arm-none-eabi/bin:${PATH}
なおこの後は一度作成ディレクトリ(arm_build)を削除して再度 configure
する必要があります。
fallthroughのエラーが起きる
ビルド時に -Werror
(警告をすべてエラー化するオプション)が有効になっているためです。現在のディレクトリを削除し、再度 configure
をやり直す必要があります。
その際、--disable-werror
を追加してください。こうすることでビルドが通ることがあります。
MPFRのバージョンがダメだとか言われる
contrib/download_prerequisites
を前もって実行してください。
〆
ということで、今まで以上にコンパイラのビルド法を丁寧に説明したつもりです。
次回はリンカスクリプトの準備です。