SlideShare a Scribd company logo
1 of 46
Download to read offline
12ステップで作る組込みOS自作入門
      2ndステップ




                @sandai
【参考書籍】
12ステップで作る組込みOS自作入門
【内容】
1ステップずつ、実際に動かしながらプログラムを発展さ
せていく方式で無理なく学べる。OSやハードウェアに詳
しくない方にも理解できるよう
に十分な説明を提供

坂井 弘亮(著)
カットシステム(2010/5)

【税込価格】
4,410円

【サポートページ】
http://kozos.jp/books/makeos/
もくじ
1.メモリマップドI/O
2.内蔵シリアル・コントローラ
3.ライブラリ関数の追加と実行
4.スタート・アップ
5.まとめ
1.メモリマップドI/O
組込みシステムの目的
●   周辺ハードウェアの制御、操作
●   周辺ハードウェアの呼び名は以下のようなもの
    がある。どれも同じような意味
    –   ペリフェラル
    –   周辺インタフェース
    –   周辺I/O
シリアル通信
●   データ転送には送信元と受信先があり、様々な
    決まりごとを守らなくてはならない
    –   この決まりごとをインタフェースと言う
●   またデータの転送にはいくつか手順がある
    –   データ転送の手順をプロトコルと呼ぶ
シリアル通信の制御
●   シリアル通信の制御をCPUで行うとなれば非常
    に面倒なことになる
●   そこで、通信を制御するICチップを実装する
    –   こういったICチップをコントローラと呼び、シリア
        ル通信では「シリアル・コントローラ」と言う
●   信号の制御はこのICチップにまかせれば、CPU
    からはコントローラに対してデータの送信要求
    を出したり、コントローラからデータを受信す
    るだけで済むようになる
コントローラの操作方法
●   コントローラの制御はレジスタ経由で行う
    –   コントローラの持つ特定のレジスタに1バイト書き
        込むと、コントローラ側でそのデータをシリアル送
        信する
    –   シリアル通信のパラメータは特定のレジスタの特定
        のビットを立てたり落としたりすることで設定する
●   コントローラもアドレス線を持っており、特定
    のアドレスに対して特定のレジスタが配置され
    ている
●   このように、レジスタを読み書きして操作する
DRAMとCPU
●   CPUのビット数は内部で扱うデータのビット幅
    を指す
    –   32ビットのCPUならレジスタのサイズは32ビット
●   データ・バス
    –   数値データを転送するためにCPUが持っている入出
        力ピン
●   アドレス・バス
    –   アドレス指定するためにCPUが持っている出力ピン
メモリとCPU
●   DRAMのデータを読み書きする場合、どの位置の
    データかアドレス・バスによってDRAMに通知す
    る
●   アドレス・バスが32ビットなら、ポインタも32
    ビットとなる
    –   char *c;はchar型へのポインタだけど、ポインタの
        サイズは32ビットだよね
●   1バイトで表現できる数値は0x00~0xff
●   4バイト(32ビット)だと0x00000000~0xffffffff
●   つまり、32ビットなら4GBのメモリを扱うこと
    ができる
アドレス・バスとCPU
●   32ビットのアドレス・バスをDRAMと直結すれば
    4GBの領域にアクセスできる
●   DRAMは数メガバイト単位で分割されている
●   1メガバイトで分割されていれば、20ビット
    (20本)で接続して、上位12ビットは無視する
●   そこで、右のよ
    うに接続すると
    衝突してしまう
    ので、チップ・
    セレクトを使う


            57頁 図2.3 1メガバイトのDRAMチップを4個接続する より
チップ・セレクト(CS)
●   衝突の問題は上位12ビットを無視していること
     – 無視をせず値に応じてDRAMのアクセスを制御
●   DRAMが持っているCSに上位12ビットを接続し、
    ONとOFFで制御する
●   直接接続するわけではなく比較器を通して接続
    し、ONかOFFかをここで判断する
●   比較器は特定のビット数のデータを比較して、
    一致していれば1の信号(ON)を出すような回路
マッピング
●   上位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の対応 より
シリアル・コントローラ
         のマッピング
●   シリアル・コントローラもアドレス線を持って
    おり、アドレスによってどのレジスタを制御で
    きるか決まっている
●   アドレス・バスの下位4ビットをそのまま接続
    して、上位28ビットは比較器を通してCSに接続
    される
●   こうすると、CPUからは0x1000000~0x1000000f
    というアドレスを読み書きすることでレジスタ
    を制御できる
●   これを、シリアル・コントローラのレジスタは
    0x1000000~0x1000000fにマッピングされている
    と表現する
メモリマップドI/O
●   コントローラのレジスタをアドレス空間上に
    マッピングすることで、CPUからの制御が可能
    となり、デバイスを操作できる
●   このように、様々なコントローラのレジスタも
    アドレス上に存在するI/OをメモリマップドI/O
    と呼ぶ
C言語からのデバイス操作
●   このような形でC言語からレジスタ1を操作でき
    る
char c;
volatile char *reg1 = (char *)0x10000000;

C = *reg1; /* レジスタ1からの読み出し */
*reg1 = 0x01 /* レジスタ1への書き込み */
volatile
●   volatileキーワードを使えば最適化が抑制され
    る
●   コンパイラは下記のようなコードを最適化する
    が、volatileをつければ防げる
serreg->reg1 = 0x01
serreg->reg1 = 0x02
serreg->reg2 = 0x04
2.内蔵シリアル・コントローラ
マイクロ・コントローラ
●   組込み向けCPUでははじめから周辺コントロー
    ラを内蔵しているのが普通
●   こういったCPUはマイクロ・コントローラと呼
    ばれる
●   H8/3069FはSCIというシリアル・コントローラ
    を内蔵している
    –   3つ内蔵しており、SCI0、SCI1、SCI2がある
SCI
●   H8/3069Fのシリアル・コネクタにはSCI1が接続
    されている
    –   ここでシリアル経由の入出力が可能となる。コン
        ソールを通して文字の入出力ができるってこと
●   SCIはCPUに内蔵してあるのでレジスタは最初か
    ら固定でマッピングされている




        65頁 表2.3 H8/3069FでのSCI1のレジスタ・マッピング より
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 },
};
SCI1での送信の設定
●   パラメータ設定でSMRとSCRの2つのレジスタの
    設定が必要
●   転送速度の指定はBRRで行う
●   文字の送信のためにTDR、SSRを使う
SMR
●   SMRはシアルモードレジスタと言う
●   これは入出力のパラメータ設定を行う
●   いくつか設定内容はあるが、現在ではデータ長
    は8ビット、ストップビット長は1ビット、パリ
    ティ無しというのが主流
●   sci->scr = 0といったように、ゼロに設定して
    おけば問題ない
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; /* 最
後 */
BRR
●   BRRはビットレートレジスタと言う
    –   シリアル通信の速度設定にあたる
●   9600bpsが一般的
    –   1秒間に9600ビット転送できる速度
●   serial_init()ではsci->brr = 64にしている
    –   20MHz、分週比1、9600bpsとして、ドキュメントの
        表(表13.3)から64にしている
TDRとSSR
●   シリアルへの1文字出力はTDR(トランスミート
    データレジスタ)とSSR(シリアルステータスレ
    ジスタ)を使う
●   手順は次の通り
    1.SSRの送信完了ビットが落ちていないか確認
    2.TDRに送信したい文字を書き込む
    3.SSRの送信完了ビットを落とす
    4.送信が完了すると、コントローラがSSRの送信完了
      ビットを立てる
端末変換
●   C言語では改行コードは'n'だが、シリアル通
    信では'r'となる
●   文字をシリアル送信する場合は'n'を'r'に変
    換しなければならない
●   このようなコード変換を端末変換という
3.ライブラリ関数の追加と実行
ヘッダ・ファイル
●   ヘッダ・ファイルに関数のプロトタイプ宣言を
    すると、どのファイルでもincludeすれば扱え
    るようになる
    –   プリプロセスによってできるんだったけな
16ビットCPUのint型
●   H8は16ビットCPUなのでint型は16ビットになる
●   longで32ビット
    –   あれ、でもポインタのサイズが32ビットなのはなん
        でだろ。調べたけどわかんねえや
●   gccだと-mint32オプションを使えばint型を32
    ビットにできるが、いろいろ面倒なのでやって
    ない
プログラムの実行
●   修正したファイルは以下の通り
    –   lib.h lib.c
    –   main.c
●   ライブラリ関数を追加した
    –   本書では標準ライブラリ関数も自作するらしい
●   main.cで先ほど追加した関数を試したと
    ろ、putxval(0xffff, 0)の出力が????になった
putxval()
●   数値の16進数を表示するための関数
●   下記のように使ったところ、0xffffが????で出
    力された
●   そこで、一度電源を入れなおしたらffffと表示
    されるようになった
    –   何が原因だったかわからない

putxval(0x10, 0);   puts("n");
putxval(0xffff, 0); puts("n");
4.スタート・アップ
組込みプログラムの最初
●   プログラムの実行はstartup.sの_startから始
    まっている
    –   スタックポインタの設定を行なってからmain()に
        ジャンプしている
    –   startup.cはcrt.sという名前を使う場合もある
●   この動作開始処理を一般にスタート・アップと
    言う
割込み
●   どうやって_startから処理を開始するか理解す
    るには、割込みベクタについて知る必要がある
●   CPUには割込みという機能がある
    –   CPUがある処理をしているときに、割込みの信号を
        受けとって別の処理に入るというもの
    –   割込み時の処理は割り込みハンドラという
●   処理を終えると中断していた処理に戻る
●   具体的にはCPUの割込み線というピンに電圧が
    かかったかどうかで処理が行われている
割込みハンドラの実行
●   どのハンドラを実行するのか設定する必要があ
    り、大きく分けて2通りある
    1.特定のアドレスから実行する
    2.どのアドレスから実行するか特定のアドレスに設
      定しておく
1.特定のアドレスから実行
●   割込みハンドラを配置するアドレスをCPU側で
    固定
●   その割込みが発生したら強制的にそのアドレス
    に飛ばすというもの
2.どのアドレスから実行するか
    特定のアドレスに設定して実行
●   割込みハンドラを配置するアドレスを特定のア
    ドレスに記述しておく
●   「ハンドラのアドレスを記述しておく特定のア
    ドレス」を割り込みベクタと言う
    –   この方法をベクタ割込み方式と呼ぶ
H8の割り込みベクタ方式
●   H8は割り込みベクタ方式で設定する
●   割り込みベクタは種類に応じて、0x000000~か
    ら0x0000ffのメモリ上に配置されている
●   割込みはいくつか種類があるが、まずリセッ
    ト・ベクタについて知る必要がある
H8のリセット・ベクタ
●   電源のONやリセットも割込みの一種
●   電源の起動やリセット直後に参照するメモリ位
    置がリセット・ベクタ
    –   ここから動作を開始する
●   で、割込みベクタの先頭がリセット・ベクタに
    なってる
vectors[]
●   vector.cのvectors[]が割込みベクタの設定
    –   vectors[0]にstart()関数を配置しており、これが
        startup.sの_startにあたる
●   vectors[]の内容は0x000000~0x0000ffのアドレ
    スに配置される
    –   ld.scrによって先頭に配置するようになっている
●   つまり、リセット・ベクタにstart()関数が割
    り当てられている
ld.scr
●   ld.scrはリンカ・スクリプト
    –   オブジェクトファイルをリンクして実行ファイルに
        するとき、関数や変数をアドレス上にどのように配
        置するか指定する役割を持つ
●   vectors.oはld.scrの下記のコード部分で先頭
    に配置されることが分かる
SECTIONS
{
. = 0x0;

.vectors : {
         vector.o(.data)
}
スタート・アップのまとめ
●   ld.scrによってvector.oを先頭に配置するよう
    になっている
●   vectors[]は0x000000~0x0000ffのアドレス上に
    配置され、割込みベクタとして登録される
●   よって、電源ON時に割り込みベクタとして
    vector[0]のアドレス位置にあるstart()から処
    理を開始する
5.まとめ
まとめ
●   CPUからデバイスを操作できるように、アドレ
    ス空間上からコントローラのレジスタにアクセ
    スできるようになっている
●   組込み向けCPUははじめからシリアル・コンロ
    ローラを内蔵しているのが一般的で、これをマ
    イクロ・コントローラという
    –   H8/3069FはSCIというコントローラを内蔵してお
        り、レジスタは固定でマッピングされている
●   電源をONにしたとき、id.scrにリセット・ベク
    タの位置に設定したstart()関数から開始する
    ようになっている
メモ
●   これまでの内容だと変数の書き換えができない
    んだと
●   厳密には自動変数は大丈夫だけど静的変数は書
    き換えができないって状態らしい
●   自動変数と静的変数の違いがわからんな
●   これは次の3rdステップで明らかになるらしい
    ので、ちゃんと読もうかいな

More Related Content

Viewers also liked

【学習メモ#9th】12ステップで作る組込みOS自作入門
【学習メモ#9th】12ステップで作る組込みOS自作入門 【学習メモ#9th】12ステップで作る組込みOS自作入門
【学習メモ#9th】12ステップで作る組込みOS自作入門 sandai
 
【学習メモ#11th】12ステップで作る組込みOS自作入門
【学習メモ#11th】12ステップで作る組込みOS自作入門 【学習メモ#11th】12ステップで作る組込みOS自作入門
【学習メモ#11th】12ステップで作る組込みOS自作入門 sandai
 
【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 sandai
 
QEMUでARM64bitベアメタルプログラミング
QEMUでARM64bitベアメタルプログラミングQEMUでARM64bitベアメタルプログラミング
QEMUでARM64bitベアメタルプログラミングYuma Ohgami
 
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくばHirotaka Kawata
 
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -Kishi Shundo
 
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)kozossakai
 
やってよかったOS作り
やってよかったOS作りやってよかったOS作り
やってよかったOS作りHidemi Kawai
 
低レイヤー入門
低レイヤー入門低レイヤー入門
低レイヤー入門demuyan
 
ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門Hirotaka Kawata
 
【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介Yuma Ohgami
 
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめ
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめWeb系だって低レイヤーがやりたいんだよ! コンパイラことはじめ
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめNisei Kimura
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門uchan_nos
 
Ctfのためのpython入門
Ctfのためのpython入門Ctfのためのpython入門
Ctfのためのpython入門shiracamus
 
ハッキング実演
ハッキング実演ハッキング実演
ハッキング実演Ken Ogura
 
CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)kikuchan98
 

Viewers also liked (17)

【学習メモ#9th】12ステップで作る組込みOS自作入門
【学習メモ#9th】12ステップで作る組込みOS自作入門 【学習メモ#9th】12ステップで作る組込みOS自作入門
【学習メモ#9th】12ステップで作る組込みOS自作入門
 
【学習メモ#11th】12ステップで作る組込みOS自作入門
【学習メモ#11th】12ステップで作る組込みOS自作入門 【学習メモ#11th】12ステップで作る組込みOS自作入門
【学習メモ#11th】12ステップで作る組込みOS自作入門
 
【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門
 
QEMUでARM64bitベアメタルプログラミング
QEMUでARM64bitベアメタルプログラミングQEMUでARM64bitベアメタルプログラミング
QEMUでARM64bitベアメタルプログラミング
 
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば
30日でできない!コンピューター自作入門 - カーネル/VM探検隊@つくば
 
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -
組み込み向けC++のやり方を探る - mbedで楽しい組み込みプログラミング -
 
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)
組込みOSを作ってみよう!(オープンソースカンファレンス内セミナー資料)
 
やってよかったOS作り
やってよかったOS作りやってよかったOS作り
やってよかったOS作り
 
低レイヤー入門
低レイヤー入門低レイヤー入門
低レイヤー入門
 
人工知能概論 1
人工知能概論 1人工知能概論 1
人工知能概論 1
 
ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門ゼロから始める自作 CPU 入門
ゼロから始める自作 CPU 入門
 
【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介【2000行弱!】x86用自作カーネルの紹介
【2000行弱!】x86用自作カーネルの紹介
 
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめ
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめWeb系だって低レイヤーがやりたいんだよ! コンパイラことはじめ
Web系だって低レイヤーがやりたいんだよ! コンパイラことはじめ
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門
 
Ctfのためのpython入門
Ctfのためのpython入門Ctfのためのpython入門
Ctfのためのpython入門
 
ハッキング実演
ハッキング実演ハッキング実演
ハッキング実演
 
CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)
 

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

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