2013-03
2013-02 FM3 RX62N SH2A PIC32MX
3月
- 先月は、秋月PIC32MX220F032B用のブートローダーを作っていた。
- 作ったといっても、UBW32用のHIDBoot.Xを少し改造しただけ。
- read more : PIC32MX
持ち越し案件
- pic32mxでFTDI互換(JTAG)ファーム
PIC32MX220F032
先月までの成果まとめ。
- 開発環境構築
- PinguinoがArduinoっぽくてお手軽。
- MPLAB-Xは駄目。MPLABとそれに付属のpic32-gccを使うべし。(-mips16もちゃんと使える)
- ブートローダー探し。HIDBoot.Xで決まり。
- AN1388はHEXテキストをそのまま扱うっぽいので、ローダーがでかいしコードも複雑。それにPinguino互換じゃない。
- ライターはPicKit2/3がベスト。ライターソフトはpic32progで決まり。
- PicKit2互換機は手軽に作れて安いし、WinXP/8(64bit)の両方でドライバー導入要らずで、しかも安定動作する。
- ファームウェア/アプリケーション
- Pinguinoのスケッチは手軽でシンプル。便利。
- PinguinoスケッチをGUIを使わずに、付属のmake.exeを使ってビルドするCUI環境を作った。
- ついでに、bootloaderを使用せずに自力起動するビルドも可能にしてみた。Flash領域32kB目一杯使い切れる。
- Pinguinoのスケッチは手軽でシンプル。便利。
- HIDBoot.Xのファームウェアは汎用的に使える。
- PCから簡単にPIC32MX上のメモリーやポートを読み書きできる。
- USB HIDデバイスのお手本になっている。
- MPLAB付属のpic32-gccでビルドする(GUI)方法と、Pinguinoのmips-gccでビルドする(コマンドラインmake)環境の 両方を用意した。
- これにより、60日試用期間を過ぎても安心してサイズ最適化や-mips16オプションが使えるようになった。
PIC32MXの続編
- オーバークロック/アンダークロック
- 16MHz〜72MHzまで、安定動作範囲。
- 80MHzは動きはするものの、不安定。
- 水晶を使わずにUSB
- すでにやった人がいる。
- 外部回路は要らないけれど、ピン同士の配線(内蔵RC発振の外だし)が必要。
- やってみてもいいけれど水晶安い(50円)し周波数が安定しているので、あえて50円をケチる理由が無い。たまたま8MHz切らしてるときも4〜20MHzの4MHz刻みのどれかなんて、ジャンク箱あされば出てくるし。
- オシロスコープとかロジアナの簡易実装
- これはPIC32MXを使う目的のひとつでもある。
- 壊しても惜しくないし小さく作れる。
- FT2232互換 JTAGドングルのソフトウェア実装
- これがそもそもPIC32MXを使ってやってみようと思った動機。
- どう無駄に作っても32kB以内に実装出来そうだし、それほど複雑でもないし。SRAMも足りる。
- これまで、独自実装のOpenOCDデバイスを作ったりしたけれども、OpenOCDのリポジトリ更新に付いていけないと分かったので、だったらMPSSEの一部コマンド(OpenOCDで使ってるものだけ)を実装したほうが話が早いし、動作も速い。
- 220円+αで作れるので、FT2232より安く作れる。ファーム書くのが少し面倒臭い程度。
- VGAとかNTSC出力のGDPもどきを実装。
- いわゆるあれ、ARM(STM32)でも同様のを見たけど。ワンチップ・テレタイプ端末(RS-232C)っぽいやつ。
- TVゲーム作ってる人も居たなぁ。
- レトロBSD , Z80 (CP/M) エミュレータ
- MX220F032Bでやろうと思っても、RAMが足らない。
- AVRの作例みたいに、強引な外付けS-RAMとか外付けD-RAMという手段は残っている。
- 面白いか、と言われると、うーん、どうなんだろう。
- AVRでやると、凄いなーと思われるけれど、MIPS32だと出来て当たり前だし。
- retroBSDは置いといて、CP/Mのほうは、もうアプリ持って無い。Z80マシン語も今更書きたくない。(全部覚えてるけど)
- Android Accesory
- PIC32MXがUSBホストになって、それより遥かに高性能なアンドロイド端末をUSBデバイスとして接続。
- ADBのプロトコルに間借りする形でソケットコネクションして、あとはデータ転送するだけなので、結局のところ論理的にはRS232Cで繋がってるのとたいして変わらない(のだと思っている)。
- MPLABのUSBフレームワークサンプルにADKのやつがあったので、MX220対応させるだけで多分そのまま動くと思うんだ。
- Androidのアプリ考えるのが面倒面倒。
結論
- まずは、ロジアナとオシロを書いて、
- 気が向いたらMPSSE互換機、
- 最後に、応用でVGA出力のGDP実装。
だけど、ARM弄る気あんまり残ってないのでJTAG要らんかなぁ・・・FT2232は実物あるし。
まあ、そんな感じ。
PIC32MXで仮想シリアル
- やってみた結果、PinguinoのUSB CDCは遅い(390kBPSしか出ない)ということが分かった。
- Mchipサンプルのほうが優秀で、2M BPS出る。
- Mchipサンプルから作成したUSB-シリアル変換器も動いた。(以前はuart2.cがおかしくてBugっていたので、uart1.cを新たに起こした。)
- USB HOST(KeyBoard)は、sbrkのバグを直して、とりあえず動作確認の手前に辿り着いた。けど肝心のキーボードが規格外(HUB内蔵)だったので、別のキーボードを探し中
続きを読む: PIC32MXで仮想シリアル
続きを読む: USBカスタムデバイス
続きを読む: USBホスト
- USB HOST Mouseも動いた。
ここまでのまとめ。
- Pinguinoのmips-gccを使って、MchipのUSBサンプルを動かす技はほぼ会得した。
- HOSTとかAndroid ADKなんかも動く(と思う。ビルドだけは成功している)けど24kB超える勢いなのでブートローダーからの書き込みは無理。当然'-mips16'で'-Os'で'--gc-sections'さらにcrt0.Sも改造済み。
- cdcserialは動いたと思ったけど、UARTのIO Remapに失敗している気配。(USBデバイスとしては認識OKでWindowsからは正常に動いているように見える)
- bulk(WinUSB)デバイスは速い。1MB/s。
- クロックは72MHzで常用している。80MHzでは無理。それから間違って水晶を12MHzで実装してしまった(ICソケットの中に埋めた)のでIDIVを1/3 (12MHz->4MHz)で使っている。ブートローダーで試すときはFuseや水晶のことは考えなくてOK。(configを無視するので)
これからどうするか。
- オシロとロジアナっぽいやつをでっちあげてみる。(WinUSB叩いて)
- JTAGは飽きたのでやめ。
- VGA出力も、要らんかなぁ・・・(USBキーボードと液晶モニタ繋いで英字が出せる端末は作れるけどそれ以上の用途が思いつかない)
- たぶんNTSC出力出して、32kBレギュレーションのイントロ・デモ(メガデモの一種)に挑戦するのも悪くないとは思うけれど自分はセンスが無いのでやらない。
- sdcardくらいは繋げてみるか。
まあともかく
- 220円+少ない外付け部品で、12Mbit/sまでのUSBをとことん堪能できるチップは稀有だと思う。
- 32kB Flash+8kB SRAMはアプリを書くには少なすぎるけれど、デバイスとしてはむしろ充分だし72MHzはDIPにしては充分速い。(定格上は50MHz)
- このコスパに対抗できるチップって、ないんだな。Cortex系でUSB入りだと高いしDIP品種がないし。
- 8bitで遅くて良いならArduino LeonardのATmega32u8とかあるけど、あっちのほうがUSB SIEとしてはしょぼい。
USB HOSTサンプルのビルド。
USB HOST Keyboard
- ちゃんと動いている。
- ファームサイズは24kBを少し超えている。
- ためしに-mips16を外したら、32kBを2kB程度超えるので、焼けない。2kBの大半は.dataセクションで0連続が多いのと、3kBのBOOT ROMはまだ空いているので、詰め込めなくはないけれど、Mchipのコンパイラを使ってたら絶望だな。(うわさでは-O0オプションしか許さないらしい。どういう罰ゲームなんだろ)
- 問題は、空きエリアがあと8kBも無いので、USBキーボードが使えるVGA端末を作ることは不可能だ。(英字フォントを入れるだけで4kBくらいは消費してしまい、残り4kB以内でVGA OUTとターミナルを書かなければならない。絶対無理だ)
Android ADK
- 諦めた。
- 容量的には、20kB以内。
- 動いてるんだけどAndroidと通信しない。理由がさっぱりわからない。(どっちも組み込みなので、調べようがない)
- print吐くようにして調べた結果、物理的に全くネゴシエーションしていないっぽい。
- Android側が480Mbpsで送信してきて、PIC32MX側は「ハァ?意味わかんねー」って感じでUSB SIEが応答できない感じ。12MHzのマイコンに480MHzなんか聞こえるわけねーじゃん。
- そういえば、HighSpeedデバイスをFullSpeedホストに繋ぐ場合、どういうネゴが行なわれるんだろうか?
- FullとLowでは、デバイス側のPullUpポートがD+とかD-の片側だけにしていて、ホスト側はどちらかのピンがPullUpされたらデバイスが接続されたと認識してたはずだけど・・・。
- LowSpeedではD-が、FullSpeedではD+がPullUpされる。
- HighSpeedのときはどうなってたっけ、
PullUpじゃなくていきなり480MHzで話しかけるのかな。(要調査)- HighSpeedデバイスも、まずはFullSpeedでネゴシエーションしてから480Mbpsに移行するらしい。---そこが出来ていないんじゃあ?
- FullとLowでは、デバイス側のPullUpポートがD+とかD-の片側だけにしていて、ホスト側はどちらかのピンがPullUpされたらデバイスが接続されたと認識してたはずだけど・・・。
追記:
- MicroChipのADKアプリはPlayストアで配布されているので、それを入手する。
- usb_host.c あたりで DEBUG_MODE を定義すると、attachとかdetachの表示をしてくれる(Serial Printに繋ぐ)
- それで、ADKのファームを再ビルドして、いろいろなデバイスを繋いでみる。
- KB MouseなどのLowSpeedデバイスはちゃんと認識する。
- USB内蔵マイコン(FullSpeed)を使ったHIDやCDCデバイスはだいたい認識する。
- USBメモリーの中には認識するものとしないものがある。しないものは無反応。
- Androidを、(アプリ起動状態あり、なしの両方で)接続してみたけれど、PIC32MX側は全く無反応。
どうやら、Android端末がHighSpeedデバイスなので、そもそも物理的にネゴシエーションしてないんじゃないか疑惑。
続きはWEBで!
- USB_HOSTに少し足を突っ込んでみたので、次のテーマとしては、
- (1)USB_HOSTに接続されたデバイスのディスクリプタやエンドポイントを列挙するツール。
- (2)USB Keyboardをシリアルポートに変換する変換器
- (3)USB Keyboardを楽器演奏に使ってみる。
(3)はPS/2キーボードを使った演奏プログラム(KeyBoardマニア)を移植してみるテスト。
RETROF-16のエミュレータ再び
retrof-16とは?
- duo6750さんが作成中の(21世紀に実在する)
- TTLのみで作るコンピュータです。
- 下記サイトに詳細があります。
実行例写真
出来てるところ
- Windows/Linux上のgcc/makeでビルドできる。
- なんとなく命令セットをエミュレートしているように見える。
- 逆アセンブルもする。
- GUIっぽいものを追加しました。←ここが新しいところ
- SPACEキーを押すと実行速度を変えられます
R16アセンブラ、+cina16 + ナイトライダー風サンプル
- R16 asmソースを入力して、バイナリーとリストを出力します。
- バイナリーは常に0番地から始まるイメージです。
遊び方。
- Windows XP/Vista/7/8のどれかを用意します。
- 上記の2つのzipをどこか適当なdirに(並べて)展開します。
- MinGW32 gccとmakeをインストールしておいてください。
- asm16/nr.c がナイトライダーです。
/* R16: ナイトライダー */ org 0; do { r80h = 7; r81h = 16; do { ld r80h; OUT 0; do { r82h++; } while(nf); // } while(r82h != 0xFFFF) ; ld(r80h); sfl; st(r80h); // r80h <<= 1 ; r81h--; } while(nf); // if (r81h != (-1)) goto A0002; } while(1);
- nr.lst
0000: org 0 0000: __do000: 0000:8007 c480 mov r80h,7 0002:8010 c481 mov r81h,16 0004: __do001: 0004:9080 ld r80h 0005:c600 OUT 0 0006: __do002: 0006:9082 8801 c482 inc r82h 0009:0b04 jnf __do002 000a: __od002: 000a:9080 ld r80h 000b:cc0b sfl 000c:c480 st r80h 000d:9081 8c01 c481 dec r81h 0010:0b0d jnf __do001 0011: __od001: 0011:0812 jmp __do000 0012: __od000:
SYMBOL LIST: = 17 (0x11) __od000 = 18 (0x12) __od001 = 17 (0x11) __od002 = 10 (0xa) __do000 = 0 (0x0) __do001 = 4 (0x4) __do002 = 6 (0x6)
- asm16ディレクトリで make test するとビルドが完了します。
- r16simディレクトリで a.bat を実行するとエミュレータが動きます。
エミュレータは逆アセンブル表示が遅いので、カーソル上キーを1回押して、スペースキーを1回押してください。
- ナイトライダーします。
- 詳しくは各ディレクトリのReadMe.txtを参照してください。
R16でインベーダー
- 一匹表示のみです。ゲームではありません。
- ソース
//------------------------------------------- org 0; goto _start; // 暗黙のレジスタ at equ r13; // assembler temp. lr equ r14; // link register. sp equ r15; // stack pointer. // ユーザー割り当てレジスタ x equ r16; y equ r17; bc equ r18; de equ r19; hl equ r20; ix equ r21; a equ r22; i equ r23; j equ r24; k equ r25; // 定数equ. r equ 4; g equ 2; b equ 1; w equ 7; b equ 0; c equ 3; p equ 5; org 256; /*------------------------------------------- * スタートアップ. *------------------------------------------- */ _start: sp=0x100; main(); halt; /*------------------------------------------- * データ *------------------------------------------- */ invdata: dot 0,0,0,0,0,0,0,0 dot 0,0,0,g,g,g,0,0 dot 0,0,g,g,g,g,g,0 dot 0,g,0,g,g,g,0,g dot 0,0,g,g,g,g,g,0 dot 0,0,0,g,0,g,0,0 dot 0,0,g,0,0,0,g,0 dot 0,0,0,0,0,0,0,0 /*------------------------------------------- * メイン *------------------------------------------- */ main() { subr(); } /*------------------------------------------- * サブ *------------------------------------------- */ subr() { cls(); k=0;do { // // 虫を画面いっぱいに敷き詰める. // (x,y)は座標. ixはVRAMアドレス. y=0;do { x=0;do { ix=y;ix<<=7; // 128倍. ix+=x; at=k;at>>=4; // ix += (k/16) ずらし. ix+=at; putdata1(); //一匹虫を書く. x+=4; //左へ8ドット. }while(x!=128); y+=8; //下へ8ドット. }while(y!=256); k++; OUT 0; //LEDを更新してみる. }while(1); //無限ループ. } /*------------------------------------------- * 虫を一匹だけ書く. *------------------------------------------- * 引数 * ix : VRAMアドレス. */ putdata1() { hl=ix; de=invdata;blit8x8(); } /*------------------------------------------- * 画面を消す. *------------------------------------------- */ cls() { hl=0; do { ld 0; stv([hl]); hl++; }while(hl!=0x8000); // }while(hl!=0x8); } /*------------------------------------------- * 画面に8x8のデータを書き込む. *------------------------------------------- * 引数: * de: 8x8ドットデータの存在するアドレス * hl: 書き込み先のVRAMアドレス. */ blit8x8() { j=8;do { i=4;do { // 8dot=4ワード. ld([de]); stv([hl]); hl++; de++; }while(--i); hl+=124; }while(--j); } /*------------------------------------------- * 以下、テストパターン. *------------------------------------------- */ test1() { hl=1024; for(bc=0;bc<2000;bc++) { // for文のテスト. if(de<hl) a++; } test2: while(a!=100) { // while文のテスト. bc++; } test3: a=0; do { a++; }while(a==0x4a); // do〜while文のテスト. test4: a=0; do { a++; }while(a<0x4a); // do〜while文のテスト(終了判定が不等式). } /*------------------------------------------- * おまけ:ナイトライダー. *------------------------------------------- */ subr2() { do { r80h = 7; r81h = 16; do { ld r80h; OUT 0; do { r82h++; } while(nf); // } while(r82h != 0xFFFF) ; r80h <<= 1 ; r81h--; } while(nf); // if (r81h != (-1)) goto A0002; } while(1); }
- コンパイル結果
0000: org 0 0000:04ff jmp _start 0001: at: equ r13 0001: lr: equ r14 0001: sp: equ r15 0001: x: equ r16 0001: y: equ r17 0001: bc: equ r18 0001: de: equ r19 0001: hl: equ r20 0001: ix: equ r21 0001: a: equ r22 0001: i: equ r23 0001: j: equ r24 0001: k: equ r25 0001: r: equ 4 0001: g: equ 2 0001: b: equ 1 0001: w: equ 7 0001: b: equ 0 0001: c: equ 3 0001: p: equ 5 0100: org 256 0100: _start: 0100:b000 0100 c40f mov sp,0100h 0103:c202 c40e 0422 call main 0106:cf00 0106 halt 0108: invdata: 0108:0000 0000 0000 0000 dot 0,0,0,0,0,0,0,0 010c:0000 0002 0022 0000 dot 0,0,0,g,g,g,0,0 0110:0000 0022 0022 0020 dot 0,0,g,g,g,g,g,0 0114:0002 0002 0022 0002 dot 0,g,0,g,g,g,0,g 0118:0000 0022 0022 0020 dot 0,0,g,g,g,g,g,0 011c:0000 0002 0002 0000 dot 0,0,0,g,0,g,0,0 0120:0000 0020 0000 0020 dot 0,0,g,0,0,0,g,0 0124:0000 0000 0000 0000 dot 0,0,0,0,0,0,0,0 0128: main: 0128:900f 8401 c40f 900e d40f enter 012d:c202 c40e 040b call subr 0130:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 013b: subr: 013b:900f 8401 c40f 900e d40f enter 0140:c202 c40e 0459 call cls 0143:8000 c419 mov k,0 0145: __do000: 0145:8000 c411 mov y,0 0147: __do001: 0147:8000 c410 mov x,0 0149: __do002: 0149:9011 c415 mov ix,y 014b:9015 c801 c801 c801 c801 c801 c801 c801 c415 sfl ix,7 0154:9015 9810 c415 add ix,x 0157:9019 c40d mov at,k 0159:900d c601 c601 c601 c601 c40d sfr at,4 015f:9015 980d c415 add ix,at 0162:c202 c40e 041f call putdata1 0165:9010 8804 c410 add x,4 0168:8080 9410 cp x,128 016a:8401 sub 1 016b:0a23 jnf __do002 016c: __od002: 016c:9011 8808 c411 add y,8 016f:b000 0100 9411 cp y,256 0172:8401 sub 1 0173:0a2d jnf __do001 0174: __od001: 0174:9019 8801 c419 inc k 0177:cc00 OUT 0 0178:0834 jmp __do000 0179: __od000: 0179:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 0184: putdata1: 0184:900f 8401 c40f 900e d40f enter 0189:9015 c414 mov hl,ix 018b:b000 0108 c413 mov de,invdata 018e:c202 c40e 0427 call blit8x8 0191:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 019c: cls: 019c:900f 8401 c40f 900e d40f enter 01a1:8000 c414 mov hl,0 01a3: __do003: 01a3:8000 ld 0 01a4:de14 stv [hl] 01a5:9014 8801 c414 inc hl 01a8:b000 8000 9414 cp hl,08000h 01ab:8401 sub 1 01ac:0a0a jnf __do003 01ad: __od003: 01ad:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 01b8: blit8x8: 01b8:900f 8401 c40f 900e d40f enter 01bd:8008 c418 mov j,8 01bf: __do004: 01bf:8004 c417 mov i,4 01c1: __do005: 01c1:a013 ld [de] 01c2:de14 stv [hl] 01c3:9014 8801 c414 inc hl 01c6:9013 8801 c413 inc de 01c9:9017 8401 c417 dec i 01cc:8401 sub 1 01cd:0a0d jnf __do005 01ce: __od005: 01ce:9014 887c c414 add hl,124 01d1:9018 8401 c418 dec j 01d4:8401 sub 1 01d5:0a17 jnf __do004 01d6: __od004: 01d6:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 01e1: test1: 01e1:900f 8401 c40f 900e d40f enter 01e6:b000 0400 c414 mov hl,1024 01e9:8000 c412 mov bc,0 01eb: __fo006: 01eb:b000 07d0 9412 cp bc,2000 01ee:440a jnc __of006 01ef:9014 9413 cp de,hl 01f1:4403 jnc __el007 01f2:9016 8801 c416 inc a 01f5: __el007: 01f5:9012 8801 c412 inc bc 01f8:080e jmp __fo006 01f9: __of006: 01f9: test2: 01f9: __wh008: 01f9:8064 9416 cp a,100 01fb:8401 sub 1 01fc:0704 jf __ew008 01fd:9012 8801 c412 inc bc 0200:0808 jmp __wh008 0201: __ew008: 0201: test3: 0201:8000 c416 mov a,0 0203: __do009: 0203:9016 8801 c416 inc a 0206:804a 9416 cp a,04ah 0208:8401 sub 1 0209:0b07 jf __do009 020a: __od009: 020a: test4: 020a:8000 c416 mov a,0 020c: __do010: 020c:9016 8801 c416 inc a 020f:804a 9416 cp a,04ah 0211:4906 jc __do010 0212: __od010: 0212:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave 021d: subr2: 021d:900f 8401 c40f 900e d40f enter 0222: __do011: 0222:8007 c480 mov r80h,7 0224:8010 c481 mov r81h,16 0226: __do012: 0226:9080 ld r80h 0227:cc00 OUT 0 0228: __do013: 0228:9082 8801 c482 inc r82h 022b:8401 sub 1 022c:0a05 jnf __do013 022d: __od013: 022d:9080 c801 c480 sfl r80h,1 0230:9081 8401 c481 dec r81h 0233:8401 sub 1 0234:0a0f jnf __do012 0235: __od012: 0235:0814 jmp __do011 0236: __od011: 0236:a00f c40e 900f 8801 c40f c204 c40d 900e d40d 3000 0000 leave SYMBOL LIST: = 566 (0x236) a = R22 (0x16) b = 0 (0x0) c = 3 (0x3) subr = 315 (0x13b) g = 2 (0x2) i = R23 (0x17) j = R24 (0x18) k = R25 (0x19) p = 5 (0x5) r = 4 (0x4) w = 7 (0x7) x = R16 (0x10) y = R17 (0x11) __od000 = 377 (0x179) __od001 = 372 (0x174) __od002 = 364 (0x16c) __od003 = 429 (0x1ad) __od004 = 470 (0x1d6) __od005 = 462 (0x1ce) __od010 = 530 (0x212) __od009 = 522 (0x20a) __od011 = 566 (0x236) __od012 = 565 (0x235) __od013 = 557 (0x22d) invdata = 264 (0x108) cls = 412 (0x19c) subr2 = 541 (0x21d) bc = R18 (0x12) at = R13 (0xd) de = R19 (0x13) hl = R20 (0x14) ix = R21 (0x15) lr = R14 (0xe) sp = R15 (0xf) blit8x8 = 440 (0x1b8) test1 = 481 (0x1e1) test2 = 505 (0x1f9) test3 = 513 (0x201) test4 = 522 (0x20a) __do000 = 325 (0x145) __do001 = 327 (0x147) __do002 = 329 (0x149) __do003 = 419 (0x1a3) __do004 = 447 (0x1bf) __do005 = 449 (0x1c1) __do010 = 524 (0x20c) __do009 = 515 (0x203) __do011 = 546 (0x222) __do012 = 550 (0x226) __do013 = 552 (0x228) __of006 = 505 (0x1f9) __ew008 = 513 (0x201) __el007 = 501 (0x1f5) main = 296 (0x128) _start = 256 (0x100) __wh008 = 505 (0x1f9) __fo006 = 491 (0x1eb) putdata1 = 388 (0x184)