このドキュメントは http://icrus.org/fpga_atlys_design/ 上にあります.
本日はATLYS UARTのシリアル通信について述べます.
今まで,単独で利用してきたATLYSですがUARTをマスターするとコンピュータから自由にデータをやり取りできます.ATLYSには,あらかじめパソコンとシリアル通信する機能が付属しており,USBケーブルとデバイスドライバを用意することにより手軽にパソコン-ATLYS間通信が利用でます.この機能をUART(Universal Asynchronous Receiver Transmitter)といいます.
①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で検索して,putty-0.63-jp20130916.zipをダウンロードし,解凍する.
②puttyjp.exeをダブルクリックし起動を確認する.
(http://hp.vector.co.jp/authors/VA024651/download/file/putty-0.63-jp20130916.zip)
このスループログラムが動作すれば,デバイス,デバイスドライバ,ケーブル,通信ソフトが完全に動いていることを確認できます.
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
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との通信は自由自在に行えます.
次に,UARTのシリアル通信について説明しよう.まず,①~⑤の5点がシリアル通信の基本設定があり確認の必要がある.
①<スピード9600bps> スピード(通信速度)はいろいろ選べるが,ここでは代表的な9600bpsで説明する.
②<データ長8ビット> 8ビットが基本.
③<ストップビット1> 今回は1ビットとする.
④<パリティNone> 今回は使用しない
⑤<フロー制御None> 今回は使用しない
②~⑤は必要がなければこのまま,使用する.①は次の範囲で任意に設定できる.
スピード[bps] | 1ビットの 長さ[μs] | 1ビットの長の クロック数 (fclk=100MHzの場合) |
300 | 3,333.3 | 333,333.3 |
600 | 1,666.7 | 166,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μ秒)かかる.
リスト3,4を入力・実行するとキーボードからの入力された文字コードがATLYSのLEDに表示される.
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
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;
<動作>チャタリング防止回路を使って,通信回線上のノイズの影響を軽減する.半ビットカウンタを利用してビットの中心でビットを測定する(図3).このプログラムを利用するとパソコンから任意のデータをATLYSに送信できる.
ここまでに習得してきた,オーディオプログラムとUARTプログラムを使って,パソコンのキーボード入力により,ATLYSから音階を出力する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
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@
足立工科大学 工学部 情報通信工学科