RX220のシリアル通信サンプルプログラムを読み解く

基本なので頑張る．
通信ができないとデバッガなしにはきつい．

サンプルが動くのでまあいいのだが，勉強のためにも読むついでにコメントを日本語にして自分で読みやすくする．英語ぐらいパパッと読めますよ，面倒なだけです(棒)．

どうでもいいのだが，UARTのことをルネサスではSCIと呼ぶらしい．正直統一してほしい，というか知らないと検索できない．

今回は使用コードがサンプルのままで完全に動いたので読み解くこととなった．サンプルが楽に動くと嬉しい(読み解くのも楽ではないが)．

## 環境
* マイコン：R5F52206BDFM([AKI-RX220ボード](http://akizukidenshi.com/catalog/g/gK-08769/))
* 開発環境：e2studio
* 書き込みソフト：RenesasFlashProgrammer(RFP)

# SCIの設定
例のごとく初期化フローチャートの例が存在したのでそれなりに準じて読んでみる．基本はルネサスのサンプルプログラムAsync_Serialです．
![rx220_sci_init_chart.png](https://qiita-image-store.s3.amazonaws.com/0/102650/06f8e6fe-c736-9b27-0c66-d6b92432b316.png)


## MPUの設定
まずモジュールを起こす
その後[1]ということでピンを通信用に変更する．
機能別端子一覧（48ピンLQFP）によると
RxD:P30
TxD:P26
とのことなのでこいつらを設定する．
20.3.1 端子入出力機能設定手順に準じて設定を行う．
1番:初期値なのでそのまま(設定してもいい，というかした方がより安全?)
2番:PDRの設定．TxDは出力，RxDは入力．
3番:保護解除
4番:周辺機能の選択(20. マルチファンクションピンコントローラの項を参照)
5番:保護
6番:周辺機能モードにする
ということで以下のコードとなった．

``` C
SYSTEM.PRCR.WORD = 0x0A50b;             //クロックソース選択の保護解除
MSTP(SCI1) = 0;							//SCI1を有効にする
SYSTEM.PRCR.WORD = 0x0A500;             //クロックソース選択の保護

//TxD(P26),RxD(P30)
PORT2.PDR.BIT.B6 = 1;					//TxD
PORT3.PDR.BIT.B0 = 1;					//RxD

MPC.PWPR.BIT.B0WI = 0;					//PFSレジスタの保護解除をするPFSWEレジスタの保護解除
MPC.PWPR.BIT.PFSWE = 1;					//PFSレジスタの保護解除

MPC.P20PFS.BIT.PSEL = 0xA;				//P2nの周辺機能を設定
MPC.P30PFS.BIT.PSEL = 0xA;				//P3nの周辺機能を設定

MPC.PWPR.BIT.PFSWE = 0;					//PFSレジスタの保護
MPC.PWPR.BIT.B0WI = 1;					//PFSレジスタの保護をするPFSWEレジスタの保護

PORT2.PMR.BIT.B6 = 1;					//P26だけ周辺機能ポートにする
PORT3.PMR.BIT.B0 = 1;					//P30だけ周辺機能ポートにする

```

## SCIの初期設定
欄外の最初の部分と[2]番を設定するために，SCRbyteを設定する．
まず[TIE,RIE,TE,RE,TEIE]らはフローに0にしろと書いてあるので0にする．
そのついでにCKEも設定するが，ここでは0を選択．1との差は調べてもよくわからないのでサンプルに従っておく．必要になったら調べるでしょう．
[3]は設定を変更していないのでたぶん省略して大丈夫．
[4]は沢山設定する．
まずSMRだが7要素設定する．
クロックの分周はそのまま(早い方がいいだけ)，マルチプロセッサモード，ストップビットレングスは少ないほうが効率がいい気がするので1bit，パリティイネーブルビットは0(別にパリティは要らない)，キャラクタレングスビットは多いほうが効率がいいので8bit，コミュニケーションモードビットは調歩同期式にする．

さて調歩同期式が何かわからないので調べたところ
[「シリアル通信」とは？](http://www.picfun.com/cpu12.html)曰く通信データの転送幅を相手に教えるためにデータの前後に入れる調歩同期式と別の線からクロックを流すクロック同期式(I2CとかSPI?)の2つがあることがわかった．当然もう一本追加する必要は(今回の状態では)ないので調歩同期式にする．

次にSCMRも4要素設定する．
まずSMIFは通信形式の選択なので当然シリアルで通信するので0とする．スマートカードインターフェースがなんなのかは調べが付かなかったが，なんとなくICカードっぽい感じの非接触型の通信とかなのかと(知りません)
続いてSINVは送受信データを反転させるかどうか．正直使い道がわからないのだが，[FAQ 1010847](https://support.renesas.com/hc/ja/articles/211562947-FAQ-1010847-%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%81%AE%E8%AA%BF%E6%AD%A9%E5%90%8C%E6%9C%9F%E5%BC%8F%E3%83%A2%E3%83%BC%E3%83%89%E3%81%A7%E3%82%82-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%AB%E3%83%BC%E3%83%89%E3%83%A2%E3%83%BC%E3%83%89%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF-SCMR-%E3%81%AE%E9%80%81%E5%8F%97%E4%BF%A1%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A4%E3%83%B3%E3%83%90%E3%83%BC%E3%83%88%E3%83%93%E3%83%83%E3%83%88-SINV-%E3%81%AB%E3%82%88%E3%82%8A%E9%80%81%E5%8F%97%E4%BF%A1%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E6%A5%B5%E6%80%A7%E3%82%92%E5%8F%8D%E8%BB%A2%E3%81%95%E3%81%9B%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E5%8F%AF%E8%83%BD%E3%81%A7%E3%81%99%E3%81%8B-)でスマートカードインターフェース以外の時の動作を保証していないとのことなのでスマートカードインターフェース用なのだろうということで放っておく．
SDIRは送受信データをどっちから送るかを決めるそうで，多分エンディアンの差を埋めるためなのかなぁと予想．知りません
BCP2は送受信速度を決めるよう．サンプルに従います．

最後にBRR，ボーレートを設定する．サンプルが19200bpsなのでそのままといきたいが，そもそものPCLKの設定が違うので少し変わってBBRは15となる(PCLKを1/2に分周してある)．
計算式は表27.8 BRRレジスタの設定値NとビットレートBの関係に載っている．このときのnはSMRで分周をした時の設定値となる(SMRの項を参照)．

そして謎の時間調整があり，シリアルステータスレジスタを設定する．
ここではMBRT,MPB,TENDを1にしてPER,FER,ORERを0にしている．
まずMBRTはマルチプロセッサビットトランスファの設定でマルチプロセッサビットをID送信サイクルかデータ送信サイクルにする．
(マルチプロセッサビットは多数の相手とシリアル通信をする際に用いるもので)ID送信サイクル/データ送信サイクルはどちらも受信側にどう受信させるか区別させるためのもので，ID送信サイクルは指定されたIDでない場合は受信データを受信せず指定されたIDがくるまで待つ．サイクルビットは何だろうとひとまず受信する．そんなのだった気がします．
しかしSMRでマルチプロセッサ通信は禁止しているので関係ない．
MPBも同様．これは自分が受信するときの設定．これはread専用なのでそもそもどうでもいい．
TENDは送信が終わったかどうかを調べるフラグ．これも同じくread専用．ここらは送信関数を作る時に使う．
PER,FER,ORERはエラー用のフラグなのでクリアしないと通信できない(はず)．

ここまでたった6行なのに(文章が)長かった．

``` C
//SCI設定
SCI1.SCR.BYTE = 0;						//[TIE,RIE,TE,RE,TEIE]を0にする．かつCKEでクロックを内部ボーレートジェネレータ(BBRで設定)とする
SCI1.SMR.BYTE = 0;						//clock,stop bit,parity
SCI1.SCMR.BYTE = 0xf2;					//いろいろ
SCI1.BRR = 15;							//ボーレート19200bps

for(int k=0; k<100;k++);							//待つ

SCI1.SSR.BYTE &= 0xC7;					// ORER,PER,FERをクリアする

```

最後にSCIを有効にする．それだけです．
割り込みハンドラはサンプルでは使っていますが，使わなくても送信するだけなら有効にしなくて大丈夫(と思われ)．
最後のSCRは必須．

``` C
//SCI割り込み設定
IPR(SCI1,RXI1) = 0x7;					//SCI1のRXI1の割り込み優先度を7に設定
IEN(SCI1,RXI1) = 0x1;					//SCI1のRXI1の割り込みを有効化
IR(SCI1,RXI1) = 0x0;					//SCI1のRXI1の割り込みフラグをクリア

SCI1.SCR.BYTE = 0xF0;					//TIE,RIE,RE，TEを設定して割り込みを有効化
```

# 送信関数
SCIの設定が終わっても送信する関数がないと何もできない．
サクッと読む．
char型の配列msg_stringの中身が0になるまでループして1つ1つ送っていく．送れたかの確認をSSR.BIT.TENDでして，送るものをSCI1.TDRに入れいている．TDRに関しては27.2.3 トランスミットデータレジスタ（ TDR ）に載っている．8bitのレジスタなので8bit分しか送れない．そのままですね．
完全に転載とならないようにコメント位は書き直しておく．

``` C
static void text_write (const char * const msg_string)
{
	int i = 0x0;
	int j = 0x0;

	//1文字ずつバッファに入れていく
	for (i = 0; msg_string[i]; i++)
	{
		//送信が終わるまで待機
		while (0x0 == SCI1.SSR.BIT.TEND);

		//次に送信する文字をセット
		SCI1.TDR = (unsigned char)msg_string[i];

		//(送信が始まるまで)ちょっと待つ
		for (j = 0; j < 1000u; j++);
	}
}

```

# 使用コード
長くなったのでまとめておく．初期設定関数，送信関数，main関数があります．

``` C

void init_SCI1(){
	SYSTEM.PRCR.WORD = 0x0A503;				//クロックソース選択の保護解除
	MSTP(SCI1) = 0;							//SCI1を有効にする
	SYSTEM.PRCR.WORD = 0x0A500;				//クロックソース選択の保護

	//ピン設定　TxD(P26),RxD(P30)
	PORT2.PDR.BIT.B6 = 1;					//TxDなので出力設定
	PORT3.PDR.BIT.B0 = 1;					//RxDなので入力設定

	MPC.PWPR.BIT.B0WI = 0;					//PFSレジスタの保護解除をするPFSWEレジスタの保護解除
	MPC.PWPR.BIT.PFSWE = 1;					//PFSレジスタの保護解除

	MPC.P26PFS.BIT.PSEL = 0xA;				//P2nの周辺機能を設定
	MPC.P30PFS.BIT.PSEL = 0xA;				//P3nの周辺機能を設定

	MPC.PWPR.BIT.PFSWE = 0;					//PFSレジスタの保護
	MPC.PWPR.BIT.B0WI = 1;					//PFSレジスタの保護をするPFSWEレジスタの保護

	PORT2.PMR.BIT.B6 = 1;					//P26だけ周辺機能ポートにする
	PORT3.PMR.BIT.B0 = 1;					//P30だけ周辺機能ポートにする

	//SCI設定
	SCI1.SCR.BYTE = 0;						//[TIE,RIE,TE,RE,TEIE]を0にする．かつCKEでクロックを内部ボーレートジェネレータ(BBRで設定)とする
	SCI1.SMR.BYTE = 0;						//clock,stop bit,parity
	SCI1.SCMR.BYTE = 0xf2;					//いろいろ
	SCI1.BRR = 15;							//ボーレート19200bps

	for(int k=0; k<100;k++);

	SCI1.SSR.BYTE &= 0xC7;					// ORER,PER,FERをクリアする

	//SCI割り込み設定
	IPR(SCI1,RXI1) = 0x1;					//SCI1のRXI1の割り込み優先度を7に設定
	IEN(SCI1,RXI1) = 0x1;					//SCI1のRXI1の割り込みを有効化
	IR(SCI1,RXI1) = 0x0;					//SCI1のRXI1の割り込みフラグをクリア

	SCI1.SCR.BYTE = 0xF0;					//TIE,RIE,RE，TEを設定して割り込みを有効化

}

static void text_write (const char * const msg_string)
{
	int i = 0x0;
	int j = 0x0;

	//1文字ずつバッファに入れていく
	for (i = 0; msg_string[i]; i++)
	{
		//送信が終わるまで待機
		while (0x0 == SCI1.SSR.BIT.TEND);

		//次に送信する文字をセット
		SCI1.TDR = (unsigned char)msg_string[i];

		//(送信が始まるまで)ちょっと待つ
		for (j = 0; j < 1000u; j++);
	}
}

void main(void)
{
	PORT0.PDR.BIT.B3 = 1;

	init_SCI1();

	while(1){
		PORT0.PODR.BIT.B3 = 1;
		for(int k=0; k<100000;k++);
		PORT0.PODR.BIT.B3 = 0;
		text_write("test\r\n");
		for(int k=0; k<100000;k++);
	}
}
```

# LINK
[RX220 CubeSuite+ 用ルネサススタータキットのサンプルコード](https://www.renesas.com/ja-jp/software/D3014201.html)