ロジアナで見たらFT245RLの信号が汚いのでAVRでやろうかと思ったけれど、これ以上SDカードに時間をかけるのも嫌と思って、FT245RLの制御をもうちょっと頑張ってみた。
まず、クロックが汚いので、ウェイトを入れることにした。time.sleep()の精度は4 msなんでしたっけ。クロックの変化の間に、4 msよりも小さいwaitをかけてみたら、6 msくらいの間が入っていい感じになった。綺麗になったクロックがこちら。
それで次の問題を探したら、どうもリセットコマンドCMD0の後に電源が落ちてるぽい。ので、リセットを二回連続で発行してみた。二回目のリセットの後は電源が落ちなくなったようだが、それでもうまく読み書きができない。根本的に解決をしようと、電源をFT245RLのIOピンからでなく、3V3OUTピンから頂くことにしました。そしたら書き込みできるようになりました。
無事、SEND_STATUS CMD13の返り値が0になった様子。
512
crc: 0x00
< 0
0b11100101 data accepted.
wait for releasing busy state (DO = 1)
cmd13, SEND_STATUS
< 4d
< 0
< 1
> ff
> 0
r2: 0
wait 8bit with CS = 1: ff
セクタ0を"Hello, world!"で埋めれたのをwindows 7上でダンプして確認。
pythonコードはこちら
from pylibftdi import BitBangDevice, Bus
import time
class sd(object):
"""
The FT245R is wired to the SD as follows:
DB0 to DI
DB1 to D0
DB2 to CLK
DB3 to CS
DB4 to POW
"""
DI = Bus(0)
DO = Bus(1)
CLK = Bus(2)
CS = Bus(3)
POW = Bus(4)
def __init__(self, device):
# The Bus descriptor assumes we have a 'device'
# attribute which provides a port
self.device = device
def _trigger(self, n = 1):
"generate a H->L"
for _ in range(n):
#self.CLK = 0
self.CLK = 1
self.CLK = 0
def _getDO(self): #read when clk down -> up mode 0
#self.CLK = 0
self.CLK = 1 #up
time.sleep(0.0001)
do = self.DO #read
self.CLK = 0
return do
def _putDI(self, di):
#self.CLK = 0
self.DI = di #write
self.CLK = 1 #up
time.sleep(0.0001)
self.CLK = 0
def _write_raw(self, byte, l = 8):
for i in range(l):
di = (byte >> (l-1-i)) & 0b1
self._putDI(di)
print "< %x" % byte
# print
def _read_raw(self, l = 8):
res = 0
for i in range(l):
do = self._getDO()
#print "%d" % do
res += do << (l-1-i)
return res
def read_res(self, l = 1):
#print "read_res (timeout >= 8 byte)"
for i in range(8):
res = self._read_raw()
print " > %x" % res
if res != 0xFF:
for _ in range(l-1):
res = (res << 8) + self._read_raw()
break
return res
def _wait_sd(self):
self.CS = 1
print "wait 8bit with CS = 1: %x" % self._read_raw(8)
#self._trigger(8*8)
self.CS = 0
def write_cmd(self, cmd, addr, crc): #cmd 6bit, addr 8x4bit, crc7bit
#cmd
self._write_raw(0b01000000 + cmd)
#addr
#for i in range(4):
# self._write_raw((addr >> (3-i)*8) & 0xff)
self._write_raw(addr, 8*4)
#CRC
self._write_raw(0b1 + (crc << 1))
#up
#self.DI = 1 #stop bit is always 1
#print "DI after cmd: ", self.DI
def init_spi(self):
self.POW = 0
self.DI = 0
self.CS = 0
self.CLK = 0
time.sleep(0.1)
print "power on and wait > 1ms"
self.POW = 1
self.CS = 0
#self._trigger(100)#more than 74 times
time.sleep(0.001)
print "dummy clock >= 74 with CS and DI high"
self.CS = 1
self.DI = 1
self._trigger(100)#more than 74 times
#self._wait_sd()
#time.sleep(0.001)
print "CMD0 with CS low"
self.CS = 0
while 1:
self.write_cmd(0, 0, 0b1001010)
if self.read_res() == 0b1:
print "cmd0 ok (response == 1)"
#self._wait_sd()
break
self._trigger(8)#more than 74 times
print "CMD0 with CS low"
self.CS = 0
while 1:
self.write_cmd(0, 0, 0b1001010)
if self.read_res() == 0b1:
print "cmd0 ok (response == 1)"
#self._wait_sd()
break
#cmd 8?
#print "cmd 8 (chk SD Ver.2)"
#self.write_cmd(8, 0x000001aa, 0x43)
#if self.read_res() == 0x01:
# print "SDC V2"
# if self.read_res(4) != 0x000001aa:
# print "card mismatch"
# exit()
#self._wait_sd()
type = 1 #if cmd1 is used, host cannot distinguish MMC or SD
#cmd1
if type == 0:
print "cmd1"
while 1:
self.write_cmd(1, 0, 0)
if self.read_res() == 0b0:
break
print "cmd1 ok (res == 0)"
self._wait_sd()
#cmd55
else:
print "ACMD41"
while 1:
#print "CMD55"
self.write_cmd(55, 0, 0)
if self.read_res() == 0b1:
#print "wait 8bit..: %x" % self._read_raw(8)
#print "cmd55 ok (response == 1)"
#print "CMD41"
self.write_cmd(41, 0x40000000, 0)
if self.read_res() == 0b0:
print "ACMD41 ok (response == 0)"
#print "wait 8bit..: %x" % self._read_raw(8)
break
"""
def _wait_DO_0(self, timeout = 8):
for i in range(timeout*8):
do = self._getDO()
print "%d" % do,
if (do == 0):
break
if (i == timeout*8-1):
print "timeout"
sys.exit()
"""
def single_read(self, addr, l = 512):
#cmd17
print "single read CMD17, addr: %x" % addr, "len: %d" % l
while 1:
self.write_cmd(17, addr, 0)
if self.read_res() == 0b0:
print "cmd17 ok, response: 0"
break
#start 0xfe
while (self.read_res() != 0xfe): #_wait_DO_0()
pass
print "start data"
#f = open('sdout.bin', 'wb')
#for i in range(16):#byte
# for j in range(32):#byte
for i in range(l):
c = self._read_raw()
print "%x" % c,
#f.write(chr(c))
if i%32==31:
print
#f.close()
print "crc: %x" % self._read_raw(8*2)
self._wait_sd()
# print "wait 8bit..: %x" % self._read_raw(8)
def single_write(self, addr, l = 512):
print "single write CMD24, addr: %d" % addr, "len: %d" % l
while 1:
self.write_cmd(24, addr, 0)
if self.read_res() == 0b0:
print "cmd24 ok, response: 0"
break
print "wait >= 1 byte"
self._trigger(8)
self._write_raw(0xfe) #data token
print "send data"
#f = open('sdout.bin', 'wb')
text = "Hello, world!"
for i in range(l / len(text)):
for c in text:
self._write_raw(ord(c))
print c, bin(ord(c))
print i
#fill 0xff
#for i in range(512):#range(l % len(text)):
self._write_raw(0, (l % len(text))*8)
print (l/len(text))*len(text) + l % len(text)
#crc
#print "crc: %x" % self._read_raw(8*2)
print "crc: 0x00"
self._write_raw(0, 8*2)
self.DI = 1
#self._trigger(8*2)
#responce
#self._wait_DO_0()
res = self._read_raw()
if (res & 0b00011111) == 0b00101:
print bin(res), "data accepted."
else:
print bin(res), "error."
print "wait for releasing busy state (DO = 1)"
while self._read_raw() != 0x0:
print " > busy..."
#print "busy? %x" % res
#res = self._read_raw()
#print "busy? %x" % res
#res = self._read_raw()
#print "busy? %x" % res
# print "do is 1"
# break
#self._wait_sd()
#self._wait_sd()
#print "wait 8bit..: %x" % self._read_raw()
#print "wait 8bit..: %x" % self._read_raw()
#self.get_status()
def set_blocklen(self, l):
#cmd16
print "set blocklen cmd16 len: %d" % l
while 1:
self.write_cmd(16, l, 0)
if self.read_res() == 0b0:
break
print "cmd16 ok, response: 0"
def multi_read(self, addr):
#cmd18
print "cmd18, addr: %d" % addr
while 1:
self.write_cmd(18, addr, 0)
if self.read_res() == 0b0:
break
print "cmd18 ok, response: 0"
f = open('sdout.bin', 'wb')
for j in range(10):
self._wait_DO_0()
print "start data"
for i in range(512):#byte
c = self._read_raw(8)
print "%x" % c,
f.write(chr(c))
if i%32==0:
print
#crc
print "crc:", self._read_raw(8*2)
f.close()
self.POW = 0
def get_status(self):
print "cmd13, SEND_STATUS"
self.write_cmd(13, 0, 0)
#r2
print "r2: %x" % self.read_res(2) #p.96, 92
#self._wait_sd()
self._wait_sd()
print "wait 8bit..: %x" % self._read_raw(8)
def get_ocr(self):
print "cmd58, READ_OCR"
self.write_cmd(58, 0, 0)
#r3
print "r3: %x" % self.read_res(5) #p.37, 92
print "wait 8bit..: %x" % self._read_raw(8)
def get_cid(self):
print "cmd10, SEND_CID"
#r1, 128/8 byte
while 1:
self.write_cmd(10, 0, 0)
r1 = self.read_res() #p.38, 92
print "r1: %x" % r1
if r1 == 0:
break
while (self.read_res() != 0xfe):
pass
for i in range(16):
c = self._read_raw()
print "%x" % c,
print
print "crc: %x" % self._read_raw(8*2)
print "wait 8bit..: %x" % self._read_raw(8)
def get_csd(self):
print "cmd9, SEND_CSD"
self.write_cmd(9, 0, 0)
#r1, 128/8 byte = 16 byte
print "r2: %x" % self.read_res(2) #p.39
def power_off(self):
self.POW = 0
def display(device_id=None):
with BitBangDevice(device_id) as bb:
# the actual baudrate is 16x this in bitbang mode...
#bb.baudrate = 307200, 153600, 76800, 38400, 19200, 9600, 4800
bb.baudrate = 9600
print bb.baudrate
#bb.ftdi_fn.ftdi_set_latency_timer(1)
bb.direction = 0b00011101
#bb.port = 0x00 #output (not pullup)
sdc = sd(bb)
sdc.init_spi()
print "complete init"
sdc.single_write(0)
sdc.get_status()
sdc.single_read(0x0)
sdc.get_status()
if __name__ == '__main__':
import sys
display()