kopia lustrzana https://github.com/micropython/micropython
drivers/sdcard: Add support for multi-block read/write; add SD test.
rodzic
67e8108345
commit
2bd758fe96
|
@ -25,6 +25,9 @@ class SDCard:
|
||||||
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
||||||
#R1_ADDRESS_ERROR = const(1 << 5)
|
#R1_ADDRESS_ERROR = const(1 << 5)
|
||||||
#R1_PARAMETER_ERROR = const(1 << 6)
|
#R1_PARAMETER_ERROR = const(1 << 6)
|
||||||
|
TOKEN_CMD25 = const(0xfc)
|
||||||
|
TOKEN_STOP_TRAN = const(0xfd)
|
||||||
|
TOKEN_DATA = const(0xfe)
|
||||||
|
|
||||||
def __init__(self, spi, cs):
|
def __init__(self, spi, cs):
|
||||||
self.spi = spi
|
self.spi = spi
|
||||||
|
@ -136,6 +139,18 @@ class SDCard:
|
||||||
self.spi.send(0xff)
|
self.spi.send(0xff)
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
def cmd_nodata(self, cmd):
|
||||||
|
self.spi.send(cmd)
|
||||||
|
self.spi.send_recv(0xff) # ignore stuff byte
|
||||||
|
for _ in range(CMD_TIMEOUT):
|
||||||
|
if self.spi.send_recv(0xff)[0] == 0xff:
|
||||||
|
self.cs.high()
|
||||||
|
self.spi.send(0xff)
|
||||||
|
return 0 # OK
|
||||||
|
self.cs.high()
|
||||||
|
self.spi.send(0xff)
|
||||||
|
return 1 # timeout
|
||||||
|
|
||||||
def readinto(self, buf):
|
def readinto(self, buf):
|
||||||
self.cs.low()
|
self.cs.low()
|
||||||
|
|
||||||
|
@ -154,11 +169,11 @@ class SDCard:
|
||||||
self.cs.high()
|
self.cs.high()
|
||||||
self.spi.send(0xff)
|
self.spi.send(0xff)
|
||||||
|
|
||||||
def write(self, buf):
|
def write(self, token, buf):
|
||||||
self.cs.low()
|
self.cs.low()
|
||||||
|
|
||||||
# send: start of block, data, checksum
|
# send: start of block, data, checksum
|
||||||
self.spi.send(0xfe)
|
self.spi.send(token)
|
||||||
self.spi.send(buf)
|
self.spi.send(buf)
|
||||||
self.spi.send(0xff)
|
self.spi.send(0xff)
|
||||||
self.spi.send(0xff)
|
self.spi.send(0xff)
|
||||||
|
@ -176,29 +191,62 @@ class SDCard:
|
||||||
self.cs.high()
|
self.cs.high()
|
||||||
self.spi.send(0xff)
|
self.spi.send(0xff)
|
||||||
|
|
||||||
|
def write_token(self, token):
|
||||||
|
self.cs.low()
|
||||||
|
self.spi.send(token)
|
||||||
|
self.spi.send(0xff)
|
||||||
|
# wait for write to finish
|
||||||
|
while self.spi.send_recv(0xff)[0] == 0:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.cs.high()
|
||||||
|
self.spi.send(0xff)
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
return self.sectors
|
return self.sectors
|
||||||
|
|
||||||
def readblocks(self, block_num, buf):
|
def readblocks(self, block_num, buf):
|
||||||
# TODO support multiple block reads
|
nblocks, err = divmod(len(buf), 512)
|
||||||
assert len(buf) == 512
|
assert nblocks and not err, 'Buffer length is invalid'
|
||||||
|
if nblocks == 1:
|
||||||
# CMD17: set read address for single block
|
# CMD17: set read address for single block
|
||||||
if self.cmd(17, block_num * self.cdv, 0) != 0:
|
if self.cmd(17, block_num * self.cdv, 0) != 0:
|
||||||
return 1
|
return 1
|
||||||
|
# receive the data
|
||||||
# receive the data
|
self.readinto(buf)
|
||||||
self.readinto(buf)
|
else:
|
||||||
|
# CMD18: set read address for multiple blocks
|
||||||
|
if self.cmd(18, block_num * self.cdv, 0) != 0:
|
||||||
|
return 1
|
||||||
|
offset = 0
|
||||||
|
mv = memoryview(buf)
|
||||||
|
while nblocks:
|
||||||
|
self.readinto(mv[offset : offset + 512])
|
||||||
|
offset += 512
|
||||||
|
nblocks -= 1
|
||||||
|
return self.cmd_nodata(12)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def writeblocks(self, block_num, buf):
|
def writeblocks(self, block_num, buf):
|
||||||
# TODO support multiple block writes
|
nblocks, err = divmod(len(buf), 512)
|
||||||
assert len(buf) == 512
|
assert nblocks and not err, 'Buffer length is invalid'
|
||||||
|
if nblocks == 1:
|
||||||
|
# CMD24: set write address for single block
|
||||||
|
if self.cmd(24, block_num * self.cdv, 0) != 0:
|
||||||
|
return 1
|
||||||
|
|
||||||
# CMD24: set write address for single block
|
# send the data
|
||||||
if self.cmd(24, block_num * self.cdv, 0) != 0:
|
self.write(TOKEN_DATA, buf)
|
||||||
return 1
|
else:
|
||||||
|
# CMD25: set write address for first block
|
||||||
# send the data
|
if self.cmd(25, block_num * self.cdv, 0) != 0:
|
||||||
self.write(buf)
|
return 1
|
||||||
|
# send the data
|
||||||
|
offset = 0
|
||||||
|
mv = memoryview(buf)
|
||||||
|
while nblocks:
|
||||||
|
self.write(TOKEN_CMD25, mv[offset : offset + 512])
|
||||||
|
offset += 512
|
||||||
|
nblocks -= 1
|
||||||
|
self.write_token(TOKEN_STOP_TRAN)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Test for sdcard block protocol
|
||||||
|
# Peter hinch 30th Jan 2016
|
||||||
|
import os, sdcard, pyb
|
||||||
|
|
||||||
|
def sdtest():
|
||||||
|
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X21) # Compatible with PCB
|
||||||
|
pyb.mount(sd, '/fc')
|
||||||
|
print('Filesystem check')
|
||||||
|
print(os.listdir('/fc'))
|
||||||
|
|
||||||
|
line = 'abcdefghijklmnopqrstuvwxyz\n'
|
||||||
|
lines = line * 200 # 5400 chars
|
||||||
|
short = '1234567890\n'
|
||||||
|
|
||||||
|
fn = '/fc/rats.txt'
|
||||||
|
print()
|
||||||
|
print('Multiple block read/write')
|
||||||
|
with open(fn,'w') as f:
|
||||||
|
n = f.write(lines)
|
||||||
|
print(n, 'bytes written')
|
||||||
|
n = f.write(short)
|
||||||
|
print(n, 'bytes written')
|
||||||
|
n = f.write(lines)
|
||||||
|
print(n, 'bytes written')
|
||||||
|
|
||||||
|
with open(fn,'r') as f:
|
||||||
|
result1 = f.read()
|
||||||
|
print(len(result1), 'bytes read')
|
||||||
|
|
||||||
|
fn = '/fc/rats1.txt'
|
||||||
|
print()
|
||||||
|
print('Single block read/write')
|
||||||
|
with open(fn,'w') as f:
|
||||||
|
n = f.write(short) # one block
|
||||||
|
print(n, 'bytes written')
|
||||||
|
|
||||||
|
with open(fn,'r') as f:
|
||||||
|
result2 = f.read()
|
||||||
|
print(len(result2), 'bytes read')
|
||||||
|
|
||||||
|
pyb.mount(None, '/fc')
|
||||||
|
|
||||||
|
print()
|
||||||
|
print('Verifying data read back')
|
||||||
|
success = True
|
||||||
|
if result1 == ''.join((lines, short, lines)):
|
||||||
|
print('Large file Pass')
|
||||||
|
else:
|
||||||
|
print('Large file Fail')
|
||||||
|
success = False
|
||||||
|
if result2 == short:
|
||||||
|
print('Small file Pass')
|
||||||
|
else:
|
||||||
|
print('Small file Fail')
|
||||||
|
success = False
|
||||||
|
print()
|
||||||
|
print('Tests', 'passed' if success else 'failed')
|
Ładowanie…
Reference in New Issue