Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

【学習メモ#2nd】12ステップで作る組込みOS自作入門

3,619 views

Published on

12ステップで作る組込みOS自作入門
http://www.amazon.co.jp/dp/4877832394/
坂井 弘亮(著)
カットシステム

Published in: Technology
  • Be the first to comment

【学習メモ#2nd】12ステップで作る組込みOS自作入門

  1. 1. 12ステップで作る組込みOS自作入門 2ndステップ @sandai
  2. 2. 【参考書籍】12ステップで作る組込みOS自作入門【内容】1ステップずつ、実際に動かしながらプログラムを発展させていく方式で無理なく学べる。OSやハードウェアに詳しくない方にも理解できるように十分な説明を提供坂井 弘亮(著)カットシステム(2010/5)【税込価格】4,410円【サポートページ】http://kozos.jp/books/makeos/
  3. 3. もくじ1.メモリマップドI/O2.内蔵シリアル・コントローラ3.ライブラリ関数の追加と実行4.スタート・アップ5.まとめ
  4. 4. 1.メモリマップドI/O
  5. 5. 組込みシステムの目的● 周辺ハードウェアの制御、操作● 周辺ハードウェアの呼び名は以下のようなもの がある。どれも同じような意味 – ペリフェラル – 周辺インタフェース – 周辺I/O
  6. 6. シリアル通信● データ転送には送信元と受信先があり、様々な 決まりごとを守らなくてはならない – この決まりごとをインタフェースと言う● またデータの転送にはいくつか手順がある – データ転送の手順をプロトコルと呼ぶ
  7. 7. シリアル通信の制御● シリアル通信の制御をCPUで行うとなれば非常 に面倒なことになる● そこで、通信を制御するICチップを実装する – こういったICチップをコントローラと呼び、シリア ル通信では「シリアル・コントローラ」と言う● 信号の制御はこのICチップにまかせれば、CPU からはコントローラに対してデータの送信要求 を出したり、コントローラからデータを受信す るだけで済むようになる
  8. 8. コントローラの操作方法● コントローラの制御はレジスタ経由で行う – コントローラの持つ特定のレジスタに1バイト書き 込むと、コントローラ側でそのデータをシリアル送 信する – シリアル通信のパラメータは特定のレジスタの特定 のビットを立てたり落としたりすることで設定する● コントローラもアドレス線を持っており、特定 のアドレスに対して特定のレジスタが配置され ている● このように、レジスタを読み書きして操作する
  9. 9. DRAMとCPU● CPUのビット数は内部で扱うデータのビット幅 を指す – 32ビットのCPUならレジスタのサイズは32ビット● データ・バス – 数値データを転送するためにCPUが持っている入出 力ピン● アドレス・バス – アドレス指定するためにCPUが持っている出力ピン
  10. 10. メモリとCPU● DRAMのデータを読み書きする場合、どの位置の データかアドレス・バスによってDRAMに通知す る● アドレス・バスが32ビットなら、ポインタも32 ビットとなる – char *c;はchar型へのポインタだけど、ポインタの サイズは32ビットだよね● 1バイトで表現できる数値は0x00~0xff● 4バイト(32ビット)だと0x00000000~0xffffffff● つまり、32ビットなら4GBのメモリを扱うこと ができる
  11. 11. アドレス・バスとCPU● 32ビットのアドレス・バスをDRAMと直結すれば 4GBの領域にアクセスできる● DRAMは数メガバイト単位で分割されている● 1メガバイトで分割されていれば、20ビット (20本)で接続して、上位12ビットは無視する● そこで、右のよ うに接続すると 衝突してしまう ので、チップ・ セレクトを使う 57頁 図2.3 1メガバイトのDRAMチップを4個接続する より
  12. 12. チップ・セレクト(CS)● 衝突の問題は上位12ビットを無視していること – 無視をせず値に応じてDRAMのアクセスを制御● DRAMが持っているCSに上位12ビットを接続し、 ONとOFFで制御する● 直接接続するわけではなく比較器を通して接続 し、ONかOFFかをここで判断する● 比較器は特定のビット数のデータを比較して、 一致していれば1の信号(ON)を出すような回路
  13. 13. マッピング● 上位12ビットの値でどのDRAMにアクセスするか 決定される● たとえば、下のスクリーンショットの例でいえ ば、DRAM2チップは0x00100000~0x001fffffのア ドレスにマッピングされていると表現する● こうすることで分割されたアドレス空間を連続 した形で利用できる アドレス指定(太字は上位12ビット) 動作する(CSが有効になる)DRAM 0x00000000 ~ 0x000fffff DRAM1 0x00100000 ~ 0x001fffff DRAM2 0x00200000 ~ 0x002fffff DRAM3 0x00300000 ~ 0x003fffff DRAM4 59頁 表2.1 図2.4の接続によるアドレス指定とDRAMの対応 より
  14. 14. シリアル・コントローラ のマッピング● シリアル・コントローラもアドレス線を持って おり、アドレスによってどのレジスタを制御で きるか決まっている● アドレス・バスの下位4ビットをそのまま接続 して、上位28ビットは比較器を通してCSに接続 される● こうすると、CPUからは0x1000000~0x1000000f というアドレスを読み書きすることでレジスタ を制御できる● これを、シリアル・コントローラのレジスタは 0x1000000~0x1000000fにマッピングされている と表現する
  15. 15. メモリマップドI/O● コントローラのレジスタをアドレス空間上に マッピングすることで、CPUからの制御が可能 となり、デバイスを操作できる● このように、様々なコントローラのレジスタも アドレス上に存在するI/OをメモリマップドI/O と呼ぶ
  16. 16. C言語からのデバイス操作● このような形でC言語からレジスタ1を操作でき るchar c;volatile char *reg1 = (char *)0x10000000;C = *reg1; /* レジスタ1からの読み出し */*reg1 = 0x01 /* レジスタ1への書き込み */
  17. 17. volatile● volatileキーワードを使えば最適化が抑制され る● コンパイラは下記のようなコードを最適化する が、volatileをつければ防げるserreg->reg1 = 0x01serreg->reg1 = 0x02serreg->reg2 = 0x04
  18. 18. 2.内蔵シリアル・コントローラ
  19. 19. マイクロ・コントローラ● 組込み向けCPUでははじめから周辺コントロー ラを内蔵しているのが普通● こういったCPUはマイクロ・コントローラと呼 ばれる● H8/3069FはSCIというシリアル・コントローラ を内蔵している – 3つ内蔵しており、SCI0、SCI1、SCI2がある
  20. 20. SCI● H8/3069Fのシリアル・コネクタにはSCI1が接続 されている – ここでシリアル経由の入出力が可能となる。コン ソールを通して文字の入出力ができるってこと● SCIはCPUに内蔵してあるのでレジスタは最初か ら固定でマッピングされている 65頁 表2.3 H8/3069FでのSCI1のレジスタ・マッピング より
  21. 21. SCIの定義このコードは、3つのSCIをregs[]という構造体●の配列で管理していることになるstatic struct { volatile struct h8_3069f_sci *sci;} regs[SERIAL_SCI_NUM] = { { H8_3069F_SCI0 }, { H8_3069F_SCI1 }, { H8_3069F_SCI2 },};
  22. 22. SCI1での送信の設定● パラメータ設定でSMRとSCRの2つのレジスタの 設定が必要● 転送速度の指定はBRRで行う● 文字の送信のためにTDR、SSRを使う
  23. 23. SMR● SMRはシアルモードレジスタと言う● これは入出力のパラメータ設定を行う● いくつか設定内容はあるが、現在ではデータ長 は8ビット、ストップビット長は1ビット、パリ ティ無しというのが主流● sci->scr = 0といったように、ゼロに設定して おけば問題ない
  24. 24. SCR● SCRはシリアルコントロールレジスタ● シリアル入出力の制御を行う● serial_init()では最初にsci->scr = 0にして シリアル送信と割り込みを無効化している● 次にSMRとBBRを設定したあと、SCRの送受信を 有効化している。こういった方法が一般的sci->scr = 0; /* 最初 */sci->smr = 0;sci->brr = 64;sci->scr = H8_3069F_SCI_SCR_RE | H8_3069F_SCI_SCR_TE; /* 最後 */
  25. 25. BRR● BRRはビットレートレジスタと言う – シリアル通信の速度設定にあたる● 9600bpsが一般的 – 1秒間に9600ビット転送できる速度● serial_init()ではsci->brr = 64にしている – 20MHz、分週比1、9600bpsとして、ドキュメントの 表(表13.3)から64にしている
  26. 26. TDRとSSR● シリアルへの1文字出力はTDR(トランスミート データレジスタ)とSSR(シリアルステータスレ ジスタ)を使う● 手順は次の通り 1.SSRの送信完了ビットが落ちていないか確認 2.TDRに送信したい文字を書き込む 3.SSRの送信完了ビットを落とす 4.送信が完了すると、コントローラがSSRの送信完了 ビットを立てる
  27. 27. 端末変換● C言語では改行コードはnだが、シリアル通 信ではrとなる● 文字をシリアル送信する場合はnをrに変 換しなければならない● このようなコード変換を端末変換という
  28. 28. 3.ライブラリ関数の追加と実行
  29. 29. ヘッダ・ファイル● ヘッダ・ファイルに関数のプロトタイプ宣言を すると、どのファイルでもincludeすれば扱え るようになる – プリプロセスによってできるんだったけな
  30. 30. 16ビットCPUのint型● H8は16ビットCPUなのでint型は16ビットになる● longで32ビット – あれ、でもポインタのサイズが32ビットなのはなん でだろ。調べたけどわかんねえや● gccだと-mint32オプションを使えばint型を32 ビットにできるが、いろいろ面倒なのでやって ない
  31. 31. プログラムの実行● 修正したファイルは以下の通り – lib.h lib.c – main.c● ライブラリ関数を追加した – 本書では標準ライブラリ関数も自作するらしい● main.cで先ほど追加した関数を試したと ろ、putxval(0xffff, 0)の出力が????になった
  32. 32. putxval()● 数値の16進数を表示するための関数● 下記のように使ったところ、0xffffが????で出 力された● そこで、一度電源を入れなおしたらffffと表示 されるようになった – 何が原因だったかわからないputxval(0x10, 0); puts("n");putxval(0xffff, 0); puts("n");
  33. 33. 4.スタート・アップ
  34. 34. 組込みプログラムの最初● プログラムの実行はstartup.sの_startから始 まっている – スタックポインタの設定を行なってからmain()に ジャンプしている – startup.cはcrt.sという名前を使う場合もある● この動作開始処理を一般にスタート・アップと 言う
  35. 35. 割込み● どうやって_startから処理を開始するか理解す るには、割込みベクタについて知る必要がある● CPUには割込みという機能がある – CPUがある処理をしているときに、割込みの信号を 受けとって別の処理に入るというもの – 割込み時の処理は割り込みハンドラという● 処理を終えると中断していた処理に戻る● 具体的にはCPUの割込み線というピンに電圧が かかったかどうかで処理が行われている
  36. 36. 割込みハンドラの実行● どのハンドラを実行するのか設定する必要があ り、大きく分けて2通りある 1.特定のアドレスから実行する 2.どのアドレスから実行するか特定のアドレスに設 定しておく
  37. 37. 1.特定のアドレスから実行● 割込みハンドラを配置するアドレスをCPU側で 固定● その割込みが発生したら強制的にそのアドレス に飛ばすというもの
  38. 38. 2.どのアドレスから実行するか 特定のアドレスに設定して実行● 割込みハンドラを配置するアドレスを特定のア ドレスに記述しておく● 「ハンドラのアドレスを記述しておく特定のア ドレス」を割り込みベクタと言う – この方法をベクタ割込み方式と呼ぶ
  39. 39. H8の割り込みベクタ方式● H8は割り込みベクタ方式で設定する● 割り込みベクタは種類に応じて、0x000000~か ら0x0000ffのメモリ上に配置されている● 割込みはいくつか種類があるが、まずリセッ ト・ベクタについて知る必要がある
  40. 40. H8のリセット・ベクタ● 電源のONやリセットも割込みの一種● 電源の起動やリセット直後に参照するメモリ位 置がリセット・ベクタ – ここから動作を開始する● で、割込みベクタの先頭がリセット・ベクタに なってる
  41. 41. vectors[]● vector.cのvectors[]が割込みベクタの設定 – vectors[0]にstart()関数を配置しており、これが startup.sの_startにあたる● vectors[]の内容は0x000000~0x0000ffのアドレ スに配置される – ld.scrによって先頭に配置するようになっている● つまり、リセット・ベクタにstart()関数が割 り当てられている
  42. 42. ld.scr● ld.scrはリンカ・スクリプト – オブジェクトファイルをリンクして実行ファイルに するとき、関数や変数をアドレス上にどのように配 置するか指定する役割を持つ● vectors.oはld.scrの下記のコード部分で先頭 に配置されることが分かるSECTIONS{. = 0x0;.vectors : { vector.o(.data)}
  43. 43. スタート・アップのまとめ● ld.scrによってvector.oを先頭に配置するよう になっている● vectors[]は0x000000~0x0000ffのアドレス上に 配置され、割込みベクタとして登録される● よって、電源ON時に割り込みベクタとして vector[0]のアドレス位置にあるstart()から処 理を開始する
  44. 44. 5.まとめ
  45. 45. まとめ● CPUからデバイスを操作できるように、アドレ ス空間上からコントローラのレジスタにアクセ スできるようになっている● 組込み向けCPUははじめからシリアル・コンロ ローラを内蔵しているのが一般的で、これをマ イクロ・コントローラという – H8/3069FはSCIというコントローラを内蔵してお り、レジスタは固定でマッピングされている● 電源をONにしたとき、id.scrにリセット・ベク タの位置に設定したstart()関数から開始する ようになっている
  46. 46. メモ● これまでの内容だと変数の書き換えができない んだと● 厳密には自動変数は大丈夫だけど静的変数は書 き換えができないって状態らしい● 自動変数と静的変数の違いがわからんな● これは次の3rdステップで明らかになるらしい ので、ちゃんと読もうかいな

×