From ce1c786297e69df4a82e83ac379f8ef068e709f6 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 25 Aug 2016 10:54:59 +0200 Subject: [PATCH] drivers/sdcard: Port the SDCard driver to new machine API. With backwards compatibility for pyboard. --- drivers/sdcard/sdcard.py | 139 ++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fba383ae3..fc7a8af7c 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -4,31 +4,41 @@ Micro Python driver for SD cards using SPI bus. Requires an SPI bus and a CS pin. Provides readblocks and writeblocks methods so the device can be mounted as a filesystem. -Example usage: +Example usage on pyboard: import pyb, sdcard, os sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) pyb.mount(sd, '/sd2') os.listdir('/') +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) + os.umount() + os.VfsFat(sd, "") + os.listdir() + """ -import pyb +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +#R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +#R1_COM_CRC_ERROR = const(1 << 3) +#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) + class SDCard: - CMD_TIMEOUT = const(100) - - R1_IDLE_STATE = const(1 << 0) - #R1_ERASE_RESET = const(1 << 1) - R1_ILLEGAL_COMMAND = const(1 << 2) - #R1_COM_CRC_ERROR = const(1 << 3) - #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 self.cs = cs @@ -42,30 +52,39 @@ class SDCard: # initialise the card self.init_card() + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + def init_card(self): # init CS pin - self.cs.high() - self.cs.init(self.cs.OUT_PP) + self.cs.init(self.cs.OUT, value=1) # init SPI bus; use low data rate for initialisation - self.spi.init(self.spi.MASTER, baudrate=100000, phase=0, polarity=0) + self.init_spi(100000) # clock card at least 100 cycles with cs high for i in range(16): - self.spi.send(0xff) + self.spi.write(b'\xff') - # CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts) + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) for _ in range(5): - if self.cmd(0, 0, 0x95) == R1_IDLE_STATE: + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: break else: raise OSError("no SD card") # CMD8: determine card version r = self.cmd(8, 0x01aa, 0x87, 4) - if r == R1_IDLE_STATE: + if r == _R1_IDLE_STATE: self.init_card_v2() - elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND): + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): self.init_card_v1() else: raise OSError("couldn't determine SD card version") @@ -86,10 +105,10 @@ class SDCard: raise OSError("can't set 512 block size") # set to high data rate now that it's initialised - self.spi.init(self.spi.MASTER, baudrate=1320000, phase=0, polarity=0) + self.init_spi(1320000) def init_card_v1(self): - for i in range(CMD_TIMEOUT): + for i in range(_CMD_TIMEOUT): self.cmd(55, 0, 0) if self.cmd(41, 0, 0) == 0: self.cdv = 512 @@ -98,8 +117,8 @@ class SDCard: raise OSError("timeout waiting for v1 card") def init_card_v2(self): - for i in range(CMD_TIMEOUT): - pyb.delay(50) + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) self.cmd(58, 0, 0, 4) self.cmd(55, 0, 0) if self.cmd(41, 0x40000000, 0) == 0: @@ -120,87 +139,87 @@ class SDCard: buf[3] = arg >> 8 buf[4] = arg buf[5] = crc - self.spi.send(buf) + self.spi.write(buf) # wait for the repsonse (response[7] == 0) - for i in range(CMD_TIMEOUT): - response = self.spi.send_recv(0xff)[0] + for i in range(_CMD_TIMEOUT): + response = self.spi.read(1, 0xff)[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): - self.spi.send(0xff) + self.spi.write(b'\xff') if release: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return response # timeout self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') 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.spi.write(cmd) + self.spi.read(1, 0xff) # ignore stuff byte + for _ in range(_CMD_TIMEOUT): + if self.spi.read(1, 0xff)[0] == 0xff: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 0 # OK self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 1 # timeout def readinto(self, buf): self.cs.low() # read until start byte (0xff) - while self.spi.send_recv(0xff)[0] != 0xfe: + while self.spi.read(1, 0xff)[0] != 0xfe: pass # read data mv = self.dummybuf_memoryview[:len(buf)] - self.spi.send_recv(mv, recv=buf) + self.spi.write_readinto(mv, buf) # read checksum - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.write(b'\xff') + self.spi.write(b'\xff') self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write(self, token, buf): self.cs.low() # send: start of block, data, checksum - self.spi.send(token) - self.spi.send(buf) - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b'\xff') + self.spi.write(b'\xff') # check the response - if (self.spi.send_recv(0xff)[0] & 0x1f) != 0x05: + if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write_token(self, token): self.cs.low() - self.spi.send(token) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(b'\xff') # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0x00: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def count(self): return self.sectors @@ -224,7 +243,7 @@ class SDCard: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(12) + return self.cmd_nodata(b'\x0c') # cmd 12 return 0 def writeblocks(self, block_num, buf): @@ -236,7 +255,7 @@ class SDCard: return 1 # send the data - self.write(TOKEN_DATA, buf) + self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: @@ -245,8 +264,8 @@ class SDCard: offset = 0 mv = memoryview(buf) while nblocks: - self.write(TOKEN_CMD25, mv[offset : offset + 512]) + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) offset += 512 nblocks -= 1 - self.write_token(TOKEN_STOP_TRAN) + self.write_token(_TOKEN_STOP_TRAN) return 0