Micropython学习交流群 学习QQ群:786510434 提供多种固件下载和学习交流。
Micropython-扇贝物联 QQ群:31324057 扇贝物联是一个让你与智能设备沟通更方便的物联网云平台
Micropython学习交流群 学习QQ群:468985481 学习交流ESP8266、ESP32、ESP8285、wifi模块开发交流、物联网。
Micropython老哥俩的IT农场分享QQ群:929132891 为喜欢科创制作的小白们分享一些自制的计算机软硬件免费公益课程,由两位多年从事IT研发的中年大叔发起。
esp_sdcard.py
""" MicroPython 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. # Examples of how to use # ESP32 - mount sd card import uos import esp_sdcard sd = esp_sdcard.Esp_sdcard(slot=2) uos.mount(sd, '/sd') Notes: Format SD FAT32 not FAT or other When sd_init=True sd bus/slot will not get initialized if SD card is not inserted/available # If card was removed you can remount uos.umount('/sd') sd.init() uos.mount(sd, '/sd') # List file on sd card uos.listdir('/sd') # Try to creat and write to a file f = open('/sd/data.txt', 'w') f.write('some data') f.close() # Try to read from a file f = open('/sd/data.txt') f.read() f.close() """ from micropython import const from machine import SPI, Pin class Esp_sdcard: # Class constants _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, slot=2, baudrate=1000000, polarity=0, phase=0, bits=8, firstbit=0, sck=None, mosi=None, miso=None, cs=None, sd_init=True): # Instance variables self.spi = None self.baudrate = baudrate # just storing value to initialize with slower baud self.cs = None self.cdv = 1 self.sectors = None # SPI Type if slot == 1: # Use default pins if not entered if sck is None: sck = 14 if mosi is None: mosi = 13 if miso is None: miso = 12 if cs is None: cs = 15 elif slot == 2: # Use default pins if not entered if sck is None: sck = 18 if mosi is None: mosi = 23 if miso is None: miso = 19 if cs is None: cs = 5 else: raise OSError("Invalid SPI slot") # Set baud floor value? (should probably remove) if self.baudrate < 100000: self.baudrate = 100000 # Initialize chip select pin try: self.cs = Pin(cs) self.cs.init(self.cs.OUT, value=1) except: raise OSError("Failed to initialize CS") # Initialize SPI bus try: self.spi = SPI(slot) self.spi.init(baudrate=self.baudrate, polarity=polarity, phase=phase, bits=bits, firstbit=firstbit, sck=Pin(sck), mosi=Pin(mosi), miso=Pin(miso)) except: raise OSError("Failed to initialize SPI bus") # SD read buffers self.cmdbuf = bytearray(6) self.dummybuf = bytearray(512) self.tokenbuf = bytearray(1) for i in range(512): self.dummybuf[i] = 0xFF self.dummybuf_memoryview = memoryview(self.dummybuf) # Initialise SD card if sd_init: self.init() # May want to put in try block so atleast # De-initialize SPI bus def deinit(self): self.spi.deinit() # Initialize SD card def init(self): # Initialise the SPI bus with slow baudrate by default self.spi.init(baudrate=100000) # Set CS pin high self.cs(1) # clock card at least 100 cycles with cs high for i in range(_CMD_TIMEOUT):#16): self.spi.write(b"\xFF") # CMD0: Reset card; should return _R1_IDLE_STATE # Response: 0xFF 0x01 for i in range(_CMD_TIMEOUT):#5): self.init_cmd(0, 0, 0x95, 2) # Read Two bytes first being garbage #check sd card is in idle mode if (self.dummybuf_memoryview[1] == _R1_IDLE_STATE): # only care about the second byte break if i== (_CMD_TIMEOUT-1): print(bytes(self.dummybuf_memoryview[0:2])) # all bytes read raise OSError("no SD card") # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF # CMD8: determine card version # Response: 0xFF 0x01 0x00 0x00 0x01 0xAA self.init_cmd(8, 0x01AA, 0x87, 6) if self.dummybuf_memoryview[1] == _R1_IDLE_STATE: # Only care about the second byte for i in range(_CMD_TIMEOUT): # CMD55 Indicates to the card that the next command is an application specific command # Response: 0xFF 0x01 (Don't care) #self.init_cmd(55, 0, 0, 2) self.init_cmd(55, 0, 0x87, 2) # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF #ACM41 Sends HCS, asks OCR content in the response # Response: 0xFF 0x00 self.init_cmd(41, 0x40000000, 0x87, 2) if (self.dummybuf_memoryview[1] == 0): # Only care about the second byte #if the response is 0x00 your good # and set cdv = 1 #self.cdv = 1 break if i == (_CMD_TIMEOUT - 1): print(bytes(self.dummybuf_memoryview[0:2])) raise OSError("timeout waiting for v2 card") # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF self.dummybuf_memoryview[2] = 0xFF self.dummybuf_memoryview[3] = 0xFF self.dummybuf_memoryview[4] = 0xFF self.dummybuf_memoryview[5] = 0xFF #ACM58 Check card version # Response V2 HC: 0xFF 0x00 0xC0 0xFF 0x80 0x00 # Response V1 SC: 0xFF 0x00 0x80 0xFF 0x80 0x00 self.init_cmd(58, 0, 0xFF, 6) if self.dummybuf_memoryview[2] == 0x80: # CMD55 Indicates to the card that the next command is an application specific command # Response: 0xFF 0x01 (Don't care) self.init_cmd(55, 0, 0x87, 2) # CMD42: ... # Response: ... (Don't care) self.init_cmd(42, 0, 0x87, 2) self.cdv = 512 else: self.cdv = 1 # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF self.dummybuf_memoryview[2] = 0xFF self.dummybuf_memoryview[3] = 0xFF self.dummybuf_memoryview[4] = 0xFF self.dummybuf_memoryview[5] = 0xFF # CMD16: set block length to 512 bytes # Response: 0xFF 0x00 self.init_cmd(16, 0x00000200, 0x87, 2) if self.dummybuf_memoryview[1] != 0: # Only care about the second byte print(bytes(self.dummybuf_memoryview[0:2])) raise OSError("Can't set 512 block size") # Clean borrowed buffers self.dummybuf_memoryview[0] = 0xFF self.dummybuf_memoryview[1] = 0xFF else: print(bytes(self.dummybuf_memoryview[0:6])) # all bytes read raise OSError("Couldn't determine SD card version") # CMD9: response R2 (R1 byte + 16-byte block read) # Response: 0xFF 0x01 0x... 0xFE if self.cmd(9, 0, 0xAF, 0, False) != 0: raise OSError("no response from SD card") # Get sector size csd = bytearray(16) self.readinto(csd) if csd[0] & 0xC0 == 0x40: # CSD version 2.0 self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) else: raise OSError("SD card CSD format not supported") # Clean whole buffer for i in range(512): self.dummybuf[i] = 0xFF self.dummybuf_memoryview = memoryview(self.dummybuf) # Set back to requested baud rate self.spi.init(baudrate=self.baudrate) # Send dummy byte for clock sync self.cs(0) self.spi.write(b"\xFF") self.cs(1) def init_cmd(self, cmd=None, arg=0, crc=0, resp_size=2): # send dummy byte before every command self.cs(0) self.spi.write(b"\xFF") self.cs(1) self.cs(0) # Create and send the command buf = self.cmdbuf buf[0] = 0x40 | cmd buf[1] = arg >> 24 buf[2] = arg >> 16 buf[3] = arg >> 8 buf[4] = arg buf[5] = crc self.spi.write(buf) # Get response from SD and save to buffer self.spi.readinto(self.dummybuf_memoryview[0:resp_size], 0xFF) # For debugging sd card init #print(bytes(buf)) # Command #print(bytes(self.dummybuf_memoryview[0:resp_size])) # Response self.cs(1) def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): # send dummy byte before every command self.cs(0) self.spi.write(b"\xFF") self.cs(1) self.cs(0) # create and send the command buf = self.cmdbuf buf[0] = 0x40 | cmd buf[1] = arg >> 24 buf[2] = arg >> 16 buf[3] = arg >> 8 buf[4] = arg buf[5] = crc self.spi.write(buf) if skip1: self.spi.readinto(self.tokenbuf, 0xFF) # wait for the response (response[7] == 0) for i in range(_CMD_TIMEOUT): self.spi.readinto(self.tokenbuf, 0xFF) response = self.tokenbuf[0] # For debugging sd card commands #print(bytes(buf)) # Command #print(bytes(response)) # Response if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): self.spi.write(b"\xff") if release: self.cs(1) self.spi.write(b"\xff") #print(bytes(response)) # Debug Response return response # timeout self.cs(1) self.spi.write(b"\xff") return -1 def readinto(self, buf): self.cs(0) # read until start byte (0xff) for i in range(_CMD_TIMEOUT): self.spi.readinto(self.tokenbuf, 0xFF) if self.tokenbuf[0] == _TOKEN_DATA: break else: self.cs(1) raise OSError("timeout waiting for response") # read data mv = self.dummybuf_memoryview if len(buf) != len(mv): mv = mv[: len(buf)] self.spi.write_readinto(mv, buf) # read checksum self.spi.write(b"\xff") self.spi.write(b"\xff") self.cs(1) self.spi.write(b"\xff") def write(self, token, buf): self.cs(0) # send: start of block, data, checksum 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.read(1, 0xFF)[0] & 0x1F) != 0x05: self.cs(1) self.spi.write(b"\xff") return # wait for write to finish while self.spi.read(1, 0xFF)[0] == 0: pass self.cs(1) self.spi.write(b"\xff") def write_token(self, token): self.cs(0) self.spi.read(1, token) self.spi.write(b"\xff") # wait for write to finish while self.spi.read(1, 0xFF)[0] == 0x00: pass self.cs(1) self.spi.write(b"\xff") def readblocks(self, block_num, buf): nblocks = len(buf) // 512 assert nblocks and not len(buf) % 512, "Buffer length is invalid" if nblocks == 1: # CMD17: set read address for single block if self.cmd(17, block_num * self.cdv, 1, release=False) != 0: # release the card self.cs(1) raise OSError(5) # EIO # receive the data and release card self.readinto(buf) else: # CMD18: set read address for multiple blocks if self.cmd(18, block_num * self.cdv, 1, release=False) != 0: # release the card self.cs(1) raise OSError(5) # EIO offset = 0 mv = memoryview(buf) while nblocks: # receive the data and release card self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 if self.cmd(12, 0, 0xFF, skip1=True): raise OSError(5) # EIO def writeblocks(self, block_num, 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, 1) != 0: raise OSError(5) # EIO # send the data self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 1) != 0: raise OSError(5) # EIO # 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) def ioctl(self, op, arg): if op == 4: # get number of blocks return self.sectors
sd_card.py
# Import libraries import uos import esp_sdcard class SD_card: def __init__(self, sd_slot=2, sd_loc='/sd'): # Load class variables # change slot if using different spi or mmc self.sd_slot = sd_slot self.sd_loc = sd_loc self.sd = None try: self.sd = esp_sdcard.Esp_sdcard(slot=self.sd_slot, sd_init=False) # SD gets initialized except: raise OSError("Failed to set SD bus") # Initialize SD card def initialize(self): initialized = True # Attempt to initialize SD card try: self.sd.init() except: initialized = False return initialized # Mount SD card def mount(self): mounted = True file = self.sd_loc + '/.avail' # Maybe should check if its already available before remounting? # First try to unmount prevous sd mount try: uos.umount(self.sd_loc) except: pass #try to mount try: uos.mount(self.sd, self.sd_loc) ## Create file to check SD is writable f = open(file, 'w') f.write('1') f.close() except: mounted = False return mounted # Check if SD card is available def available(self): available = True file = self.sd_loc + '/.avail' # Try to write to a file try: f = open(file, 'w') f.write('1') f.close() # If not accessible to to remount except: # Re-initialize card self.initialize() # Remount SD card if self.mount(): # # Try to write to a file try: f = open(file, 'w') f.write('1') f.close() except: available = False else: available = False return available
Copyright © 2014 ESP56.com All Rights Reserved
执行时间: 0.0093598365783691 seconds