imadedede のブログ

今出川潤の出張所。

「12ステップで作る組み込みOS自作入門」環境構築した

「12ステップで作る組み込みOS自作入門」始めてはや数日。 6章まで終わってようやく折り返し地点。 環境構築がいろいろ大変だったのでその記録をしていく。 基本的には書籍とサポートページを行ったり来たりしながら環境構築をすすめる。

kozos.jp

概要

VirtualBox + Vagrant で仮想環境を使って開発環境を構築していく。

わざわざ仮想化せんでもええやん。ただ環境構築はミスって不可逆的な変更でいろいろ汚してしまった時、気持ちが辛くなる。仮想化することで、間違ったらいつでも捨てることができると自分に言い聞かせ、作業の心理的安全性を確保する。

ええんや! メモリもCPUも資源は潤沢なんやから! これが富豪的ソフトウェア開発や!

ホストにはエディタとセルフコンパイラとシリアル接続。そして Git でバージョン管理。

ゲストにはセルフコンパイラとクロスコンパイラをインストール。

VirtualBox の設定で、ゲストにUSBシリアル変換アダプタからの接続をバイパスすることはできたけど、あまりメリットがなかった(後述)。

64bit OS だといろいろ不都合があるので 32bit OS を使う。

具体的には GCC ビルド時にパッチを当てる必要がある。gcc3.4.6だとコンパイル時に負数の即値があると警告が出てくる。警告であってエラーではないので、もしかしたら動作に問題はないのかもしれない(そこまで詳しく調査してない)が、ビルド時に警告を無視し続けるのは精神衛生上あまりよろしくないので、64bit を避ける。

たぶん、64bitOS ならGCCも新しいバージョンにすればいいんだけど、書籍との環境を変えすぎると、問題が起こったときに原因の切り分けがとても大変になるので、なるべく書籍での環境に合わせる。

ゲストOS設定

VirtualBox + Vagrant 設定を作っていく。

まず vagrant-vbguest プラグイン導入。これがないと起動直後の共有フォルダ同期でコケる。

できたらゲスト OS を Vagrant Cloud からダウンロードする。

Vagrant box ubuntu/xenial32 - Vagrant Cloud

vagrant init ubuntu/xenial32
vagrant up

これでダウンロードが始まるのでしばらく待つ。無事起動したら、Vagrantfile に共有フォルダ設定を追記する。

設定ファイルではホストゲスト間の共有フォルダを設定していく。ホスト OS の Vagrantfile と同じディレクトリにある workspace ディレクトリをゲスト OS と共有する。ソースファイル編集の作業は主にこの共有フォルダ内で行う。ちなみにこの設定は46行目あたりにあった。

  config.vm.synced_folder "./workspace", "/home/vagrant/workspace"

設定したら vagrant reload してゲスト OS を再起動。

セルフコンパイラは最新でOK。いつの間にか入っていた。

ロスコンパイラの構築

binutilsgcc の tar を取ってきて解凍。

書籍のサポートページによると、クロスコンパイラに関しては最新ではないほうがいいらしい。なので、書籍にて検証済みのバージョンを使用する。

binutils

書籍の手順に従ってインストール。./configure 時のオプションに --disable-werror がないと make install でコケる。

gcc

インストール前にパッチを当てる。パッチはサポートページから入手。パッチコマンドで当てる。

書籍の手順にしたがってソースコードを修正し ./configure して make して sudo make install する。これでインストールはOK。

ビルド後の後片付け

両方のインストール後は使用したファイルをそのままにしてはいけない。

GCCディレクトリが、なぜかあとで vagrant reload または vagrant up したときに、起動直後の rsync でエラーを起こしてしまう。そしてホストゲスト間のフォルダ同期に失敗してしまう。

対策は、gcc フォルダを削除する。あるいは、Vagrant 設定ファイルがあるディレクトリ以下からどこか別の場所に移動する。 これだけで何事もなかったように動く。 なんで GCC の解凍後のディレクトリが rsync を邪魔するのかはわからん。沼が深そうなので、調査は一旦後回し。

シリアル接続

バイナリイメージ作成はゲストOSでやって、マイコンボードとの通信はホストOSでやる。

今回使ったのは USBシリアル変換コード。秋月電子で買った。ドライバの追加なしでいきなり使えた。

接続するとコマンドで /dev/ttyUSB0 が出てるのが確認できる。

ただしこのままでは通信できない。/dev/ttyUSB0 には一般ユーザのアクセス権がないため。なので権限設定をしていく。

とりあえず接続できるようにするには chmod 666 /dev/ttyUSB0 でいい。しかしこれだと、USB 接続を外すたびに権限がリセットされる。なので接続ごとに毎回設定をするようにする。

lsusb コマンドでベンダ ID とプロダクト ID を見る。そして /etc/udev/rules.d/50-usb-serial.rules に追記する。

以下の記事を参考にした。

これで USB を挿し直しても無事に権限設定ができている。

ぶっちゃけ、なんで ttyUSB0 でなんで 0 なのかはわからん。1 かもしれないし 2 かもしれないけど、それを確認するコマンドもわからん。とりあえず ttyUSB0 で決め打ちして動いてるからOKとした。あとで調べる。

そして Hello, World! へ……

シリアル通信は ckermit で行う。初見ではボードに電源をつないでも何も反応がなかったので、本当に動いているのか不安だったけど、ちゃんと動いていた。

kermit の設定は書籍に従う。自分の環境だと set carrier-watch off をつけないとうまくいかなかった。 kermit 設定は ~/.kermrc に記述すればいい。

# ckermit デフォルト設定
set line /dev/ttyUSB0   # 接続先

# 接続設定
set speed 9600          # ボーレート
set terminal bytesize 8 # ビット
set stop-bits 1         # ストップビット
set parity none         # パリティ
set carrier-watch off   # キャリア検出
set flow-control none   # フロー制御

# 4章以降で必要(後述)
# lrzsz を利用したファイルの送受信プロトコル設定
set protocol xmodem rx {rx -b} {sx %s} {sx -b %s} rx rx

以下の記事を参考にした。

これで kermit 起動後は connect で接続できる。

書籍1章に従って正しくプログラムを転送できているなら、これでリセットボタンを押すごとに Hello, World! を受信できる。

たまに出力される文字列が化けて出てくることがある。そんなときは、とりあえず USB シリアルケーブルの USB-PC 間を一度抜き挿しすると直る。

ゲストOSにUSBシリアル接続をバイパスする場合

最終的には見送ったが、ゲストにUSBをバイパスする方法もある

VirtualBox のゲスト OS 設定画面でシリアルポートのパスに /dev/ttyUSB0 を設定。これでゲストOSの /dev/ttyS0 に接続することでシリアル通信ができる。

……はずなのだけど、なぜか自分の環境では受信できたりできなかったり、画面上の文字列表示がずれてたりで、うまくできなかった。これがバイパス設定を見送った主な理由。

他にも単純な問題はある。ホストOSのデバイスをゲストOSに常にバイパスする設定だと、USBが挿さっていない状態でゲストOSを起動すると常にエラーが起きる。これがはっきり言って面倒くさい。

このふたつの理由から、USBシリアルはホストから通信したほうが手間かからずにいいな、となった。

2章以降での問題と解決など

3章以降でのリンカスクリプトの修正について

Google グループ によると、書籍3章のリンカスクリプトは厳密な記述ではないらしく、根本的な解決方が紹介されていた。なので適用した。

さらに、

www.slideshare.net

51ページ以降にて、ビルド時の問題とその解決方法が載っている(GCC 4.7)。このコードの変更も適用した。

4章以降でのファイル転送のオプション変更

4章以降、シリアル通信でファイル転送を行うようになる。

そのとき kermit で接続するなら lxzsz を追加にインストールして送受信するのだけど、その設定コマンドは書籍から以下のように変更している。

set protocol xmodem rx {rx -b} {sx %s} {sx -b %s} rx rx

-a オプションから -b オプションへ変更している。man ページによると -a オプションは ascii モードで、-b オプションは binary モードで送信する。この違いは何かというと、-a モードでは改行コードの LF が CRLF に変換されてしまう。

これだと4章でのテキストファイル送信時に、ローカルでのファイルダンプと送信済みファイルのダンプが一致しない。送信過程で LF が CRLF に変換されてしまうため。ちなみに改行コードを CRLF で送信すると CRCRLF になる。そのため binary モードで送信するよう、オプションを変更している。

感想

こんな感じの設定で6章まで来た。お疲れ様でした。

この環境でこれまで問題なかったので、たぶんこの先も大丈夫じゃないかな……。

残り半分。頑張っていきましょう。

とか言っている間に、最後まで終わりました。非常に有意義な時間を過ごせました。感想はまた別の記事で。

学習中にコミットしていたリポジトリはこちら。

github.com

お疲れさまでした。