前回で、手動での64Kramに切り替えができました。今回はもう一つの課題のSPIによるSDCARDの初期化/読み書きについて、モニタに組み込んでいきたいと思います。

SDCARDは3.3V仕様なので、電圧変換内蔵のカードアダプタで接続します。
実際に接続するのは、8255のポートCを使用します。
まずは、8255のポートアドレスを定義します。

PPIA 		.equ 	0x88		;PPI-A PORT DATA REG
PPIB		.equ	0x89		;PPI-B PORT DATA REG
PPIC		.equ	0x8a		;PPI-C PORT DATA REG
PPICNT		.equ	0x8b		;PPI  CONTL REG

SPIでの通信のための端子を定義します。
実際には、8255のポートCに接続される端子を定義します。
上位4ビットは出力として定義され、DI、CS、CLKを定義します。
下位4ビットは入力として定義され、DOを定義します。

	;OUTPUT-PORT
S_DI 	.equ 7 ;0b10000000 D7
S_CS 	.equ 6 ;0b01000000 D6
S_CLK 	.equ 5 ;0b00100000 D5

	;INPUT-PORT
DO 	.equ 0 ;0b00000001 D0

8255の初期化ルーチンでは、ポートAは出力に、ポートBは入力に、Cポート上位4ビットは出力に、下位4ビットは入力に設定します。

ppi_init:
	ld	a,0b10000011		;PPIA mode0,output PPIB mode0,input
	out	(PPICNT),a		;PPIC C7-C4 output,C3-C0 input
	ret	

SPIでは、8ビットシリアルの入出力は、DI、DO端子で、同期用のパルス列はCLKで、選択信号は、CSで行います。
SDCARADのSPIでのやり取りは8ビット単位で行いますので、8ビットでのパラレル→シリアル、シリアル→パラレルの変換ルーチンを作成します。

過去のZ8S180で初期化手順を記載していますが、初期化の手順にあたってはELM by ChaNさんの「MMC/SDCの使い方」のほか、いろんなサイトをご参考にさせていただきました。貴重な情報ありがとうございます。 

初期化の手順の大まかな手順は次のようになります。
(過去記載のZ8S180、TMPZ84C015の初期化手順と同じです。)

1、DI、CSを”H"してCLKを74クロック以上、発行する。(ここでは80クロック)
2、CMD0を発行する。(ソフトウェアリセットしSPIモードに入る)CRCは有効
3、CMD8を発行する。(SD Ver2以上かチェック)戻り値が0x1AAであればSDVer2以上)
4、CMD55を発行する。(次のコマンドがアプリケーションコマンドであることを知らせる。)
5、ACMD41を発行する。(初期化開始、レスポンス0x00が戻るまでコマンドを繰り返す。)
6、CMD58を発行する。(初期化完了及びSDHCかVer2を確認する。)
7、初期化終了


初期化の最初は、CLKを80クロック出力します。この時、DIは”H"、CSも”H"レベルにします。

spi_card_init:
        xor     a
        set     S_CS,a          ;CS="H" 
        set     S_DI,a          ;DI="H"
        out    (PPIC),a
        ld      b,80            ;80 clok output
        call    loopspii

80クロックは loopspiiで出力します。
コール前に Bレジスタに80を設定し、CLKに”L"、続いて”H"を設定、djnzでループしました。

loopspii:
        res     S_CLK,a         ;CLK    L
        out    (PPIC),a
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop

        set     S_CLK,a         ;CLK    H
        out    (PPIC),a
        nop
        nop
        nop
        nop
        nop
        djnz    loopspii
        ret

80クロックを出力した後、CSを”L"にして選択をアクティブにします。
ここから、コマンドによる制御に移ります。
最初は”CMD0"コマンドを発行します。48ビット列で、8ビット*6で構成されています。
最初の8Bit がコマンドインデックスで0x40、8ビット*4が引数、最後の8ビットがCRCになっています。CMD0ではCRCが必衰ですが、このコマンドは固定なのでCRCは0x95に固定です。

cmd0:                           ;;48bit(6byte) Fixed length 
        .db     0x40            ;;command index 
        .db     0x00            ;;argument
        .db     0x00            ;;argument
        .db     0x00            ;;argument
        .db     0x00            ;;argument
        .db     0x95            ;;CRC 

CMD0を発行します。戻り値が0x01でない場合は、初期化エラーとします。

        call    cmd0_out
        cp      0x01
        jp      nz,init_err

実際のCMD0の発行ルーチンは次のようになります。
HLレジに先ほどのCMD0テーブルアドレスをセットします。
cmd_outでコマンドを発行し、そのレスポンスをr1_respで受け取ります。
レスポンスの内容を表示(動作確認のため)した後、復帰します。

cmd0_out: 
        ld      hl,cmd0
        call    cmd_out
        call    r1_resp
        push    af
        ld      hl,cmd0_msg
        call    msgout
        pop     af
        push    af
        call    hex_a_disp
        ld      a,0x0d
        call    putchar
        pop     af
        ret

cmd_outは、8ビットごとに、spi_8bitを6回コールします。
8bitごとのデータはDレジスタにセットされます。

cmd_out:                        ;command out
        push    hl
        push    bc
        ld      b,0x06          ;command line word count
cmd_out1:
        ld      d,(hl)          ;command line area
        call    spi_8bit
        inc     hl
        djnz    cmd_out1
        pop     bc
        pop     hl
        ret

spi_8bitは、Dレジスタの7bit目を左シフトしキャリーフラグにセット(rlc d)し、このキャリーフラグの内容を右シフトしAレジスタの7bit目にセット(rra)します。CLKを”L"に変化させるとともに、7bit目のDIを出力します(パルスの立下り)。
時間稼ぎをした後、CLKを”H"にするとともに、ポートCの内容を読み込みます。(パルスの立ち上がり)
読み込まれたデータのAレジスタの0bit目のDOは、右シフトし(rrca)キャリーフラグにセットし、このキャリ―フラグをEレジスター左シフトして0bit目に格納します。この動作を8回繰り返し、8ビットのDレジスタの内容をシリアル出力し、入力されたシリアルデータをEレジスタに格納します。

spi_8bit:                       ;outdata Dreg,inputdata Ereg
        push    bc
        ld      c,0x00
        ld      b,0x08        
loopspi:
        xor     a
        rlc     d
        rra
        res     S_CLK,a         ;CLK    L
        out    (PPIC),a
        nop
        nop
        nop
        nop
        nop
        nop
        set     S_CLK,a         ;CLK    H
        out    (PPIC),a
        in     a,(PPIC)
        rrca
        rl      e
        djnz    loopspi
        xor     a
        out    (PPIC),a
        pop     bc
        ret

コマンドを発行した後のレスポンスの受信は、r1_respで行います。
レスポンスの受信は、DIを”H"にした(データとして”0xFF”)まま、先ほどのspi_8bitをコールし、戻り値(Eレジスタ)を取得します。
レスポンスr1_respでは、戻り値が0xFF以外の場合、respではそのまま、戻り値を返します。

r1_resp:
        call    resp
        cp      0xff
        jr      z,r1_resp
        ret

resp:
        ld      d,0xff  
        call    spi_8bit
        ld      a,e
        ret

CMD0を発行した後は、順にCMD8、CMD55、ACMD41、CMD58と発行していき、戻り値をチェックしていきます。

        call    cmd0_out
        cp      0x01
        jp      nz,init_err
        call    cmd8_out
        cp      0x01
        jp      nz,init_err
        call    cmd55_out
        cp      0x01
        jp      nz,init_err
        call    acmd41_out
        call    cmd58_out
        ld      a,(r7)
        bit     7,a
        jp      z,init_err
        bit     6,a
        jr      z,SD_ver2
        ld      hl,sdhc_msg
init_msg:
        call    msgout
        ret
SD_ver2:
        ld      hl,sd_ver2_msg
        jr      init_msg

CMD58では、レスポンスの30bit、31bit目をチェックします。
30bit目 0:SDVer2  1:SDHC
31bit目 0:初期化未完了 1:初期化完了

31ビット目が1であれば、初期化完了です。

実際に作成したモニタで初期化したログを確認してみました。
(手持ちの8GB SDHCで確認しました)
モニタでのカードの初期化コマンドはaiコマンドになります。

Monitor Z80+8251+8255 ver0.71(SPI)  by Pinecone 2020/09/12                     
>?                                                                              
?  Help                                                                         
d  memory dump                                                                  
m  memory change   address old new                                              
l  hex file load                                                                
j  jump                                                                         
i  i/o register    i/o-address old new                                          
c  call                                                                         
ai spi(sd-card) Initialization                                                  
ar spi(sd-card) read  (512byte/block)  0x0000-0xffff set                        
aw spi(sd-card) write (512byte/block)  0x0000-0xffff set                        
>a spi(sd-card) Initialize : Yes:                                               
CMD0:01                                                                         
CMD8:01000001AA                                                                 
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:01                                                                       
CMD55:01                                                                        
ACMD41:00                                                                       
CMD58:00C0FF8000                                                                
:SDHC                                                                           
OK                                                                              
>

ちゃんとうまくいったみたいです。
次回は、カードのリード/ライトを確認したいと思います。
ソースは次回に、HEXファイルは下記の通りです。

:03000000C3000139
:20010000310000CDFE06CD1207211707CDE0063E3ECDF306CDEA06CDF306FE3FCC4F01FEE9
:2001200064CC4402FE6DCC5A02FE6CCCB101FE6ACC5C01FE69CC8E02FE63CC8601FE61CC9B
:20014000CD02FE0D28C9FE0028C5CD560118C0215307CDE006C93E0DCDF306C93E20CDF3FE
:2001600006CD5006FE00201A3E20CDF3063E79CDF3063E3ACDF306CDEA06FE792004CD56C4
:2001800001E9CD5601C93E20CDF306CD5006FE0020F03E20CDF3063E79CDF3063E3ACDF35A
:2001A00006CDEA06FE7920DACD560111B001D5E9C9CDEB01FEFF2819FE0120F53E0DCDF388
:2001C000063E4FCDF3063E4BCDF3063E0DCDF306C93E0DCDF3063E45CDF3063E52CDF306ED
:2001E0003E52CDF3063E0DCDF306C93E0DCDF3061600CDEA06FE3A2048CD4B06457A805797
:20020000CD5006E5DDE17A858457CD4B067DFE002020CD4B06DD7500DD237D825710F3CDCF
:200220004B067A85FE002019CDEA06FE0A20123E00C9FE01200BCD4B067DFEFF20033E0115
:20024000C93EFFC93E20CDF306CD5006FE002803FDE5E1CD7606E5FDE1C93E20CDF306CDD6
:200260005006FE0028063E0DCDF306C93E20CDF3067ECDA7063E20CDF306E5CD4B06FE00E1
:200280002803E1AFC94DE1713E0DCDF306C93E20CDF306CD4B06FE0028063E0DCDF306C919
:2002A0003E20CDF30606004DED78CDA7063E20CDF306CD4B06FE002802AFC97DED793E0DD8
:2002C000CDF306C9E521C108CDE006E1C9CDEA06FE69CC7E04FE72CCE002FE77CCD003C9F6
:2002E00021D008CDE006CD5006FE002805CD5601AFC93A0CFFCB77CA04037C3203FF7D32B1
:2003000004FF18087C3202FF7D3203FF21F108CDE006CD5006FE002805CD5601AFC9CDC412
:2003200002CDEA06FE79C29C05E5CDE3052100FFCD1A06CD0B06FE00203DCD0B06FEFE204A
:20034000F90600E1CD1306772310F90600CD1306772310F9CD1306CD130616FFCD280601C8
:200360000002ED423E0DCDF306CD7F03CDF306CD7F03CDF306AFC9E1211809CDE006C9C535
:200380000600E5216808CDE006E17CCDA7067DCDA7063E20CDF306CDF3067E23CDA70678E3
:2003A000FE01282378E60FFE0128073E20CDF30618153E0DCDF3067CCDA7067DCDA7063ECB
:2003C00020CDF306CDF30610D13E0DCDF306C1C921E008CDE006CD5006FE002805CD5601C7
:2003E000AFC93A0CFFCB77CAF4037C3209FF7D320AFF18087C3208FF7D3209FF21FD08CD50
:20040000E006CD5006FE002805CD5601AFC9CDC402CDEA06FE79C29C05E5CDE3052106FF22
:20042000CD1A06CD0B06FE00C2760416FECD2806E106005623CD280610F906005623CD28D0
:200440000610F916FFCD2806CD2806CD0B06E60FFE052023CD0B06FE0028F9CDE3050100B6
:2004600002ED423E0DCDF306CD7F03CDF306CD7F03CDF306AFC9E1212309CDE006C9CD9F82
:2004800004213F09CDE006CDC402CDEA06FE79C29C05CD5601CDBC0421C708CDE006C906EF
:2004A00006217E091100FF7E12231310FA06062184091106FF7E12231310FAC9AFCBF7CB09
:2004C000FFD38A0650CDF305AFD38ACD0105FE01C2A005CD1D05FE01C2A005CD5705FE01E3
:2004E000C2A005CD7605CDAC053A0CFFCB7FCAA005CB772807212E09CDE006C92135091815
:20050000F7215A09CD1A06CD0B06F5219F08CDE006F1F5CDA7063E0DCDF306F1C9CDE30545
:20052000216009CD1A06CD0B06FE01C00604210CFFCD1306772310F921A508CDE0063E0128
:20054000CDA706210CFF06047ECDA7062310F93E0DCDF3063E01C9CDE305217209CD1A0670
:20056000CD0B06F521AB08CDE006F1F5CDA7063E0DCDF306F1C9CDE305216609CD1A06CDF7
:200580000B06FE00F521B208CDE006F1F5CDA7063E0DCDF306F1C8CD570518DACD5601C997
:2005A000210A09CDE006CD5601C30001CDE305216C09CD1A06CD0B06F50604210CFFCD134B
:2005C00006772310F921BA08CDE006F1F5CDA706210CFF06047ECDA7062310F93E0DCDF317
:2005E00006F1C9AFCBF7CBFFD38A0608CDF305AFD38AC9CBAFD38A0000000000000000CB59
:20060000EFD38A000000000010E9C9CD1306FEFF28F9C916FFCD28067BC9E5C5060656CDD2
:2006200028062310F9C1E1C9C50E000608AFCB021FCBAFD38A000000000000CBEFD38ADBB0
:200640008A0FCB1310E7AFD38AC1C9C506021803C50604210000180429292929CDEA06CD74
:20066000F306CDBA06FEFF2809E60FB56F10E9C1AFC93EFFC1C93E0DCDF306E5216808CD60
:20068000E006E17CCDA7067DCDA7063E20CDF306CDF30606107E23CDA7063E20CDF3061057
:2006A000F43E0DCDF306C9F50F0F0F0FCDD406CDF306F1CDD406CDF306C9D6303813FE0A4E
:2006C000380ED611FE063806D620FE063003C60AC93EFFC9E60FFE0A3803C637C9C630C922
:2006E0007EFE00C8CDF3062318F6DB85CB4F28FADB84C9F5DB85CB4728FAF1D384C9AF06AC
:2007000003D38510FC3E40D3853E4ED3853E37D385C93E83D38BC94D6F6E69746F72205AD8
:2007200038302B383235312B3832353520766572302E3731285350492920206279205069F3
:200740006E65636F6E6520323032302F30392F31320D000D3F202048656C700D6420206DD3
:20076000656D6F72792064756D700D6D20206D656D6F7279206368616E6765202020616479
:200780006472657373206F6C64206E65770D6C20206865782066696C65206C6F61640D6A7A
:2007A00020206A756D700D692020692F6F20726567697374657220202020692F6F2D616482
:2007C0006472657373206F6C64206E65770D63202063616C6C0D6169207370692873642D74
:2007E000636172642920496E697469616C697A6174696F6E0D6172207370692873642D6373
:20080000617264292072656164202028353132627974652F626C6F636B292020307830305D
:2008200030302D307866666666207365740D6177207370692873642D636172642920777236
:200840006974652028353132627974652F626C6F636B2920203078303030302D3078666616
:200860006666207365740D006164647220202B30202B31202B32202B33202B34202B352067
:200880002B36202B37202B38202B39202B41202B42202B43202B44202B45202B460D0043C7
:2008A0004D44303A00434D44383A00434D4435353A0041434D4434313A00434D4435383A50
:2008C00000205965733A004F4B0D004552520D00207265616420626C6F636B204E6F3A00F2
:2008E00020777269746520626C6F636B204E6F3A00207361766520616464723A002077729E
:2009000069746520616464723A0053706920496E6974204572720D00636D643137204572F7
:20092000720D00636D643234204572720D003A534448430D003A534420566572320D002062
:200940007370692873642D636172642920496E697469616C697A65203A00400000000095FB
:2009600048000001AA876940FF8000FF7A00000000FF7700000000FF5000000200FF510045
:0A098000000200FF5800000200FF13
:0CFF00005100000200FF5800000200FF4A
:00000001FF

おすすめの記事