failing CRC7 implementation

This commit is contained in:
soypat
2024-01-14 14:17:04 -03:00
parent 2f85c8bd04
commit 46cd56951c
4 changed files with 198 additions and 76 deletions
+11 -7
View File
@@ -32,7 +32,7 @@ func main() {
if err != nil {
panic(err.Error())
}
sdcard := sd.NewCard(spibus, SPI_CS_PIN.Set)
sdcard := sd.NewSPICard(spibus, SPI_CS_PIN.Set)
err = sdcard.Init()
if err != nil {
@@ -47,20 +47,24 @@ func main() {
data := csd.RawCopy()
crc := sd.CRC7(data[:15])
always1 := data[15]&(1<<7) != 0
println("CSD not valid got", crc, "want", data[15]&^(1<<7), "always1:", always1)
fmt.Printf("ourCRC7=%#b theirCRC7=%#b for data %d\n", crc, csd.CRC7(), data[:15])
println("CSD not valid got", crc, "want", csd.CRC7(), "always1:", always1)
return
} else {
println("CSD valid!")
}
fmt.Printf("name=%s\ncsd=\n%s\n", pname, csd.String())
return
var buf [512]byte
for i := 1; i < 11; i += 1 {
time.Sleep(time.Millisecond)
err = sdcard.ReadBlock(uint32(i), buf[:])
for i := 0; i < 11; i += 1 {
time.Sleep(100 * time.Millisecond)
err = sdcard.ReadBlock(int64(i), buf[:])
if err != nil {
println("err reading block", i, ":", err.Error())
continue
}
fmt.Printf("block %d crc=%#x:\n\t%#x\n", i, sdcard.LastReadCRC(), buf[:])
expectCRC := sd.CRC16(buf[:])
fmt.Printf("block %d theircrc=%#x ourcrc=%#x:\n\t%#x\n", i, sdcard.LastReadCRC(), expectCRC, buf[:])
}
}
+80 -53
View File
@@ -3,6 +3,7 @@ package sd
import (
"encoding/binary"
"errors"
"math"
"runtime"
"strconv"
"time"
@@ -21,33 +22,36 @@ var (
errNeed512 = errors.New("sd:need 512 bytes for I/O")
errWrite = errors.New("sd:write")
errWriteTimeout = errors.New("sd:write timeout")
errOOB = errors.New("sd:oob block access")
errNoblocks = errors.New("sd:no readable blocks")
)
type digitalPinout func(b bool)
type Card struct {
bus drivers.SPI
cs digitalPinout
bufcmd [6]byte
buf [512]byte
bufTok [1]byte
kind CardKind
cid CID
csd CSD
lastCRC uint16
timers [2]timer
type SPICard struct {
bus drivers.SPI
cs digitalPinout
bufcmd [6]byte
buf [512]byte
bufTok [1]byte
kind CardKind
cid CID
csd CSD
lastCRC uint16
timers [2]timer
numblocks int64
}
func NewCard(spi drivers.SPI, cs digitalPinout) *Card {
return &Card{bus: spi, cs: cs}
func NewSPICard(spi drivers.SPI, cs digitalPinout) *SPICard {
return &SPICard{bus: spi, cs: cs}
}
func (c *Card) csEnable(b bool) { c.cs(!b) }
func (c *SPICard) csEnable(b bool) { c.cs(!b) }
// LastReadCRC returns the CRC for the last ReadBlock operation.
func (c *Card) LastReadCRC() uint16 { return c.lastCRC }
func (c *SPICard) LastReadCRC() uint16 { return c.lastCRC }
func (d *Card) Init() error {
func (d *SPICard) Init() error {
dummy := d.buf[:]
for i := range dummy {
dummy[i] = 0xFF
@@ -92,7 +96,7 @@ func (d *Card) Init() error {
status := byte(0)
for i := 0; i < 3; i++ {
var err error
status, err = d.bus.Transfer(byte(0xFF))
status, err = d.bus.Transfer(0xFF)
if err != nil {
return err
}
@@ -103,7 +107,7 @@ func (d *Card) Init() error {
for i := 3; i < 4; i++ {
var err error
status, err = d.bus.Transfer(byte(0xFF))
status, err = d.bus.Transfer(0xFF)
if err != nil {
return err
}
@@ -143,7 +147,7 @@ func (d *Card) Init() error {
return err
}
statusb, err := d.bus.Transfer(byte(0xFF))
statusb, err := d.bus.Transfer(0xFF)
if err != nil {
return err
}
@@ -152,7 +156,7 @@ func (d *Card) Init() error {
}
// discard rest of ocr - contains allowed voltage range
for i := 1; i < 4; i++ {
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(0xFF)
}
}
err = d.cmdEnsure0Status(CMD16_SET_BLOCKLEN, 0x0200, 0xff)
@@ -169,20 +173,33 @@ func (d *Card) Init() error {
if err != nil {
return err
}
nb := d.csd.NumberOfBlocks()
if nb > math.MaxUint32 {
return errCardNotSupported
} else if nb == 0 {
return errNoblocks
}
d.numblocks = int64(nb)
return nil
}
// ReadData reads 512 bytes from sdcard into dst.
func (d *Card) ReadBlock(block uint32, dst []byte) error {
func (d *SPICard) NumberOfBlocks() uint64 {
return uint64(d.numblocks)
}
// ReadBlock reads 512 bytes from sdcard into dst.
func (d *SPICard) ReadBlock(block int64, dst []byte) error {
if len(dst) != 512 {
return errNeed512
} else if block >= d.numblocks {
return errOOB
}
// use address if not SDHC card
if d.kind != TypeSDHC {
block <<= 9
}
err := d.cmdEnsure0Status(CMD17_READ_SINGLE_BLOCK, block, 0xFF)
err := d.cmdEnsure0Status(CMD17_READ_SINGLE_BLOCK, uint32(block), 0xFF)
if err != nil {
return err
}
@@ -198,23 +215,25 @@ func (d *Card) ReadBlock(block uint32, dst []byte) error {
}
// skip CRC (2byte)
hi, _ := d.bus.Transfer(byte(0xFF))
lo, _ := d.bus.Transfer(byte(0xFF))
hi, _ := d.bus.Transfer(0xFF)
lo, _ := d.bus.Transfer(0xFF)
d.lastCRC = uint16(hi)<<8 | uint16(lo)
return nil
}
// WriteBlock writes 512 bytes from dst to sdcard.
func (d *Card) WriteBlock(block uint32, src []byte) error {
func (d *SPICard) WriteBlock(block int64, src []byte) error {
if len(src) != 512 {
return errNeed512
} else if block >= d.numblocks {
return errOOB
}
// use address if not SDHC card
if d.kind != TypeSDHC {
block <<= 9
}
err := d.cmdEnsure0Status(CMD24_WRITE_BLOCK, block, 0xFF)
err := d.cmdEnsure0Status(CMD24_WRITE_BLOCK, uint32(block), 0xFF)
if err != nil {
return err
}
@@ -229,11 +248,11 @@ func (d *Card) WriteBlock(block uint32, src []byte) error {
}
// send dummy CRC (2 byte)
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(0xFF)
d.bus.Transfer(0xFF)
// Data Resp.
r, err := d.bus.Transfer(byte(0xFF))
r, err := d.bus.Transfer(0xFF)
if err != nil {
return err
}
@@ -251,12 +270,12 @@ func (d *Card) WriteBlock(block uint32, src []byte) error {
}
// CID returns a copy of the Card Identification Register value last read.
func (d *Card) CID() CID { return d.cid }
func (d *SPICard) CID() CID { return d.cid }
// CSD returns a copy of the Card Specific Data Register value last read.
func (d *Card) CSD() CSD { return d.csd }
func (d *SPICard) CSD() CSD { return d.csd }
func (d *Card) readCID() (CID, error) {
func (d *SPICard) readCID() (CID, error) {
buf := d.buf[len(d.buf)-16:]
if err := d.readRegister(CMD10_SEND_CID, buf); err != nil {
return CID{}, err
@@ -264,7 +283,7 @@ func (d *Card) readCID() (CID, error) {
return DecodeCID(buf)
}
func (d *Card) readCSD() (CSD, error) {
func (d *SPICard) readCSD() (CSD, error) {
buf := d.buf[len(d.buf)-16:]
if err := d.readRegister(CMD9_SEND_CSD, buf); err != nil {
return CSD{}, err
@@ -272,7 +291,7 @@ func (d *Card) readCSD() (CSD, error) {
return DecodeCSD(buf)
}
func (d *Card) readRegister(cmd uint8, dst []byte) error {
func (d *SPICard) readRegister(cmd uint8, dst []byte) error {
err := d.cmdEnsure0Status(cmd, 0, 0xFF)
if err != nil {
return err
@@ -282,20 +301,20 @@ func (d *Card) readRegister(cmd uint8, dst []byte) error {
}
// transfer data
for i := uint16(0); i < 16; i++ {
r, err := d.bus.Transfer(byte(0xFF))
r, err := d.bus.Transfer(0xFF)
if err != nil {
return err
}
dst[i] = r
}
// skip CRC.
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(0xFF)
d.bus.Transfer(0xFF)
d.csEnable(false)
return nil
}
func (d *Card) appCmd(cmd byte, arg uint32) (response1, error) {
func (d *SPICard) appCmd(cmd byte, arg uint32) (response1, error) {
status, err := d.cmd(CMD55_APP_CMD, 0, 0xFF)
if err != nil {
return status, err
@@ -303,7 +322,7 @@ func (d *Card) appCmd(cmd byte, arg uint32) (response1, error) {
return d.cmd(cmd, arg, 0xFF)
}
func (d *Card) cmdEnsure0Status(cmd byte, arg uint32, crc byte) error {
func (d *SPICard) cmdEnsure0Status(cmd byte, arg uint32, crc byte) error {
status, err := d.cmd(cmd, arg, crc)
if err != nil {
return err
@@ -314,7 +333,17 @@ func (d *Card) cmdEnsure0Status(cmd byte, arg uint32, crc byte) error {
return nil
}
func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
func putCmd(dst []byte, cmd byte, arg uint32) {
if len(dst) < 6 {
panic("bad buflength")
}
dst[0] = 0x40 | cmd
binary.BigEndian.PutUint32(dst[1:5], arg)
dst[5] = CRC7(dst[:5])<<1 | 1 // CRC and stop bit.
}
// 0100000000000000000000000000000000000000
func (d *SPICard) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
d.csEnable(true)
if cmd != 12 {
@@ -322,9 +351,8 @@ func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
}
// create and send the command
buf := d.bufcmd[:]
buf[0] = 0x40 | cmd
binary.BigEndian.PutUint32(buf[1:5], arg)
buf := d.bufcmd[:6]
putCmd(buf, cmd, arg)
buf[5] = crc
err := d.bus.Tx(buf, nil)
if err != nil {
@@ -332,14 +360,13 @@ func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
}
if cmd == 12 {
// skip 1 byte
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(0xFF)
}
// wait for the response (response[7] == 0)
d.buf[0] = 0xFF
dummy := d.buf[:1]
buf[0] = 0xFF
for i := 0; i < 0xFFFF; i++ {
d.bus.Tx(dummy, d.bufTok[:])
d.bus.Tx(buf[:1], d.bufTok[:])
response := response1(d.bufTok[0])
if (response & 0x80) == 0 {
return response, nil
@@ -349,15 +376,15 @@ func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
// TODO
//// timeout
d.csEnable(false)
d.bus.Transfer(byte(0xFF))
d.bus.Transfer(0xFF)
return 0xFF, nil // -1
}
func (d *Card) waitNotBusy(timeout time.Duration) error {
func (d *SPICard) waitNotBusy(timeout time.Duration) error {
tm := d.timers[1].setTimeout(timeout)
for !tm.expired() {
r, err := d.bus.Transfer(byte(0xFF))
r, err := d.bus.Transfer(0xFF)
if err != nil {
return err
}
@@ -369,12 +396,12 @@ func (d *Card) waitNotBusy(timeout time.Duration) error {
return nil
}
func (d *Card) waitStartBlock() error {
func (d *SPICard) waitStartBlock() error {
status := byte(0xFF)
tm := d.timers[0].setTimeout(300 * time.Millisecond)
for !tm.expired() {
var err error
status, err = d.bus.Transfer(byte(0xFF))
status, err = d.bus.Transfer(0xFF)
if err != nil {
d.csEnable(false)
return err
+58 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
)
func TestCRC(t *testing.T) {
func TestCRC16(t *testing.T) {
tests := []struct {
block string
wantcrc uint16
@@ -27,3 +27,60 @@ func TestCRC(t *testing.T) {
}
}
}
func TestCRC7(t *testing.T) {
const cmdSendMask = 0x40
tests := []struct {
data []byte
wantCRC uint8
}{
{ // See CRC7 Examples from section 4.5 of the SD Card Physical Layer Simplified Specification.
data: []byte{cmdSendMask, 5: 0}, // CMD0, arg=0
wantCRC: 0b1001010,
},
{
data: []byte{cmdSendMask | 17, 5: 0}, // CMD17, arg=0
wantCRC: 0b0101010,
},
{
data: []byte{17, 4: 0b1001, 5: 0}, // Response of CMD17
wantCRC: 0b0110011,
},
{ // CSD for a 8GB card.
data: []byte{64, 14, 0, 50, 83, 89, 0, 0, 60, 1, 127, 128, 10, 64, 0},
wantCRC: 0b1100101,
},
}
for _, tt := range tests {
gotcrc := CRC7(tt.data[:])
if gotcrc != tt.wantCRC {
t.Errorf("got crc=%#b, want=%#b", gotcrc, tt.wantCRC)
}
}
cmdTests := []struct {
cmd byte
arg uint32
wantCRC uint8
}{
{
cmd: CMD0_GO_IDLE_STATE,
arg: 0,
wantCRC: 0x95,
},
{
cmd: CMD8_SEND_IF_COND,
arg: 0x1AA,
wantCRC: 0x87,
},
}
var dst [6]byte
for _, test := range cmdTests {
putCmd(dst[:], test.cmd, test.arg)
gotcrc := dst[5]
if gotcrc != test.wantCRC {
t.Errorf("got crc=%#x, want=%#x", gotcrc, test.wantCRC)
}
}
}
+49 -15
View File
@@ -196,6 +196,15 @@ func (c *CSD) DeviceCapacity() (size uint64) {
return size
}
// NumberOfBlocks returns amount of readable blocks in the device given by Capacity/ReadBlockLength.
func (c *CSD) NumberOfBlocks() (numBlocks uint64) {
rblocks := c.ReadBlockLen()
if rblocks == 0 {
return 0
}
return c.DeviceCapacity() / uint64(rblocks)
}
// After byte 5 CSDv1 and CSDv2 differ in structure at some fields.
// DeviceCapacity returns the device capacity in bytes.
@@ -440,9 +449,9 @@ func b2u8(b bool) uint8 {
}
// CRC16 computes the CRC16 checksum for a given payload using the CRC-16-CCITT polynomial.
func CRC16(buf []byte) (sum uint16) {
func CRC16(buf []byte) (crc uint16) {
const poly uint16 = 0x1021 // Generator polynomial G(x) = x^16 + x^12 + x^5 + 1
var crc uint16 = 0x0000 // Initial value
for _, b := range buf {
crc ^= (uint16(b) << 8) // Shift byte into MSB of crc
for i := 0; i < 8; i++ { // Process each bit
@@ -457,19 +466,44 @@ func CRC16(buf []byte) (sum uint16) {
}
// CRC7 computes the CRC7 checksum for a given payload using the polynomial x^7 + x^3 + 1.
func CRC7(data []byte) uint8 {
const poly uint8 = 0x09 // Generator polynomial G(x) = x^7 + x^3 + 1
var crc uint8 = 0x00 // Initial value
func CRC7(data []byte) (crc uint8) {
for _, b := range data {
crc ^= b // Initial XOR
for i := 0; i < 8; i++ { // Process each bit
if crc&0x80 != 0 {
crc = (crc << 1) ^ poly
} else {
crc <<= 1
}
}
crc = crc7_table[crc^b]
}
return crc >> 1
return crc
}
var crc7_table = [256]byte{
0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee,
0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c,
0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc,
0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a,
0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a,
0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28,
0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8,
0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6,
0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26,
0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84,
0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14,
0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2,
0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42,
0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0,
0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70,
0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc,
0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c,
0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce,
0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e,
0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98,
0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08,
0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa,
0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a,
0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34,
0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4,
0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06,
0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96,
0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50,
0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0,
0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62,
0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2,
}