Spartan6でmicroblaze mcs を動かす③ソフトウェア編

"[Spartan6でmicroblaze mcs を動かす②SDK編](https://qiita.com/cyebu1103/items/28128b21875495d04b03)"までの手順を行うと、シリアルポートからhellow worldを喋るテンプレートが生成されます。

hellow worldを喋ったところで何もうれしくないので、プログラムを少し変更してみます。


#プログラムの動作仕様
* 最初にスタートメッセージを発する
* メインループは何もしない
* UART受信割り込みを検出したら、割り込みハンドラに飛ぶ
* 割り込みハンドラ内で受信した文字(押したキー)を判定する
* エンターキーを押した場合、8bitのLED（GPO）をインクリメントする
* バックスペースキーを押した場合、8bitのLED（GPO）をデクリメントする
* UART受信文字をエコーバック（そのままUART送信に返す）

以上の動作を満たすCのコードを書いてみます。

# Cソース
```main.c
#include "platform.h"		//とりあえず必要
#include "mb_interface.h"	//とりあえず必要
#include "ADR_MAP.h"		//自前のヘッダファイル

//ASCIIコードのバイナリ定義
	#define	BS		0x08	//バックスペース
	#define	CR		0x0D	//復帰
	#define	LF		0x0A	//改行
	#define	ESC		0x1B	//エスケープ

//-----------------------------
//グローバル変数
//-----------------------------
	unsigned char g_led=0;

//-------------------------------------------------------------------------------
//割込みハンドラ
//-------------------------------------------------------------------------------
void Int_Handl(void) {
	unsigned char msg;
	
	//割り込みフラグ落とす
	IRQ_ACK = 0xFFFFFFFF;

	//受信文字を持ってくる
	msg=UART_RX;

	//エコーバック
	xil_printf("%c",msg);
	
	//受信文字に応じた処理
	switch(msg){
		case CR://エンター
			//LEDをインクリメント
			g_led++;
			GPO1=g_led;
			break;
		case BS://バックスペース
			//LEDをデクリメント
			g_led--;
			GPO1=g_led;
			break;
		default://
			//なにもしない
			break;
	}//switch
}

//============================================================
//メインループ
//============================================================
void main()
{
	//ハードの初期化
    init_platform();
	
    //割込みハンドラの登録
    microblaze_register_handler((XInterruptHandler)Int_Handl,(void*)0);
    
	//使用する割込み選択(bit[2]⇒UART割り込み)
    IRQ_ENABLE = 0x00000004;
	
    //割り込みを有効にする
	microblaze_enable_interrupts();
	
	xil_printf("*******************\r");
	xil_printf("Start!!!!!\r");
	xil_printf("*******************\r");
	
	//メインループ
    while(1){
		
    }
	
}
```

# ヘッダーファイル
今回使用しているレジスタは、`UART_RX` と `GPO1`だけです。

```ADR_MAP.h
#ifndef ADR_MAP_H_
#define ADR_MAP_H_

	#define UART_RX			(*(volatile unsigned int *) 0x80000000)
	#define UART_TX			(*(volatile unsigned int *) 0x80000004)
	#define UART_STATUS		(*(volatile unsigned int *) 0x80000008)
	
	#define GPO1			(*(volatile unsigned int *) 0x80000010)
//	#define GPO2			(*(volatile unsigned int *) 0x80000014)
//	#define GPO3			(*(volatile unsigned int *) 0x80000018)
//	#define GPO4			(*(volatile unsigned int *) 0x8000001C)
	
	#define GPI1			(*(volatile unsigned int *) 0x80000020)
//	#define GPI2			(*(volatile unsigned int *) 0x80000024)
//	#define GPI3			(*(volatile unsigned int *) 0x80000028)
//	#define GPI4			(*(volatile unsigned int *) 0x8000002C)
	
	#define IRQ_STATUS		(*(volatile unsigned int *) 0x80000030)
	#define IRQ_ENABLE		(*(volatile unsigned int *) 0x80000038)
	#define IRQ_ACK			(*(volatile unsigned int *) 0x8000003C)

//MicroBraze_mcs のIOﾊﾞｽは 0xC000_0000　が先頭アドレス

#endif
```

# ビルド
SDK でctrl+B を押すとプログラムをビルドします。
`Debug`フォルダにelfファイルが生成されます。

#プログラムの書き込み時の注意事項
いよいよプログラムを書き込みます。

今回使用している[Spartan6 ATLYSボード](http://store.digilentinc.com/atlys-spartan-6-fpga-trainer-board-limited-time-see-nexys-video/)は、FPGAの書き込みデータ(bitファイル)をimpactで書き込む際に　"PROG"と表記されているUSBコネクタから書き込みできます。
しかし、SDKからプログラムのアップロードをする場合には、エラーになってしまいます。（私の環境では）

<font color="Red">XilinxのFPGAライター(Platform Cable USB Ⅱ)を使用している場合は問題なく書き込みできています。</font>


#プログラムの書き込み
`Program FPGA`ボタンを押します

![UpLoad1.jpg](https://qiita-image-store.s3.amazonaws.com/0/204268/f8fd4430-8103-95ca-167f-d1f15254bd48.jpeg)

項目|指定するデータ
---|---|---
Bitstream|ISEで生成したbitファイルを指定します
BMM File|SDKのワークディレクトリ内に作成したハードウェアプロジェクトディレクトリにあるもの（LOC情報を追記したもの）を指定します
ELF File|SDKでビルド完了後に生成されたelfファイルを指定します

あとは "Program"ボタンを押すと、回路データ（bitファイル）とソフトウェア(elfファイル）を合成したデータがFPGAに転送され、
プログラムが走ります。

![UpLoad2.jpg](https://qiita-image-store.s3.amazonaws.com/0/204268/1089057e-fdd6-9299-0e69-b54fc6cf9ac7.jpeg)

# 動作確認
Tera Termを使用しシリアルポートを立ち上げておきます。
ATLYSボードでは"UART"と書いてあるJ17コネクタにmicro USBを接続することでCOMポートとして認識します。

TeraTermからエンターやバックスペースを押すと無事にLED点灯位置が応答していました。