From 1b726ef2bd5fd756005766953437177f91c73ebb Mon Sep 17 00:00:00 2001 From: soypat Date: Mon, 15 Jan 2024 01:31:03 -0300 Subject: [PATCH] fully comply --- sd/card.go | 256 +------------------------------------------------- sd/rustref.go | 80 ++++++++++++++-- 2 files changed, 71 insertions(+), 265 deletions(-) diff --git a/sd/card.go b/sd/card.go index d3fd23e..d64d281 100644 --- a/sd/card.go +++ b/sd/card.go @@ -1,9 +1,7 @@ package sd import ( - "encoding/binary" "errors" - "math" "time" "tinygo.org/x/drivers" @@ -82,147 +80,7 @@ func (c *SPICard) LastReadCRC() uint16 { return c.lastCRC } // Init initializes the SD card. This routine should be performed with a SPI clock // speed of around 100..400kHz. One may increase the clock speed after initialization. func (d *SPICard) Init() error { - dummy := d.buf[:512] - for i := range dummy { - dummy[i] = 0xFF - } - defer d.csEnable(false) - - d.csEnable(true) - // clock card at least 100 cycles with cs high - d.bus.Tx(dummy[:10], nil) - d.csEnable(false) - - d.bus.Tx(dummy[:], nil) - - // CMD0: init card; sould return _R1_IDLE_STATE (allow 5 attempts) - println("first timer") - ok := false - tm := d.timers[0].setTimeout(2 * time.Second) - for !tm.expired() { - // Wait up to 2 seconds to be the same as the Arduino - result, err := d.cmd(cmdGoIdleState, 0, 0x95) - if err != nil { - return err - } - if result == _R1_IDLE_STATE { - ok = true - break - } - } - if !ok { - return errNoSDCard - } - - // CMD8: determine card version - r1, err := d.cmd(cmdSendIfCond, 0x01AA, 0x87) - if err != nil { - return err - } - if r1.IllegalCmdError() { - d.kind = TypeSD1 - return errCardNotSupported - } - // r7 response - status := byte(0) - for i := 0; i < 3; i++ { - var err error - status, err = d.bus.Transfer(0xFF) - if err != nil { - return err - } - } - if (status & 0x0F) != 0x01 { - return makeResponseError(response1(status)) - } - - for i := 3; i < 4; i++ { - var err error - status, err = d.bus.Transfer(0xFF) - if err != nil { - return err - } - } - if status != 0xAA { - return makeResponseError(response1(status)) - } - d.kind = TypeSD2 - - // initialize card and send host supports SDHC if SD2 - arg := uint32(0) - if d.kind == TypeSD2 { - arg = 0x40000000 - } - - // check for timeout - println("app cmd") - ok = false - tm = tm.setTimeout(2 * time.Second) - for !tm.expired() { - println("timer") - r1, err = d.appCmd(acmdSD_APP_OP_COND, arg) - if err != nil { - return err - } - if r1 == 0 { - break - } - } - if r1 != 0 { - return makeResponseError(r1) - } - println("preensure") - // if SD2 read OCR register to check for SDHC card - if d.kind == TypeSD2 { - err := d.cmdEnsure0Status(cmdReadOCR, 0, 0xFF) - if err != nil { - return err - } - - statusb, err := d.bus.Transfer(0xFF) - if err != nil { - return err - } - if (statusb & 0xC0) == 0xC0 { - d.kind = TypeSDHC - } - // discard rest of ocr - contains allowed voltage range - for i := 1; i < 4; i++ { - d.bus.Transfer(0xFF) - } - } - println("ensure") - err = d.cmdEnsure0Status(cmdSetBlocklen, 0x0200, 0xff) - if err != nil { - return err - } - println("get to update csdid") - return d.updateCSDCID() -} - -func (d *SPICard) updateCSDCID() (err error) { - // read CID - d.cid, err = d.readCID() - if err != nil { - return err - } - d.csd, err = d.readCSD() - if err != nil { - return err - } - blockshift := d.csd.ReadBlockLenShift() - blocklen := uint16(1) << blockshift - capacity := d.csd.DeviceCapacity() - if blocklen == 0 || capacity < uint64(blocklen) { - return errNoblocks - } - nb := capacity / uint64(blocklen) - if nb > math.MaxUint32 { - return errCardNotSupported - } - d.blockshift = blockshift - d.numblocks = int64(nb) - return nil + return d.initRs() } func (d *SPICard) NumberOfBlocks() int64 { @@ -235,118 +93,6 @@ func (d *SPICard) CID() CID { return d.cid } // CSD returns a copy of the Card Specific Data Register value last read. func (d *SPICard) CSD() CSD { return d.csd } -func (d *SPICard) readCID() (CID, error) { - buf := d.buf[len(d.buf)-16:] - if err := d.readRegister(cmdSendCID, buf); err != nil { - return CID{}, err - } - return DecodeCID(buf) -} - -func (d *SPICard) readCSD() (CSD, error) { - buf := d.buf[len(d.buf)-16:] - if err := d.readRegister(cmdSendCSD, buf); err != nil { - return CSD{}, err - } - return DecodeCSD(buf) -} - -func (d *SPICard) readRegister(cmd command, dst []byte) error { - err := d.cmdEnsure0Status(cmd, 0, 0xFF) - if err != nil { - return err - } - if err := d.waitStartBlock(); err != nil { - return err - } - // transfer data - for i := uint16(0); i < 16; i++ { - r, err := d.bus.Transfer(0xFF) - if err != nil { - return err - } - dst[i] = r - } - // skip CRC. - d.bus.Transfer(0xFF) - d.bus.Transfer(0xFF) - d.csEnable(false) - return nil -} - -func (d *SPICard) appCmd(cmd appcommand, arg uint32) (response1, error) { - status, err := d.cmd(cmdAppCmd, 0, 0xFF) - if err != nil { - return status, err - } - return d.cmd(command(cmd), arg, 0xFF) -} - -func (d *SPICard) cmdEnsure0Status(cmd command, arg uint32, precalcCRC byte) error { - status, err := d.cmd(cmd, arg, precalcCRC) - if err != nil { - return err - } - if status != 0 { - return makeResponseError(status) - } - return nil -} - -func (d *SPICard) cmd(cmd command, arg uint32, precalcCRC byte) (response1, error) { - const transmitterBit = 1 << 6 - if cmd >= transmitterBit { - panic("invalid SD command") - } - d.csEnable(true) - - if cmd != cmdStopTransmission { - err := d.waitNotBusy(d.timeout) - if err != nil { - return 0, err - } - } - - // create and send the command - buf := d.bufcmd[:6] - // Start bit is always zero; transmitter bit is one since we are Host. - - buf[0] = transmitterBit | byte(cmd) - binary.BigEndian.PutUint32(buf[1:5], arg) - if precalcCRC != 0 { - buf[5] = precalcCRC - } else { - // CRC and end bit which is always 1. - buf[5] = crc7noshift(buf[:5]) | 1 - } - - err := d.bus.Tx(buf, nil) - if err != nil { - return 0, err - } - if cmd == cmdStopTransmission { - // skip 1 byte - d.bus.Transfer(0xFF) - } - - tm := d.timers[1].setTimeout(d.timeout) - for { - tok, _ := d.bus.Transfer(0xff) - response := response1(tok) - if (response & 0x80) == 0 { - // NOMINAL FUNCTION EXIT HERE - return response, nil - } else if tm.expired() { - break - } - d.yield() - } - println("============== BAD EXIT ================") - d.csEnable(false) - d.bus.Transfer(0xFF) - return 0xFF, errCmdGeneric -} - func (d *SPICard) yield() { time.Sleep(d.wait) } func (d *SPICard) waitNotBusy(timeout time.Duration) error { diff --git a/sd/rustref.go b/sd/rustref.go index 96b1291..985469e 100644 --- a/sd/rustref.go +++ b/sd/rustref.go @@ -20,18 +20,22 @@ func (d *SPICard) initRs() error { d.send(0xff) } d.csEnable(false) - + for i := 0; i < 512; i++ { + d.receive() + } d.csEnable(true) defer d.csEnable(false) // Enter SPI mode const maxRetries = 32 retries := maxRetries tm := d.timers[0].setTimeout(2 * time.Second) + println("cmdGoIdle") for retries > 0 { - stat, err := d.card_command(cmdGoIdleState, 0) + stat, err := d.card_command(cmdGoIdleState, 0) // CMD0. if err != nil { if isTimeout(err) { retries-- + println("cmdGoIdle timeout") continue // Try again! } return err @@ -47,9 +51,10 @@ func (d *SPICard) initRs() error { if retries <= 0 { return errNoSDCard } - const enableCRC = false + println("cmdGoIdle done; start cmdCRCON/OFF") + const enableCRC = true if enableCRC { - stat, err := d.card_command(cmdCRCOnOff, 1) + stat, err := d.card_command(cmdCRCOnOff, 1) // CMD59. if err != nil { return err } else if stat != _R1_IDLE_STATE { @@ -57,12 +62,13 @@ func (d *SPICard) initRs() error { } } - tm.setTimeout(d.timeout) + println("cmdCRCON/OFF done; start cmdSendIfCond") + tm.setTimeout(time.Second) for { - stat, err := d.card_command(cmdSendIfCond, 0x1aa) + stat, err := d.card_command(cmdSendIfCond, 0x1AA) // CMD8. if err != nil { return err - } else if stat == _R1_IDLE_STATE || stat == _R1_ILLEGAL_COMMAND { + } else if stat == (_R1_ILLEGAL_COMMAND | _R1_IDLE_STATE) { d.kind = TypeSD1 break } @@ -84,7 +90,9 @@ func (d *SPICard) initRs() error { if d.kind != TypeSD1 { arg = 0x4000_0000 } - for { + println("cmdSendIfCond done; start cmdAppCmd", arg) + tm.setTimeout(time.Second) + for !tm.expired() { stat, err := d.card_acmd(acmdSD_APP_OP_COND, arg) if err != nil { return err @@ -93,7 +101,7 @@ func (d *SPICard) initRs() error { } d.yield() } - + println("cmdAppCmd done; start cmdReadOCR") err := d.updateCSDCID() if err != nil { return err @@ -103,6 +111,7 @@ func (d *SPICard) initRs() error { return nil // Done if not SD2. } + println("discover high capacity") // Discover if card is high capacity. stat, err := d.card_command(cmdReadOCR, 0) if err != nil { @@ -123,6 +132,31 @@ func (d *SPICard) initRs() error { return nil } +func (d *SPICard) updateCSDCID() (err error) { + // read CID + d.cid, err = d.read_cid() + if err != nil { + return err + } + d.csd, err = d.read_csd() + if err != nil { + return err + } + blockshift := d.csd.ReadBlockLenShift() + blocklen := uint16(1) << blockshift + capacity := d.csd.DeviceCapacity() + if blocklen == 0 || capacity < uint64(blocklen) { + return errNoblocks + } + nb := capacity / uint64(blocklen) + if nb > math.MaxUint32 { + return errCardNotSupported + } + d.blockshift = blockshift + d.numblocks = int64(nb) + return nil +} + // ReadBlock reads to a buffer multiple of 512 bytes from sdcard into dst starting at block `startBlockIdx`. func (d *SPICard) ReadBlocks(dst []byte, startBlockIdx int64) error { numblocks, err := d.checkBounds(startBlockIdx, len(dst)) @@ -247,6 +281,32 @@ func (d *SPICard) checkBounds(startBlockIdx int64, datalen int) (numblocks int, return numblocks, nil } +func (d *SPICard) read_cid() (csd CID, err error) { + err = d.cmd_read(cmdSendCID, 0, d.buf[:16]) // CMD10. + if err != nil { + return csd, err + } + return DecodeCID(d.buf[:16]) +} + +func (d *SPICard) read_csd() (csd CSD, err error) { + err = d.cmd_read(cmdSendCSD, 0, d.buf[:16]) // CMD9. + if err != nil { + return csd, err + } + return DecodeCSD(d.buf[:16]) +} + +func (d *SPICard) cmd_read(cmd command, args uint32, buf []byte) error { + status, err := d.card_command(cmd, args) + if err != nil { + return err + } else if status != 0 { + return makeResponseError(response1(status)) + } + return d.read_data(buf) +} + func (d *SPICard) card_acmd(acmd appcommand, args uint32) (uint8, error) { _, err := d.card_command(cmdAppCmd, 0) if err != nil { @@ -312,7 +372,7 @@ func (d *SPICard) read_data(data []byte) (err error) { } func (s *SPICard) wait_not_busy() error { - tm := s.timers[0].setTimeout(s.timeout) + tm := s.timers[1].setTimeout(s.timeout) for { tok, err := s.receive() if err != nil {