PICでUSBを!(知識ゼロからのスタートです)
PIC18F14K50のUSB機能を100%自前のソフトで制御する試みです。しかもアセンブラで!
当記事は2009年12月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 2011.7.9

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

PICとのつきあいはもうずいぶん長いのですが、今まで使ってきたのはPIC16FXXというナンバーのものばかりでした。
PIC18FXXは初めてさわります。
PIC18FXXはPIC16FXXに比べるとハードウェア、ソフトウェアの機能がかなり拡張されていることがわかりました。
USBを扱うためには、その拡張されたハード、ソフトについて理解する必要がありそうです。
ということでまずはPIC18F4550の機能を理解することからエントリーいたします。

[第21回]

●PICアセンブラは賢いアセンブラでした

今日(1月5日)になってから前回([第20回])を読み直していましたら、終わり近くのところで、PIC18F4550の命令に付加された’a’パラメータの説明が、’0’と’1’を取り違えていることに気がつきましたので、訂正をいたしました。

で、その’a’パラメータなのですが、PIC18F4550Datasheetのinstruction setの説明によると、デフォルトでは’1’になっています。
ということは、たとえば
movwf BSR
というように、’a’パラメータを省略すると、アセンブラによってデフォルトの’1’が指定されることになるのではないか、と。

しかし’1’が指定されるということはBSRの値が指定しているメモリバンクがセレクトされてしまいます。
もしBSRが0F(=15)以外の値だったとすると、
movwf BSRは、「BSRをアクセスできない」ということになってしまいます。

そうならないためには、ここは’a’パラメータを省略せずに、
movwf BSR,0
と書かなければ行けないのではないか、ということに、ずっとあとになってから気がつきました。

ええ。そんなことには、気が付いていなかったのです。
どうしていたかといいますと、全く気にもしないで、
movwf PORTB
とか
bsf PORTA,2
なんて調子で使っていました。

実はBSRそのものの値はRESETすると、0クリアされてしまいますから、プログラムスタート後に新たにBSRに値を設定しない限り、メモリバンク0がずっと選択されたままになっているのです。
すると、PORTAもPORTBもF60〜FFFのバンク15にあるのですから、’a’パラメータを’0’にして命令に付加しなければ、正しく選択されない(だってデフォルトでは’a’は’1’になるというのですから)はず…、なのですけれど、いったいどうなっているのでしょう。

おかしいではないか。
いや、何の気なしに使っていた、私の使い方は非常にノーマルで素直な使い方だとは思うのですが、そしてそれについては期待通りにアセンブル(機械語に翻訳)してくれているらしいことにも満足していたのですけれど、気が付いてみると、そりゃあ確かにおかしい。このままの方が都合はいいけれど、そりゃあ説明か、アセンブラかどちらかが間違っているのではないの?

で簡単なプログラムを書いて、そこのところがどうなっているのかを確認をしてみました。



このプログラムは’a’パラメータが全て省略されています。
16F88とか16F628のまんまといった風のプログラムですから、こんな具合に書けるのならば、16Fも18Fも同じ、という感覚で使えますから非常に好都合です。
そればかりか、PIC16Fならば、TRISAやTRISBはバンク1にあったはずですから、ここはバンク1を選択するために、
bsf STATUS,5
が必要だったところです。
それすらもありません。
なんともすっきりしたプログラムでバンク切り換えの形跡もなにも全くありません。

こんなんでよいのか?
といいますと、これでよいのです。
PIC18FはPIC16Fよりも複雑であるにもかかわらず、「アセンブラ」はかえって使い易くなっているのです。
それなのに、PIC16Fではまだアセンブラのプログラムを見かけるのですが、PIC18Fとなると、もう軒並みCばっかりつうのはどういうことなのでしょうかねぇ。

●機械語を確認してみました

いつもはMPLABでquick buildして、すぐにPIC Writerで焼いてしまって、それでおしまい、という調子なのですが、今回はアセンブラによっていったいどのように機械語に翻訳されるのかを見てみることにしました。
いつもは気にもしていませんが、ちゃんとアセンブル後のリストも毎回しっかり作成されています。
今回はそのリストを見てみることにしたのです。



これが上のプログラムをアセンブラが機械語に翻訳したときに作成されたリストです。
え?そんな難しいものは読めません?
んなことはありません。
ちゃんと読めるのですよ。

左の列がプログラムのアドレスです。
PIC18F4550の機械語命令の多くは2バイトです。
movwfという命令がたくさん使われています。
movwf ADCON1の機械語のところを見てみると、アドレス00001Cに6EC1となっています。
もうひとつmovwf TRISAを見てみると、アドレス000020に6E92となっています。
6Eというのがmovwfらしいということはすぐにわかります。
前回お見せしたPIC18F4550datasheetのmovwfの説明をもう一度見てみましょう。

Encodingを見ると、0110111aと書いてあります。
おお、確かに6Eです。
あれ?それだとa=0になってしまいますね。その下のDescriptionには’1’がdefaultである、と書いてあるのですがねえ。

その点についてはちょっと置くとしまして、レジスタのアドレスについて確認をしてみます。
PIC18F4550のシステムレジスタについては[第16回]でメモリマップをお見せしました。
でも下に再掲いたします。


PICのシステムレジスタはSFR(special function register)といいます。
この表の中からADCON1を探してみますと、アドレスFC1にあります。
TRISAはF92にあります。
さきほどのアセンブルリストの機械語コードをもう一度見てください。
movwf ADCON1は6EC1に、そしてmovwf TRISAは6E92に翻訳されています。
今のところ、その理由はペンディングということにしておきますが、ともかくmovwfの機械語で’a’のビットが’0’になっているので、BSRは無視されて「アクセスバンク」が選択されるため、ここは正しくFC1、F92がセレクトされることに間違いはありません。

では、もう一度さきほどのアセンブルリストに戻って、今度は、movwf cntr0の機械語を見てみましょう。
アドレス00002Aに6E12と翻訳されています。
cntr0はプログラムの先頭で、データメモリアドレスの12番地に割り付けるように定義していますから、ここも正しく翻訳されているようです。
でも、あれえ?
ここでも’a’ビットは’0’になっていますねえ。
ひょっとして、デフォルトがa=1というのはミスプリントでa=0が正解なのでしょうか。
ま、それもちょっと置くとしまして、次のmovwf cntr2の機械語も見てみることにしましょう。
アドレス00002Cに6F95と翻訳されています。

おおお。ここは’6F’ということは、a=1になっています。
cntr2はプログラムの先頭で、アドレス95に割り付けるように指定しています。
確かに、このcntr2に対するmovwf命令の機械語が’6E95’だったとするとa=0なので、データメモリの095ではなくて、F95がアクセスされてしまいます。
それは「確実に誤り」です。
ここが’6F95’であると、BSR=0でさえあれば、正しく095番地が選択されます。

うう。なんだかめちゃめちゃ賢いアセンブラではありませんか。
んでも、そりゃあ賢いアセンブラだと思いますけれど、そのほうが都合がいいとも思いますけれど、でもデフォルトが’1’つうのは、ありゃあウソか?

んで、もう一度、さきほどのmovwf命令の説明のところをよく読んでみますと、

If ’a’=’1’,the BSR is used to select the GPR bank(default).

と書いてあるのですよね。
あ。確かに、そう書いてあるわあ。
しっかし…。

GPRというのは、general purpose RAM、つまりユーザー用データRAMのことで000〜7FFのRAMエリアのことです。
そのバンク、つまりバンク0〜バンク7が、a=1のときにはBSRを使って選択される(それがデフォルトの指定である)、と書いてあるのですけれど。
バンク15はSFR(Special Function Register)バンクなので、GPRバンクではない、だからSFRレジスタ(TRISAなどのシステムレジスタ)に対して’a’を省略しても、このデフォルトルールが適用されるとは書いてないのですよねえ。

むむむ。こういう書き方はずるいなあ。
これじゃまるで保険契約書の説明みたいではないか。
あー。保険屋さん。ごめんなさい。
いえ、日本の保険の話じゃありません。英語ですから、あちらの保険のお話ですう。

まあしかし、説明の解釈はともかくとしまして、確かに、システムレジスタはバンク15にあるのですから、ここをアクセスするのに、BSR=0F(15)にしておいて、a=1を指定してアクセスするというのは不合理でそのようなプログラムは賢くはありません。
a=0にすれば、BSRの現在の値に拘束されることなく、「アクセスバンク」が選択され、かつ、そのときにアドレス60〜FFの範囲を指定していれば、それはF60〜FFFをアクセスすることになるのですから、TRISAやPORTAなどのSFRに対する命令をアセンブラが機械語に翻訳するとき、a=0にして翻訳するのは、なかなかによく考えられたアセンブラだと思います。

それと同様に、cntr0は000〜05Fの範囲にあるレジスタ(アドレス12)として定義したので、それもa=0にして翻訳すれば、BSR=0以外の場合でも必ずアドレス012が選択されますから、これも賢い翻訳である、と言えると思います。

前回と今回の説明で、バンク0とバンク15のアクセスについては、バンクを気にしないで、PIC16Fのときと同じような感覚でプログラムを書けばよさそうだ、ということがおわかりいただけたかと思います。
しかし、バンク1〜バンク7についてはちょいとお話は変わってきてしまいます。
それについては次回に説明することにいたします。
CPUをつくろう!第413回(2010.1.5upload)を再編集

PICでUSBを![第21回]
2011.7.9upload

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