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 }