mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-17 13:23:26 +00:00
no crc errors in status; closing the gap?
This commit is contained in:
+1
-2
@@ -36,7 +36,7 @@ func main() {
|
|||||||
|
|
||||||
err = sdcard.Init()
|
err = sdcard.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic("sd card init:" + err.Error())
|
||||||
}
|
}
|
||||||
cid := sdcard.CID()
|
cid := sdcard.CID()
|
||||||
pname := cid.ProductName()
|
pname := cid.ProductName()
|
||||||
@@ -61,7 +61,6 @@ func main() {
|
|||||||
|
|
||||||
var buf [512]byte
|
var buf [512]byte
|
||||||
for i := 0; i < 11; i += 1 {
|
for i := 0; i < 11; i += 1 {
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
err = sdcard.ReadBlock(0, buf[:])
|
err = sdcard.ReadBlock(0, buf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("err reading block", i, ":", err.Error())
|
println("err reading block", i, ":", err.Error())
|
||||||
|
|||||||
+16
-64
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
@@ -44,7 +44,8 @@ type SPICard struct {
|
|||||||
numblocks int64
|
numblocks int64
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
// relative card address.
|
// relative card address.
|
||||||
rca uint32
|
rca uint32
|
||||||
|
lastr1 r1
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPICard(spi drivers.SPI, cs digitalPinout) *SPICard {
|
func NewSPICard(spi drivers.SPI, cs digitalPinout) *SPICard {
|
||||||
@@ -55,6 +56,7 @@ func (c *SPICard) csEnable(b bool) { c.cs(!b) }
|
|||||||
|
|
||||||
// LastReadCRC returns the CRC for the last ReadBlock operation.
|
// LastReadCRC returns the CRC for the last ReadBlock operation.
|
||||||
func (c *SPICard) LastReadCRC() uint16 { return c.lastCRC }
|
func (c *SPICard) LastReadCRC() uint16 { return c.lastCRC }
|
||||||
|
func (c *SPICard) LastR1() r1 { return c.lastr1 }
|
||||||
|
|
||||||
func (d *SPICard) Init() error {
|
func (d *SPICard) Init() error {
|
||||||
dummy := d.buf[:]
|
dummy := d.buf[:]
|
||||||
@@ -184,7 +186,7 @@ func (d *SPICard) Init() error {
|
|||||||
return errNoblocks
|
return errNoblocks
|
||||||
}
|
}
|
||||||
d.numblocks = int64(nb)
|
d.numblocks = int64(nb)
|
||||||
|
return nil
|
||||||
err = d.readRegister(cmdSendRelativeAddr, d.buf[:4])
|
err = d.readRegister(cmdSendRelativeAddr, d.buf[:4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -386,12 +388,16 @@ func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1
|
|||||||
d.bus.Transfer(0xFF)
|
d.bus.Transfer(0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 0xFFFF; i++ {
|
tm := d.timers[0].setTimeout(d.timeout)
|
||||||
|
for {
|
||||||
tok, _ := d.bus.Transfer(0xff)
|
tok, _ := d.bus.Transfer(0xff)
|
||||||
response := response1(tok)
|
response := response1(tok)
|
||||||
if (response & 0x80) == 0 {
|
if (response & 0x80) == 0 {
|
||||||
return response, nil
|
return response, nil
|
||||||
|
} else if tm.expired() {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
|
|
||||||
d.csEnable(false)
|
d.csEnable(false)
|
||||||
@@ -400,14 +406,14 @@ func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *SPICard) waitNotBusy(timeout time.Duration) error {
|
func (d *SPICard) waitNotBusy(timeout time.Duration) error {
|
||||||
if d.waitToken(timeout, 0xff) {
|
if _, ok := d.waitToken(timeout, 0xff); ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errBusyTimeout
|
return errBusyTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *SPICard) waitStartBlock() error {
|
func (d *SPICard) waitStartBlock() error {
|
||||||
if d.waitToken(d.timeout, tokSTART_BLOCK) {
|
if _, ok := d.waitToken(d.timeout, tokSTART_BLOCK); ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
d.csEnable(false)
|
d.csEnable(false)
|
||||||
@@ -416,76 +422,22 @@ func (d *SPICard) waitStartBlock() error {
|
|||||||
|
|
||||||
// waitToken transmits over SPI waiting to read a given byte token. If argument tok
|
// waitToken transmits over SPI waiting to read a given byte token. If argument tok
|
||||||
// is 0xff then waitToken will wait for a token that does NOT match 0xff.
|
// is 0xff then waitToken will wait for a token that does NOT match 0xff.
|
||||||
func (d *SPICard) waitToken(timeout time.Duration, tok byte) bool {
|
func (d *SPICard) waitToken(timeout time.Duration, tok byte) (byte, bool) {
|
||||||
tm := d.timers[1].setTimeout(timeout)
|
tm := d.timers[1].setTimeout(timeout)
|
||||||
for {
|
for {
|
||||||
received, err := d.bus.Transfer(0xFF)
|
received, err := d.bus.Transfer(0xFF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return received, false
|
||||||
}
|
}
|
||||||
matchTok := received == tok
|
matchTok := received == tok
|
||||||
if matchTok || (!matchTok && tok == 0xff) {
|
if matchTok || (!matchTok && tok == 0xff) {
|
||||||
return true
|
return received, true
|
||||||
} else if tm.expired() {
|
} else if tm.expired() {
|
||||||
return false
|
return received, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type response1Err struct {
|
|
||||||
context string
|
|
||||||
status response1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e response1Err) Error() string {
|
|
||||||
return e.status.Response()
|
|
||||||
if e.context != "" {
|
|
||||||
return "sd:" + e.context + " " + strconv.Itoa(int(e.status))
|
|
||||||
}
|
|
||||||
return "sd:status " + strconv.Itoa(int(e.status))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e response1) Response() string {
|
|
||||||
b := make([]byte, 0, 8)
|
|
||||||
return string(e.appendf(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r response1) appendf(b []byte) []byte {
|
|
||||||
b = append(b, '[')
|
|
||||||
if r.IsIdle() {
|
|
||||||
b = append(b, "idle,"...)
|
|
||||||
}
|
|
||||||
if r.EraseReset() {
|
|
||||||
b = append(b, "erase-rst,"...)
|
|
||||||
}
|
|
||||||
if r.EraseSeqError() {
|
|
||||||
b = append(b, "erase-seq,"...)
|
|
||||||
}
|
|
||||||
if r.CRCError() {
|
|
||||||
b = append(b, "crc-err,"...)
|
|
||||||
}
|
|
||||||
if r.AddressError() {
|
|
||||||
b = append(b, "addr-err,"...)
|
|
||||||
}
|
|
||||||
if r.ParamError() {
|
|
||||||
b = append(b, "param-err,"...)
|
|
||||||
}
|
|
||||||
if r.IllegalCmdError() {
|
|
||||||
b = append(b, "illegal-cmd,"...)
|
|
||||||
}
|
|
||||||
if len(b) > 1 {
|
|
||||||
b = b[:len(b)-1]
|
|
||||||
}
|
|
||||||
b = append(b, ']')
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeResponseError(status response1) error {
|
|
||||||
return response1Err{
|
|
||||||
status: status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var timeoutTimer [2]timer
|
var timeoutTimer [2]timer
|
||||||
|
|
||||||
type timer struct {
|
type timer struct {
|
||||||
|
|||||||
@@ -456,136 +456,6 @@ func (t TAAC) AccessTime() (d time.Duration) {
|
|||||||
return time.Duration(log10table[t&0b111]) * time.Nanosecond
|
return time.Duration(log10table[t&0b111]) * time.Nanosecond
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
_CMD_TIMEOUT = 100
|
|
||||||
|
|
||||||
_R1_IDLE_STATE = 1 << 0
|
|
||||||
_R1_ERASE_RESET = 1 << 1
|
|
||||||
_R1_ILLEGAL_COMMAND = 1 << 2
|
|
||||||
_R1_COM_CRC_ERROR = 1 << 3
|
|
||||||
_R1_ERASE_SEQUENCE_ERROR = 1 << 4
|
|
||||||
_R1_ADDRESS_ERROR = 1 << 5
|
|
||||||
_R1_PARAMETER_ERROR = 1 << 6
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tokens that are sent by card during polling.
|
|
||||||
// https://github.com/arduino-libraries/SD/blob/master/src/utility/SdInfo.h
|
|
||||||
const (
|
|
||||||
tokSTART_BLOCK = 0xfe
|
|
||||||
tokSTOP_TRAN = 0xfd
|
|
||||||
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 }
|
|
||||||
func (r response1) IllegalCmdError() bool { return r&_R1_ILLEGAL_COMMAND != 0 }
|
|
||||||
func (r response1) CRCError() bool { return r&_R1_COM_CRC_ERROR != 0 }
|
|
||||||
func (r response1) EraseReset() bool { return r&_R1_ERASE_RESET != 0 }
|
|
||||||
func (r response1) EraseSeqError() bool { return r&_R1_ERASE_SEQUENCE_ERROR != 0 }
|
|
||||||
func (r response1) AddressError() bool { return r&_R1_ADDRESS_ERROR != 0 }
|
|
||||||
func (r response1) ParamError() bool { return r&_R1_PARAMETER_ERROR != 0 }
|
|
||||||
|
|
||||||
func b2u8(b bool) uint8 {
|
func b2u8(b bool) uint8 {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
+331
@@ -0,0 +1,331 @@
|
|||||||
|
package sd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CMD_TIMEOUT = 100
|
||||||
|
|
||||||
|
_R1_IDLE_STATE = 1 << 0
|
||||||
|
_R1_ERASE_RESET = 1 << 1
|
||||||
|
_R1_ILLEGAL_COMMAND = 1 << 2
|
||||||
|
_R1_COM_CRC_ERROR = 1 << 3
|
||||||
|
_R1_ERASE_SEQUENCE_ERROR = 1 << 4
|
||||||
|
_R1_ADDRESS_ERROR = 1 << 5
|
||||||
|
_R1_PARAMETER_ERROR = 1 << 6
|
||||||
|
)
|
||||||
|
|
||||||
|
type response1 uint8
|
||||||
|
|
||||||
|
func (r response1) IsIdle() bool { return r&_R1_IDLE_STATE != 0 }
|
||||||
|
func (r response1) IllegalCmdError() bool { return r&_R1_ILLEGAL_COMMAND != 0 }
|
||||||
|
func (r response1) CRCError() bool { return r&_R1_COM_CRC_ERROR != 0 }
|
||||||
|
func (r response1) EraseReset() bool { return r&_R1_ERASE_RESET != 0 }
|
||||||
|
func (r response1) EraseSeqError() bool { return r&_R1_ERASE_SEQUENCE_ERROR != 0 }
|
||||||
|
func (r response1) AddressError() bool { return r&_R1_ADDRESS_ERROR != 0 }
|
||||||
|
func (r response1) ParamError() bool { return r&_R1_PARAMETER_ERROR != 0 }
|
||||||
|
|
||||||
|
type response1Err struct {
|
||||||
|
context string
|
||||||
|
status response1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e response1Err) Error() string {
|
||||||
|
return e.status.Response()
|
||||||
|
if e.context != "" {
|
||||||
|
return "sd:" + e.context + " " + strconv.Itoa(int(e.status))
|
||||||
|
}
|
||||||
|
return "sd:status " + strconv.Itoa(int(e.status))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e response1) Response() string {
|
||||||
|
b := make([]byte, 0, 8)
|
||||||
|
return string(e.appendf(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r response1) appendf(b []byte) []byte {
|
||||||
|
b = append(b, '[')
|
||||||
|
if r.IsIdle() {
|
||||||
|
b = append(b, "idle,"...)
|
||||||
|
}
|
||||||
|
if r.EraseReset() {
|
||||||
|
b = append(b, "erase-rst,"...)
|
||||||
|
}
|
||||||
|
if r.EraseSeqError() {
|
||||||
|
b = append(b, "erase-seq,"...)
|
||||||
|
}
|
||||||
|
if r.CRCError() {
|
||||||
|
b = append(b, "crc-err,"...)
|
||||||
|
}
|
||||||
|
if r.AddressError() {
|
||||||
|
b = append(b, "addr-err,"...)
|
||||||
|
}
|
||||||
|
if r.ParamError() {
|
||||||
|
b = append(b, "param-err,"...)
|
||||||
|
}
|
||||||
|
if r.IllegalCmdError() {
|
||||||
|
b = append(b, "illegal-cmd,"...)
|
||||||
|
}
|
||||||
|
if len(b) > 1 {
|
||||||
|
b = b[:len(b)-1]
|
||||||
|
}
|
||||||
|
b = append(b, ']')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeResponseError(status response1) error {
|
||||||
|
return response1Err{
|
||||||
|
status: status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// is part of specification but not used in every implementation out there...
|
||||||
|
func (d *SPICard) readR1() (resp r1, err error) {
|
||||||
|
first, ok := d.waitToken(d.timeout, 0xff)
|
||||||
|
if !ok {
|
||||||
|
return resp, errBusyTimeout
|
||||||
|
}
|
||||||
|
err = d.bus.Tx(nil, d.buf[1:6])
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
d.buf[0] = first
|
||||||
|
copy(resp.data[:], d.buf[:6])
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands used to help generate this file:
|
||||||
|
// - stringer -type=state -trimprefix=state -output=state_string.go
|
||||||
|
// - stringer -type=status -trimprefix=status -output=status_string.go
|
||||||
|
|
||||||
|
// Tokens that are sent by card during polling.
|
||||||
|
// https://github.com/arduino-libraries/SD/blob/master/src/utility/SdInfo.h
|
||||||
|
const (
|
||||||
|
tokSTART_BLOCK = 0xfe
|
||||||
|
tokSTOP_TRAN = 0xfd
|
||||||
|
tokWRITE_MULT = 0xfc
|
||||||
|
)
|
||||||
|
|
||||||
|
type state uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
stateIdle state = iota
|
||||||
|
stateReady
|
||||||
|
stateIdent
|
||||||
|
stateStby
|
||||||
|
stateTran
|
||||||
|
stateData
|
||||||
|
stateRcv
|
||||||
|
statePrg
|
||||||
|
stateDis
|
||||||
|
)
|
||||||
|
|
||||||
|
// status represents the Card Status Register (R1), as per section 4.10.1.
|
||||||
|
type status uint32
|
||||||
|
|
||||||
|
func (s status) state() state {
|
||||||
|
return state(s >> 9 & 0xf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First status bits.
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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, s.state().String()...)
|
||||||
|
b = append(b, '[')
|
||||||
|
if s == 0 {
|
||||||
|
return append(b, ']')
|
||||||
|
}
|
||||||
|
for bit := 0; bit < 32; bit++ {
|
||||||
|
if s&(1<<bit) != 0 {
|
||||||
|
b = append(b, status(bit).string()...)
|
||||||
|
b = append(b, delim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = append(b[:len(b)-1], ']')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
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[stateIdle-0]
|
||||||
|
_ = x[stateReady-1]
|
||||||
|
_ = x[stateIdent-2]
|
||||||
|
_ = x[stateStby-3]
|
||||||
|
_ = x[stateTran-4]
|
||||||
|
_ = x[stateData-5]
|
||||||
|
_ = x[stateRcv-6]
|
||||||
|
_ = x[statePrg-7]
|
||||||
|
_ = x[stateDis-8]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _state_name = "IdleReadyIdentStbyTranDataRcvPrgDis"
|
||||||
|
|
||||||
|
var _state_index = [...]uint8{0, 4, 9, 14, 18, 22, 26, 29, 32, 35}
|
||||||
|
|
||||||
|
func (i state) String() string {
|
||||||
|
if i >= state(len(_state_index)-1) {
|
||||||
|
return "<reserved state>"
|
||||||
|
}
|
||||||
|
return _state_name[_state_index[i]:_state_index[i+1]]
|
||||||
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
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<<bit) != 0 {
|
|
||||||
b = append(b, status(bit).string()...)
|
|
||||||
b = append(b, delim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b = append(b[:len(b)-1], ']')
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user