「USB CDC IN トランザクション(0) 」で受信した Get_Descriptor ( device ) に対するデータステージについて、経験したことを紹介します。 <PICデバイス=18F2550> ターゲットは秋月電子通商さんの USBマイコンボード 完成品(PIC18F2550) +α の RRP2550-0 です。
前回記事の最後に以下の SETUP ステージ を受信しています。
BDステータス = 34 ( bit2~bit5 がSETUPを示す)
受信バッファ = 80 06 00 01 00 00 12 00
2byte目 06 は Get_Descriptor()
4byte目 01 は 標準device
7byte目 12 は データ・ステージのbyte数( 18byte )
これに続くデータステージを完了するまでに試行錯誤を繰り返しましたが、以下の方法でデータステージ及び、ステータスステージを完了しています。 下図は標準デバイス・ディスクリプタとして準備したデータです。
エンドポイント0 のバッファ長に合わせて 8byte 毎にラベルを付けています。
処理は以下の手順で行います。
<<< 1~8byte目送信 >>>
先の Get_Descriptor ( device ) 転送完了割り込みの中で以下の通りバッファとBDステータス等を設定して次フレームの IN トランザクションを待ちます。
エンドポイント0 IN 側バッファに上図 usbdevdb に続く 8byte を転送
BD ステータスレジスター(アドレス404H) 値 C8H
BDアドレスカウンターレジスター(アドレス405H) 値 08H
BD ステータスレジスター(アドレス400H) 値 88H
BDアドレスカウンターレジスター(アドレス401H) 値 08H
UCON<PKTDIS> をクリア
<<< 9~16byte目送信 >>>
上のデータを読み出す IN トランザクションの転送完了割り込みの中で、以下の通りバッファとBDステータス等を設定して次フレームの IN トランザクションを待ちます。
エンドポイント0 IN 側バッファに上図 usbdevdb1 に続く 8byte を転送
BD ステータスレジスター(アドレス404H) 値 88H
BDアドレスカウンターレジスター(アドレス405H) 値 08H
BD ステータスレジスター(アドレス400H) 値 88H
BDアドレスカウンターレジスター(アドレス401H) 値 08H
UCON<PKTDIS> をクリア
<<< 17~18byte目送信 >>>
上のデータを読み出す IN トランザクションの転送完了割り込みの中で、以下の通りバッファとBDステータス等を設定して次フレームの IN トランザクションを待ちます。
エンドポイント0 IN 側バッファに上図 usbdevdb2 に続く 2byte を転送
BD ステータスレジスター(アドレス404H) 値 C8H
BDアドレスカウンターレジスター(アドレス405H) 値 02H
BD ステータスレジスター(アドレス400H) 値 88H
BDアドレスカウンターレジスター(アドレス401H) 値 08H
UCON<PKTDIS> をクリア
以上で、データステージを完了し、続くステータスステージは前々回同様に割り込み無しで完了します。 詳しくは前々回記事をご覧下さい。
次の SETUP ステージでは以下の通り Get_Descriptor ( config ) を受信しました。
BDステータス = 34 ( bit2~bit5 がSETUPを示す)
受信バッファ = 80 06 00 02 00 00 09 00
2byte目 06 は Get_Descriptor()
4byte目 01 は 標準構成( Configuration )
7byte目 09 は データ・ステージのbyte数
USB関連記事のインデックスは右記事の末尾にあります。→ USB CDC
「楽々PIC」は楽しい道具を作りながら学ぶブログを目指します。
18f2550
受信した Set_Address() は以下の通りでした。
BDステータス = 34 (bit2~bit5 がSETUPを示す)
受信バッファ = 00 05 02 00 00 00 00 00
2byte目 05 は Set_Address()
3byte目 02 は デバイス・アドレス
受信したら、エンドポイント0の OUT 側の再設定と、UCON<PKTDIS> クリアを行います。
Set_Address() はデータステージが無い為、次のフレームでは空の IN トランザクションに対応する必要があります。 この IN トランザクション完了の直後に、受信済みのデバイス・アドレスを UADDR に書き込むんで次の SETUP ステージを正常に受け取れるように備えます。
具体的には Set_Address() 受信直後に、空の IN トランザクションに応答する為に、エンドポイント0の IN 側に以下の設定をして転送完了割り込みを受けて、UADDR に受信していたデバイス・アドレスを書き込みます。
BD ステータスレジスター(アドレス404H) 値 C8H
BDアドレスカウンターレジスター(アドレス405H) 値 00H
Set_Address() 受信直後に、次の SETUP ステージに備えてエンドポイント0の OUT 側も忘れずに設定し、UCON<PKTDIS> をクリアします。
BD ステータスレジスター(アドレス400H) 値 88H
BDアドレスカウンターレジスター(アドレス401H) 値 08H
そして次の SETUP ステージで再び Get_Descriptor ( device ) を受信しました。
BDステータス = 34 ( bit2~bit5 がSETUPを示す)
受信バッファ = 80 06 00 01 00 00 12 00
2byte目 06 は Get_Descriptor()
4byte目 01 は 標準device
7byte目 12 は データ・ステージのbyte数
最初に受信した Get_Descriptor ( device ) と比べると7byte目の値が異なります。
USB CDC 実現の取り組みは長期化が予想される為、ブレッドボードを小型のものに変え、電源もPICkit3からの供給に切り替えました。 他の実験と切り離してじっくり取り組みたいと思います。
USB関連記事のインデックスは右記事の末尾にあります。→ USB CDC
「楽々PIC」は楽しい道具を作りながら学ぶブログを目指します。
前回までに USB ハブからのリセット信号を受けた後に Get_Descriptor ( device ) を受信する SETUP トランザクションを経験しました。 今回は IN トランザクションの経験について説明します。 <PICデバイス=18F2550> ターゲットは秋月電子通商さんの USBマイコンボード 完成品(PIC18F2550) +α の RRP2550-0 です。
Get_Descriptor ( device ) の次のフレームで IN トランザクションを行うことが決まっていて、それまで(1msec未満)に IN トランザクション時に送信するデータとエンドポイント0のINバッファに準備する必要があります。 Device Descriptor として下図を準備しました。
エンドポイント0のバッファサイズは 8byte に決まっているようなので、実際にバッファに準備するのは 8byte づつに区切ったデータになります。 まずは最初の 8byte をバッファに転送し、BDステータスレジスターに Data1 , トグル同期させる設定と、BDバイトカウンターレジスターに 8byte を設定します。
ピンポンバッファを使わない設定の場合のBDステータスレジスターとBDアドレスレジスターの値は以下の通りです。
BD ステータスレジスター(アドレス404H) 値 C8H
BDアドレスカウンターレジスター(アドレス405H) 値 08H
さらに、IN トランザクションの最後にホストが送ってくる空の OUT トランザクションに自動で ACK 応答するために、エンドポイント0の OUT側 BDステータスレジスターに 88H を書き込みます。
BD ステータスレジスター(アドレス400H) 値 88H
BDアドレスカウンターレジスター(アドレス401H) 値 08H
また、SETUP 動作中は UCON<PKTDIS> が自動的にセットされるので、このビットをクリアします。
以上の設定を行って、次のフレームを待つと(Windows XPで) IN トランザクションを完了して、RESET 信号が送られてきます。 先に送られて来た Get_Descriptor ( device ) は以下の通りですから、データ・ステージのbyte数 64byteに対して8byteだけで IN トランザクションが完了したことになりますが、とにかく完了します。
BDステータス = 34 ( bit2~bit5 がSETUPを示す)
受信バッファ = 80 06 00 01 00 00 40 00
2byte目 06 は Get_Descriptor()
4byte目 01 は 標準device
7byte目 40 は データ・ステージのbyte数
セットアップステージに続く、データステージとして IN トランザクションが完了し、ステータスステージでホストからDATA1 として空のデータを送る OUT トランザクションがあるのですが、前述の通り OUT側 BDステータスレジスターに 88H を設定している為に受信バッファを更新することなく(割り込みも無く)ACK応答しています。
BD ステータスレジスターの bit4 ( DTSEN )をセットしていると、指定された DATA0/1 と異なる場合にはバッファを更新せず、割り込みフラグもセットしない(割り込みも発生しない)まま ACK を返す仕様を利用しています。 BD ステータスレジスターの値 88H は bit6 ( DTS )が 0 なので DATA0 を待っているのに対して、DATA1 を受信することで割り込み無しで ACK 応答している訳です。
Windows XPでは、2度目の RESET に続いて、Set_Address() が送られてきます。 受信例は以下の通りでした。
BDステータス = 34 (bit2~bit5 がSETUPを示す)
受信バッファ = 00 05 02 00 00 00 00 00
2byte目 05 は Set_Address()
3byte目 02 は デバイス・アドレス
USB関連記事のインデックスは右記事の末尾にあります。→ USB CDC
「楽々PIC」は楽しい道具を作りながら学ぶブログを目指します。
あくまで、最初の SETUP トランザクション Get_Descriptor ( device ) を受信するまでの処理で、連続して開始される IN トランザクションに至らない状態であることにご注意下さい。
以下に実施例のアセンブラ・ソースを紹介しますが、試行錯誤を重ねて書き進め、デバッグ目的で不要なコードが点在しています。 あくまでも参考程度にご利用下さい。
USBハブからの RESET 信号を受けた際には、割り込みフラグをクリアし、BDステータスレジスタ用に準備する設定値を RESET 直後の値に設定します。 ( 下図のラベル inth に始まる処理 )
転送完了割り込みを受けた際には、最初に USTAT をコピー(退避)して割り込みフラグをクリアします。 ( 上図のラベル inth10 に始まる処理 ) 割り込み処理開始時点で既に複数の割り込みが発生している場合には手順違いが処理抜けに繋がる重要な手順です。 その後、BDステータスを読み出し、受信バッファのデータをコピー(退避)します。 上図ではデバックの為、他に幾つかのデータを間接アドレスポインター POSTINC1 に転送して、履歴を取っています。
上図で RCALL ihuoic の直後にブレークポイントを設定するなどして、受信データを確認すると以下を受信しているはずです。
BDステータス = 34 ( bit2~bit5 がSETUPを示す)
受信バッファ = 80 06 00 01 00 00 40 00
2byte目 06 は Get_Descriptor()
4byte目 01 は 標準device
7byte目 40 は データ・ステージのbyte数
下図は、割り込み処理を抜ける部分です。 割り込み処理中に他の割り込みが発生していないか確認し(必要に応じて処理を済ませ)割り込みフラグ USBIF をクリアして割り込み処理を終わります。
下図は、参考までに私が設定しているシンボルです。 まだデバック用のシンボルが多い状態ですから、説明は省きます。
USB関連記事のインデックスは右記事の末尾にあります。→ USB CDC
「楽々PIC」は楽しい道具を作りながら学ぶブログを目指します。
<<< USBモジュールのエンドポイント設定 UEPn >>>
ハンドシェークモード、Control モード、OUT、IN、Stall を設定するレジスターですが、データシートを見るとUEP0を先頭(若いアドレス F70H )に連続する16個のSFRでしたから、ここでは下図のデータをブロック転送して設定しています。
<<< USB割り込み制御用SFR >>>
通信時のエラーを知らせる割り込み許可は全て禁止にしています。
( UEIE )=00H
通信状態を知らせる割り込みは RESET と転送完了割り込みだけ許可します。
( UIE )=09H
以上で許可された割り込みの代表する割り込み USBIF を高位割り込みとして許可します。
IPR2 <USBIP>=1 、 PIE2<USBIE>=1
(事前に割り込み優先順位有効の設定が必要です。)
全ての割り込み許可の前に当該割り込みフラグをクリアして下さい。
<<< 基本動作モードの設定 >>>
内臓トランシーバーをプルアップ付きで使い、FullSpeed でピンポンバッファ無しにします。
( UCFG )=14H
パケット転送許可状態で、USB モジュールを動作開始します。
( UCON )=08H
セットアップ中の UCON<PKTDIS>は SIE (シリアル・インターフェース・エンジン)によって頻繁にセットされ、送受信の都度プログラムでクリアする必要があります。
以上の初期設定を済ませ、今後の記事で説明する割り込み処理を実現した状態で RRP2550-0 を Windows PC に接続し、RESET と転送完了割り込み( Get_Descriptor( device ) )を確認出来ています。
今回は、様々な書籍や Web ページを参考にさせて頂いていますが、多くの資料が広範囲に説明している為に、「今の自分に必要なこと」に行きあたらずイライラする場面が多かったと思います。 ここで紹介する一連の記事では PIC18F2550 内臓の USB モジュールを使い、アセンブラで CDC を実現することに特化して、実際の設定値等をズバリ紹介する予定です。 広く USB を知りたい方には不向きな内容になる点、ご了承ください。
PIC18F2550 の USB 機能の理解も不十分で、USB の規格やプラグ&プレイ( Enumeration )の間にホスト( PC )が行う手順の実例も知らないと言う情報不足の中にあって、推理ゲームのような試行錯誤を強いられています。 当初、試行錯誤の過程も記事にしようと考えていましたが、自分自身も混乱するような推理ゲームを記事にしたのではご迷惑をお掛けすると考え直したところです。
完成を待たずに記事にしながらも、記事を書く時点で自分なりに納得できたものを紹介する予定です。 ただし、途中で間違いに気付いて修正する可能性を否定出来ません。 間違った記事は履歴付きで修正する予定ですが、事情を御理解の上で参考にして下さいますようお願いします。
USB関連記事のインデックスは右記事の末尾にあります。→ USB CDC
「楽々PIC」は楽しい道具を作りながら学ぶブログを目指します。
--- ご了承下さい ---
注意して記事を書いていますが、記事及びリンク先の情報による不利益について、一切責任を負い(負え)ません。
バナーを作成
jyosou_robot