summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorPeter Hinch <peter@hinch.me.uk>2016-01-30 07:21:43 +0000
committerDamien George <damien.p.george@gmail.com>2016-02-02 11:16:15 +0000
commit2bd758fe96e2913f48c1a0fdccafddc3dfb31cf9 (patch)
treed550b5a4b1a6638882353c79d89f082eb2aaa2ab
parent67e810834569ec63d85016bff8e619a933b65c3a (diff)
downloadmicropython-2bd758fe96e2913f48c1a0fdccafddc3dfb31cf9.tar.gz
micropython-2bd758fe96e2913f48c1a0fdccafddc3dfb31cf9.zip
drivers/sdcard: Add support for multi-block read/write; add SD test.
-rw-r--r--drivers/sdcard/sdcard.py88
-rw-r--r--drivers/sdcard/sdtest.py57
2 files changed, 125 insertions, 20 deletions
diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py
index a3372e3152..fba383ae39 100644
--- a/drivers/sdcard/sdcard.py
+++ b/drivers/sdcard/sdcard.py
@@ -25,6 +25,9 @@ class SDCard:
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
#R1_ADDRESS_ERROR = const(1 << 5)
#R1_PARAMETER_ERROR = const(1 << 6)
+ TOKEN_CMD25 = const(0xfc)
+ TOKEN_STOP_TRAN = const(0xfd)
+ TOKEN_DATA = const(0xfe)
def __init__(self, spi, cs):
self.spi = spi
@@ -136,6 +139,18 @@ class SDCard:
self.spi.send(0xff)
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):
self.cs.low()
@@ -154,11 +169,11 @@ class SDCard:
self.cs.high()
self.spi.send(0xff)
- def write(self, buf):
+ def write(self, token, buf):
self.cs.low()
# send: start of block, data, checksum
- self.spi.send(0xfe)
+ self.spi.send(token)
self.spi.send(buf)
self.spi.send(0xff)
self.spi.send(0xff)
@@ -176,29 +191,62 @@ class SDCard:
self.cs.high()
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):
return self.sectors
def readblocks(self, block_num, buf):
- # TODO support multiple block reads
- assert len(buf) == 512
-
- # CMD17: set read address for single block
- if self.cmd(17, block_num * self.cdv, 0) != 0:
- return 1
-
- # receive the data
- self.readinto(buf)
+ nblocks, err = divmod(len(buf), 512)
+ assert nblocks and not err, 'Buffer length is invalid'
+ if nblocks == 1:
+ # CMD17: set read address for single block
+ if self.cmd(17, block_num * self.cdv, 0) != 0:
+ return 1
+ # receive the data
+ 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
def writeblocks(self, block_num, buf):
- # TODO support multiple block writes
- assert len(buf) == 512
-
- # CMD24: set write address for single block
- if self.cmd(24, block_num * self.cdv, 0) != 0:
- return 1
-
- # send the data
- self.write(buf)
+ nblocks, err = divmod(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
+
+ # send the data
+ self.write(TOKEN_DATA, buf)
+ else:
+ # CMD25: set write address for first block
+ if self.cmd(25, block_num * self.cdv, 0) != 0:
+ 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
diff --git a/drivers/sdcard/sdtest.py b/drivers/sdcard/sdtest.py
new file mode 100644
index 0000000000..438baa245d
--- /dev/null
+++ b/drivers/sdcard/sdtest.py
@@ -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')