第6回 シリアル通信制御
公式
\[ F(s) = \int_{0}^{\infty} f(t)e^{-st}dt \]

内 容

このドキュメントは http://icrus.org/fpga_atlys_design/ 上にあります.

本日はATLYS UARTのシリアル通信について述べます.

今まで,単独で利用してきたATLYSですがUARTをマスターするとコンピュータから自由にデータをやり取りできます.ATLYSには,あらかじめパソコンとシリアル通信する機能が付属しており,USBケーブルとデバイスドライバを用意することにより手軽にパソコン-ATLYS間通信が利用でます.この機能をUART(Universal Asynchronous Receiver Transmitter)といいます.

6-1 準備 デバイスドライバのインストール

サイトからデバイスドライバをダウンロードして,ケーブル接続後,インストール

http://www.exar.com/connectivity/uart-and-bridging-solutions/usb-uarts/xr21v1410 にアクセスしページ右側Technical AssetsのSoftware Driversより,使用コンピュータに必要なドライバをダウンロードし,フォルダを解凍する.

②パソコンのUSB端子とATLYSのUART端子(ボード左側手前)をUSBケーブルで接続し,ATLYSの電源を入れる.

③ドライバインストールに失敗する.

④デバイスマネジャから,「×」の付いたデバイスを探し,右クリック→「デバイスソフトウェアの更新」を選び,ダウンロードし解凍済みのフォルダを選択してデバイスソフトウェアの更新を実行する.

⑤デバイスマネジャでドライバが正常にインストールされたことを確認する.このとき,デバイス名(XR21V1410 USB UART(COM3)など)をメモしておくこと.

通信ソフト『PuTTYjp』PuTTYjpのインストール

①PuTTYjpで検索して,putty-0.63-jp20130916.zipをダウンロードし,解凍する.

②puttyjp.exeをダブルクリックし起動を確認する.

(http://hp.vector.co.jp/authors/VA024651/download/file/putty-0.63-jp20130916.zip)

6-2 スループログラムの実行

『まずは簡単なスループログラムから』

このスループログラムが動作すれば,デバイス,デバイスドライバ,ケーブル,通信ソフトが完全に動いていることを確認できます.

リスト 6-1 uart_thru.v ソース


001 `timescale 1ns / 1ps
002 // Create Date:    03:52:49 12/30/2013 
003 // Module Name:    uart_thru 
004 module uart_thru(
005 	input  wire uart_r, // シリアル受信 comx→ATLYS
006 	output wire uart_t, // シリアル送信 ATLYS→comx
007 	output wire led
008 );
009 	
010 	//受信したものをそのまま送信へ(スルー)
011 	assign uart_t = uart_r; 
012 	assign led = uart_t;
013 endmodule
014 

リスト 6-2 uart_thru.ucf ソース


001 net uart_r loc=A16; // シリアル受信
002 net uart_t loc=B16; // シリアル送信
003 
004 net led    loc=U18;

機能と操作方法

このプログラムはパソコンのCOMポート(受信)に送られたデータをそのまま,COMポート(送信)に戻すプログラムで,パソコン,ATLYS双方のドライバの動作検証を行うことができるチェックプログラムです.

リスト1,2を入力・実行すると,LD0(右端のLED)が点灯する.次に,PuTTYjpを起動し,次の①~④を設定後,「開く」ボタンをクリックする.

①接続タイプで「Serial」をクリック

②シリアルポートの「COMX」のXを自分のパソコンのUART用COMポート番号を入力.

③スピードを「9600」とする.

④ダイアログ左の「カテゴリ」から接続→シリアルを選び,「フロー制御」で「None」を選択.

<その他設定>「カテゴリ」の「端末」をクリック.「どのCRにも絶対にLFを入れる」をνチェック.

<参考>ダイアログ左の「カテゴリ」からセッションで「セッション一覧」にセッション名を適当に入力して,「保存」をクリックすると,設定を保存できる.

キーボードから文字を入力すると,押したキーが画面に表示されます.キーボードからのデータは,パソコンのCOMXポートから出力されUSBケーブルを通して,ATLYS上のUARTデバイスに入力され,A16端子を通してFPGAに入力されます.FPGA上ではそのデータを何も手を加えずB16端子を通してUARTデバイスに返し,それがUSBケーブルを介してCOMXポートに戻されます.つまり,このプログラムの機能はスルーのみであるため,入力したキーがそのままコンソール上に表示される.スルーさえできれば,UARTは正常に動作しているので,あとは,工夫次第で何でもでき,パソコンとATLYSとの通信は自由自在に行えます.

図 6-1 UARTの信号のやり取り

6-3 シリアル通信の基礎

次に,UARTのシリアル通信について説明しよう.まず,①~⑤の5点がシリアル通信の基本設定があり確認の必要がある.

①<スピード9600bps> スピード(通信速度)はいろいろ選べるが,ここでは代表的な9600bpsで説明する.
②<データ長8ビット> 8ビットが基本.
③<ストップビット1>  今回は1ビットとする.
④<パリティNone> 今回は使用しない
⑤<フロー制御None>  今回は使用しない
②~⑤は必要がなければこのまま,使用する.①は次の範囲で任意に設定できる.

表 6-1 通信速度と1ビットの長さ
スピード[bps]1ビットの
長さ[μs]
1ビットの長の
クロック数
(fclk=100MHzの場合)
3003,333.3333,333.3
6001,666.7166,666.7
1200 833.3 83,333.3
2400 416.7 41,666.7
4800 208.3 20,833.3
9600 104.2 10,416.7
19200 52.1 5,208.3
38400 26.0 2,604.2
14400 69.4 6,944.4
28800 34.7 3,472.2
57600 17.4 1,736.1
115200 8.7 868.1

つまり,9600bpsならば,通信で使用される1ビットの長さは104μ秒(スピードの逆数)になり,ATLYS(fclk=100MHz)のクロック数でいうと,1 ビット当たり10416クロック(約1万クロック)で,1ビットの中心までは,5208クロックである.また,1文字を送るためには,スタートビット1 ビット,データービット8ビット,ストップビット1ビットの合計10ビットが必要なので,1m秒(≒1042μ秒)かかる.

図 6-2 データパターンの例

6-4 UARTの通信

リスト3,4を入力・実行するとキーボードからの入力された文字コードがATLYSのLEDに表示される.

リスト 6-3 uart_disp.v ソース


001 `timescale 1ns / 1ps
002 //////////////////////////////////////////////////////////////////////////////////
003 // Create Date:    04:43:38 12/30/2013 
004 // Module Name:    uart_disp 
005 //////////////////////////////////////////////////////////////////////////////////
006 module uart_disp(
007 	input  wire clk, 
008 	input  wire uart_r, // シリアル受信 comx→ATLYS
009 	output wire uart_t, // シリアル送信 ATLYS→comx
010 	output wire [7:0] led
011 );
012 	
013 // UART Recive ///////////////////////
014 	parameter MAX1=10416; // 9600bpsの1ビットのクロック数
015 	parameter MAX2= 5208; // 9600bpsの0.5ビットのクロック数
016 	
017 	assign uart_t = uart_r; // 受信したものをそのまま送信へスルーする
018 
019 	reg [12:0] cc=13'b0; 	// クロックカウンタ
020 	reg last_r=1'b1;			// 1つ前の受信ビット
021 	reg reciving=1'b0;		// 受信中
022 	reg [4:0] bit_n=5'b0;	// 半ビットカウンタ
023 	reg [7:0] data_r=8'b0;	// 受信文字(8ビット)
024 	assign led = data_r;		// LED制御
025 
026 	always @(posedge clk)begin
027 		if( reciving )begin // 受信中
028 			if(cc==MAX2-1)begin
029 				if(bit_n==18)begin // 19にはカウントアップしないで終了
030 					bit_n<=1'b0;
031 					reciving<=1'b0;
032 				end
033 				else begin 
034 					bit_n<=bit_n+1'b1;
035 					if(bit_n>=2 && bit_n[0]==0)
036 						data_r[bit_n[4:1]-1] <= 									anti_chattering; 
037 								// 受信ビットを記録
038 				end
039 				cc<=1'b0;
040 			end
041 			else begin
042 				cc<=cc+1'b1;
043 			end
044 		end		
045 		else begin
046 			if( {last_r,anti_chattering}==2'b10 )begin // スタートビット検出
047 				reciving <= 1'b1;
048 				cc<=1'b0;
049 				bit_n<=1'b0;
050 			end
051 		end
052 		last_r <= anti_chattering;
053 	end
054 
055 // アンチチャタリング回路 ////////////////
056 	reg anti_chattering=1'b1;
057 	parameter rec_size=8;
058 	reg [rec_size-1:0] rec={rec_size{1'b1}};
059 	always @(posedge clk)begin
060 		rec<={rec[rec_size-2:0],uart_r};
061 		if(rec=={rec_size{1'b0}})      anti_chattering<=1'b0;
062 		else if(rec=={rec_size{1'b1}}) anti_chattering<=1'b1;
063 	end
064 	
065 endmodule
066 

リスト 6-4 uart_disp.ucf ソース


001 // uart_disp.ucf
002 net clk    loc=L15;
003 
004 net uart_r loc=A16; // シリアル受信
005 net uart_t loc=B16; // シリアル送信
006 
007 net led(7)    loc=N12;
008 net led(6)    loc=P16;
009 net led(5)    loc=D4;
010 net led(4)    loc=M13;
011 net led(3)    loc=L14;
012 net led(2)    loc=N14;
013 net led(1)    loc=M14;
014 net led(0)    loc=U18;
図 6-3 半ビットカウンタbit_nのタイミング

<動作>チャタリング防止回路を使って,通信回線上のノイズの影響を軽減する.半ビットカウンタを利用してビットの中心でビットを測定する(図3).このプログラムを利用するとパソコンから任意のデータをATLYSに送信できる.

6-5 UART通信の応用

ここまでに習得してきた,オーディオプログラムとUARTプログラムを使って,パソコンのキーボード入力により,ATLYSから音階を出力するuart_play.vを実行しましょう.

リスト 6-5 uart_play.v ソース


001 `timescale 1ns / 1ps
002 //////////////////////////////////////////////////////////////////////////////////
003 // Create Date:    19:11:25 01/24/2015 
004 // Module Name:    uart_play 
005 //////////////////////////////////////////////////////////////////////////////////
006 module uart_play(
007 	input wire 			clk, // 100MHz
008 	input wire 			reset,
009 
010 	input wire uart_r, // シリアル受信 comx→ATLYS
011 	output wire uart_t, // シリアル送信 ATLYS→comx
012 	
013 	input wire  aud_bit_clk,
014 	output reg  aud_sdo,
015 	output reg  aud_sync,
016 	output wire aud_reset,
017 	input wire  sw7,
018 	output wire [7:0] led
019 );
020 
021 	reg[1:0] count=2'd0;
022 	wire 		clk25MHz=count[1]; 
023 	
024 	always@( posedge clk ) begin  // make 25MHz clock
025 		count <= count+2'd1;
026 	end
027   
028  // UART ///////////////////////
029 	parameter MAX1=10416; // 9600bpsの1ビットのクロック数
030 	parameter MAX2= 5208; // 9600bpsの0.5ビットのクロック数
031 	
032 	assign uart_t = uart_r; // 受信したものをそのまま送信へスルーする
033 
034 	reg [12:0] cc=13'b0;
035 	reg last_r=1'b1;
036 	reg reciving=1'b0;
037 	reg [4:0] bit_n=5'b0;
038 	reg [7:0] data_r=10'b0;
039 
040 	always @(posedge clk)begin
041 		if( reciving )begin
042 			if(cc==MAX2-1)begin
043 				if(bit_n==18)begin
044 					bit_n<=1'b0;
045 					reciving<=1'b0;
046 				end
047 				else begin 
048 					bit_n<=bit_n+1'b1;
049 					if(bit_n>=2 && bit_n<=16 && bit_n[0]==0)begin
050 						data_r[bit_n[4:1]-1]<=uart_r;
051 					end
052 				end
053 				cc<=1'b0;
054 			end
055 			else begin
056 				cc<=cc+1'b1;
057 			end
058 		end		
059 		else begin
060 			if( {last_r,uart_r}==2'b10 )begin
061 				reciving <= 1'b1;
062 				cc<=1'b0;
063 				bit_n<=1'b0;
064 			end
065 		end
066 		last_r <= uart_r;
067 	end
068 	
069 	
070 	
071 // 音出力 /////////////////////////	
072 	reg [7:0] key=1'b0;
073 	
074 	reg [7:0] t=7'd0;
075 	assign aud_reset=(!reset);
076 	reg[7:0] a_count=8'd255;
077 	assign led=c[23:16];
078 	reg n_frame=1'b1;
079 	
080 	reg[23:0] c=24'h0;
081 	reg signed[19:0] wave=20'h0;
082 	
083 	parameter tag=16'b_1111_1000_0000_0000;
084 	parameter[19:0] control[0:3] ={
085 		20'h_04_000, 20'h_18_000, 20'h_0000_0, 20'h_0808_0
086 	};
087 	
088 	// sine-wave generator (preparation)
089 	reg signed[31:0] y0;
090 	reg signed[15:0] y1=16'h_03af, y2=16'h_0000;
091 	parameter signed[15:0] a1=16'h_7fc9, a2=16'h_c000;
092 	
093 	always @( posedge aud_bit_clk ) begin
094 		if( a_count==8'd255 || a_count<8'd14 )
095 			aud_sync=1'b1;
096 		else
097 			aud_sync=1'b0;
098 		
099 		if( a_count<=8'd15)
100 			aud_sdo=tag[15-a_count];
101 		else if( a_count<=8'd35 )
102 			aud_sdo=control[n_frame][35-a_count];
103 		else if( a_count <=8'd55 )
104 			aud_sdo=control[n_frame][55-a_count];
105 		else if(a_count <= 8'd75 )
106 			aud_sdo=wave[75-a_count];
107 		else if(a_count<=8'd95)
108 			aud_sdo=wave[95-a_count];
109 		else
110 			aud_sdo=1'd0;
111 				
112 		if( a_count==8'd255 )begin
113 			// sine-wave ganerator
114 			y0= y1*1*a1 + y2*a2;
115 			y2 = y1;
116 			y1 = { y0[31], y0[28:14]};
117 			if(sw7==1'b1)
118 				wave = y0[31:12];
119 			else begin
120 				case( data_r )
121 					8'h61: key=8'd109;
122 					8'h77: key=8'd102; 
123 					8'h73: key=8'd97; 
124 					8'h64: key=8'd91; 
125 					8'h72: key=8'd86; 
126 					8'h66: key=8'd81; 
127 					8'h74: key=8'd77; 
128 					8'h67: key=8'd72; 
129 					8'h68: key=8'd68; 
130 					8'h75: key=8'd64; 
131 					
132 					8'h6a: key=8'd61; 
133 					8'h69: key=8'd57;  
134 					8'h6b: key=8'd54;  
135 					8'h6f: key=8'd51;  
136 					8'h6c: key=8'd48;  
137 					8'h3b: key=8'd45;  
138 					8'h40: key=8'd43;  
139 					8'h3a: key=8'd40;  
140 					8'h5b: key=8'd38;  
141 					8'h5d: key=8'd36; 
142 					default: key=8'd0;
143 				endcase
144 			
145 				if(t<key )begin
146 					wave = 20'h_f_f000;
147 					t=t+1'b1;
148 				end
149 				else if(t<{key[6:0],1'b0})begin
150 					wave = 20'h_0_0fff;
151 					t=t+1'b1;
152 				end
153 				else if(t>={key[6:0],1'b0})begin
154 					wave = 20'h_0_0fff;
155 					t=0;
156 				end
157 			end
158 			
159 			n_frame = n_frame+1'b1;
160 		end
161 
162 		a_count = a_count+1'b1;
163 		c = c+1'b1;
164 	end
165 	
166 
167 endmodule 
168 
169 

リスト 6-6 uart_play.ucf ソース


001 // uart_play
002 NET clk		LOC = L15;
003 NET reset 	LOC = P3;
004 
005 net uart_r loc=A16; // シリアル受信
006 net uart_t loc=B16; // シリアル送信
007 
008 net aud_bit_clk loc=L13;
009 net aud_sdo     loc=N16;
010 net aud_sync    loc=U17;
011 net aud_reset   loc=T17;
012 
013 net sw7 loc=E4;
014 
015 net led(7) loc=N12;
016 net led(6) loc=P16;
017 net led(5) loc=D4;
018 net led(4) loc=M13;
019 net led(3) loc=L14;
020 net led(2) loc=N14;
021 net led(1) loc=M14;
022 net led(0) loc=U18;
023 
024  

以上,今回はシリアル通信の使い方でした.

UART通信についてまとめ,ツールとして利用できるプログラムを提供したので,それぞれに独創的な課題作品を仕上げてください.


ssatoh@

足立工科大学 工学部 情報通信工学科