tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/sdcard/sdcard.go (about)

     1  // package sdcard provides a TinyGo driver for sdcard/mmc devices
     2  // using a SPI connection.
     3  //
     4  // To use a file system on the SDcard, please see the TinyFS repo:
     5  //
     6  // https://github.com/tinygo-org/tinyfs
     7  package sdcard
     8  
     9  import (
    10  	"fmt"
    11  	"machine"
    12  	"time"
    13  )
    14  
    15  const (
    16  	_CMD_TIMEOUT = 100
    17  
    18  	_R1_IDLE_STATE           = 1 << 0
    19  	_R1_ERASE_RESET          = 1 << 1
    20  	_R1_ILLEGAL_COMMAND      = 1 << 2
    21  	_R1_COM_CRC_ERROR        = 1 << 3
    22  	_R1_ERASE_SEQUENCE_ERROR = 1 << 4
    23  	_R1_ADDRESS_ERROR        = 1 << 5
    24  	_R1_PARAMETER_ERROR      = 1 << 6
    25  
    26  	// card types
    27  	SD_CARD_TYPE_SD1  = 1 // Standard capacity V1 SD card
    28  	SD_CARD_TYPE_SD2  = 2 // Standard capacity V2 SD card
    29  	SD_CARD_TYPE_SDHC = 3 // High Capacity SD card
    30  )
    31  
    32  var (
    33  	dummy [512]byte
    34  )
    35  
    36  type Device struct {
    37  	bus        *machine.SPI
    38  	sck        machine.Pin
    39  	sdo        machine.Pin
    40  	sdi        machine.Pin
    41  	cs         machine.Pin
    42  	cmdbuf     []byte
    43  	dummybuf   []byte
    44  	tokenbuf   []byte
    45  	sdCardType byte
    46  	CID        *CID
    47  	CSD        *CSD
    48  }
    49  
    50  func New(b *machine.SPI, sck, sdo, sdi, cs machine.Pin) Device {
    51  	return Device{
    52  		bus:        b,
    53  		cs:         cs,
    54  		sck:        sck,
    55  		sdo:        sdo,
    56  		sdi:        sdi,
    57  		cmdbuf:     make([]byte, 6),
    58  		dummybuf:   make([]byte, 512),
    59  		tokenbuf:   make([]byte, 1),
    60  		sdCardType: 0,
    61  	}
    62  }
    63  
    64  func (d *Device) Configure() error {
    65  	return d.initCard()
    66  }
    67  
    68  func (d *Device) initCard() error {
    69  	d.bus.Configure(machine.SPIConfig{
    70  		SCK:       d.sck,
    71  		SDO:       d.sdo,
    72  		SDI:       d.sdi,
    73  		Frequency: 250000,
    74  		LSBFirst:  false,
    75  		Mode:      0, // phase=0, polarity=0
    76  	})
    77  
    78  	// set pin modes
    79  	d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
    80  	d.cs.High()
    81  
    82  	for i := range dummy {
    83  		dummy[i] = 0xFF
    84  	}
    85  
    86  	// clock card at least 100 cycles with cs high
    87  	d.bus.Tx(dummy[:10], nil)
    88  
    89  	d.cs.Low()
    90  	d.bus.Tx(dummy[:], nil)
    91  
    92  	// CMD0: init card; sould return _R1_IDLE_STATE (allow 5 attempts)
    93  	ok := false
    94  	tm := setTimeout(0, 2*time.Second)
    95  	for !tm.expired() {
    96  		// Wait up to 2 seconds to be the same as the Arduino
    97  		if d.cmd(CMD0_GO_IDLE_STATE, 0, 0x95) == _R1_IDLE_STATE {
    98  			ok = true
    99  			break
   100  		}
   101  	}
   102  	if !ok {
   103  		return fmt.Errorf("no SD card")
   104  	}
   105  
   106  	// CMD8: determine card version
   107  	r := d.cmd(CMD8_SEND_IF_COND, 0x01AA, 0x87)
   108  	if (r & _R1_ILLEGAL_COMMAND) == _R1_ILLEGAL_COMMAND {
   109  		d.sdCardType = SD_CARD_TYPE_SD1
   110  		return fmt.Errorf("init_card_v1 not impl\r\n")
   111  	} else {
   112  		// r7 response
   113  		status := byte(0)
   114  		for i := 0; i < 3; i++ {
   115  			var err error
   116  			status, err = d.bus.Transfer(byte(0xFF))
   117  			if err != nil {
   118  				return err
   119  			}
   120  		}
   121  		if (status & 0x0F) != 0x01 {
   122  			return fmt.Errorf("SD_CARD_ERROR_CMD8 %02X", status)
   123  		}
   124  
   125  		for i := 3; i < 4; i++ {
   126  			var err error
   127  			status, err = d.bus.Transfer(byte(0xFF))
   128  			if err != nil {
   129  				return err
   130  			}
   131  		}
   132  		if status != 0xAA {
   133  			return fmt.Errorf("SD_CARD_ERROR_CMD8 %02X", status)
   134  		}
   135  		d.sdCardType = SD_CARD_TYPE_SD2
   136  	}
   137  
   138  	// initialize card and send host supports SDHC if SD2
   139  	arg := uint32(0)
   140  	if d.sdCardType == SD_CARD_TYPE_SD2 {
   141  		arg = 0x40000000
   142  	}
   143  
   144  	// check for timeout
   145  	ok = false
   146  	tm = setTimeout(0, 2*time.Second)
   147  	for !tm.expired() {
   148  		if d.acmd(ACMD41_SD_APP_OP_COND, arg) == 0 {
   149  			ok = true
   150  			break
   151  		}
   152  	}
   153  
   154  	if !ok {
   155  		return fmt.Errorf("SD_CARD_ERROR_ACMD41")
   156  	}
   157  
   158  	// if SD2 read OCR register to check for SDHC card
   159  	if d.sdCardType == SD_CARD_TYPE_SD2 {
   160  		if d.cmd(CMD58_READ_OCR, 0, 0xFF) != 0 {
   161  			return fmt.Errorf("SD_CARD_ERROR_CMD58")
   162  		}
   163  
   164  		status, err := d.bus.Transfer(byte(0xFF))
   165  		if err != nil {
   166  			return err
   167  		}
   168  		if (status & 0xC0) == 0xC0 {
   169  			d.sdCardType = SD_CARD_TYPE_SDHC
   170  		}
   171  		// discard rest of ocr - contains allowed voltage range
   172  		for i := 1; i < 4; i++ {
   173  			d.bus.Transfer(byte(0xFF))
   174  		}
   175  	}
   176  
   177  	if d.cmd(CMD16_SET_BLOCKLEN, 0x0200, 0xFF) != 0 {
   178  		return fmt.Errorf("SD_CARD_ERROR_CMD16")
   179  	}
   180  
   181  	var buf [16]byte
   182  	// read CID
   183  	err := d.ReadCID(buf[:])
   184  	if err != nil {
   185  		return err
   186  	}
   187  	d.CID = NewCID(buf[:])
   188  
   189  	// read CSD
   190  	err = d.ReadCSD(buf[:])
   191  	if err != nil {
   192  		return err
   193  	}
   194  	d.CSD = NewCSD(buf[:])
   195  
   196  	d.cs.High()
   197  
   198  	d.bus.Configure(machine.SPIConfig{
   199  		SCK:       d.sck,
   200  		SDO:       d.sdo,
   201  		SDI:       d.sdi,
   202  		Frequency: 4000000,
   203  		LSBFirst:  false,
   204  		Mode:      0, // phase=0, polarity=0
   205  	})
   206  
   207  	return nil
   208  }
   209  
   210  func (d Device) acmd(cmd byte, arg uint32) byte {
   211  	d.cmd(CMD55_APP_CMD, 0, 0xFF)
   212  	return d.cmd(cmd, arg, 0xFF)
   213  }
   214  
   215  func (d Device) cmd(cmd byte, arg uint32, crc byte) byte {
   216  	d.cs.Low()
   217  
   218  	if cmd != 12 {
   219  		d.waitNotBusy(300 * time.Millisecond)
   220  	}
   221  
   222  	// create and send the command
   223  	buf := d.cmdbuf
   224  	buf[0] = 0x40 | cmd
   225  	buf[1] = byte(arg >> 24)
   226  	buf[2] = byte(arg >> 16)
   227  	buf[3] = byte(arg >> 8)
   228  	buf[4] = byte(arg)
   229  	buf[5] = crc
   230  	d.bus.Tx(buf, nil)
   231  
   232  	if cmd == 12 {
   233  		// skip 1 byte
   234  		d.bus.Transfer(byte(0xFF))
   235  	}
   236  
   237  	// wait for the response (response[7] == 0)
   238  	for i := 0; i < 0xFFFF; i++ {
   239  		d.bus.Tx([]byte{0xFF}, d.tokenbuf)
   240  		response := d.tokenbuf[0]
   241  		if (response & 0x80) == 0 {
   242  			return response
   243  		}
   244  	}
   245  
   246  	// TODO
   247  	//// timeout
   248  	d.cs.High()
   249  	d.bus.Transfer(byte(0xFF))
   250  
   251  	return 0xFF // -1
   252  }
   253  
   254  func (d Device) waitNotBusy(timeout time.Duration) error {
   255  	tm := setTimeout(1, timeout)
   256  	for !tm.expired() {
   257  		r, err := d.bus.Transfer(byte(0xFF))
   258  		if err != nil {
   259  			return err
   260  		}
   261  		if r == 0xFF {
   262  			return nil
   263  		}
   264  	}
   265  	return nil
   266  }
   267  
   268  func (d Device) waitStartBlock() error {
   269  	status := byte(0xFF)
   270  
   271  	tm := setTimeout(0, 300*time.Millisecond)
   272  	for !tm.expired() {
   273  		var err error
   274  		status, err = d.bus.Transfer(byte(0xFF))
   275  		if err != nil {
   276  			d.cs.High()
   277  			return err
   278  		}
   279  		if status != 0xFF {
   280  			break
   281  		}
   282  	}
   283  
   284  	if status != 254 {
   285  		d.cs.High()
   286  		return fmt.Errorf("SD_CARD_START_BLOCK")
   287  	}
   288  
   289  	return nil
   290  }
   291  
   292  // ReadCSD reads the CSD using CMD9.
   293  func (d Device) ReadCSD(csd []byte) error {
   294  	return d.readRegister(CMD9_SEND_CSD, csd)
   295  }
   296  
   297  // ReadCID reads the CID using CMD10
   298  func (d Device) ReadCID(csd []byte) error {
   299  	return d.readRegister(CMD10_SEND_CID, csd)
   300  }
   301  
   302  func (d Device) readRegister(cmd uint8, dst []byte) error {
   303  	if d.cmd(cmd, 0, 0xFF) != 0 {
   304  		return fmt.Errorf("SD_CARD_ERROR_READ_REG")
   305  	}
   306  	if err := d.waitStartBlock(); err != nil {
   307  		return err
   308  	}
   309  	// transfer data
   310  	for i := uint16(0); i < 16; i++ {
   311  		r, err := d.bus.Transfer(byte(0xFF))
   312  		if err != nil {
   313  			return err
   314  		}
   315  		dst[i] = r
   316  	}
   317  	d.bus.Transfer(byte(0xFF))
   318  	d.bus.Transfer(byte(0xFF))
   319  	d.cs.High()
   320  
   321  	return nil
   322  }
   323  
   324  // ReadData reads 512 bytes from sdcard into dst.
   325  func (d Device) ReadData(block uint32, dst []byte) error {
   326  	if len(dst) < 512 {
   327  		return fmt.Errorf("len(dst) must be greater than or equal to 512")
   328  	}
   329  
   330  	// use address if not SDHC card
   331  	if d.sdCardType != SD_CARD_TYPE_SDHC {
   332  		block <<= 9
   333  	}
   334  	if d.cmd(CMD17_READ_SINGLE_BLOCK, block, 0xFF) != 0 {
   335  		return fmt.Errorf("CMD17 error")
   336  	}
   337  	if err := d.waitStartBlock(); err != nil {
   338  		return fmt.Errorf("waitStartBlock()")
   339  	}
   340  
   341  	err := d.bus.Tx(dummy[:512], dst)
   342  	if err != nil {
   343  		return err
   344  	}
   345  
   346  	// skip CRC (2byte)
   347  	d.bus.Transfer(byte(0xFF))
   348  	d.bus.Transfer(byte(0xFF))
   349  
   350  	// TODO: probably not necessary
   351  	d.cs.High()
   352  
   353  	return nil
   354  }
   355  
   356  // WriteMultiStart starts the continuous write mode using CMD25.
   357  func (d Device) WriteMultiStart(block uint32) error {
   358  	// use address if not SDHC card
   359  	if d.sdCardType != SD_CARD_TYPE_SDHC {
   360  		block <<= 9
   361  	}
   362  	if d.cmd(CMD25_WRITE_MULTIPLE_BLOCK, block, 0xFF) != 0 {
   363  		return fmt.Errorf("CMD25 error")
   364  	}
   365  
   366  	// skip 1 byte
   367  	d.bus.Transfer(byte(0xFF))
   368  
   369  	return nil
   370  }
   371  
   372  // WriteMulti performs continuous writing. It is necessary to call
   373  // WriteMultiStart() in prior.
   374  func (d Device) WriteMulti(buf []byte) error {
   375  	// send Data Token for CMD25
   376  	d.bus.Transfer(byte(0xFC))
   377  
   378  	for i := 0; i < 512; i++ {
   379  		_, err := d.bus.Transfer(buf[i])
   380  		if err != nil {
   381  			return err
   382  		}
   383  	}
   384  
   385  	// send dummy CRC (2 byte)
   386  	d.bus.Transfer(byte(0xFF))
   387  	d.bus.Transfer(byte(0xFF))
   388  
   389  	// Data Resp.
   390  	r, err := d.bus.Transfer(byte(0xFF))
   391  	if err != nil {
   392  		return err
   393  	}
   394  	if (r & 0x1F) != 0x05 {
   395  		return fmt.Errorf("SD_CARD_ERROR_WRITE")
   396  	}
   397  
   398  	// wait no busy
   399  	err = d.waitNotBusy(600 * time.Millisecond)
   400  	if err != nil {
   401  		return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
   402  	}
   403  
   404  	return nil
   405  }
   406  
   407  // WriteMultiStop exits the continuous write mode.
   408  func (d Device) WriteMultiStop() error {
   409  	defer d.cs.High()
   410  
   411  	// Stop Tran token for CMD25
   412  	d.bus.Transfer(0xFD)
   413  
   414  	// skip 1 byte
   415  	d.bus.Transfer(byte(0xFF))
   416  
   417  	err := d.waitNotBusy(600 * time.Millisecond)
   418  	if err != nil {
   419  		return nil
   420  	}
   421  
   422  	return nil
   423  }
   424  
   425  // WriteData writes 512 bytes from dst to sdcard.
   426  func (d Device) WriteData(block uint32, src []byte) error {
   427  	if len(src) < 512 {
   428  		return fmt.Errorf("len(src) must be greater than or equal to 512")
   429  	}
   430  
   431  	// use address if not SDHC card
   432  	if d.sdCardType != SD_CARD_TYPE_SDHC {
   433  		block <<= 9
   434  	}
   435  	if d.cmd(CMD24_WRITE_BLOCK, block, 0xFF) != 0 {
   436  		return fmt.Errorf("CMD24 error")
   437  	}
   438  
   439  	// wait 1 byte?
   440  	token := byte(0xFE)
   441  	d.bus.Transfer(token)
   442  
   443  	err := d.bus.Tx(src[:512], nil)
   444  	if err != nil {
   445  		return err
   446  	}
   447  
   448  	// send dummy CRC (2 byte)
   449  	d.bus.Transfer(byte(0xFF))
   450  	d.bus.Transfer(byte(0xFF))
   451  
   452  	// Data Resp.
   453  	r, err := d.bus.Transfer(byte(0xFF))
   454  	if err != nil {
   455  		return err
   456  	}
   457  	if (r & 0x1F) != 0x05 {
   458  		return fmt.Errorf("SD_CARD_ERROR_WRITE")
   459  	}
   460  
   461  	// wait no busy
   462  	err = d.waitNotBusy(600 * time.Millisecond)
   463  	if err != nil {
   464  		return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
   465  	}
   466  
   467  	// TODO: probably not necessary
   468  	d.cs.High()
   469  	return nil
   470  }
   471  
   472  // ReadAt reads the given number of bytes from the sdcard.
   473  func (dev *Device) ReadAt(buf []byte, addr int64) (int, error) {
   474  	block := uint64(addr)
   475  	// use address if not SDHC card
   476  	if dev.sdCardType == SD_CARD_TYPE_SDHC {
   477  		block >>= 9
   478  	}
   479  
   480  	idx := uint32(0)
   481  
   482  	start := uint32(addr % 512)
   483  	end := uint32(0)
   484  	remain := uint32(len(buf))
   485  
   486  	// If data starts in the middle
   487  	if 0 < start {
   488  		if start+remain <= 512 {
   489  			end = start + remain
   490  		} else {
   491  			end = 512
   492  		}
   493  
   494  		err := dev.ReadData(uint32(block), dev.dummybuf)
   495  		if err != nil {
   496  			return 0, err
   497  		}
   498  		copy(buf[idx:], dev.dummybuf[start:end])
   499  
   500  		remain -= end - start
   501  		idx += end - start
   502  		block++
   503  	}
   504  
   505  	// If more than 512 bytes left
   506  	for 512 <= remain {
   507  		start = 0
   508  		end = 512
   509  
   510  		err := dev.ReadData(uint32(block), dev.dummybuf)
   511  		if err != nil {
   512  			return 0, err
   513  		}
   514  		copy(buf[idx:], dev.dummybuf[start:end])
   515  
   516  		remain -= end - start
   517  		idx += end - start
   518  		block++
   519  	}
   520  
   521  	// Read to the end
   522  	if 0 < remain {
   523  		start = 0
   524  		end = remain
   525  
   526  		err := dev.ReadData(uint32(block), dev.dummybuf)
   527  		if err != nil {
   528  			return 0, err
   529  		}
   530  		copy(buf[idx:], dev.dummybuf[start:end])
   531  
   532  		remain -= end - start
   533  		idx += end - start
   534  		block++
   535  	}
   536  
   537  	return int(idx), nil
   538  }
   539  
   540  // WriteAt writes the given number of bytes to sdcard.
   541  func (dev *Device) WriteAt(buf []byte, addr int64) (n int, err error) {
   542  	block := uint64(addr)
   543  	// use address if not SDHC card
   544  	if dev.sdCardType == SD_CARD_TYPE_SDHC {
   545  		block >>= 9
   546  	}
   547  
   548  	idx := uint32(0)
   549  
   550  	start := uint32(addr % 512)
   551  	end := uint32(0)
   552  	remain := uint32(len(buf))
   553  
   554  	// If data starts in the middle
   555  	if 0 < start {
   556  		if start+remain <= 512 {
   557  			end = start + remain
   558  		} else {
   559  			end = 512
   560  		}
   561  
   562  		err := dev.ReadData(uint32(block), dev.dummybuf)
   563  		if err != nil {
   564  			return 0, err
   565  		}
   566  		copy(dev.dummybuf[start:end], buf[idx:])
   567  
   568  		err = dev.WriteData(uint32(block), dev.dummybuf)
   569  		if err != nil {
   570  			return 0, err
   571  		}
   572  
   573  		remain -= end - start
   574  		idx += end - start
   575  		block++
   576  	}
   577  
   578  	// If more than 512 bytes left
   579  	for 512 <= remain {
   580  		start = 0
   581  		end = 512
   582  
   583  		err := dev.WriteData(uint32(block), buf[idx:idx+512])
   584  		if err != nil {
   585  			return 0, err
   586  		}
   587  
   588  		remain -= end - start
   589  		idx += end - start
   590  		block++
   591  	}
   592  
   593  	// Write to the end
   594  	if 0 < remain {
   595  		start = 0
   596  		end = remain
   597  
   598  		err := dev.ReadData(uint32(block), dev.dummybuf)
   599  		if err != nil {
   600  			return 0, err
   601  		}
   602  		copy(dev.dummybuf[start:end], buf[idx:])
   603  
   604  		err = dev.WriteData(uint32(block), dev.dummybuf)
   605  		if err != nil {
   606  			return 0, err
   607  		}
   608  
   609  		remain -= end - start
   610  		idx += end - start
   611  		block++
   612  	}
   613  
   614  	return int(idx), nil
   615  }
   616  
   617  // Size returns the number of bytes in this sdcard.
   618  func (dev *Device) Size() int64 {
   619  	return int64(dev.CSD.Size())
   620  }
   621  
   622  // WriteBlockSize returns the block size in which data can be written to
   623  // memory.
   624  func (dev *Device) WriteBlockSize() int64 {
   625  	return 512
   626  }
   627  
   628  // EraseBlockSize returns the smallest erasable area on this sdcard in bytes.
   629  func (dev *Device) EraseBlockSize() int64 {
   630  	return 512
   631  }
   632  
   633  // EraseBlocks erases the given number of blocks.
   634  func (dev *Device) EraseBlocks(start, len int64) error {
   635  	dev.WriteMultiStart(uint32(start))
   636  
   637  	for i := range dev.dummybuf {
   638  		dev.dummybuf[i] = 0
   639  	}
   640  
   641  	for i := 0; i < int(len); i++ {
   642  		dev.WriteMulti(dev.dummybuf)
   643  	}
   644  
   645  	dev.WriteMultiStop()
   646  	return nil
   647  }