SNSへはこちら

ゼロからマイコンでLチカをするまで(1) - 概要・開発の準備

この記事 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.hstring.h 等の標準ライブラリはこれがないと使えない。
  • 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-languagesc++ をカンマ区切りで追加しておきましょう。

$ ../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 を前もって実行してください。

ということで、今まで以上にコンパイラのビルド法を丁寧に説明したつもりです。
次回はリンカスクリプトの準備です。