找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4082|回复: 1
收起左侧

Micropython SD卡驱动源码(无文件系统 按块号存取)

[复制链接]
ID:313579 发表于 2018-4-22 10:58 | 显示全部楼层 |阅读模式
SPI协议 micropython  无文件系统  按块号存取

Micropython源程序如下:
  1. """
  2. MicroPython driver for SD cards using SPI bus.

  3. Requires an SPI bus and a CS pin.  Provides readblocks and writeblocks
  4. methods so the device can be mounted as a filesystem.

  5. Example usage on pyboard:

  6.     import pyb, sdcard, os
  7.     sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)
  8.     pyb.mount(sd, '/sd2')
  9.     os.listdir('/')

  10. Example usage on ESP8266:

  11.     import machine, sdcard, os
  12.     sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15))
  13.     os.mount(sd, '/sd')
  14.     os.listdir('/')

  15. """

  16. from micropython import const
  17. import time


  18. _CMD_TIMEOUT = const(100)

  19. _R1_IDLE_STATE = const(1 << 0)
  20. #R1_ERASE_RESET = const(1 << 1)
  21. _R1_ILLEGAL_COMMAND = const(1 << 2)
  22. #R1_COM_CRC_ERROR = const(1 << 3)
  23. #R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
  24. #R1_ADDRESS_ERROR = const(1 << 5)
  25. #R1_PARAMETER_ERROR = const(1 << 6)
  26. _TOKEN_CMD25 = const(0xfc)
  27. _TOKEN_STOP_TRAN = const(0xfd)
  28. _TOKEN_DATA = const(0xfe)


  29. class SDCard:
  30.     def __init__(self, spi, cs):
  31.         self.spi = spi
  32.         self.cs = cs

  33.         self.cmdbuf = bytearray(6)
  34.         self.dummybuf = bytearray(512)
  35.         self.tokenbuf = bytearray(1)
  36.         for i in range(512):
  37.             self.dummybuf[i] = 0xff
  38.         self.dummybuf_memoryview = memoryview(self.dummybuf)

  39.         # initialise the card
  40.         self.init_card()

  41.     def init_spi(self, baudrate):
  42.         try:
  43.             master = self.spi.MASTER
  44.         except AttributeError:
  45.             # on ESP8266
  46.             self.spi.init(baudrate=baudrate, phase=0, polarity=0)
  47.         else:
  48.             # on pyboard
  49.             self.spi.init(master, baudrate=baudrate, phase=0, polarity=0)

  50.     def init_card(self):
  51.         # init CS pin
  52.         self.cs.init(self.cs.OUT, value=1)

  53.         # init SPI bus; use low data rate for initialisation
  54.         self.init_spi(100000)

  55.         # clock card at least 100 cycles with cs high
  56.         for i in range(16):
  57.             self.spi.write(b'\xff')

  58.         # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
  59.         for _ in range(5):
  60.             if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
  61.                 break
  62.         else:
  63.             raise OSError("no SD card")

  64.         # CMD8: determine card version
  65.         r = self.cmd(8, 0x01aa, 0x87, 4)
  66.         if r == _R1_IDLE_STATE:
  67.             self.init_card_v2()
  68.         elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
  69.             self.init_card_v1()
  70.         else:
  71.             raise OSError("couldn't determine SD card version")

  72.         # get the number of sectors
  73.         # CMD9: response R2 (R1 byte + 16-byte block read)
  74.         if self.cmd(9, 0, 0, 0, False) != 0:
  75.             raise OSError("no response from SD card")
  76.         csd = bytearray(16)
  77.         self.readinto(csd)
  78.         if csd[0] & 0xc0 == 0x40: # CSD version 2.0
  79.             self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014
  80.         elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB)
  81.             c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4
  82.             c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7
  83.             self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2))
  84.         else:
  85.             raise OSError("SD card CSD format not supported")
  86.         #print('sectors', self.sectors)

  87.         # CMD16: set block length to 512 bytes
  88.         if self.cmd(16, 512, 0) != 0:
  89.             raise OSError("can't set 512 block size")

  90.         # set to high data rate now that it's initialised
  91.         self.init_spi(1320000)

  92.     def init_card_v1(self):
  93.         for i in range(_CMD_TIMEOUT):
  94.             self.cmd(55, 0, 0)
  95.             if self.cmd(41, 0, 0) == 0:
  96.                 self.cdv = 512
  97.                 #print("[SDCard] v1 card")
  98.                 return
  99.         raise OSError("timeout waiting for v1 card")

  100.     def init_card_v2(self):
  101.         for i in range(_CMD_TIMEOUT):
  102.             time.sleep_ms(50)
  103.             self.cmd(58, 0, 0, 4)
  104.             self.cmd(55, 0, 0)
  105.             if self.cmd(41, 0x40000000, 0) == 0:
  106.                 self.cmd(58, 0, 0, 4)
  107.                 self.cdv = 1
  108.                 #print("[SDCard] v2 card")
  109.                 return
  110.         raise OSError("timeout waiting for v2 card")

  111.     def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
  112.         self.cs(0)

  113.         # create and send the command
  114.         buf = self.cmdbuf
  115.         buf[0] = 0x40 | cmd
  116.         buf[1] = arg >> 24
  117.         buf[2] = arg >> 16
  118.         buf[3] = arg >> 8
  119.         buf[4] = arg
  120.         buf[5] = crc
  121.         self.spi.write(buf)

  122.         if skip1:
  123.             self.spi.readinto(self.tokenbuf, 0xff)

  124.         # wait for the response (response[7] == 0)
  125.         for i in range(_CMD_TIMEOUT):
  126.             self.spi.readinto(self.tokenbuf, 0xff)
  127.             response = self.tokenbuf[0]
  128.             if not (response & 0x80):
  129.                 # this could be a big-endian integer that we are getting here
  130.                 for j in range(final):
  131.                     self.spi.write(b'\xff')
  132.                 if release:
  133.                     self.cs(1)
  134.                     self.spi.write(b'\xff')
  135.                 return response

  136.         # timeout
  137.         self.cs(1)
  138.         self.spi.write(b'\xff')
  139.         return -1

  140.     def readinto(self, buf):
  141.         self.cs(0)

  142.         # read until start byte (0xff)
  143.         while True:
  144.             self.spi.readinto(self.tokenbuf, 0xff)
  145.             if self.tokenbuf[0] == 0xfe:
  146.                 break

  147.         # read data
  148.         mv = self.dummybuf_memoryview
  149.         if len(buf) != len(mv):
  150.             mv = mv[:len(buf)]
  151.         self.spi.write_readinto(mv, buf)

  152.         # read checksum
  153.         self.spi.write(b'\xff')
  154.         self.spi.write(b'\xff')

  155.         self.cs(1)
  156.         self.spi.write(b'\xff')

  157.     def write(self, token, buf):
  158.         self.cs(0)

  159.         # send: start of block, data, checksum
  160.         self.spi.read(1, token)
  161.         self.spi.write(buf)
  162.         self.spi.write(b'\xff')
  163.         self.spi.write(b'\xff')

  164.         # check the response
  165.         if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05:
  166.             self.cs(1)
  167.             self.spi.write(b'\xff')
  168.             return

  169.         # wait for write to finish
  170.         while self.spi.read(1, 0xff)[0] == 0:
  171.             pass

  172.         self.cs(1)
  173.         self.spi.write(b'\xff')

  174.     def write_token(self, token):
  175.         self.cs(0)
  176.         self.spi.read(1, token)
  177.         self.spi.write(b'\xff')
  178.         # wait for write to finish
  179.         while self.spi.read(1, 0xff)[0] == 0x00:
  180.             pass

  181.         self.cs(1)
  182.         self.spi.write(b'\xff')

  183.     def count(self):
  184.         return self.sectors

  185.     def readblocks(self, block_num, buf):
  186.         nblocks = len(buf) // 512
  187.         assert nblocks and not len(buf) % 512, 'Buffer length is invalid'
  188.         if nblocks == 1:
  189.             # CMD17: set read address for single block
  190.             if self.cmd(17, block_num * self.cdv, 0) != 0:
  191.                 raise OSError(5) # EIO
  192.             # receive the data
  193.             self.readinto(buf)
  194.         else:
  195.             # CMD18: set read address for multiple blocks
  196.             if self.cmd(18, block_num * self.cdv, 0) != 0:
  197.                 raise OSError(5) # EIO
  198.             offset = 0
  199.             mv = memoryview(buf)
  200. ……………………

  201. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
sdcard.zip (2.41 KB, 下载次数: 21)
0.jpg
回复

使用道具 举报

ID:415979 发表于 2019-4-5 01:38 | 显示全部楼层
感谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表