標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第637回]

●PIC18F14K50のUSBデータ送受信の仕組み

というテーマで書こうと思ったのですけれど、まてよ、ひょっとしたら、と思って過去記事を検索してみましたら、やっぱり書いてしまっておりました。
[第482回]●PIC18F4550のUSB送受信の仕組み と題して書いておりますので、まずはそちらをお読みくださいませ。

その当時はPIC18F14K50ではなくてPIC18F4550を使っての説明でした。
もっともUSB動作の仕組みそのものは、PIC18F14K50とPIC18F4550とでは全く同じで、ただ異なっているのは、USBバッファとして使われるRAMのアドレスと容量だけです。
PIC18F4550でUSBバッファとして利用可能なRAMは、アドレス0400〜07FFの1KBです。
これに対してPIC18F14K50でUSBバッファとして利用可能なRAMは、アドレス0200〜02FFの256バイトです。

あっと、もうひとつ異なっているものがありました。
PIC18F4550ではエンドポイントはEP0〜EP15の16個まで扱うことができますが、これに対してPIC18F14K50ではその半分、EP0〜EP7の8個しか扱うことができません。
各エンドポイントはそれぞれINとOUTの2通りが設定可能で、さらにそのそれぞれがDATA0とDATA1に分けて設定することができます。それはPIC18F4550でもPIC18F14K50でも同じですから、PIC18F4550では合計64のエンドポイントを設定することができ、PIC18F14K50では合計32のエンドポイントが設定できます。

そのエンドポイントを実際に使うためには、各エンドポイント毎にRAMアドレス200から順にそれぞれ4バイトずつ割り当てられたバッファデスクリプタテーブルに必要な値をセットする必要があります(下図)。


[出典]Microchip社PIC18F14K50DataSheet

この割り当て(mapping)はモード毎に決定されていて、ユーザーが勝手に適当に配置することはできません。
上のメモリマップを見ますと、その割り当てには4通りあります。
その4通りの区別はping−pongバッファを使うか使わないかによって分けられているようです。

●ping−pong BUFFER

当初は、なんじゃそりゃあ、ということで、なんだかわからんなあ状態でした。
今でもどこまで本当にわかっているのか怪しいものなのですが。
ping−pong BUFFERは、同じエンドポイントの同じINあるいはOUTに対して2つのバッファを割り当てる方式のことをいいます。
そしてping−pongの名前の通り、その割り当てたバッファを交互に使う仕組みなのです。
HIDの場合、SETUPのときのUSBホストコントローラから送られるコマンドやPIC18F14K50がホストに送るデスクリプタデータはともに8バイト長で送られます。
また通常のデータは64バイトずつ送られます。

PIC18F14K50がデータを送る、あるいはデータやコマンドを受け取る仕組みは、[第482回]で説明しています。
送信の場合は、あらかじめそのエンドポイントのBUFFER DESCREPTORで指定されたバッファに送信データをセットしておいて、BDnSTAT(エンドポイントnのBUFFER DESCREPTORの第1バイト)のビット7を1にします。
ビット7=1のときは、PIC18F14K50内蔵のUSBSIE(USB Serial Interface Engine)が所定のタイミングでデータをホストに向かって送出してくれます。
データの送出が完了すると、BDnSTATのビット7が0になりますから、それをプログラムで見ていて、ビット7が0になったら次の送信データをバッファにセットします。

そのような方法では送信完了を確認してから次のデータをバッファにセットすることになりますから、データをバッファにセットするための時間が必要です。
もしもping−pong BUFFERを使うように指定しておくと、DATA0のバッファにデータをセットして、そのBDnSTATを1にしたらすぐにDATA1のバッファに次のデータを書き込むことができますから、効率よい送信処理が行えます。

受信の場合もこれと同じ理屈で、受信データが2つのバッファに交互に入れられます。
ところで、何回か書いておりますように、HIDの場合にはどうやら1msecに1回、最大64バイトのデータしか送受信できないようですから、そんなping−pong BUFFERなどという、ややこしいものは使う必要はないのでは?
と思いました。

たしかにデータの送信や受信についてはその通りです。
ただ、64バイト以上のデータを連続して送信、または受信する場合には、DATA0、DATA1を交互に指定しなければなりません。
しかしそれはping−pong BUFFERでなければできない、ということではなくて、プログラムでその順番を管理しておいて、先にDATA0で送ったから今度はDATA1で送る、というように指定すればよいのです。
DATA0、DATA1はデータの送受信のときにデータパケットにつけられるPID(パケットの属性を示すマークのようなもの)で示されます。
プログラムでDATA0、DATA1は、BDnSTATのビット6で指定します。

ところで、いろいろな試行錯誤の過程でわかってきたことなのですが、Enumerationのときのホストからの送信は、コマンドはDATA0で送られてくるのですが、そのほかに意味不明のデータがDATA1で送られてくるようなのです。
なにしろかれこれ1年近くもの間、PICのUSB通信と格闘していたものですから、今となっては、そこのところは余りはっきりしたことは言えないのですが…。
そのDATA1は捨ててしまって構わないようなのですが、受け取るだけは受け取らないといけないようです(多分)。

というようなことから、EP0(OUT)のみping−pong BUFFERを使う設定にしました。
さきほどのBUFFER DESCREPTOR MAPでは2番目のPPB<1:0>=01になります。
4通りのうちのどれを選択するかは、UCFGレジスタのビット1、ビット0で指定します。

●UCFGレジスタ


[出典]Microchip社PIC18F14K50DataSheet

細かいことですが、bit1−0の指定のうち11=は …Endpoints 1 to 15 となっていますが、ここは 1 to 7 の間違いでしょう。

ND80ZVのPIC18F14K50では、UCFG=15Hにします。

なお、どのエンドポイントをどのように使うかということは、UEP0〜UEP7の各レジスタに必要な値をセットすることで定義します。

●UEPnレジスタ


[出典]Microchip社PIC18F14K50DataSheet

ND80ZVで使うPIC18F14K50では、EP0のほかにはデータの送信、受信用にEP1(OUT)、EP1(IN)を使います。
ですからUEP0=16H、UEP1=1EHにします。
PIC18F14K50のプログラムで、UEP0、UEP1とUCFGを設定しているところです。

movlw 16
lfsr 2,0f53;UEP0
movwf INDF2
movlw 15;ping-pong buffer set for EP0(out) only	
movwf UCFG

movlw 1e;in,out enable
lfsr 2,0f54;UEP1
movwf INDF2


本日は時間がなくなってしまいました。この続きは次回にいたします。
2010.10.14upload

前へ
次へ
ホームページトップへ戻る