diff --git a/examples/sd/main.go b/examples/sd/main.go index b4a42c7..a314ac1 100644 --- a/examples/sd/main.go +++ b/examples/sd/main.go @@ -62,7 +62,7 @@ func main() { var buf [512]byte for i := 0; i < 11; i += 1 { time.Sleep(100 * time.Millisecond) - err = sdcard.ReadBlock(int64(i), buf[:]) + err = sdcard.ReadBlock(0, buf[:]) if err != nil { println("err reading block", i, ":", err.Error()) continue diff --git a/sd/card.go b/sd/card.go index 89bb00d..494d1ab 100644 --- a/sd/card.go +++ b/sd/card.go @@ -43,6 +43,8 @@ type SPICard struct { timers [2]timer numblocks int64 timeout time.Duration + // relative card address. + rca uint32 } func NewSPICard(spi drivers.SPI, cs digitalPinout) *SPICard { @@ -182,6 +184,12 @@ func (d *SPICard) Init() error { return errNoblocks } d.numblocks = int64(nb) + + err = d.readRegister(cmdSendRelativeAddr, d.buf[:4]) + if err != nil { + return err + } + d.rca = binary.BigEndian.Uint32(d.buf[:4]) return nil } @@ -271,6 +279,13 @@ func (d *SPICard) WriteBlock(block int64, src []byte) error { return nil } +func (d *SPICard) ReadStatus() (response1, error) { + if err := d.readRegister(cmdSendStatus, d.buf[:4]); err != nil { + return 0, err + } + return response1(binary.BigEndian.Uint32(d.buf[:4])), nil +} + // CID returns a copy of the Card Identification Register value last read. func (d *SPICard) CID() CID { return d.cid } diff --git a/sd/definitions.go b/sd/definitions.go index ccdc2be..4ff3381 100644 --- a/sd/definitions.go +++ b/sd/definitions.go @@ -476,6 +476,106 @@ const ( tokWRITE_MULT = 0xfc ) +type status uint32 + +// First status bits. +// +//go:generate stringer -type=status -trimprefix=status -output=status_string.go +const ( + statusRsvd0 status = iota + statusRsvd1 + statusRsvd2 + statusAuthSeqError + statusRsvdSDIO + statusAppCmd + statusFXEvent + statusRsvd7 + statusReadyForData +) + +// Upper bound status bits. +const ( + statusEraseReset status = iota + 13 + statusECCDisabled + statusWPEraseSkip + statusCSDOverwrite + _ + _ + statusGenericError + statusControllerError // internal card controller error + statusECCFailed + statusIllegalCommand + statusComCRCError // CRC check of previous command failed + statusLockUnlockFailed + statusCardIsLocked // Signals that the card is locked by the host. + statusWPViolation // Write protected violation + statusEraseParamError // invalid write block selection for erase + statusEraseSeqError // error in erase sequence + statusBlockLenError // tx block length not allowed + statusAddrError // misaligned address + statusAddrOutOfRange // address out of range +) + +// r1 is the normal response to a command. +type r1 struct { + data [48 / 8]byte // 48 bits of response. +} + +func (r *r1) RawCopy() [6]byte { return r.data } +func (r *r1) startbit() bool { + return r.data[0]&(1<<7) != 0 +} +func (r *r1) txbit() bool { + return r.data[0]&(1<<6) != 0 +} +func (r *r1) cmdidx() uint8 { + return r.data[0] & 0b11_1111 +} +func (r *r1) cardstatus() status { + return status(binary.BigEndian.Uint32(r.data[1:5])) +} +func (r *r1) CRC7() uint8 { return r.data[5] >> 1 } +func (r *r1) endbit() bool { return r.data[5]&1 != 0 } + +func (r *r1) IsValid() bool { + return r.endbit() && CRC7(r.data[:5]) == r.CRC7() +} + +type r6 struct { + data [48 / 8]byte +} + +func (r *r6) RawCopy() [6]byte { return r.data } +func (r *r6) startbit() bool { + return r.data[0]&(1<<7) != 0 +} +func (r *r6) txbit() bool { + return r.data[0]&(1<<6) != 0 +} +func (r *r6) cmdidx() uint8 { + return r.data[0] & 0b11_1111 +} +func (r *r6) rca() uint16 { + return binary.BigEndian.Uint16(r.data[1:3]) +} +func (r *r6) cardstatus() status { + moveBit := func(b status, from, to uint) status { + return (b & (1 << from)) >> from << to + } + // See 4.9.5 R6 (Published RCA response) of the SD Simplified Specification. + s := status(binary.BigEndian.Uint16(r.data[1:5])) + s = moveBit(s, 13, 19) + s = moveBit(s, 14, 22) + s = moveBit(s, 15, 23) + return s +} +func (r *r6) CRC7() uint8 { return r.data[5] >> 1 } +func (r *r6) endbit() bool { return r.data[5]&1 != 0 } + +func (r *r6) IsValid() bool { + return r.endbit() && CRC7(r.data[:5]) == r.CRC7() +} + type response1 uint8 func (r response1) IsIdle() bool { return r&_R1_IDLE_STATE != 0 } diff --git a/sd/status_string.go b/sd/status_string.go new file mode 100644 index 0000000..82b77de --- /dev/null +++ b/sd/status_string.go @@ -0,0 +1,79 @@ +package sd + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[statusRsvd0-0] + _ = x[statusRsvd1-1] + _ = x[statusRsvd2-2] + _ = x[statusAuthSeqError-3] + _ = x[statusRsvdSDIO-4] + _ = x[statusAppCmd-5] + _ = x[statusFXEvent-6] + _ = x[statusRsvd7-7] + _ = x[statusReadyForData-8] + _ = x[statusEraseReset-13] + _ = x[statusECCDisabled-14] + _ = x[statusWPEraseSkip-15] + _ = x[statusCSDOverwrite-16] + _ = x[statusGenericError-19] + _ = x[statusControllerError-20] + _ = x[statusECCFailed-21] + _ = x[statusIllegalCommand-22] + _ = x[statusComCRCError-23] + _ = x[statusLockUnlockFailed-24] + _ = x[statusCardIsLocked-25] + _ = x[statusWPViolation-26] + _ = x[statusEraseParamError-27] + _ = x[statusEraseSeqError-28] + _ = x[statusBlockLenError-29] + _ = x[statusAddrError-30] + _ = x[statusAddrOutOfRange-31] +} + +const ( + _status_name_0 = "Rsvd0Rsvd1Rsvd2AuthSeqErrorRsvdSDIOAppCmdFXEventRsvd7ReadyForData" + _status_name_1 = "EraseResetECCDisabledWPEraseSkipCSDOverwrite" + _status_name_2 = "GenericErrorControllerErrorECCFailedIllegalCommandComCRCErrorLockUnlockFailedCardIsLockedWPViolationEraseParamErrorEraseSeqErrorBlockLenErrorAddrErrorAddrOutOfRange" +) + +var ( + _status_index_0 = [...]uint8{0, 5, 10, 15, 27, 35, 41, 48, 53, 65} + _status_index_1 = [...]uint8{0, 10, 21, 32, 44} + _status_index_2 = [...]uint8{0, 12, 27, 36, 50, 61, 77, 89, 100, 115, 128, 141, 150, 164} +) + +func (i status) string() string { + switch { + case i <= 8: + return _status_name_0[_status_index_0[i]:_status_index_0[i+1]] + case 13 <= i && i <= 16: + i -= 13 + return _status_name_1[_status_index_1[i]:_status_index_1[i+1]] + case 19 <= i && i <= 31: + i -= 19 + return _status_name_2[_status_index_2[i]:_status_index_2[i+1]] + default: + return "" + } +} + +func (s status) String() string { + return string(s.appendf(nil, ',')) +} + +func (s status) appendf(b []byte, delim byte) []byte { + b = append(b, '[') + if s == 0 { + return append(b, ']') + } + for bit := 0; bit < 32; bit++ { + if s&(1<