相変わらず、SDHCなどの高容量タイプで、ACMD41が失敗する問題に悩んで1週間くらい?
ロジックアナライザを繋いで制御ピンの状態を確認するとか、ありとあらゆる方策を試していたが・・・
全く成果無し状態でいた。
電源の状態が悪いのかとかも確認したが、電源のリップルはそれ程多くは無く、許容範囲だった。
RTK5 RX65N Envision Kit では、SD カード電源制御と、電源電圧の確認用に専用のICを使っているが、それは実装されていない為、とりあえず、P チャネルの MOSFET を取り付けて、電源制御を加えてみたりもしたが、全く効果は無い。
※秋月電子で入手出来る「DMG3415U」を使った。
LA2016 には、色々な解析モードが用意されており、それを使う事で、CMDピンで、ホストとスレーブ間でやりとりするデータ列を具体的に確認する事が出来る。
凄く便利で、素晴らしい機能だーー
※今まで、こんなに便利な機能なのに、あまり積極的に使っていなかった、他にも色々と解析が出来るので、これからは重宝すると思う。
これで、確認した限りでは、問題無さそうで、2GのSDカードと8GのSDカードの違いは無さそうだった。
※ただ、SDHCカードでは、BUSYのまま・・・
SD カード関係の正規資料なども、色々読んで、何か間違いが無いかを確認していた。
そんな時、アルテラ社のFPGA向けライブラリでSDIOの説明を見つけ、ACMD41関係の部分を読んでいたら、
> SD_SEND_OP_COND(ACMD41)コマンドを送信します。
> ビット [23:0] = サポートされている電圧範囲
ん?
サポートされている電圧範囲?
現状では、0x000000 を送っている・・・
SPI だと、0x000000 を送っていて、SDHCカードを使えている。
それで、ルネサスの r_sdhi ソースを確認してみると、2.7V から 3.6V の場合、0xFF8000 を設定する事が判った・・・
で、修正してみると、今度は成功する・・・
今までの苦労は何だったのか・・・
まぁ、良くある話ではあるのだが、思い込みで、正規の資料を読んでも、重要な事をスルーしてしまう・・・
まぁ動いたから「ヨシ」とする・・
SDモードでの初期化の手順をまとめると・・・
・SDモードによる初期化手順
(1)CMD0、0x00000000
※複数打った方が良いかもしれない(SDカードは応答を返さない)
(2)CMD8、0x000001AA
※0x100 は電圧範囲(2.7V ~ 3.6V)
※0x0AA は、マッチパターン
(3)CMD8 のステータスで、0x1AA が返れば、SDV2 カード
それ以外の場合、エラー
※CMD8のレスポンスが無い場合、そのカードはCMD8をサポートしておらず、別の初期化シーケンスに切り替える。
これは多分、容量が少ない昔のカードの場合など(自分のドライバーでは、現状、サポートしていない)
(4)ACMD41、0x40FF8000
レスポンスのB31が「1」になるまで投げ続ける。
※1回投げて、1ms 待つ、1000回繰り返しても「1」に成らなければエラーとする。
※レスポンスで、B30が「1」なら、そのカードは、ブロックアクセスを行う。
これは、32 ビットだと 0 ~ 4G までしかアクセス出来ないので、それに対応する方法、このビットが有効なら、read/write はブロックアクセスとなる。
(5)CMD2、0 で CID を取得
(6)CMD3、0 で RCA を取得(B31~B16)
(7)CMD7、RCA でカード選択
(8)CMD16,512 でセクターサイズ設定
(9)ACMD6、0x00000002 で、バス幅を4ビットにする。
※1ビットの場合、0x00000000
(10)SDHI のバス幅を切り替えて、クロック速度をブーストする。
まだ、エラー検査とかがズブズブで、割り込みやDMAに対応していないが、とりあえず、動くようになった・・・
速度はかなり高速で、以下のような感じ~
※GitHub のマスターにマージ済み
QIDIAN MLC 32GB (SDHC) Class10
# write test.bin
disk_ioctl: 00
Open: 0 [ms]
Write: 440393 Bytes/Sec
Write: 430 KBytes/Sec
Close: 5 [ms]
# read test.bin
SD Read test...
Open: 0 [ms]
Read: 1048576 Bytes/Sec
Read: 1024 KBytes/Sec
Close: 0 [ms]
Lexar 633x 8GB (SDHC) Class10
# write test.bin
disk_ioctl: 00
Open: 170 [ms]
Write: 215048 Bytes/Sec
Write: 210 KBytes/Sec
Close: 12 [ms]
# read test.bin
SD Read test...
Open: 2 [ms]
Read: 1302578 Bytes/Sec
Read: 1272 KBytes/Sec
Close: 0 [ms]
SanDisk Industrial 8GB (SDHC) Class10
# write test.bin
disk_ioctl: 00
Open: 3 [ms]
Write: 338359 Bytes/Sec
Write: 330 KBytes/Sec
Close: 98 [ms]
# read test.bin
SD Read test...
Open: 1 [ms]
Read: 1747626 Bytes/Sec
Read: 1706 KBytes/Sec
Close: 0 [ms]
SanDisk Industrial 16GB (SDHC) Class10
# write test.bin
disk_ioctl: 00
Open: 6 [ms]
Write: 397941 Bytes/Sec
Write: 388 KBytes/Sec
Close: 5 [ms]
# read test.bin
SD Read test...
Open: 2 [ms]
Read: 1227840 Bytes/Sec
Read: 1199 KBytes/Sec
Close: 0 [ms]
TOSHIBA 40MB/s Taiwan 32GB (SDHC) Class10
# write test.bin
disk_ioctl: 00
Open: 1 [ms]
Write: 204920 Bytes/Sec
Write: 200 KBytes/Sec
Close: 46 [ms]
# read test.bin
SD Read test...
Open: 1 [ms]
Read: 1091130 Bytes/Sec
Read: 1065 KBytes/Sec
Close: 0 [ms]
SanDisk Industrial 16GB (SDHC) Class10 for Soft-SPI
# write test3.bin
Open: 0 [ms]
Write: 181634 Bytes/Sec
Write: 177 KBytes/Sec
Close: 17 [ms]
# read test3.bin
SD Read test...
Open: 2 [ms]
Read: 232758 Bytes/Sec
Read: 227 KBytes/Sec
Close: 0 [ms]
以下のようにして、SDHIインターフェースを使う場合とSPI(ソフトSPI)を使う場合を切り替えできる。
// カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
// typedef device::NULL_PORT SDC_POWER;
typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
#ifdef SDHI_IF
// RX65N Envision Kit の SDHI ポートは、候補3になっている
typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, device::port_map::option::THIRD> SDHI;
SDHI sdh_;
#else
// Soft SDC 用 SPI 定義(SPI)
typedef device::PORT<device::PORT2, device::bitpos::B2> MISO; // DAT0
typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI; // CMD
typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK; // CLK
typedef device::spi_io2<MISO, MOSI, SPCK> SPI; ///< Soft SPI 定義
SPI spi_;
typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT; // DAT3 カード選択信号
typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT; // CD カード検出
typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC; // ハードウェアー定義
MMC sdh_(spi_, 35000000);
#endif