稼働中

マイクロビット(e_24)SDカード モジュール(3)書込み CMD24 消去 CMD32

SDカードのシングルブロック書込み CMD24、消去 CMD32

前回に続いてmicro:bitを使ったSDカードのシングルブロック書込みと消去について記載します。
※thonny-microbitのMicroPythonを使っています。

CDM24 WRITE_BLOCK

CMD24(WRITE_BLOCK)でシングルブロックを書込みます。単一ブロックは512バイトです。CMD16(SET_BLOCKLEN)で変更が可能です。

CDM24を送信し、応答(R1)を待ってから、開始トークン(0xFE)を送信し、続いて512バイトのデータを送信します。さらに、データ後に2バイトのCRCを送ります。ここのCRCは何でも良いようです。

CMD17(READ_SINGLE_BLOCK)と同じく、512バイトをブロックで書き込みします。
32ビットアドレスはHigh Capacity SD Cards(2GB<)はブロック単位、Standard Capacity Cards(<=2GB)はバイト単位なので512バイトの倍数で指定します。 正常に書込みが終わるとData Responseが返ります。レスポンス値と'0x1f'と積で評価します。’0x05'で正常です。 data-response
※Physical Layer Simplified Specification Version 2.00から引用

スクリプト

以下のようなスクリプトにしました。※関数部分は先と同じなので省略して記載しています。
ここでは512番から書込みます。
書込みテストのデータは0x00~0xffを2回の512バイトとしました。


# SPI init bps=100kHz
spi.init(baudrate=100000, bits=8, mode=0, sclk=pin13, mosi=pin15, miso=pin14)
sleep(10)
# command
cmd24=0x58              #WRITE_BLOCK
# Write Data 512byte (00~256) x2    書込みテストデータ 0x00~0xff を2回
block_buf=bytearray(512)
for i in range(512):
    if i <= 256:
        block_buf[i]=i
    else:
        block_buf[i]=i-256
sleep(100)
#
#-------------------------------------------CMD24 (SDHC)
print('cmd24 WRITE_BLOCK START')
# SPI MODE
CS(1)
for i in range(10):
    spi_ff()
CS(0)
#
spi_ff()
spi_cmd(cmd24,0x00,0x00,0x02,0x00,0x01)
while True:
    #spi_ff()
    res=spi_res()
    if res== b'\x00':           # 異常なし
        print('cmd24 OK')
        break
spi_ff() 
spi.write(b'\xfe')      #Start Block Token
spi.write(block_buf)    #512バイトデータを送ります
spi.write(b'\x00') #//Send CRC1
spi.write(b'\x01') #//Send CRC2
#
cnt=0
while True:
    cnt=cnt+1
    res=spi_res()
    re=res[0] & 0x1f    # データレスポンス 0x05でOK
    if re==0x05:
        print('write-ok res=5',res,bin(res[0]))
        break
    if cnt>10:
        print('WRITE-NG',cnt)
        sys.exit()
#end
spi_ff()
CS(1)
spi_ff()

#end
spi_ff()
CS(1)
spi_ff()

実行結果

実行結果です。Thonnyのshell枠に表示されます。

SDHCカード
SDHC 16GBのカードに書込みました。


>>> %Run 220113_sd_b01_cmd24_01.py
cmd24 WRITE_BLOCK START
b'\xff'
b'\x00'
cmd24 OK
b'\xe5'             # データレスポンス
write-ok res=5 b'\xe5' 0b11100101   # 正常に書込みが完了
>>> 

先のCMD17のスクリプトを実行して書込みを確認します。
書込み出来ているようです。


>>> %Run 220113_sd_b01_cmd17.py
cmd17 READ_SINGLE_BLOCK START
b'\x00'
cmd17 pass >>
b'\xfe'
token OK 0xfe
read_block_address= bytearray(b'\x00\x00\x02\x00') 512bytes= b'\x00\x01\x02\x03\x04
\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\
省略
\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\
x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@AB
省略
\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'  CRC2= b'@\xda'
>>> 

標準SDカード
同様に初期化済みの標準SD 1GBカードに書き込んでみます。
実行結果です。エラーになりました。


>>> %Run 220113_sd_b01_cmd24_01.py
cmd24 WRITE_BLOCK START
b'\xff'
b'\x00'
cmd24 OK
b'\x00'
b'\x07'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
b'\xff'
WRITE-NG 11     #10回繰り返したが正値が戻らなかった

先のCMD17のスクリプトを実行して書込みされたデータを見てみると・・


>>> %Run 220113_sd_b01_cmd17.py
cmd17 READ_SINGLE_BLOCK START
b'\x00'
cmd17 pass >>
b'\xff'
b'\xfe'
token OK 0xfe
read_block_address= bytearray(b'\x00\x00\x02\x00') 512bytes= b'\x7f\xff\x00\x00\x81\x01\
x82\x02\x83\x03\x84\x04\x85\x05\x86\x06\x87\x07\x88\x08\x89\t\x8a\n\x8b\x0b\x8c\x0c\x8d\r
省略
\xf1q\xf2r\xf3s\xf4t\xf5u\xf6v\xf7w\xf8x\xf9y\xfaz\xfb{\xfc|\xfd}\xfe~'  CRC2= b'\xecr'
>>> 

それらしきデータは書込まれていますが、何故かしら書込みデータが違うです。
例えば、ブロックデータの頭に不要な’\x7f\xff\’があります。
理由は分かりませんが、先のスクリプトでCMD24のレスポンス評価の部分(while文の部分)を削除すると
上手く書込めました。


削除部分
while True:
    #spi_ff()
    res=spi_res()
    if res== b'\x00':           # 異常なし
        print('cmd24 OK')
        break
spi_ff() 

while文の部分を削除したスクリプトの実行結果です。正常に書込めたようです。


>>> %Run 220113_sd_b01_cmd24_02.py
cmd24 WRITE_BLOCK START
b'\xe5'
write-ok res=5 b'\xe5' 0b11100101
>>> 

CMD17のスクリプトで書込みデータ確認します。
結果です。


>>> %Run 220113_sd_b01_cmd17.py
cmd17 READ_SINGLE_BLOCK START
b'\x00'
cmd17 pass >>
b'\xff'
b'\xfe'
token OK 0xfe
read_block_address= bytearray(b'\x00\x00\x02\x00') 512bytes= b'\x00\x01\x02\x03\x04
省略
\xfd\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\
省略
\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'  CRC2= b'@\xda'
>>> 

CDM32 ERASE

CDM32(ERASE_WR_BLK_START_ADDR)>CMD33(ERASE_WR_BLK_END_ADDR)>CMD38(ERASE Erases) でブロックを消去します。単一ブロックは512バイトです。
CDM32、CMD33で各々消去の最初、最後のブロックアドレスを指定してCMD38で消去を実行します。各コマンドのレスポンスは1バイトです。

スクリプト

以下のようなスクリプトにしました。※関数部分は先と同じなので省略して記載しています。
ここでは0x00から0x0200まで消去します。
カードはSDHC 16GBを使いました。ACMD41のスクリプトで初期化し、CMD24のスクリプトで0x00から0x0400には0x00~0xffのデータを繰返しで書込んでいます。


# SPI init bps=100kHz
spi.init(baudrate=100000, bits=8, mode=0, sclk=pin13, mosi=pin15, miso=pin14)
sleep(10)
# command
cmd32=0x60    #ERASE_WR_BLK_START_ADDR R1
cmd33=0x61    #ERASE_WR_BLK_END_ADDR   R1
cmd38=0x66    #ERASE  Erases           R1b
# power up sqc
print('CLK >= 80 out')
CS(1)
for i in range(10):
    spi_ff()
CS(0)
spi_ff()
#
## BLK_ERASE_START
# --------------------------------------------- CMD32 BLK_START_ADD

spi_ff()
sadr=spi_cmd(cmd32,0x00,0x00,0x00,0x00,0x01)
s_adr=sadr[1:5]             # start adr
spi_ff() 
res=spi_res(1)
if res != b'\x00':
   print('CMD32 START ADD SET ERROR',res)
   sys.exit()
# --------------------------------------------- CMD33 BLK_END_ADD
spi_ff()
e_adr=spi_cmd(cmd33,0x00,0x00,0x02,0x00,0x01)
e_adr=e_adr[1:5]             # end adr 
spi_ff() 
res=spi_res(1)
if res != b'\x00':
   print('CMD33 END ADD SET ERROR',res)
   sys.exit()
    
# --------------------------------------------- CMD38 ERASE
spi_ff()
spi_cmd(cmd38,0x00,0x00,0x00,0x00,0x01) 
spi_ff() 
res=spi_res(1)
if res != b'\x00':
   print('CMD38 ERASE ERROR',res)
   sys.exit()
print('ERASE OK DONE')
print('START ADD',s_adr)
print(' END  ADD',e_adr)
#end
spi_ff()
CS(1)
spi_ff()

実行結果

実行結果です。※Thonnyのshell枠に表示されます。
SDHC 16GBカード
消去時の表示です。異常なく消去できたようです。


>>> %Run 220117_sd_cmd32_erase_01.py
CLK >= 80 out
resp= b'\x00'
resp= b'\x00'
resp= b'\x00'
ERASE OK DONE
START ADD bytearray(b'\x00\x00\x00\x00')
 END  ADD bytearray(b'\x00\x00\x02\x00')

CMD17のスクリプトでデータを確認しました。略記します。
spi_cmd(cmd17,0x00,0x00,0x00,0x00,0x01) 全て空
spi_cmd(cmd17,0x00,0x00,0x02,0x00,0x01) 全て空
spi_cmd(cmd17,0x00,0x00,0x04,0x00,0x01) 全て残
で指定のアドレスで消去ができていました。

標準SD 1GBカード
標準SD 1GBカードの場合です。各コマンドでエラーが出ました。


>>> %Run 220117_sd_cmd32_erase_01.py
CLK >= 80 out
resp= b'\xff'
CMD32 START ADD SET ERROR b'\xff'

コマンドのレスポンスがエラーの場合にコマンド送信を繰り返すようにスクリプトを変更して試しました。※上手く動作しなかったのでスクリプトは記載してません。
実行すると各コマンドが数回繰返し送信され、表面上はエラー無く終了しました。
しかしながら、CMD17のスクリプトでデータを確認すると’0xfe’のトークンが返らずエラーになりました。
どこか問題があるのだと思いますが分かりませんでした。素人レベルの限界です。そのため2GB以下の標準SDカードの消去はできませんでした。一斉に消去はできませんが消去が必要な場合はCMD24のスクリプトを使って上書きして消去することにしました。

まとめ

SDカードの操作はまだまだ奥が深いようです。私は素人レベルなのでこのへんが限界です。とりあえずmicro:bitでSDカードの初期化、読み書き、消去ができるようになりました。機会があれば何かのデータをSDカードに記録してみようと思います。
※参考にしたサイト
AVRCチュートリアル「http://www.rjhcoding.com/avrc-tutorials-home.php」
PICを使ってSDカードを操作「http://bitcraft.web.fc2.com/embedded/microchip/microchip.html#sdhcinit」
A33FでMicroSDカードにアクセスしてみる「http://www.robotsfx.com/robot/robohow/RoboHow91/RoboHow91.html」