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

●PIC18F14K50用「動作する」USBプログラム(その2)

前回、PIC18F14K50は、USBに関係するシステムレジスタの多くが、バンク切り換えを使わない簡便なアクセス方式であるAccess Bankではアクセスできない「領域外」に置かれているために、PIC18F2550で動作するプログラムも、そこの部分を書き直す必要がある、ということについて説明をいたしました。

その対策として、前回はバンク切り換えによる方法を説明しました。
システムレジスタのあるバンク15を指定するためにBSRレジスタに0Fh(=15)をセットしておいて、バンクを切り換えてアクセスしたい命令のときだけ、命令の末尾に’a’パラメータとして’1’を表記する、という方法です。

当初私はBSRによるバンク切り換え方式はかなり面倒なプログラムになってしまうのではないか、と思っていたのですが、よくよく考えてみますと、そもそもバンク切り換えが必要なところはそれほど多くはないことがわかってきました。
それは、
@USB関係のレジスタを除いて、その他のほとんどのシステムレジスタはAccess Bankとして普通にアクセスできる
AAccess Bankとして普通にアクセスできるユーザー用の汎用メモリはアドレス000〜05Fの96バイトもあるので、ワークエリアとしては十分な場合が多い
という2つの理由からです。

Access Bankとしてアクセスする、ということは、PIC16Fと同じように、何も気にしないで(特別のパラメータを付加したりしないで)ごく普通に命令を表記するればよい、ということなのですから、普通はそうするのが最も都合が良い、と思います。

では、BSRレジスタによるバンク切り換えが必要になるときとは、どんなときなのでしょうか。
そのひとつが、前回から書いております、Access Bankではアクセスできないシステムレジスタをアクセスするとき、です。
そのシステムレジスタはUSBに関するレジスタで、アドレスF5F〜F53にあります([第520回]参照)。

USBのみに直接関係するシステムレジスタは、UCON(F64)からUEP0(F53)まで18あって、そのうちF5F〜F53にある13のレジスタはAccess Bankではアクセスできません。
数だけで言いますと、USB関係のほとんどのシステムレジスタがAccess Bankの対象外になってしまう、ということになりますが、よくよくその内容を見てみますと、対象外になるシステムレジスタのうちでも、UEP7〜UEP0はエンドポイントのためのレジスタで、それが13のうちの8個であることがわかります。
エンドポイントのためのレジスタはそのエンドポイントを使わなければ、アクセスすることはありません。
とすると、普通にHIDとして使うならば、UEP0とUEP1の2つあれば十分ですから、UEP2〜UEP7は除外して考えてもよい、ということになります。

UFRMHとUFRMLは使わなくても済むレジスタですし、UEIRとUEIEも使わなければならない、というレジスタではありません。
UEIRとUEIEはUSBの割り込みのためのレジスタですから、そりゃあ必須だろう、と思われるかも知れませんが、全然そんなことはありません。

PIC18F14K50は高速(48MHz)で動作しますし、USB(Full Speedモード)は1msごとにしか送受信しませんから、割り込みなど考える必要はないのです。
まあ割り込みを使う使わないは好き好きですから、そりゃあ使っても構わないわけですけれども、私は必要無いと考えましたので使いませんでした。

ということで、するとAccess Bankではアクセスできないシステムレジスタ、というのは、実際のところ、UADDRとUEP1とUEP0だけ、ということになります。
しかも、このいずれのレジスタも初期設定のときに必要なだけですから、プログラムの最初にBSRに0Fをセットして、処理をすませておけば、あとはアクセスする必要はありません。

実は、それ以外に、Access Bankではアクセスできない範囲外にあって、もっと頻繁にアクセスしなければならないレジスタがあります。
それは、アドレス200〜2FFにある「汎用メモリ」です。
ここはUSBのための双方向メモリになっていて、USBの送受信のたびに頻繁にアクセスしなければなりません。

このメモリエリアをBSRベースのバンク切り換えでアクセスしようとする場合には、BSRレジスタに02をセットしておいてから、そのメモリ範囲にアクセスする命令のときだけ、’a’パラメータとして’1’を付加する、ことになります。
それはちょいと面倒くさいプログラムになります。
このUSBのためのメモリバッファをアクセスするところでは、次に説明するFSRとINDFを使った間接アドレッシングに依る方が楽だと思います。

●FSRとINDFを使ったプログラム

前回の、PIC18F14K50に限って対策が必要なUSBプログラムの、その部分をFSRとINDFを使って書き直してみると、次のようになります。

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

前回のBSRによるバンク切り換えのプログラムとどちらがいいか、といいますと、まあこれも好き好きなのですが、どっちもどっち、という感じです。
あ。PIC18Fの間接アドレッシングについては、[第414回][第419回]あたりで説明をしておりますので、そちらも参照なさってください。

ことUSB用のシステムレジスタに対してのアクセスに限って考えますと、今回の間接アドレッシングによるよりも前回のBSRによるバンク切り換え方式の方が、より簡単です。
私は今回のFSR、INDFによる方法で書いてしまいましたが、こちらの方法では、いちいち各レジスタのアドレス(0f53など)を確認しながら間違えないように書かなければならないだけ、手間がかかります(間違えてもアセンブラは指摘してはくれません)。

BSRの場合なら、最初に1回だけ、movlb 0f と書いておけば、あとはmovwf UEP0,1 のように、’1’を落とさないようにすることだけ注意すればよいので、比較的楽です(レジスタ名の綴りを間違えた場合にはアセンブラが指摘してくれます)。

一方、USBメモリバッアァをアクセスする場面では、逆にBSRによるバンク切り換えよりも、FSRとINDFによる間接アドレッシングの方が簡単です。
そのサンプルは、PIC18F14K50のテストプログラムの中にあります。
下の部分です。

;
;ep0 out data0(even)
setbd0
	lfsr 1,203
	movlw 05;address high
	movwf POSTDEC1
	movlw 00;address low
	movwf POSTDEC1
	movlw 08;bytes
	movwf POSTDEC1
	movlw 80;STAS(even)
	movwf POSTDEC1
	return
;

エンドポイント0に割り当てられている特別のメモリバッファ200〜203に、エンドポイント0のための情報をセットしています。
ここで書き込んでいるデータの意味については、いずれまた説明することになると思います。
ここではPIC18FのFSRを使った間接アドレッシングで、連続したメモリをアクセスするときの便利な使い方の例として説明をいたします。

FSRはPIC18Fの間接アドレスを入れる特殊レジスタで、PICの普通の命令と違って16ビットのアドレスを扱うことができます。
PICのFSRはFSR 0、FSR 1、FSR 2の3つあります。
実際には、16ビットアドレスのうち、上位8ビットと下位8ビットは別々のレジスタになっています。
FSR0HとFSR0L、FSR1HとFSR1L、FSR2HとFSR2Lです。

そこでたとえば、
movlw 02
movwf FSR1H
movlw 03
movwf FSR1L
というようにすることもできるのですが、それよりは上のプログラムのようにlfsr命令を使って
lfsr 1,203
とした方がはるかに簡単です。

このように書きますと、なんだかむつかしそうですが、もしもZ80や8080の命令がわかる方でしたら、ああそうか、とすぐに納得できてしまうと思います。

PIC18FのFSRレジスタは、Z80や8080のHLレジスタと全く同じなのです。
16ビットのメモリアドレスを扱うときに上位8ビットのアドレスをHレジスタに、下位8ビットのアドレスをLレジスタに入れるところまで同じです。
ついでに言いますと、Z80ではHLレジスタと同じように、BCレジスタやDEレジスタを使ってメモリの間接アドレッシングができますが、PIC18Fで、FSR 0、FSR 1、FSR 2の3組のレジスタが使えるというところもZ80に似ています。

メモリの間接アドレッシングはZ80では、
LD (HL),A
のように使います。
Aレジスタの値をHLレジスタで示すメモリアドレスに書き込む、という命令です。

PIC18Fの場合も、これと全く同じように使います。
movwf INDF0
と書くと、FSR0H、FSR0Lで示されるメモリアドレスに、wレジスタの値を書く、という命令になります。

PIC18Fの場合にはさらに便利な機能が使えます。
上のプログラムで使っているPOSTDECがそれです。

movwf INDF0
と書く代わりに、
movwf POSTDEC0
と書くと、
movwf INDF0
を実行したあと、FSR0H、FSR0Lを合わせて保持している16ビットのメモリアドレスを−1(decrement)してくれます。
しかもその場合、下位8ビットから上位8ビットへのボローが生じた場合には、上位8ビットも−1してくれますから、これは実にありがたい機能です。

もちろんこれも、POSTDEC0、POSTDEC1、POSTDEC2の3通りが用意されています。
このほかさらに、POSTINC0、POSTINC1、POSTINC2やPREINC0、PREINC1、PREINC2などもあります。
これらのレジスタについては[第418回][第419回]で説明をしておりますので、くわしくはそちらをご参照願います。
2010.6.11upload

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