SSブログ
English Version

レトロマイコンZ80ボードの構想(その6)SDカード [Z80]

 前回の記事「レトロマイコンZ80ボードの構想(その5)ピンアサイン」に追記したようにSDカードとのSPI通信の実験をしています。

 picleコンパイラを使ってSDHCタイプのカードの初期化シーケンスが通るようになりました。

 SPIはパラ-シリ変換のICが対向して接続されているような単純なインターフェースでマスター側からクロック提供した場合はデータ有無にかかわらずシフトされるので受信データが発生します(データがない場合は0xff)。

 データ送信の都度、受信データを読みながらやり取りすれば処理的には簡単なのですが、送信バイト間にクロックが停止する隙間ができるのが嫌なので今回は送信データは連続して送信し、受信データは0xff送信(SDカードが送信できるようにクロックを提供)に対応した受信データを確認する(送信バッファにデータを貯めない)方法で処理しました。

 このためには送信データに対する受信データの数(=送信バイト数ー受信バイト数)を管理しておく必要があり、末尾のソース内では SpiCnt でカウントしています。

 また、トランザクション終了後にCSをdisable(high)にしてから1バイトのダミー送信する必要があり、そうしないとSDカード側の送信データのLSBがlowの場合、SPIのデータ線をLowに引っ張り続ける(下図のACMD41のように)ことがあるので、SDカード側のパラ-シリ変換にごみを残さないという意味があるものと思います。

 SDカードとの実際の通信波形はweb上では見当たらなかったので誰かの参考になればと思いロジアナの波形を載せておきます。小さいですがクリックすると拡大表示されます(モバイル環境ではJavaScriptが動かないので大きくなりません^^;)
 使用したSDカードは16MBのものです。

 クロック周波数は333KHzです。(初期化部分は100kHz~400kHzの範囲内であることが必要なようです)

★2018/02/04 23:20 追記 ACMD41波形を追加しました。
★2018/02/10 追記
 改良版の波形を「レトロマイコンZ80ボードの構想(その7)SDカード2に掲載しました。

CMD0波形

CMD8波形

ACMD41波形

CMD58波形


実験に使用したpicleソース
:l 1:# SPI test to connect SD card for PIC24FJ64GA004 with picle 2:# Ver 0.01 by skyriver 2018/02/04 3: 4:var SPISTAT,SPIBUF; 5:var _RPINR20,RPOR0; 6:var _REG,AD1PCFG; 7:var TRISA,LATA; 8: 9:var ByteTimer,SdhcFlg; 10:var SpiCnt,SpiDat,_Buf; 11: 12:proc init() { 13: SPISTAT = $0240; # SPI1 status 14: SPIBUF = $0248; 15: RPOR0 = $06c0; 16: AD1PCFG = $032c; 17: AD1PCFG[0] = $ffff; # I/O 18: TRISA = $02c0; 19: LATA = TRISA + 4; 20: 21:# SPISTAT[1] = $0079; # SPI1CON1 prescale2:2,prescale1:16 = 32:1 500k 22: SPISTAT[1] = $0075; # SPI1CON1 prescale2:3,prescale1:16 = 48:1 333k 23: SPISTAT[2] = 0; # SPI1CON2 24: SPISTAT[0] = $8000; 25: 26: _RPINR20 = $06a8; 27: _RPINR20[0] = 2; # SDI -> RP2 28: RPOR0[0] = $0708; # CLK -> RP0, SDO ->RP1 29: TRISA[0] = TRISA[0] & $fffb; 30: LATA[0] = $0004; 31: 32: _Buf = Array_(0); 33: ByteTimer = 20; 34:} 35: 36: 37:proc SpiCheck() { 38: if ( SPISTAT[0]&1 ) { 39: SpiDat = SPIBUF[0]; 40: SpiCnt = SpiCnt - 1; 41: } 42:} 43: 44: 45:# wait about 2us * n 46:proc TmWait( n ) { 47: var i; 48: for (; n ; n=n-1) { 49:# i = 123 + i; 50: SpiCheck(); 51: } 52:} 53: 54: 55:func SpiRcv() { 56: return = $ff; 57: SPISTAT[0] = $8000; 58: if ( SpiCnt = 0 ) { 59: while ( SPISTAT[0]&2 ) {} 60: SPIBUF[0] = $ff; 61: SpiCnt = 1; 62: } 63: while ( (SPISTAT[0]&1) = 0 ) {} 64: SpiCnt = SpiCnt - 1; 65: return = SPIBUF[0]; 66:} 67: 68: 69:func SpiRcvAns() { 70: do { 71: return = SpiRcv(); 72: } while ( return = $ff ); 73:} 74: 75: 76:proc SpiRcvN( n ) { 77: var i; 78: for ( i=0; i < n; i=i+1 ) { 79: _Buf[i] = SpiRcv(); 80: } 81:} 82: 83: 84:proc SpiSnd( dat ) { 85: do { 86: SpiCheck(); 87: } while ( SPISTAT[0]&2 ); 88: SpiCnt = SpiCnt + 1; 89: SPIBUF[0] = dat; 90:} 91: 92: 93:proc SetCsDisable() { 94: LATA[0] = $0004; 95: SpiSnd( $ff ); 96: TmWait( ByteTimer ); 97:} 98: 99: 100:proc PrnVal( str, val ) { 101: PrnStr_( str ); 102: PrnHex_( val ); 103:} 104: 105: 106:proc main() { 107: var ans,i; 108: 109: init(); 110: 111: LATA[0] = $0004; 112: for ( i=0; i<10; i=i+1 ) { 113: SpiSnd( $ff ); 114: } 115: TmWait( ByteTimer * 2 ); 116: LATA[0] = 0; 117: SpiSnd( $40 ); # CMD0 118: SpiSnd( 0 ); 119: SpiSnd( 0 ); 120: SpiSnd( 0 ); 121: SpiSnd( 0 ); 122: SpiSnd( $95 ); 123: 124: ans = SpiRcvAns(); 125: SetCsDisable(); 126: 127: if ( ans <> 1 ) { 128: PrnVal( "Cmd0Res:", ans ); 129: } else { 130: LATA[0] = 0; 131: SpiSnd( $48 ); # CMD8 132: SpiSnd( 0 ); 133: SpiSnd( 0 ); 134: SpiSnd( 1 ); 135: SpiSnd( $aa ); 136: SpiSnd( $87 ); 137: ans = SpiRcvAns(); 138: if ( ans <> 1 ) { 139: PrnVal( "CMD8 err:", ans ); 140: LATA[0] = $0004; 141: } else { 142: SpiRcvN( 4 ); # 16M:00 00 01 aa 143: SetCsDisable(); 144: if ( (_Buf[2] <> $01) | (_Buf[3] <> $aa ) ) { 145: PrnStr_("SDC not v2" ); 146: } else { 147: do { 148: LATA[0] = 0; 149: SpiSnd( $77 ); # CMD55 150: SpiSnd( 0 ); 151: SpiSnd( 0 ); 152: SpiSnd( 0 ); 153: SpiSnd( 0 ); 154: SpiSnd( $65 ); 155: ans = SpiRcvAns(); 156: if ( ans = 1 ) { 157: SpiSnd( $69 ); # ACMD41 158: SpiSnd( $40 ); 159: SpiSnd( $ff ); 160: SpiSnd( $80 ); 161: SpiSnd( $00 ); 162: SpiSnd( $17 ); 163: ans = SpiRcvAns(); 164: } 165: SetCsDisable(); 166: } while ( ans <> 0 ); 167: LATA[0] = 0; 168: SpiSnd( $7a ); # CMD58 169: SpiSnd( 0 ); 170: SpiSnd( 0 ); 171: SpiSnd( 0 ); 172: SpiSnd( 0 ); 173: SpiSnd( $fd ); 174: ans = SpiRcvAns(); 175: SpiRcvN( 4 ); # 16MB:c0 ff 80 00 176: SetCsDisable(); 177: if ( ans <> 0 ) { 178: PrnVal( "CMD58 err:", ans ); 179: } else { 180: PrnStr_( "SDC V2" ); 181: } 182: } 183: } 184: } 185: LATA[0] = $0004; 186:} :run SDC V2 :


[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。