歩き遍路 平成19年春(J1) 記録の準備
UTMI/ULPIでUSB( 1) VBUSの制御

 ULPIは、UTMI+ Low Pin Interface の略称で、UTMIのインターフェースの配線本数を削減した規格です。それでは UTMIとは、USB2.0 Transceiver Macrocell Interface の略称で、USBのコントローラー(論理層回路)とトランシーバー(物理層回路)間のインターフェース規格です。ややこしいですね。ここでは、ULPI のICを使ってUSBの実験をします。それぞれの規格書はWEBで検索すると入手できます。
 ULPIは、USB2.0 のインターフェースなのでハイスピードの480Mビット/sをサポートしているので、ULPIのインターフェースは60Mバイト/sと高速です。マイコンでは速度不足なのでFPGAをVerilogHDLのハードウエアを使います。
 手始めにULPIのICであるSMSC社のUSB3300とALTERA社のCycloneVを接続してUSBコネクタに有るVBUSを制御します。 USB3300とCycloneVは、ICを実装してある基盤を購入して使います。

●USB3300とCycloneVのハードウエア

 写真の左がCycloneVを実装した基板で、台湾から輸入した基板のDE0です。$119です。
 写真の右の上がUSB3300を実装した基板で、アメリカから輸入した基板のEVB−USB−3300です。下の写真はEVB−USB−3300の拡大写真です。
 USB3300のインターフェースが60MBpsなので手配線では配線が長くなるので心配です。





 回路図です。
 左がUSB3300で右のCycloneVとULPIで接続しています。




●ULPIインターフェースの概要

 次にULPI Register WriteとULPI Register Readのタイミングを示します。これ以外にULPI TransmitとULPI Receiveが有ります。
 ULPIインターフェースは、ULPIはスレーブ側になります。それでは、ULPI Register Writeの動きを見ていきます。
 @コントローラはDATAラインに1バイトのコマンドを載せることで動作が開始します。上位2ビットが 10 がRegister Writeコマンドで下位6ビットがレジスタアドレスです。
 Aコマンドを載せると、ULPIがコマンドを認識して NXT を発行してデータを要求するので、コントローラは速やかにデータをDATAラインに設定します。
 B続いて、コントローラはDATAラインにアイドルを設定することと、 STP を発行して動作サイクル完了を報せます。
Register Writeコマンドは、コマンド表に示します。







●コントローラ の制御の内容

 FPGAのコントローラは VerilogHDL で記述したステートマシンで実現しました。ステートマシンの主要部を次に示します。
 

////////////////////////////////////////////////////////////////////
//////////////////////// Controller Interface ////////////////////
////////////////////////////////////////////////////////////////////

// ********** Pll1 interface **********
//?? Pll1 Pll1 (
//?? .inclk0(EXT_CLOCK),
//?? .c0(I_Clk60M_PllC0), .locked(I_PllLocked)
//?? );

// ********** Controller **********


// ********** Controller Sequence Register control
always @(posedge EXT_CLOCK or negedge I_nMclr )
begin
if ( I_nMclr == 1'b0) //Reset
begin
r_SeqCtrl <= 6'h01; //SeqCtrl <- 01h
r_IBR1 <= 6'h55; //SeqCtrl <- 01h
r_IBR2 <= 6'hAA; //SeqCtrl <- 01h
r_DBo <= 1'h0; //SeqCtrl <- 01h
end
else
begin
r_SeqCtrl <= w_SeqCtrlIn; //SeqCtrl <- SeqCtrlIn
r_IBR1 <= w_IBR1In; //SeqCtrl <- SeqCtrlIn
r_IBR2 <= w_IBR2In; //SeqCtrl <- SeqCtrlIn
r_DBo <= DBoIn; //SeqCtrl <- SeqCtrlIn
end
end

// ********** Sequencer Ctrl
assign w_SeqCtrlIn = (r_SeqCtrl == 6'h01)? 6'h03 : //SC2state set
((r_SeqCtrl == 6'h03) & (Pi378 == 0 ))? 6'h04 : //BUTTON[1]==on
((r_SeqCtrl == 6'h03) & (Pi378 == 1 ))? 6'h10 : //BUTTON[2]==on
((r_SeqCtrl == 6'h04) & (Po379 == 0 ))? 6'h05 : //BUTTON[1]==on
((r_SeqCtrl == 6'h04) & (Po379 == 1 ))? 6'h14 : //BUTTON[2]==on
((r_SeqCtrl == 6'h05) & (Po37A == 0 ))? 6'h03 : //BUTTON[1]==on
((r_SeqCtrl == 6'h05) & (Po37A == 1 ))? 6'h18 : //BUTTON[2]==on

//Pi378 Register Read Sequnce
(r_SeqCtrl == 6'h10) ? 6'h11 :
((r_SeqCtrl == 6'h11) & (Pi378 == 1 ))? 6'h11 : //SeqUlpi Busy
((r_SeqCtrl == 6'h11) & (Pi378 == 0 ))? 6'h03 : //SeqUlpi Empty

//Po379 Register Write Sequnce
(r_SeqCtrl == 6'h14) ? 6'h15 :
((r_SeqCtrl == 6'h15) & (Po379 == 1 ))? 6'h14 : //SeqUlpi Busy
((r_SeqCtrl == 6'h15) & (Po379 == 0 ))? 6'h03 : //SeqUlpi Empty

//Po37A Register Write Sequnce
(r_SeqCtrl == 6'h18) ? 6'h19 :
((r_SeqCtrl == 6'h19) & (Po37A == 1 ))? 6'h18 : //SeqUlpi Busy
((r_SeqCtrl == 6'h19) & (Po37A == 0 ))? 6'h03 : //SeqUlpi Empty
6'h01; //other :no sell

// ********** Register Set
assign w_IBR1In = (r_SeqCtrl == 6'h14) ? DBi : //SC2state set
r_IBR1; //other :no sell

assign w_IBR2In = (r_SeqCtrl == 6'h18) ? DBi : //SC2state set
r_IBR2; //other :no sell

assign DBoIn = (r_SeqCtrl == 6'h10) ? SW[7:0]: //SC2state set
(r_SeqCtrl == 6'h11) ? SW[7:0]: //SC2state set
8'hzz; //other :no sell

////////////////////////////////////////////////////////////////////
//////////////////////// ULPI Interface ////////////////////////
////////////////////////////////////////////////////////////////////
// ********** ULPI Sequence Register control
//?? always @(posedge I_Clk60M_PllC0 or negedge I_nMclr )
always @(posedge EXT_CLOCK or negedge I_nMclr )
begin
if ( I_nMclr == 1'b0) //Reset
begin
r_SeqUlpi <= 6'h01; //SeqUlpi <- 00h
r_Do <= 8'h00;
r_OBR <= 8'h00;
r_Fcompl <= 1'h0; //SeqCtrl <- 01h
end
else
begin
r_SeqUlpi <= w_SeqUlpiIn; //SeqUlpi <- SeqUlpiIn
r_Do <= w_DoIn;
r_OBR <= w_OBRIn;
r_Fcompl <= w_FcomplIn;
r_STP <= w_STPIn;
end
end


// ********** Sequencer Ulpi
assign w_SeqUlpiIn = (r_SeqUlpi == 6'h01)? 6'h02 : //SC2state set
((r_SeqUlpi == 6'h02) & (r_Fgo == 0 ))? 6'h02 : //BUTTON[1]==on
((r_SeqUlpi == 6'h02) & (r_Fgo == 1 ))? 6'h03 : //BUTTON[2]==on
((r_SeqUlpi == 6'h03) & (iw_DIR == 1 ))? 6'h03 :
((r_SeqUlpi == 6'h03) & (iw_DIR == 0 ))? 6'h04 :
((r_SeqUlpi == 6'h04) & (r_IBR1[7]== 0))? 6'h02 :
((r_SeqUlpi == 6'h04) & (r_IBR1[7]== 1))? 6'h05 :
((r_SeqUlpi == 6'h05) & (r_IBR1[6]== 0))? 6'h10 :
((r_SeqUlpi == 6'h05) & (r_IBR1[6]== 1))? 6'h20 :
//Register Write Sequnce
(r_SeqUlpi == 6'h10) ? 6'h11 : //SeqUlpi Empty
((r_SeqUlpi == 6'h11) & (iw_NXT == 0 ))? 6'h11 : //SeqUlpi Busy
((r_SeqUlpi == 6'h11) & (iw_NXT == 1 ))? 6'h12 : //SeqUlpi Busy
(r_SeqUlpi == 6'h12) ? 6'h13 :
(r_SeqUlpi == 6'h13) ? 6'h14 :
((r_SeqUlpi == 6'h14) & (iw_NXT == 1 ))? 6'h14 : //SeqUlpi Busy
((r_SeqUlpi == 6'h14) & (iw_NXT == 0 ))? 6'h15 : //SeqUlpi Empty
(r_SeqUlpi == 6'h15) ? 6'h16 :
((r_SeqUlpi == 6'h16) & (r_Fgo == 1 ))? 6'h16 : //SeqUlpi Busy
((r_SeqUlpi == 6'h16) & (r_Fgo == 0 ))? 6'h16 : //SeqUlpi Empty
//Register Write Sequnce
(r_SeqUlpi == 6'h20) ? 6'h21 : //SeqUlpi Busy
((r_SeqUlpi == 6'h21) & (iw_NXT == 0 ))? 6'h21 : //SeqUlpi Empty
((r_SeqUlpi == 6'h21) & (iw_NXT == 1 ))? 6'h22 : //SeqUlpi Empty
(r_SeqUlpi == 6'h22) ? 6'h23 :
((r_SeqUlpi == 6'h23) & (iw_DIR == 0 ))? 6'h23 : //SeqUlpi Busy
((r_SeqUlpi == 6'h23) & (iw_DIR == 1 ))? 6'h24 : //SeqUlpi Empty
(r_SeqUlpi == 6'h24) ? 6'h25 :
((r_SeqUlpi == 6'h25) & (iw_DIR == 1 ))? 6'h25 : //SeqUlpi Busy
6'h25; //other :no sell

// ********** Register Set
assign w_DoIn = (r_SeqUlpi == 6'h10) ? r_IBR1 : //SC11 OTG control reg Adrs
((r_SeqUlpi == 6'h11) & (iw_NXT == 1 )) ? r_IBR2 : //SC21 SW[7:0]
(r_SeqUlpi == 6'h12) ? 8'h00 : //SC21 SW[7:0]
(r_SeqUlpi == 6'h20) ? r_IBR1 : //SC21 SW[7:0]
(r_SeqUlpi == 6'h22) ? 8'h00 : //SC21 SW[7:0]
r_Do; //other :no sell

assign w_OBRIn = (r_SeqUlpi == 6'h24) ? i_Di: //SC11 SW[7:0]
r_OBR; //other :no sell

assign w_FcomplIn = (r_SeqUlpi == 6'h01) ? 1'h0: //I_nMclr == 1'b0
(r_SeqUlpi == 6'h02) ? 1'h0 : //SC12 Set
(r_SeqUlpi == 6'h15) ? 1'h1 : //SC12 Reset
r_Fcompl; //other :no sell

assign w_STPIn = (r_SeqUlpi == 6'h01) ? 1'h0: //I_nMclr == 1'b0
(r_SeqUlpi == 6'h12) ? 1'h1 : //SC12 Set
(r_SeqUlpi == 6'h13) ? 1'h0 : //SC12 Reset
r_STP; //other :no sell




●動作

 ロジックスコープで採取したULPIの動作を次に示します。
 @ A点でDATAラインに1バイトのコマンドを載せて動作開始します。コマンドは 8Ah。
 A T点は、コマンドを認識したULPIが NXT を発行します。
 B B点は、DATAラインにデータを設定します。データは42h。
 C D点は、動作サイクル完了のため、DATAラインにアイドルを設定することと、 STP を発行します。

 




 次の写真は、VBUSラインが+5Vが供給されてLEDが点灯しました。
 暗くして写しましたので手ぶれがしています。




ホームへ戻る