12Stepで作る 組込みOS自作入門 2ndステップ ~シリアル通信

# はじめに
以下の本で学習
[12ステップで作る 組込みOS自作入門](http://kozos.jp/books/makeos/)
本記事に出てくるソースコードはここ(http://kozos.jp/kozos/osbook/) の「osbook_03.zip」

# 組込みシステムの目的
・周辺ハードウェアを制御すること
　1. データ転送の通信方法
　　- シリアル通信
　　- Ethernet　など
　　　 
　2. 送信元と受信元の決定
　　（今回はH8/3069Fマイコンが送信元、PCが送信先）

# 用語集
## インターフェース
・Input/Output間での決まりごと
　（データ転送の信号の電圧、信号速度など）

## プロトコル
・通信、データの転送手順

## ボーレート（データ転送速度）
・単位はbps（bit per second）
・9600bpsでは、1秒間に9600回のON/OFFの信号を送る

## コントローラ
・通信を制御するICチップのこと

## CPUのビット数（データバス）
・CPU内部で扱うレジスタのサイズ
・int型が32bit

## アドレスバス
・アドレス指定用にCPUが持つ出力ピン
・ポインタ変数のサイズと同じ

# シリアル通信について
## 1. コントローラの操作方法
### レジスタを経由
・シリアルコントローラの持つ特定のレジスタに1バイト書き込むと、
　その1バイトをシリアル送信する。

## 2. CPUとDRAMの接続
・アドレスバスが4バイト（32bit）ある場合、0x00000000～0xffffffff
（0～4294967296：2の32乗）までアドレスを定義できる。
　CPUと4GBのDRAMが接続されている場合、アクセス可能

![image1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/5fdc9927-42ba-a6ca-4e23-056cdb516c74.png)
(P56.図2-1を引用)

・実際は1つの大容量のDRAMではなく少量、例えば1MBのDRAMが4個接続（DRAM1～DRAM4）などある。
　その場合、1MBのアドレスに必要な信号線は20ビット(0x000fffff:2の20乗)
　しかし、アドレスバスだけを利用した場合、DRAM1～DRAM4の区別ができない

## 3. チップセレクト信号の利用
・チップセレクトとは、DRAMが持っている信号ピンのこと。
　CS = 1でチップが動作するため、このチップセレクトが1になるように
　余った信号線を接続する。これで4MBを実現している。

![image2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/5fc90976-aa6d-fdf7-15ff-c09efe0a8d46.png)
(P58.図2-4を引用)

## 4. シリアル・コントローラの接続
・シリアル・コントローラは16個の制御用のレジスタを持っている
　レジスタの識別に必要な信号線は4本（16:2の4乗）。残りは比較器に使用する。
　（アドレス：0x10000000～0x1000000f）

## 5. メモリマップドI/O（メモリ空間に配置されたI/O）
・こちらのサイトが分かりやすい（http://www.kumikomi.net/archives/2003/05/10kumi.php?page=27）

### メモリ空間にI/Oを配置する（メモリマップドI/O）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/7c73288a-910a-86dc-50c9-f4c4b3cb22df.png)
・現在主流の方法。メモリと同じアドレス空間から、入出力装置を制御する
・I/O専用の回路や命令を持たなくてもよいため、高速化や低価格化が可能

### メモリ空間とI/O空間を持つ（I/O用の命令がある）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/acd2b433-1c5a-bd59-0475-14299662a753.png)
・入出力専用の命令（I/O命令）と専用信号を使用して、メモリ空間とは別のアドレス空間から
　データバスに直結されている入出力装置を制御する

## 5. C言語からのデバイスを操作
1. レジスタのアドレスを定義
2. アドレスにアクセスして読込み、書込みを行う

```c
char c;
volatile char *reg1 = (char *)0x10000000;

c = *reg1;    /* レジスタ1の値 読込み*/
*reg1 = 0x01; /* レジスタ1へ値 書込み*/
```

## 6. volatile修飾子
### Cコンパイラの最適化を抑止するために必要！！

```c
serreg->reg1 = 0x01;
serreg->reg1 = 0x02;
serreg->reg2 = 0x04;
```
```c
serreg->reg3 = 0x01;
while(serreg->reg3 & 0x01){
  //reg3の更新以外の処理
}
```

### 1. 値書込み定義の最適化阻止
・reg1に以下のように「0x01 → 0x02」と書き込む場合、
　コンパイルの最適化で「0x01」の書き込みが省略され、以下と等価と判断される

```c
serreg->reg1 = 0x02;
serreg->reg2 = 0x04;
```

### 2. 実行順序の最適化阻止
・reg2とreg1の変数はお互いに関係ないので、実行順序は等価と判断され
　コンパイルの最適化でreg1とreg2の書き込みは、以下と等価と判断される

```c
serreg->reg2 = 0x04;
serreg->reg1 = 0x02;
```

### 3. 実行内容の最適化阻止
・reg3の値がループ中に更新されないので、while文に入ると無限ループになる

```c
serreg->reg3 = 0x01;
if(serreg->reg3 & 0x01){
  while(1){
    //reg3の更新以外の処理
  } 
}
```

## 7. 内臓シリアルコントローラ
### 1.マイクロコントローラ
・CPUにあらかじめ内蔵されているコントローラのこと
　外部と接続する場合は、比較器の構成で自由なアドレスにマッピングできたが、
　マイクロコントローラでは、アドレスが決められてる

### 2. H8/3069Fに内蔵されているシリアルコントローラ
・SCI（Serial Communication Interface）が3つ内蔵｛SCI0、SCI1、SCI2｝
　H8/3069Fの[ハードウェアマニュアル](http://www.picosystems.net/dl/ds/device/HD64F3069.pdf)の13.1.4節に記載

## 8. コントローラのモード設定
### 一旦、コントローラを無効化し、設定完了後に有効化する
・SMR（シリアルモードレジスタ）の設定
・SCR（シリアルコントロールレジスタ）の設定

## 9. ビットレートレジスタの設定を行う
### シリアル通信のボーレートは9600bps
・周波数(20MHz)、ボーレート（9600bps）、分周（1）からビットレートレジスタ（64）を設定

## 10. シリアルの1文字出力
1. 送信完了ビットが落ちていないことを確認する
2. 送信したい文字を書き込む
3. 送信完了ビットを落とす
4. 送信が完了すると、送信完了ビットを立てる

## 11.端末変換
・C言語では、改行コードは「\n」だが、シリアル通信では「\r」
　送信時「\n → \r」にコードを変換する（端末変換という）

## 12.ソースコードの変更
・ライブラリ関数の追加
　追加した関数の仕様は[こちら](https://bituse.info/c_func/9)を参照

## ソースコードの補足（serial.c）
・構造体の宣言と初期化を同時に行う
　この場合、タグ名は以下出てこないため不要
　http://www.kusa.ac.jp/~kajiura/c/kouzoutai/newpage1.htm
　の4.構造体変数の初期化

```c
static struct {
  volatile struct h8_3069f_sci *sci;
} regs[SERIAL_SCI_NUM] = {
  { H8_3069F_SCI0 }, 
  { H8_3069F_SCI1 }, 
  { H8_3069F_SCI2 }, 
};
```

# BackNumber
1.[12ステップで作る組込みOS自作入門 1stステップ](https://qiita.com/Shohei_miyasako/items/6e0e1a9f298bd8db3369)