2013/06/16

【組み込みOS自作入門】 1章&2章まで進んだ

"12ステップで作る組込みOS自作入門"という書籍で学びながら、組み込みOSを自作してみています。マイコンは、書籍のとおり H8/3069Fです。

組み込みOS自作本で勉強をはじめるという宣言のあと・・・
学業や、Webサービス開発のほうが忙しかったり、
Fedora→Arch Linuxに乗り換えたり、Raspberry PiやArduinoに手を出したり...としているうちに、めちゃくちゃ時間があいてしまいましたが(汗;)・・・

つい先日から少しずつ触りはじめ...今日やっと...まともに進めることができました。
ただいま勉強中のソースコードはGitHubで公開していますww
ソースコードをKL-01ライセンスにしてくださった本の筆者 kozosさん に感謝!
https://github.com/mugifly/study-my12os
コメントと、ちょっとしたメモも英語(Broken english(笑))で書きながら...。
(もう少し...まともな英語をかけるようになりたいものです><;)

さて...まずは、1章。


1章では、Linux上にセルフコンパイル環境とクロスコンパイル環境を構築して、
Hello, worldを表示する簡易的な”ブートローダ”や、ライブラリを作成しました。
文字を出力するための標準ライブラリを自作するというのも新鮮でした。
https://github.com/mugifly/study-my12os/tree/st1

ちなみに、クロスコンパイル環境ですが、Arch Linux (64bit)で問題なく構築できました。
https://github.com/mugifly/study-my12os/wiki/BuildEnvironment
  • binutils-2.23
  • gcc-4.8.1
PCとボードとの接続には、USBシリアル変換ケーブル "BSUSRC06"を使いました。

ボードへの書き込みは、h8write、kz_h8writeの両方で成功しています。
また、端末エミュレータには、Minicomを利用しています。

尚、ビルドと書き込みの手順は、
https://github.com/mugifly/study-my12os/wiki
にメモしておきました。

次に、2章(ブートローダの作成)です。


前章で作成したライブラリ(lib.c)におなじみの機能を追加していきます。

  • memset - メモリへのバイト書き込み
  • memcpy - メモリのコピー
  • memcmp - メモリの比較
  • strlen - 文字列の長さ取得
  • strcpy - 文字列のコピー
  • strcmp - 文字列の比較
  • strncmp - 文字列の比較 (長さ指定)

また、この章では、"SCI (シリアルコントローラ)"の話がでてきました。
要点だけ、メモしておきたいと思います。

  • H8/3069Fに搭載されたSCIは3つあり、すべてCPUに内蔵されている。
  • H8/3069Fのシリアルコネクタは、SCI1(0xffffb8)に接続されている。
    (即ち、SCI1を制御すれば、シリアル通信ができる。)
  • SCI1のレジスタマッピング: (H8/1069Fのマニュアル 13.1.4節に詳細記載)
    • SMR: 0xffffb8 - シリアルモードレジスタ
      (bitは以下の通り。今回は全bitが0となる。)
      • bit0,1 - クロックセレクト (0,0ならば、クロックそのまま)
      • bit3 -  ストップビット長 (0=1bit, 1=2bit)
      • bit4 - パリティの種類 (0=偶数, 1=奇数)
      • bit5 - パリティの有効 (0=無効, 1=有効)
      • bit6 - データ長 (0=8bit, 1=7bit)
      • bit7 - モード (0=調歩同期式, 1=クロック同期式)
    • BRR: 0xffffb9 - ビットレートレジスタ (ボーレート設定)
      あまり高速にするとうまくいかないので、9600bps。
    • SCR: 0xffffba - シリアルコントロールレジスタ (送受信の有効/無効)
      • bit0,1 - クロックイネーブル
      • bit4 - 受信イネーブル (1=送信)
      • bit5 - 送信イネーブル (1=送信)
      • bit6 - 受信割り込みイネーブル (1=割込可能)
      • bit7 - 送信割り込みイネーブル (1=割込可能)
    • TDR: 0xffffbb - トランスミットデータレジスタ (送信する1文字)
    • SSR: 0xffffbc - シリアルステータスレジスタ (送信完了/受信完了)
      • bit6 - 受信ステータス (1=受信完了)
      • bit7 - 送信ステータス (1=送信完了)
    • RDR: 0xffffbd - 受信した1文字を読み出す
  • SCI1を準備する際には・・・
    1. SCI1のSCRにすべて0を書き込むことで一旦無効化。
    2. SCI1のSMRへ通信設定を行う。
    3. 再びSCRを書き換えて有効にする。
  • SCI1で1文字送信する際には・・・
    • SCI1のSSRの送信ステータスが1であることを確認。
    • SCI1のTDRに送信したい1文字を書き込む。
    • SCI1のSSRの送信ステータスを0にする (送信依頼できる)
    • 送信完了すると・・・SCI1のSSRの送信ステータスが1になる。
  • serial.c
    • struct h8_3069f_sci として、SCIのレジスタを操作するための構造体を定義。
    • regs[] として、3つ全てのSCIのための構造体配列を生成。
  • lib.c
    • putc関数では、シリアル通信の仕様に基づいて、改行コードを '\n' → '\r'(0x0d)に変換する。これを"端末変換"という。
      端末変換された文字列は、SERIAL_DEFAULT_DEVICE(SCI1)宛に出力される。
    • 書籍では、端末変換をしない生の入出力を"シリアル"。端末変換をする入出力を"コンソール"という。
さらに、"スタートアップ"の説明もでてきました。
  • startup.s(アセンブリ)の _start からプログラム実行が開始される。
    ここではスタックポインタの設定が行われ、main関数にジャンプする。
    このような処理を"スタートアップ"という。(startup または crt(C RunTime) と呼ばれる。)
  • _startから実行が開始されるのは、CPUにより割り込みのおかげ。
  • H8は "ベクタ割込み方式"である。
    • 割込みハンドラを配置するアドレスを特定アドレス("割込みベクタ")に記述しておく方式。
    • H8の割込みベクタは、メモリ上の0x000000〜0x0000ffに、割込みの種類別に存在する。
    • 起動時(リセット時)には、"リセットベクタ"という割込みが発生する。
      H8では、割込みベクタの0番目がリセットベクタである。
      vector.cのvectors[]で、実際に割込みベクタを定義している。その0番目にstartを指定している。
    • 割込みが発生すると、CPUはこの割込みベクタを参照して、割込みハンドラの配置場所を知る。そして、割込みハンドラに処理がジャンプする。
  • "リンカスクリプト"(ld.scr)では、リンク時に関数や変数をどのアドレス上に配置するかを指定できる。
    ここで、vector.oが先頭に配置されるよう指定されている。
    即ち、vectors[]が0x000000〜0x0000ffに配置されることになる。
この章の追記はライブラリの機能追加くらいだったので、少なめでした。
こちらも無事動作しました。

次は3章です(^^)/♪ 続く...。なるべく早く続きに取り掛かりたい><

0 件のコメント:

コメントを投稿

お気軽にコメントをお寄せください m(_ _)m♪
"コメントの記入者"欄から[名前/URL]を選ぶと、登録なしでコメント投稿していただけます。