|
予想通り難航中なう。SDカードの初期化の部分でつまずいています。
CMD0でリセットかけると、カードは初期化作業に入ります。それが終わったかどうか問い合わせるのが、MMCではCMD1、SDカードではACMD41のようです。
でも、「ACMD」の「A」は「2バイトコマンド」を意味するそうで、先行してACMD5?を送信してACMD41を送信するようです。初期化作業が終わるまでコマンドを発行し続けて待ちます。
このへんのフローチャートについて、SUN DISKの資料を入手しましたが、上から下へ一部ループという見慣れたフローチャートじゃなくて、あっち行ったり、こっち行ったりするのです。挙句の果てに「対応カードじゃない!」と放り出されたり。ま、それが正しいフローですが。
今日は一日、200頁ほどの英語の資料に取り組んでくたびれました。
一行もプログラムは書けていません。だんだんと「なんだかみなさん、CMD1でうまくいってるみたいじゃん?」と、低きに流れる気持ちになっています。
あ、それと「2G超え非対応、HC非対応」と仕様書にかかなくっちゃ。
SDカードもバージョンがいろいろできてややこしいです(*´Д`*)
プログラム書く前に、処理のシーケンスを書き直します・・・>┼○ バタッ
明日か明後日、『平成ガメラ3部作』が届くので、ブログ更新は暫く滞りますw
『ゴジラ対ヘドラ』と『三大怪獣 地球最大の決戦』と『パシフィック・リム』も一緒に届く予定です。週末は怪獣三昧 ヽ( ´¬`)ノ〜♪
|
過去の投稿月別表示
-
詳細
コメント(2)
|
昼寝しながらも、コツコツと作業を進めております。
「MSX テクニカル・ハンドブック」や「MSX-DOS スーパーハンドブック」を初め、「BASIC説明書」「Z80マシン語ランド」「フラッシュ・メモリー・カードの徹底研究(以下「フラ研」という)」などなど、書籍たくさん、
MMC/SDCの使いかた
浅草ギ研 A33FでMicroSDカードにアクセスしてみる
などなどWEBもたくさん、参照させていただいてます。
「フラ研」には、SDカードでは初期化コマンドにACMD41を用いないと、MMC用のCMD1ではレスポンスが返ってこないと書いてありますが(149頁)、浅草ギ研さんとこではCMD1を使っておられて、相変わらず困惑している今日この頃です。「フラ研」の別のページでは「MMC用のソフト・ハードでSDにもアクセスできた」と書いてあり(112頁)、本当のところどうなんでしょう?
とりあえず、対応予定のCMDを並べてみました。
CMD0: DEFB 40H,00H,00H,00H,00H,95H
ACMD41: DEFB 69H,00H,00H,00H,00H,95H ↑このふたつは、SDカードのリセットに使います。いまだACMD41を使うべきかCMD1にするか迷い中。実験してから決めます。 CMD16: DEFB 50H,00H,00H,02H,00H,95H
↑このコマンドで、ブロック・サイズを512Bに設定します。2G以上のSDカードでは1024Bのこともあるようです(「フラ研」151頁)。「フラ研」の筆者のひとりは「これまで512B以外は見たことがない」と書いていますが(126頁)、2006年に発行された本なので2G以上のカードがあまり普及していなかったのでしょう。スマートメディアが「最も普及しているメモリ・カード」(11頁)とされる時代でした。 CMD17: DEFB 51H,00H
CMD17H: DEFB 00H CMD17L: DEFB 00H,95H ↑このコマンドは、読み込み時、アクセスするセクタを指定します。「H」と「L」の部分には、USR関数で渡される数値が代入されます。 CMD24: DEFB 58H,00H
CMD24H: DEFB 00H CMD24L: DEFB 00H,95H ↑このコマンドは、書き込み時、アクセスするセクタを指定します。この「H」と「L」の部分も読み込み時と同様です。 CMD59: DEFB 7BH,00H,00H,00H,00H,95H
↑このコマンドは、CRCを明示的に無効にします。SPIモードでは最初のCMD0以外、CRCは無視されるはずですが、「ごくまれにCRCを無視しないカードがある」と「フラ研」に書いてありました(106頁)。CMD0以外のコマンドのCRCが全部「95H」となっていますが意味ありません。
まあ、これぐらいのコマンドに対応しておけば大丈夫でしょう、たぶんw。
で、肝心のSDカードのアクセス部分ですが、
SDINI:;---------
CALL CSH CALL CLK80 CALL CSL RET RDSD:;----------
RET WTSD:;---------- RET まだこれだけしか書けてません。というか、全然書いてないじゃんw
ときどきダミークロックを挟まないといけない(「フラ研」95頁)とか、「CMD0とCMD1の2つのコマンドを発行するあいだはCSはずっとLOWのままのように書いてありますし、SDカードの仕様が書いたドキュメント類を読むとそのようになっているようですが、実際に実験してみた結果、CMD1後にCSをHIGHにして1バイトダミーバイトを送信しないと同期が狂うことがわかりました。よって実際のプログラムではCMD1を何回も発行する前にCS=HIGHにして1バイト送信し、CS=LOWにしてからCMD1を発行しています。(この部分でかなりの時間を消費してしまった。SDカードのドキュメントわかりづらいです。) 」(浅草ギ研さん)とか、いろんな情報が錯綜して現在調査中であります。
つじかわさんの「mmc_test.com」も理解しきれてないし。
以下、現時点でのアセンブラリストとBASICのリストを掲げておきます。現時点では何事も起きず、無事「OK」となります。SDにアクセスしてないもんな。
ここのブログ、別ファイルにて掲載する機能がないし、TABコードを半角スペースに変換するし、なので少し困っています。完成時の公開をどうしようかな? 画像では困るでしょうね。
─────────────────────
■アセンブラリスト(適宜、半角スペースをTABに変換してね。)
;===================
; SDTEST.ASM XCD /B ; KIKI 2014 ;=================== JPORT EQU 6 ;Use JPORT B
CS EQU 5 ;CS =PIN8 CLK EQU 3 ;CLK=PIN7 DIN EQU 2 ;DI =PIN6 DO EQU 0 ;DO =PIN1(#14) ORG 0C000H
MAIN:;----------
CALL SDR ;USR0=0C000H CALL PSGRST RET CALL SDW ;USR1=0C007H CALL PSGRST RET BUFF: DEFS 512 ;BUFF=0C00EH
PSG0: DEFS 1 PSG1: DEFS 1 CMD0: DEFB 40H,00H,00H,00H,00H,95H ACMD41: DEFB 69H,00H,00H,00H,00H,95H CMD16: DEFB 50H,00H,00H,02H,00H,95H CMD17: DEFB 51H,00H CMD17H: DEFB 00H CMD17L: DEFB 00H,95H CMD24: DEFB 58H,00H CMD24H: DEFB 00H CMD24L: DEFB 00H,95H CMD59: DEFB 7BH,00H,00H,00H,00H,95H SDR:;-----------
DI PUSH HL CALL PSGINI CALL SDINI LD A,(BUFF) OR A RET NZ POP HL INC HL INC HL LD A,(HL) LD (CMD17L),A INC HL LD A,(HL) LD (CMD17H),A CALL RDSD EI RET SDW:;-----------
DI PUSH HL CALL PSGINI CALL SDINI LD A,(BUFF) OR A RET NZ POP HL INC HL INC HL LD A,(HL) LD (CMD24L),A INC HL LD A,(HL) LD (CMD24H),A CALL WTSD EI RET PSGINI:;---------
LD A,15 OUT (0A0H),A IN A,(0A2H) LD (PSG0),A PUSH AF LD A,15 OUT (0A0H),A POP AF SET 6,A SET CS,A SET CLK,A SET DIN,A OUT (0A1H),A LD (PSG1),A RET SDINI:;---------
CALL CSH CALL CLK80 CALL CSL RET RDSD:;----------
RET WTSD:;----------
RET ;CS H/L --------
CSH: LD A,15 OUT (0A0H),A LD A,(PSG1) SET CS,A OUT (0A1H),A LD (PSG1),A RET CSL: LD A,15
OUT (0A0H),A LD A,(PSG1) RES CS,A OUT (0A1H),A LD (PSG1),A RET ;CLK H/L --------
CLKH: LD A,15 OUT (0A0H),A LD A,(PSG1) SET CLK,A OUT (0A1H),A LD (PSG1),A RET CLKL: LD A,15
OUT (0A0H),A LD A,(PSG1) RES CLK,A OUT (0A1H),A LD (PSG1),A RET ;DIN H/L --------
DINH: LD A,15 OUT (0A0H),A LD A,(PSG1) SET DIN,A OUT (0A1H),A LD (PSG1),A RET DINL: LD A,15
OUT (0A0H),A LD A,(PSG1) RES DIN,A OUT (0A1H),A LD (PSG1),A RET ;CLOK 80 -------
CLK80: CALL CLKL LD B,80 CLK80L: CALL CLKH CALL CLKL DJNZ CLK80L CALL CLKH RET ;DUMY CLOK 8 -------
DCLK: CALL CLKL LD B,8 DCLK8L: CALL CLKH CALL CLKL DJNZ DCLK8L CALL CLKH RET PSGRST:;--------
LD A,15 OUT (0A0H),A LD A,(PSG0) OUT (0A1H),A RET END
─────────────────────
■BASICリスト(何もなくてごめんね。)
1000 '===============
1010 ' SDTEST.BAS 1020 ' KIKI 2014 1030 '=============== 1040 SAVE "SDTEST.BAS" 1050 CLEAR 100,&HC000 1060 DEFINT A-Z 1070 BLOAD "SDTEST.OBJ" 1080 DEFUSR0=&HC000 1090 DEFUSR1=&HC007 1100 A=USR0(0) 1110 END |
|
以前から不思議に思っているのですがね。
レジスタの値の特定のビットを「1」にしたり「0」にしたりするときに、なんで「AND」や「OR」が多用されるんでしょうか?
ちゃんとビット操作用の命令「SET」「RES」があるのに。
例えば、PSG#15の初期状態が「11001111B」だったとしますね。いわゆるジョイスティックポートBが使用されている状態。
で、8番端子を「H」にしたいときは「OR 00100000B」とするんでしたっけ。
でも、値がレジスタAに入っているとして「SET 5,A」でもいいんでしょ?
事前に「CS EQU 5」と定義しておけば「SET CS,A」でもいいはず。
なんでこだわっているかと言うと、
CS EQU 5
CLK EQU 3
DI EQU 2
と抽象化しておきたいのです。
16進数でANDやORするより、「SET CS,A」のほうが「CSをHにしたな」と分かりやすいでしょ? それに、気が変わって「ジョイスティックポートAを使おう」と思ったり、ピン割り当てを変えようと思ったら、
CS EQU 4
CLK EQU 1
DI EQU 0
などと定義を書き換えるだけで済みます。ANDやORを使っていると、該当箇所を探し出して書き換えないといけません。
とはいえ、端子をひとつずつ制御する前提ですけどね。
「SET」や「RES」では、「OR 00101100B」のように一挙に変更することはできません。
実は、愛用の「MSX-DOSスーパーハンドブック」のASM.COMが2進数を扱えないという事情もありましてね。いまだに2進数をパッと16進数に置き換えられないし、ANDだっけ?ORだっけ?と混乱することもあったりして(自爆)
あ、そうそう。このASM.COMを愛用する理由をもうひとつ書いておきます。
M80などのアセンブラが信用ならないのです。MSX-DOS(1)版とMSX-DOS2版で挙動が若干違うし、MSX-DOS2版でCOMファイルを作るとリダイレクトやパイプの機能を勝手に付け加えて肥大化しちゃう。
ターミナルソフト「mabterm」で有名な馬淵さんから「それはライブラリの問題で、気に入らなければライブラリに手を入れればいい」と言われちゃいましたが、そんなことできるほど優秀なアタマではありません。アホをバカにしないでください(笑)。
それだけではありません。
MSXには「できるだけBIOSを使う」という不文律?があって直接I/Oを叩いていいのはVDPだけとなっています。でもね、PSG関連のBIOS「WRTPSG」の本体部分(1102H〜)を見ると、
DI
OUT (PSG.LW),A
PUSH AF
LD A,E
OUT (PSG.DW),A
EI
POP AF
RET
ほれほれ、勝手に割り込み許可してRETしてるでしょ!
M80とかMSX-Cとか使ってると、素知らぬ顔してこういうコードを吐き出してくるのです。「だって、BIOSを使うのがキマリだも〜ん。」
こういうのを見ると、MSXのBASIC-ROMを書き換えてやりたくなります。
なんか、今日は愚痴ばかりになりました。「私はASM.COMから進化しません!」宣言みたいな部分もw
SDカードアクセスのコーディングに向けて、肩をグルグル回している状態とご理解ください<(_ _)>ペコリ
|
|
クヨクヨ悩んでいても仕方がない。
暫定仕様を考えて、最小限の機能を実装するところから始めよう。
目標は、「ぼくが持っているSDにアクセスできること」。
この時点で、このブログは自分用の利己的なメモと化す(笑)
特徴は、BASICからアクセス可能なことだ。
さっそくアセンブラの数行を書く。歴史的な数行だ(大袈裟なw)。
暫定仕様
○読むのも書くのも、BASICからのUSR関数で呼び出す。
○どのセクターを読み書きするかは、A=USR?(n)の n で指示する。
n は2バイト整数。
○読み書きは、SDで従来から一般的な512B単位とする。
○読み書きするデータはBASICがBUFFにアクセスして入出力する。
○書き込み後、BASICはSDから読み出してベリファイを行う。
○エラーについては、BASICがBUFFに返されたデータを見て判断。
○ターゲットはSDのみとする。(MMC非対応)
○当面、FATには対応しない。いわばHBI-55モード(笑)。
マシン語側の暫定仕様
○使用コマンドは、CMD0、ACMD41、CMD17、CMD24、CMD16。
○念のため、CMD16によりセクター長を512Bとする。(省略するかも。)
○/CSはプログラム側で負論理とする(74HC14を不要とする)。
不具合があれば、正論理に変更する(74HC14を加える)。
○エラーハンドリングは、CMDレスポンスのフォーマットR1のみ。
CMDレスポンス時のエラーは、1バイトをBUFFに書き込んでRETする。
書き込み実行時のエラーレスポンスは関知しない。(BASIC任せ)
○CMD17の読み込み前にBUFFを初期化する(例えば「00」で埋める)。
CMD24の書き込み時はBUFFの初期化を行わない。
BASICは、書き込みエラーをベリファイ時に知ることになる。
○SDの容量は関知しない。人間がSDカードの表示を見ろ。
○読み書きのセクタ・アドレスは、USR関数の引数の範囲となる。(注)
(注)CMD17及びCMD24の引数は4バイトある。
ただし1セクタ512Bなので、セクタごとの引数は次のようになる。
引数バイト 3 2 1 0
セクタ0:00 00 00 00
セクタ1:00 00 02 00
セクタ2:00 00 04 00
つまり引数バイト0は常に「00」である。
一方、USR関数で与えられる引数は2バイト整数である。
下位1バイトをセクタ引数1に、上位1バイトをセクタ引数2に割り当てる。
すると、引数バイト3も常に「00」である。
従って「00 FF FE 00」が、このプログラムにおける最大引数となる。
512Bを掛けると、アクセス可能な最大容量となる。いくらになるのかな?
考え違いしてたらごめんね。このへん、よく間違うの。
本質的なところは出来たも同然だ(爆)
あとはこれを実現する実質的な部分をコツコツと書くことになる。
その前に、PSGの初期化、SDカードの初期化、/CSの上げ下げやCLKの上げ下げ、CMDの発行とレスポンスの受け取り、読み取りデータの受け取り、不要CRCの読み捨て、ビジー待ち、ダミーCLKの挿入・・・などなど、細かな段取りをリストアップする必要がある。
PSGの8ピンを「H」にしたり「L」にしたり、なんていうシモジモの原始的ルーチンは、さらにその先にある。
ルーチンを積み上げて積み上げて積み上げてルーチンを作る。
どこかでルーチンがコケたら、「みなコケた〜」。
「MSXによるSDカードの読み書きをアセンブラで書く」。ささやかな機能しか実現しないくせに、予想外の大プロジェクトになりそうだなあ〜。
大丈夫か?>自分
※上記暫定仕様は、いつの間にか変更されているかも知れません。ご了承されたし。
|
|
「成功しました!」と言いつつ、ホンマに成功したんかいな? という疑問がふつふつと。
■疑問点(その1)
つじかわさんは、なんでわざわざ/CSの信号をプログラムで反転せず、74HC14で反転したのか?
元の記事を読むと、汎用ポート直結ではうまく動作せず、バッファを入れるとあっさり動いたとのこと。つまり、汎用ポート直結の段階ではプログラムで反転していたと読める。74HC14を入れるために、わざわざプログラムを書き換えたのか?
しかし、74HC14のピンはもうワンセット余っている。プログラムを書き換えなくても、他の信号と同じように2段反転で整形すれば済むのではないか?
余った入力ピンをGNDに落とす手間と余り変わらないように思うのだが?
余談ながら、気になる記述を再度引用。
それと今回実験に使用したMSX本体(FS-A1GT)のジョイスティックポートで、妙な挙動を発見しました。
MSXは、PSGレジスタR#15のbit2/3でジョイスティックポートBのトリガA/B出力を設定出来ます。 bit2/3を同時に変化させれば、トリガA/Bが同時に変化する事が期待されます。 ところが実際には、トリガAの方がBよりも必ず600ns程度先に変化するのです。 MSXエンジン(T9769)を使用したMSXで共通なのかも知れません。 実は、CQ出版の「フラッシュ・メモリー・カードの徹底研究」(2006年12月)を片手につじかわさんの「mmc_test.com」のアセンブラリストを読んでいるところです。
SPIでは、送信はクロックの立下りで出力、受信はクロックの立上がりで入力するらしい。しかし、同書に掲載されているプログラムを見ると、クロックの立下りと同時にDI出力しています(ええかいな?)。これと同じ調子で、MSXのトリガA/Bで同時にクロック立下りとDI出力すると、トリガBの変化が遅れて誤動作するかもしれません。クロックのこまめな制御が必要となるというお話でした。
つじかわさんが選択した汎用ポートのピンへの割り当ては、ふか〜い意味があるのかもしれない。
■疑問点(その2)
こっちのほうがより深刻な疑問点かもしれない。
同書によれば、SDカードの初期化に当たっては「CMD0」に続いて、MMCカード用の「CMD1」ではなく、SDカード専用コマンド「ACMD41」を発行しなければならないらしい。SDカードは「CMD1」に対してはレスポンスを返さないと書いてあるよ!
Σ(・□・;)
「mmc_test.com」の実験成功!と思っていたが、これには「ACMD41」は使われていない。「CMD1」にレスポンスがないのに正常と判断したのか? たんに実験成功みたいな動作をしたに過ぎないのかもしれない。しかし、レスポンスがないならタイムオーバーエラーになるはずである。SDカードの仕様では「CMD1」にレスポンスしないことになっているが、たまたま使ったSDカードはMMCカードと同じ動作をしたのか?
う〜む、なんだか難産が予想されるぞ;;;;
|




