Skip to content

Latest commit

 

History

History
654 lines (475 loc) · 23.9 KB

2009-05PIC.md

File metadata and controls

654 lines (475 loc) · 23.9 KB

2009-05 ← → 2009-05ARM

PIC日記

https://github.com/iruka-/ATMEL_AVR/blob/master/web/jpg/ae18f2550.jpg

あらすじ

  • 秋月AE-18F2550基板1000円で売られているので、これを飼いならそうという企画。
  • ちなみに、18F2550のピン数だけ増設した40pin DIP IC(18F4550)は単体で400円 、同じくDIP品の18F2550も400円で売られている。

https://github.com/iruka-/ATMEL_AVR/blob/master/web/jpg/PIC/pic18f2550.jpg

  • これをUSBマイコンとして使うのに必要最小限の配線はUSB(Bもしくはmini-B)コネクタと抵抗2個、20MHz水晶1個程度であり非常に廉価だ。(USBのプルアップ抵抗も内蔵されている)
  • どちらのICとも内蔵Flash32K,RAM2K(うち1KはUSB-FIFOと共用)で、開発にはCコンパイラを使用することも出来る。

現在のステータス

  • PICライターは作った --- PIC入門
  • 開発環境は整えた ----- UBWを試す
  • MCHIP製(C18用) bootloaderをsdcc+gpasm環境でビルドできるようにした。--- PIC入門
  • diolan製(MPASM) bootloaderをAE-18F2550に移植した ------------- 下記参照のこと。
  • diolan製(MPASM) bootloaderを改造してHIDmon( + bootloadHID)にしてみよう。 ----完成。
  • bootloaderとしては充分高速です。
    • コマンドライン上で書き込めるので、Makefileやバッチに記述すると開発サイクルが短縮できます。
    • HIDデバイスなのでデバイスドライバーのインストールが不要です。
  • HIDmonの機能がわりと充実しています。
    • ユーザーメモリーエリア(0〜0x3ff)を一切壊さないので、ユーザープログラムの挙動観察に適します。
    • ユーザープログラムからputcなどを実行するとPCのコンソールに高速に表示されます。
    • コードサイズは2kB以下です。ユーザー領域は30kB使用できます。

成果物

HIDboot for AE-18F2550

  • とりあえず、MCHIP版ブートローダーから起動するバージョンを作成

read more:HIDboot


HIDmon for AE-18F2550

  • HID Bootloader 兼 HID monitor . お勧めです。

read more:HIDmon-2550


ここから意外な展開

私はPICのライター環境やMCHIP純正開発環境のことをほとんど何も知りません。

  • が、意外な純正ツールを発見致しました。

read more: PICkit2

~


戯言


read more: PIC18F4550

~

  • ファームウェアをpollコマンドに対応させた。これによりgraphの描画が速くなる。
  • FSR2を使用しているところが気に入らなかったので、全部FSR0に書き換えた。
  • 一部動作しなくなる場面があったが変更差分攻撃(累積変更を加えていって動かなくなる修正点を見つける)で撃破。--- sm_ctrl_rx みたいな関数を呼んで戻ってきたところでFSR2の値がBDT_STATを指していることを利用している奴がいた。
  • コード量が増えたので、ダイエット。

現在、余白は408バイト。

  • 全ファンクション実装済みでこれだ。
  • つまり1640バイトで実装できたということ。
  • 同じ処理をAVR gccで書いたらコードサイズはたぶん2/3くらい?になるのではないかと思う。

~ ~ ~


メモリーマッピング変更(案)

  • 現状のHIDmon (bootloader)

      000+---------------+
         | WORK AREA     | 0xa6 bytes
      0a6+---------------+
         | 未使用        |
      100+---------------+
         |               |
         | 未使用        |
         |               |
      400+---------------+
         | USB BDT       | 16byte
      410+---------------+
         | EP0 OUT BUFFER| 64byte
      450+---------------+
         | EP0 IN  BUFFER| 64byte
         | 未使用        |
      500+---------------+
         | EP1 OUT BUFFER| 64byte
      540+---------------+
         | EP1 IN  BUFFER| 64byte
         | 未使用        |
      600+---------------+
         |               |
         | 未使用        |
         |               |
      7ff+---------------+
    
  • EP1は実際には使われていない。

これを以下のように変更してみる。

000+---------------+
   |               |
   |               |
   |               |
   | 未使用        |
   |               |
   |               |
   |               |
400+---------------+
   | USB BDT       | 32byte
420+---------------+
   |               |
   | WORK AREA     | 0xa6 bytes
500+---------------+
   | EP0 OUT BUFFER| 64byte
540+---------------+
   | EP0 IN  BUFFER| 64byte
600+---------------+
   |               |
   | 未使用        |
   |               |
7ff+---------------+
  • BDTは余裕を見て8個確保(そんなにいらないと思う)
  • こうすると、どのようなメリットがあるのか?
    • HIDmonとして使用した場合に、アプリ側の使用メモリー(0〜0x400)をほぼそのままダンプすることが可能になる。
    • BSRの値を0x04に固定することで、WORKエリアの参照以外に、BDT書き換えも同一バンクで実行できるので、FSR0を使用する必要がなくなる。
    • WORK AREA内の boot_cmd[64] boot_rep[64] というパケットバッファをそのまま送受信に使ってもよいことになる(と思う)そうすると(EP0 IN BUFFERへの)メモリー転送が不要になり、速度を稼げるかもしれない。
  • ためしにリンカースクリプトをちょっと書き換えて上図のような配置にしてみたが、一応動作しているようだ。
  • 0番地を書き変えている奴がいる。不可能なはずだが・・・。

~ ~ ~


PIC BIOSを作ろうと思う。

  • もうPICに飽きたつもりだったが、もうすこしだけ追求してみる。
  • 上記メモリーマップの変更は実施した。
  • BIOSエントリーを用意した。
  • エントリーの先頭に movlb 0x04 を入れた。
  • puts / gets 関連のバッファとエントリーを設定した。
  • sdccで"Hello World"のフレームワークを作成した。
  • 面白いのは、ユーザーアプリ動作中でもメモリーダンプが出来ることだ。
  • putcが全然動かない。・・・何故?・・・
  • その後、いろいろいじっていたら、ついに動かなくなった。
  • 原因は分からない。

小休止。

  • 原因が分からないので諦めた。
  • ソース丸ごと公開。もう煮るなり焼くなりしてください。

        ↓↓↓↓

read more:HIDmon-2550

~ ~ ~

ところでsdccって、バグってない?

バグってはいないけど動きません。何故?

  • farなポインタは3バイトであり、ROMの場合 TBLPTRL,TBLPTRH,TBLPTRU(通常は0)が指し示す。

  • RAMの場合は bit[23:16]は 0x80 になる。(判別のためわざとそうしている)

  • EEPROMのgptrは未実装である。

  • ポインタの値の受け渡しは、下位より、FSR0L,PRODL,WREG の計24ビット。

  • ポインタで参照したメモリー値は WREGで返却する。

      void _gptrget1(void) __naked
      {
       __asm
         /* decode generic pointer MSB (in WREG) bits 6 and 7:
          * 00 -> code
          * 01 -> EEPROM
          * 10 -> data
          * 11 -> unimplemented
          */
         btfss	_WREG, 7
         bra		_lab_01_
      #
         ; data pointer
         ; data are already in FSR0
         movff	_PRODL, _FSR0H
         movf	_POSTINC0, w
         return
      #
      _lab_01_:
         ; code or eeprom
         btfsc	_WREG, 6
         bra		_lab_02_
      #
         ; code pointer
         movff	_FSR0L, _TBLPTRL
         movff	_PRODL, _TBLPTRH
         movwf	_TBLPTRU
      #
         tblrd*+
      #
         ; result in WREG
         movf	_TABLAT, w
      #
         return
      #
      _lab_02_:
         ; EEPROM pointer
         ; unimplemented yet
      _end_:
       return
       __endasm;
      }
    
  • *_gptrput1 はこの逆の動作を行う。 [#j329b176]

  • _gptrput1はもうすこしあっさりしている。

  • 書き込むデータ値は FSR1(stackptr) からPOP(PREINC1)して取得している。

  • FSR1が+1される(ユーザースタックレベルが変化する)

  • RAM以外は実装されていない。

void _gptrput1(void) __naked
{
 __asm
   /* decode generic pointer MSB (in WREG) bits 6 and 7:
    * 00 -> code (unimplemented)
    * 01 -> EEPROM (unimplemented)
    * 10 -> data
    * 11 -> unimplemented
    */
   btfss	_WREG, 7
   bra		_lab_01_
   
   /* data pointer  */
   /* data are already in FSR0 */
   movff	_PRODL, _FSR0H
   
   movff	_PREINC1, _POSTINC0
   
   return
   
_lab_01_:
   /* code or eeprom */
   btfss	_WREG, 6
   return
   
   /* code pointer, cannot write code pointers */
   
_lab_02_:
   /* EEPROM pointer */
   /* unimplemented yet */
 return
 __endasm;
}

~ ~

  • いっそのこと [FSR0L,PRODL,WREG]渡しを止めて、[FSR0L,FSR0H]を引数にして
  • 直接 movff _PREINC1, _POSTINC0 とか movwf _POSTINC0すればよいのに。
  • と、思っていたら、 near という(16ビットの)ポインタがあって、そっちだと

_gptrput1が呼ばれずに、以下のコードが落ちる。

003A 00459 _00105_DS_:
003A C000 FFE9 00460         MOVFF   r0x00, FSR0L
003E C000 FFF3 00461         MOVFF   r0x01, PRODL
0042 5000      00462         MOVF    r0x02, W
0044 EC00 F000 00463         CALL    __gptrget1
0048 6E00      00464         MOVWF   r0x05
004A 5000      00465         MOVF    r0x05, W
004C E000      00466         BZ      _00108_DS_
               00467 ;       .line   27; main.c      *t++ = *s++;
---> t++ を実行している。 ポインタ参照はすでに上記で実行済み
004E 2A00      00468         INCF    r0x00, F
0050 B0D8      00469         BTFSC   STATUS, 0
0052 2A00      00470         INCF    r0x01, F
0054 B0D8      00471         BTFSC   STATUS, 0
0056 2A00      00472         INCF    r0x02, F
---> *s++ = val を実行している。
0058 C000 FFE9 00473         MOVFF   r0x03, FSR0L
005C C000 FFEA 00474         MOVFF   r0x04, FSR0H
0060 C000 FFEF 00475         MOVFF   r0x05, INDF0
0064 2A00      00476         INCF    r0x03, F
0066 B0D8      00477         BTFSC   STATUS, 0
0068 2A00      00478         INCF    r0x04, F
006A D000      00479         BRA     _00105_DS_
  • 上記のコードはROM上のsポインタからRAM上のtポインタに文字列コピー(strcpy)

するコードだ。

  • つまり1文字をコピーするのに18ステップ+_gptrget1の処理ステップ数掛かる。
  • MOVFFが多用されているので、1ステップ2クロック掛かる部分が多い。
  • 仮に50クロック/文字だとして、64バイトコピーは3200クロックも掛かるのだ。
  • さすがにだめだろ。

続:ところでsdccって、バグってない?

  • できたてのHIDmon(ドッグフード)を使って、sdccのポインタに関する挙動を調査していくと、ある事実にぶち当たった。

ある事実とは

  • ポインタのインクリメントに失敗するのだ。
  • まさに、このコード!

      ---> t++ を実行している。 ポインタ参照はすでに上記で実行済み
      004E 2A00      00468         INCF    r0x00, F
      0050 B0D8      00469         BTFSC   STATUS, 0
      0052 2A00      00470         INCF    r0x01, F
      0054 B0D8      00471         BTFSC   STATUS, 0
      0056 2A00      00472         INCF    r0x02, F
    
  • さいしょのINCF r0x00, F が機能しない。そんな馬鹿な!

  • 機能はしているのだけれど、0番地だけビット化け(0xc7マスクが常時発生している感じ)なのだ。

  • 0番地以外(0〜3ffまで見た)は大丈夫。

  • なんで????

すまん、全部忘れてくれ!

  • 上の騒動はメモリー破壊とか、見えないDMAではなかった。
  • HIDmon(picmon.exe) のUSB端子マスク機能が悪さをしていた。
  • HIDmon(picmon.exe) を修正して、0番地問題は解決。

で、sdccが全く(意図に沿って)動かない原因も分かった。

	003A C000 FFE9 00460         MOVFF   r0x00, FSR0L
	003E C000 FFF3 00461         MOVFF   r0x01, PRODL
	0042 5000      00462         MOVF    r0x02, W      <==この命令がバグっていた。
	0044 EC00 F000 00463         CALL    __gptrget1
  • 上記3行目のMOVF がまともにr0x02の仮想レジスタをフェッチしていないのだ。
  • 理由は、AccessBankだ。このローダーはXINST=1で焼いているので、sdccのバイナリーを正しく動作させることは出来ないわけだ。
  • どうりで、ポインタ関連のアクセスが全滅だったわけだ

~ ~ ~ ~ ~ ~ ~ ~ ~ ~

戯言(過去)

実はバグだらけかも・・・・

  • GET_DESCRIPTORでstring tableが取得できないようだ。
  • SnoopyProで調べてみると、おかしなGET_DESCRIPTORリクエストが出ている。
  • オリジナルではちゃんと動いているのかな?
  • これもXINSTビットの呪いか?
  • 比較実験のために、外部ライターで焼き直すのが面倒くさくなってきた。
  • もう一台作るか・・・

~

  • diolanのオリジナルに非常に近いROMで試したけれど、string tableが取得できていない。
  • SnoopyProの結果はだいたい同じだ。
  • じゃあ、sdcc版Firmware-Bと比較するしかない。

~

  • オチはこうだ。sdcc版Firmware-Bはstring tableが省略されていた。

  • そして、 最後のオチとしては、

      #define USB_MFG_DESC_off  12
    
  • この12が曲者で、なんと16進だから 0x12 = 18になっていたのだ。(がーん)

  • このアセンブラは10進で数値を書きたいときは .12 と書くらしい。(それ 0.12じゃん)

  • 落とし穴だらけ
  • そして修正済みファームでもstring tableを取得できない。
  • string tableの先頭2バイトだけがパケット転送されている。

原因はわりとすぐに分かった。

  • requestパケット内の wLengthが 0x0402 になっていて
  • 返却するstring table は 0x0eバイト長だが、 wLengthの下位1バイトと比較して短いほうを選択している。
  • このコーディング、激しくダメじゃん。
  • おまけに string table は MANUFACTUREだけしかサポートされていなかった。
  • そこいらへんを修正して、HID_Reportの送受テストをやろうとしたがなかなかうまくいかない。
  • Interrupt転送(というかdiolan版HID REPORT)のときとControl転送のときでは、HID_Reportのバッファ形式が異なるようだ。
  • Interrupt転送版には、USBパケットの先頭に挿入される HID ReportIDが省略されている。
  • Reportの種類は1種類だけ、サイズのバリエーションがないというわけか。

~ ~

ところでPICのアセンブラは変態だと言われているが、どうもわざと必要な命令を抜いているとしか思えない構造。

  • cpfseq はあるが、cpfsneは無い。それから、これらの比較命令はリテラル(定数)版が欠落。
    • Wregの値によって複数分岐する処理が書けない。
  • cpfsgt,cpfsltはあるが、cpfsgeとかcpfsleがない。
  • sublwはあるがcmplw(つまりWregを破壊しない版)がない。
  • 条件分岐のbnzとかbzの分岐オフセットが8ビットしかない。
  • レジスタが異常に少ない(Wregだけ?)ので割り込みで退避するコンテクストが少なそうに見えるが実は大量に必要で、退避操作も大変。
    • TBLPTRU,TBLPTRH,TBLPTRL,TBLLAT
    • PRODH,PRODL,
    • BSR
    • FSR0H,FSR0L,
    • FSR1H,FSR1L,

~ ~ ~ ~


Linux OSネットブックの普及を阻害する、「イヤなうわさ」と「信憑性」

Linuxモデルの返品率は、Windowsモデルの返品率よりも高い?

  • むしろVistaモデルを返品したい気持ち。(アプリが動かないとかで)
  • Linuxなら最初から動かないのを承知で買うので無問題。
  • ARM搭載のubuntuノートなら大歓迎だが。
  • 一般PCショップで売るのは難しいのかも。
  • だが、現実に玄箱とかの例があるので不可能というわけではない。

~ ~ ~ ~


HIDmon : 現在のステータス

  • ECHOBACK はOK。
  • メモリーダンプ(現在は仮実装で、ROMダンプ)まで出来た。

躓き(落とし穴)

  • スキップ命令の後ろに2ワード命令(goto ,callなど)を入れてはいけない。ハングする。
  • boot_rep[64]の送信バッファはboot_cmd[64]受信バッファのコピー置き場にすこし使っていた。
  • が、これを上書きするような処理を書いてしまってはまった。
  • 変数の大小判断マクロを書いてみたが、なかなかちゃんと動かなかった。(書き方がまずかった)
    • だって、引き算の方向が普通のCPUと逆だもん。
  • USBの受信FIFOは、処理時間が長いときには次のパケットで書き潰されることがあるようだ。
  • 次のパケットが来る前に別のバッファにコピーしないと駄目なの(????)

diolan製(MPASM) bootloaderを改造してHIDmon( + bootloadHID)にしてみよう。

現在進行中。 - 実は非常に難儀している。 - とりあえずUSBデバイスとして認識し、ProductStringなどを正しく参照できるようにしたところだが - 現在、HID_Reportのやりとりでパケット同期タイミングずれがあり(ひとつ古いパケットが蓄積されていてハンドシェイクがうまくいってない)四苦八苦しているところ。 - ハンドシェイク問題はほぼ解決した。 - このPICはノイズパケットをいろいろ受信している(?)ようで、それらを無視するような条件をいれないとだめ。 - 具体的には、HID_ReportIDとCMDが正しい値域に納まっているかどうかを検査する。 - 範囲外のパケットを無視しないと上記のような問題が発生する。

HIDmon-2550 を実装中

  • Flash書き込みと消去を実装
  • ホスト側ツールも仮制作
  • 単独のブートローダーとしての動作を確認。
  • このブートローダーにアプリケーションの書き込みを行わせて、アプリケーションが起動することを確認。

~

read more: HIDmon-2550

~ ~ ~


PIC18F14K50-DIP20 お勧め

  • 20ピンなんだけど、あんまりお勧めしないなぁ・・・。
  • だって33円足すと18F2550とか18F4550が買えるわけだし。
  • 省ピンでないと困ることって、ある?
  • むしろ、アレか。1.8Vから5.5Vまでいけるので、JTAGアダプター作りにはGoodかも。
  • もちろん、PIC18F14K50-DIP20だって秋月が扱えばもっと安いとは思う。
  • 思うけれど、あそこって大量仕入れだから扱わないだろうなぁ・・・・

~ ~ ~


GNUPIC:gpasmは言うことを全く聞こうとしない。

  • HIDmon-2550のgpasm対応をやっていたが、最終的に、諦めた。
  • gpasmが悪いのは確かだが、どこが悪いのかがついに分からなかった。
  • 例のUSBディスクリプタのアセンブラ記述だが、どのような書き方をしても正しいコードを落とすことが出来ないのには参った。
  • どうやったら、このような嫌がらせアセンブラを作ることが出来るのか。
  • 理解に苦しむ。
  • PICのアーキテクチャーそのものも嫌がらせレベルは3くらいあるが、
  • gpasmのUSBディスクリプタが記述できない嫌らしさレベルはフェーズ5くらいあると思う。

詳細は、HIDmon-2550のソースファイルにあるMakefile.gpasmを使ってみれば分かります。

~ ~ ~


  • ----- 日記が長くなりすぎたので分割 ------

続きを読む

~