From 845bd6fe9384f3632e336fab7c2ab7843d9f5f89 Mon Sep 17 00:00:00 2001 From: soypat Date: Sun, 14 Jan 2024 22:50:42 -0300 Subject: [PATCH] remove some of API --- sd/card.go | 36 +++++++++++++++++++++++++++--------- sd/card_test.go | 15 ++++++++++++--- sd/definitions.go | 22 ++++++++++++++-------- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/sd/card.go b/sd/card.go index 13bfbc9..59e1848 100644 --- a/sd/card.go +++ b/sd/card.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "errors" "math" - "runtime" "time" "tinygo.org/x/drivers" @@ -43,13 +42,29 @@ type SPICard struct { timers [2]timer numblocks int64 timeout time.Duration + wait time.Duration // relative card address. rca uint32 lastr1 r1 } func NewSPICard(spi drivers.SPI, cs digitalPinout) *SPICard { - return &SPICard{bus: spi, cs: cs, timeout: 300 * time.Millisecond} + const defaultTimeout = 300 * time.Millisecond + s := &SPICard{ + bus: spi, + cs: cs, + } + s.setTimeout(defaultTimeout) + return s +} + +// setTimeout sets the timeout for all operations and the wait time between each yield during busy spins. +func (c *SPICard) setTimeout(timeout time.Duration) { + if timeout <= 0 { + panic("timeout must be positive") + } + c.timeout = timeout + c.wait = timeout / 512 } func (c *SPICard) csEnable(b bool) { c.cs(!b) } @@ -61,7 +76,7 @@ func (c *SPICard) LastR1() r1 { return c.lastr1 } // 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[:] + dummy := d.buf[:512] for i := range dummy { dummy[i] = 0xFF } @@ -343,8 +358,8 @@ func (d *SPICard) appCmd(cmd appcommand, arg uint32) (response1, error) { return d.cmd(command(cmd), arg, 0xFF) } -func (d *SPICard) cmdEnsure0Status(cmd command, arg uint32, crc byte) error { - status, err := d.cmd(cmd, arg, crc) +func (d *SPICard) cmdEnsure0Status(cmd command, arg uint32, precalcCRC byte) error { + status, err := d.cmd(cmd, arg, precalcCRC) if err != nil { return err } @@ -354,7 +369,7 @@ func (d *SPICard) cmdEnsure0Status(cmd command, arg uint32, crc byte) error { return nil } -func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1, error) { +func (d *SPICard) cmd(cmd command, arg uint32, precalcCRC byte) (response1, error) { const transmitterBit = 1 << 6 if cmd >= transmitterBit { panic("invalid SD command") @@ -374,8 +389,8 @@ func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1 buf[0] = transmitterBit | byte(cmd) binary.BigEndian.PutUint32(buf[1:5], arg) - if precalculatedCRC != 0 { - buf[5] = precalculatedCRC + if precalcCRC != 0 { + buf[5] = precalcCRC } else { // CRC and end bit which is always 1. buf[5] = crc7noshift(buf[:5]) | 1 @@ -399,7 +414,7 @@ func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1 } else if tm.expired() { break } - runtime.Gosched() + d.yield() } d.csEnable(false) @@ -407,6 +422,8 @@ func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1 return 0xFF, errCmdGeneric } +func (d *SPICard) yield() { time.Sleep(d.wait) } + func (d *SPICard) waitNotBusy(timeout time.Duration) error { if _, ok := d.waitToken(timeout, 0xff); ok { return nil @@ -437,6 +454,7 @@ func (d *SPICard) waitToken(timeout time.Duration, tok byte) (byte, bool) { } else if tm.expired() { return received, false } + d.yield() } } diff --git a/sd/card_test.go b/sd/card_test.go index c465631..2192c65 100644 --- a/sd/card_test.go +++ b/sd/card_test.go @@ -60,17 +60,17 @@ func TestCRC7(t *testing.T) { } cmdTests := []struct { - cmd byte + cmd command arg uint32 wantCRC uint8 }{ { - cmd: CMD0_GO_IDLE_STATE, + cmd: cmdGoIdleState, arg: 0, wantCRC: 0x95, }, { - cmd: CMD8_SEND_IF_COND, + cmd: cmdSendIfCond, arg: 0x1AA, wantCRC: 0x87, }, @@ -84,3 +84,12 @@ func TestCRC7(t *testing.T) { } } } + +func putCmd(dst []byte, cmd command, arg uint32) { + dst[0] = byte(cmd) | (1 << 6) + dst[1] = byte(arg >> 24) + dst[2] = byte(arg >> 16) + dst[3] = byte(arg >> 8) + dst[4] = byte(arg) + dst[5] = crc7noshift(dst[:5]) | 1 // Stop bit added. +} diff --git a/sd/definitions.go b/sd/definitions.go index 2adbb3e..66976de 100644 --- a/sd/definitions.go +++ b/sd/definitions.go @@ -88,14 +88,17 @@ type CSD struct { data [16]byte } +// CSDv1 is the Card Specific Data register for V1 devices. See [CSD] for more info. type CSDv1 struct { CSD } +// CSDv2 is the Card Specific Data register for V2 devices. See [CSD] for more info. type CSDv2 struct { CSD } +// DecodeCSD decodes the CSD from a 16-byte slice. func DecodeCSD(b []byte) (CSD, error) { if len(b) < 16 { return CSD{}, io.ErrShortBuffer @@ -108,18 +111,22 @@ func DecodeCSD(b []byte) (CSD, error) { return csd, nil } -// CSDStructure returns the version of the CSD structure. -func (c *CSD) CSDStructure() uint8 { return c.data[0] >> 6 } +// csdStructure returns the version of the CSD structure. +func (c *CSD) csdStructure() uint8 { return c.data[0] >> 6 } +// Version returns the version of the CSD structure. Effectively returns 1+CSDStructure. +func (c *CSD) Version() uint8 { return 1 + c.csdStructure() } + +// MustV1 returns the CSD as a CSDv1. Panics if the CSD is not version 1.0. func (c CSD) MustV1() CSDv1 { - if c.CSDStructure() != 0 { + if c.csdStructure() != 0 { panic("CSD is not version 1.0") } return CSDv1{CSD: c} } func (c CSD) MustV2() CSDv2 { - if c.CSDStructure() != 1 { + if c.csdStructure() != 1 { panic("CSD is not version 2.0") } return CSDv2{CSD: c} @@ -215,7 +222,7 @@ func (c *CSD) IsCopy() bool { return c.data[14]&(1<<6) != 0 } func (c *CSD) FileFormatGroup() bool { return c.data[14]&(1<<7) != 0 } func (c *CSD) DeviceCapacity() (size uint64) { - switch c.CSDStructure() { + switch c.csdStructure() { case 0: v1 := c.MustV1() size = uint64(v1.DeviceCapacity()) @@ -283,7 +290,7 @@ func (c *CSDv1) VddWriteCurrent() (min, max uint8) { } func (c *CSD) String() string { - version := c.CSDStructure() + 1 + version := c.csdStructure() + 1 if version > 2 { return "" } @@ -298,7 +305,7 @@ func (c *CSDv1) String() string { return c.CSD.String() } func (c *CSDv2) String() string { return c.CSD.String() } func (c *CSD) appendf(b []byte, delim byte) []byte { - b = appendnum(b, "Version", uint64(c.CSDStructure()+1), delim) + b = appendnum(b, "Version", uint64(c.Version()), delim) b = appendnum(b, "Capacity(bytes)", c.DeviceCapacity(), delim) b = appendnum(b, "TimeAccess_ns", uint64(c.TAAC().AccessTime()), delim) b = appendnum(b, "NSAC", uint64(c.NSAC()), delim) @@ -466,7 +473,6 @@ func b2u8(b bool) uint8 { // CRC16 computes the CRC16 checksum for a given payload using the CRC-16-CCITT polynomial. func CRC16(buf []byte) (crc uint16) { const poly uint16 = 0x1021 // Generator polynomial G(x) = x^16 + x^12 + x^5 + 1 - for _, b := range buf { crc ^= (uint16(b) << 8) // Shift byte into MSB of crc for i := 0; i < 8; i++ { // Process each bit