Raspberry Pi Pico(s_19)SDカード 用モジュール
SD Card SDc.py
SDカードモジュールはデジタル温湿度センサーです。※詳細はSDカードのデータシート等を参照ください。
Raspberry Pi PicoでSDカードモジュールを使う自作の’SDc.py’を作成しました。記事d_24を元に作成しています。
‘SDc.py’は末尾にあります。使い方だけを記載します。
使い方
■ ファイル転送
Raspberry Pi Picoへ’SDc.py’を送った後でimportして使います。
※SDc.pyの末尾に、使用例(SDc_ex.py)の## example以降をコピペ追加しても動作確認できます。
■ メソッド
‘SDc’をimportすると「SD_Init、SD_Read、SD_Write、SD_Waddr、SD_ERASE、SPI_MODE、CMD_58」のメソッドが使えるようになります。
SDC(spi_num=1,cs_num=13)で初期化します。
spi_num:使用するSPI0、SPI1の番号(0,1)です。
cs_num:CSに使うGPIO番号です。
spi_numとcs_numを設定すれば、RX, SCK, TXは指定されます。
SPI0、SPI1の[RX, Csn, SCK, TX]のGPIO番号リストは以下になります。
#SPI0 [ 0, 1, 2, 3] [ 4, 5, 6, 7] [16,17,18,19]
#SPI1 [ 8, 9,10,11] [12,13,14,15]
※RX(MISO), TX(MOSI)
(01)SD_Init()
SDC、SDHCを初期化します。
(02)SD_Read(r=[0x00,0x00,0x00,0x00])
32bit[0x00,0x00,0x00,0x00]で与えたアドレスから読み出します。
SDHCは512bytesブロックのアドレスになります。(※以下も同様)
(03)SD_Waddr(w=[0x00,0x00,0x00,0x00])
32bit[0x00,0x00,0x00,0x00]で書き込むアドレスを指定します。
(04)SD_Write(buf)
指定されたアドレスのバイトアレイデータ(512bytes)を書き込みます。
(05)SD_ERASE(es,ee)
指定したアドレスのデータを消去します。
es=[0x00,0x00,0x00,0x00]の形式で消去開始アドレスを指定します。
ee=[0x00,0x00,0x00,0x00]の形式で消去終了アドレスを指定します。
(06)ERASE_END(e=[0x00,0x00,0x02,0x00])
32bit[0x00,0x00,0x00,0x00]で消去終了アドレスを指定します。
(07)CS(dat)
CSピンの状態(0,1)を与えます。CS(0)でSPIデバイス指定されます。
(08)SPI_MODE()
SDカードをSPIモードにします。実行後はCS(0)になります。
(09)CMD_58()
OCR(Operation conditions register)の値が返ります。
(10)CMD_16()
SET_BLOCKLEN(CMD16)を実行します。ブロック長を512bytesにします。
使用例
MCP4725で温湿度を測定します。
SDc_ex.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from SDCc import SDC
## exapmle
a=SDC(1,13) #SDC(spi_num=1,cs_num=13) CS='1'
# SD SDHC card init SPI-MODE
a.SD_Init()
# 書込むデータ512byte 全部同じ 0x02
block_buf=bytearray(512)
for i in range(512):
block_buf[i]=0x02
# write ---------------------CMD24
# 32bit address
w_adr=[0x00,0x00,0x02,0x00] #BLK_WRITE_ADD
a.SD_Waddr(w_adr) #アドレスセット
a.SD_Write(block_buf) #書込み
# read ---------------------CMD17
r_adr=[0x00,0x00,0x02,0x00] #BLK_READ_ADD
r_dat,r_crc=a.SD_Read(r_adr) #読出し
print(r_dat)
print(r_crc)
# erase ---------------------CMD32-33-38
s_adr=[0x00,0x00,0x00,0x00] #BLK_END_ADD
e_adr=[0x00,0x00,0x04,0x00] #BLK_START_ADD
a.SD_ERASE(s_adr,e_adr) #消去
実行結果
実行すると以下のようになりました。※Thonnyのshellに表示されます。
>>> %Run -c $EDITOR_CONTENT
INIT SDHC #SDHCを初期化
WRITE_BLOCK #0x02を512書込み
READ _BLOCK
b'\x02\x02\x02\x02\x02\x02\x02\ #0x02を512を読出し
省略
\x02\x02\x02\x02'
b'\xd7}' #CRC16 読出し
ERASE START ['0x00', '0x00', '0x00', '0x00'] #消去区間を表示
ERASE END ['0x00', '0x00', '0x04', '0x00']
>>>
実行後にThonnyのshellでデータを確認すると消去されているのが分かります。
SDカードモジュール用
SDc.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from machine import SPI, Pin
import sys
import time
class SDC:
def __init__(self,spi_num=0,cs_num=1):
self.spi = SPI(spi_num, baudrate=1000_000,sck=Pin(cs_num+1),
mosi=Pin(cs_num+2), miso=Pin(cs_num-1))
#Chip Select Pin
self.CS_pin=Pin(cs_num, mode=Pin.OUT, value=1)
# CMD INIT
self.cmd0=0x40 #GO_IDLE_STATE
self.cmd1=0x41 #SEND_OP_CND
self.cmd8=0x48 #SEND_IF_COND
self.cmd16=0x50 #SET_BLOCKLEN
self.cmd55=0x77 #APP_CMD
self.cmd58=0x7A #READ_OCR
self.acmd41=0x69 #SD_APP_OP_COND
# CMD ERASE
self.cmd32=0x60 #ERASE_WR_BLK_START_ADDR R1
self.cmd33=0x61 #ERASE_WR_BLK_END_ADDR R1
self.cmd38=0x66 #ERASE Erases R1b
# CMD READ
self.cmd17=0x51 #READ_SINGLE_BLOCK
# CMD WRITE
self.cmd24=0x58 #WRITE_BLOCK
# Chip Select CS(0)
def CS(self,dat):
self.CS_pin.value(dat)
# Card send data
def spi_cmd(self,cmd,da1,da2,da3,da4,crc):
buf=bytearray(6)
buf[0]=cmd
buf[1]=da1
buf[2]=da2
buf[3]=da3
buf[4]=da4
buf[5]=crc
self.spi.write(buf)
return buf
# response
def spi_res(self,num=1):
response=self.spi.read(num)
return response
# dummy clock
def spi_ff(self):
self.spi.write(b'\xff')
# spi end
def spi_end(self):
self.spi_ff()
self.CS(1)
self.spi_ff()
## SDC INIT START
def SPI_MODE(self):
#print('SPI MODE')
self.CS(1) #CS=Hでダミークロックを80個送信
for i in range(10):
self.spi_ff()
# CS select
self.CS(0) #カード選択
self.spi_ff()
##(1)SD-SDHC INIT
# GO_IDLE_STATE CMD00
def CMD_00(self):
self.CS(0)
self.spi_ff()
self.spi_cmd(self.cmd0,0x00,0x00,0x00,0x00,0x95)
cnt=0
while True:
cnt=cnt+1
self.spi_ff()
res=self.spi_res()
if res== b'\x01':
#print('CMD0 OK')
#pass
#return
break
if cnt>10:
print('CMD0-NG')
sys.exit()
# SEND_IF_COND CMD08
def CMD_08(self):
self.spi_ff()
self.spi_cmd(self.cmd8,0x00,0x00,0x01,0xAA,0x87)
self.spi_ff()
#R7(5bytes)=R1+4bytes
res=self.spi_res(5)
#print('R7=',res)
if (res[0]== 0x01) or (res[0]== 0x00):
return 1 #Card='HC'
else:
#print('CMD8 ERROR')
return 0 #Card='SD'
# APP_CMD CMD55
def CMD_55(self):
#print('CMD55')
self.spi_ff()
self.spi_cmd(self.cmd55,0x00,0x00,0x00,0x00,0x01)
self.spi_ff()
res=self.spi_res()
if res == b'\x01':
#print('CMD55 Pass)
pass
else:
print('CMD55 ERROR')
sys.exit()
# SD_SEND_OP_COND ACMD41
def CMD_ACMD41(self):
#print('ACMD41')
self.spi_ff()
self.spi_cmd(self.acmd41,0x40,0x00,0x00,0x00,0x01)
self.spi_ff()
res=self.spi_res(1)
if res == b'\x00':
return (0)
# SEND_OP_CND CMD01
def CMD_01(self):
cnt=0
while True:
cnt=cnt+1
self.spi_ff()
self.spi_cmd(self.cmd1,0x00,0x00,0x00,0x00,0x01)
self.spi_ff()
res=self.spi_res()
if res== b'\x00':
break
if cnt>10:
print('CMD01 ERROR')
sys.exit()
## SDC SDHC Initialize
# CMD0>CMD8>CMD55>ACMD41, CMD0>CMD1
def SD_Init(self):
global Card
#self.Card
self.SPI_MODE()
self.CMD_00()
SEND_IF_COND=self.CMD_08()
# CMD8 NG SD <=2GB Init if SEND_IF_COND == 0: Card='SD' self.CMD_00() self.CMD_01() print('INIT SDC') # CMD8 Pass SDHC elif SEND_IF_COND == 1: Card='HC' while True: self.CMD_55() if self.CMD_ACMD41()==0: print('INIT SDHC') break else: print('CARD ERROR') sys.exit() #end self.spi_end() self.CS(0) ##(2)ERASE #BLK_START_ADD CMD32 def ERASE_START(self,s=[0x00,0x00,0x00,0x00]): # CS select self.CS(0) self.spi_ff() self.spi_cmd(self.cmd32,s[0],s[1],s[2],s[3],0x01) self.spi_ff() res=self.spi_res(1) if res != b'\x00': print('CMD32 ERROR') sys.exit() #end self.spi_end() #BLK_END_ADD CMD33 def ERASE_END(self,e=[0x00,0x00,0x02,0x00]): self.CS(0) self.spi_ff() self.spi_cmd(self.cmd33,e[0],e[1],e[2],e[3],0x01) self.spi_ff() res=self.spi_res(1) if res != b'\x00': print('CMD33 ERROR') sys.exit() #end self.spi_end() # ERASE CMD38 def ERASE_GO(self): self.CS(0) self.spi_ff() self.spi_cmd(self.cmd38,0x00,0x00,0x00,0x00,0x01) self.spi_ff() res=self.spi_res(1) if res != b'\x00': print('CMD38 ERROR') sys.exit() #end self.spi_end() def SD_ERASE(self,es,ee): self.SPI_MODE() self.ERASE_START(es) self.ERASE_END(ee) self.ERASE_GO() print('ERASE START',['{:#04x}'.format(i) for i in es]) print('ERASE END ',['{:#04x}'.format(i) for i in ee]) #end self.spi_end() time.sleep_ms(250) ##(3)READ # READ_SINGLE_ BLOCK CMD17 def SD_Read(self,r=[0x00,0x00,0x00,0x00]): #print('cmd17 READ_SINGLE_BLOCK START') # CS select self.CS(0) # time.sleep_ms(5) # self.spi_ff() # radr=self.spi_cmd(self.cmd17,r[0],r[1],r[2],r[3],0x01) # 0x00>0xfeが返るまで受信
cnt=0
while True:
cnt=cnt+1
self.spi_ff() # CMD>>0xFF out >>read response
res=self.spi_res()
if res== b'\x00':
time.sleep_ms(5) #
break
if cnt>10:
print('CMD17 ERROR')
sys.exit()
cnt=0
while True:
cnt=cnt+1
res=self.spi_res()
if res== b'\xfe':
break
if cnt>10:
print('token ERROR')
sys.exit()
print('READ _BLOCK')
block_buf=self.spi.read(512)
#CRC16 2byte read
crc_buf=self.spi.read(2)
#end
self.spi_end()
time.sleep_ms(300)
return block_buf,crc_buf
##(4)WRITE
# WRITE_BLOCK CMD24
def SD_Waddr(self,w=[0x00,0x00,0x00,0x00]):
# CS select
self.CS(0)
self.spi_ff()
self.spi_cmd(self.cmd24,w[0],w[1],w[2],w[3],0x01)
# 標準SDはCMD24の応答を確認せずに書込む
if Card=='HC':
cnt=0
while True:
cnt=cnt+1
res=self.spi_res()
if res== b'\x00':
break
if cnt>10:
print('CMD24 ERROR')
sys.exit()
def SD_Write(self, buf): #
#スタートバイト 0xFE を送ってからWriteデータを送る
self.spi_ff() #One byte gap
self.spi.write(b'\xfe') #Start Block Token
#512バイトデータを送ります
self.spi.write(buf)
cnt=0
while True:
cnt=cnt+1
res=self.spi_res()
re=res[0] & 0x1f # data response XXX1???1
if re==0x05:
print('WRITE_BLOCK')
break
if cnt>10:
print('WRITE ERROR')
sys.exit()
#end
self.spi_end()
##(5) READ_OCR CMD58
def CMD_58(self):
self.spi_ff()
self.spi_cmd(self.cmd58,0x00,0x00,0x00,0x00,0x01)
self.spi_ff()
res=self.spi_res(5)
if (res[0]== 0x01) or (res[0]== 0x00):
print('CMD58')
print('R1(1byte)+OCR(4bytes)=',res)
else:
print('CMD58 ERROR')
sys.exit()
##(6)SET_BLOCKLEN CMD16
def CMD_16(self):
cap='512bytes'
cnt=0
self.CS(0)
self.spi_ff()
self.spi_cmd(self.cmd16,0x00,0x00,0x02,0x00,01)
while True:
cnt=cnt+1
res=self.spi_res()
if res== b'\x00':
print(res,'CMD16',cap)
break
if cnt>10:
print('CMD16 ERROR')
sys.exit()
# spi end
self.spi_end()