diff --git a/sd/card.go b/sd/card.go index ba704fd..a854603 100644 --- a/sd/card.go +++ b/sd/card.go @@ -71,7 +71,7 @@ func (d *SPICard) Init() error { 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(CMD0_GO_IDLE_STATE, 0, 0x95) + result, err := d.cmd(cmdGoIdleState, 0, 0x95) if err != nil { return err } @@ -85,39 +85,38 @@ func (d *SPICard) Init() error { } // CMD8: determine card version - r1, err := d.cmd(CMD8_SEND_IF_COND, 0x01AA, 0x87) + r1, err := d.cmd(cmdSendIfCond, 0x01AA, 0x87) if err != nil { return err } if r1.IllegalCmdError() { d.kind = TypeSD1 return errCardNotSupported - } else { - // 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 } + // 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) @@ -129,7 +128,7 @@ func (d *SPICard) Init() error { ok = false tm = tm.setTimeout(2 * time.Second) for !tm.expired() { - r1, err = d.appCmd(ACMD41_SD_APP_OP_COND, arg) + r1, err = d.appCmd(acmdSD_APP_OP_COND, arg) if err != nil { return err } @@ -143,7 +142,7 @@ func (d *SPICard) Init() error { // if SD2 read OCR register to check for SDHC card if d.kind == TypeSD2 { - err := d.cmdEnsure0Status(CMD58_READ_OCR, 0, 0xFF) + err := d.cmdEnsure0Status(cmdReadOCR, 0, 0xFF) if err != nil { return err } @@ -160,7 +159,7 @@ func (d *SPICard) Init() error { d.bus.Transfer(0xFF) } } - err = d.cmdEnsure0Status(CMD16_SET_BLOCKLEN, 0x0200, 0xff) + err = d.cmdEnsure0Status(cmdSetBlocklen, 0x0200, 0xff) if err != nil { return err } @@ -200,7 +199,8 @@ func (d *SPICard) ReadBlock(block int64, dst []byte) error { if d.kind != TypeSDHC { block <<= 9 } - err := d.cmdEnsure0Status(CMD17_READ_SINGLE_BLOCK, uint32(block), 0xFF) + + err := d.cmdEnsure0Status(cmdReadSingleBlock, uint32(block), 0) if err != nil { return err } @@ -234,7 +234,7 @@ func (d *SPICard) WriteBlock(block int64, src []byte) error { if d.kind != TypeSDHC { block <<= 9 } - err := d.cmdEnsure0Status(CMD24_WRITE_BLOCK, uint32(block), 0xFF) + err := d.cmdEnsure0Status(cmdWriteBlock, uint32(block), 0xFF) if err != nil { return err } @@ -278,7 +278,7 @@ 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(CMD10_SEND_CID, buf); err != nil { + if err := d.readRegister(cmdSendCID, buf); err != nil { return CID{}, err } return DecodeCID(buf) @@ -286,13 +286,13 @@ func (d *SPICard) readCID() (CID, error) { func (d *SPICard) readCSD() (CSD, error) { buf := d.buf[len(d.buf)-16:] - if err := d.readRegister(CMD9_SEND_CSD, buf); err != nil { + if err := d.readRegister(cmdSendCSD, buf); err != nil { return CSD{}, err } return DecodeCSD(buf) } -func (d *SPICard) readRegister(cmd uint8, dst []byte) error { +func (d *SPICard) readRegister(cmd command, dst []byte) error { err := d.cmdEnsure0Status(cmd, 0, 0xFF) if err != nil { return err @@ -315,15 +315,15 @@ func (d *SPICard) readRegister(cmd uint8, dst []byte) error { return nil } -func (d *SPICard) appCmd(cmd byte, arg uint32) (response1, error) { - status, err := d.cmd(CMD55_APP_CMD, 0, 0xFF) +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(cmd, arg, 0xFF) + return d.cmd(command(cmd), arg, 0xFF) } -func (d *SPICard) cmdEnsure0Status(cmd byte, arg uint32, crc byte) error { +func (d *SPICard) cmdEnsure0Status(cmd command, arg uint32, crc byte) error { status, err := d.cmd(cmd, arg, crc) if err != nil { return err @@ -334,17 +334,10 @@ func (d *SPICard) cmdEnsure0Status(cmd byte, arg uint32, crc byte) error { return nil } -func putCmd(dst []byte, cmd byte, arg uint32) { - if len(dst) < 6 { - panic("bad buflength") +func (d *SPICard) cmd(cmd command, arg uint32, precalculatedCRC byte) (response1, error) { + if cmd >= 1<<6 { + panic("invalid SD command") } - 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 { @@ -353,8 +346,17 @@ func (d *SPICard) cmd(cmd byte, arg uint32, crc byte) (response1, error) { // create and send the command buf := d.bufcmd[:6] - putCmd(buf, cmd, arg) - buf[5] = crc + // Start bit is always zero; transmitter bit is one since we are Host. + const transmitterBit = 1 << 6 + buf[0] = transmitterBit | byte(cmd) + binary.BigEndian.PutUint32(buf[1:5], arg) + if precalculatedCRC != 0 { + buf[5] = precalculatedCRC + } 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 diff --git a/sd/definitions.go b/sd/definitions.go index 282ee29..19e7c3e 100644 --- a/sd/definitions.go +++ b/sd/definitions.go @@ -347,55 +347,62 @@ func upToNull(buf []byte) []byte { return buf[:nullIdx] } +type ( + command byte + appcommand byte +) + +// SD commands and application commands. const ( - CMD0_GO_IDLE_STATE = 0 - CMD1_SEND_OP_CND = 1 - CMD2_ALL_SEND_CID = 2 - CMD3_SEND_RELATIVE_ADDR = 3 - CMD4_SET_DSR = 4 - CMD6_SWITCH_FUNC = 6 - CMD7_SELECT_DESELECT_CARD = 7 - CMD8_SEND_IF_COND = 8 - CMD9_SEND_CSD = 9 - CMD10_SEND_CID = 10 - CMD12_STOP_TRANSMISSION = 12 - CMD13_SEND_STATUS = 13 - CMD15_GO_INACTIVE_STATE = 15 - CMD16_SET_BLOCKLEN = 16 - CMD17_READ_SINGLE_BLOCK = 17 - CMD18_READ_MULTIPLE_BLOCK = 18 - CMD24_WRITE_BLOCK = 24 - CMD25_WRITE_MULTIPLE_BLOCK = 25 - CMD27_PROGRAM_CSD = 27 - CMD28_SET_WRITE_PROT = 28 - CMD29_CLR_WRITE_PROT = 29 - CMD30_SEND_WRITE_PROT = 30 - CMD32_ERASE_WR_BLK_START_ADDR = 32 - CMD33_ERASE_WR_BLK_END_ADDR = 33 - CMD38_ERASE = 38 - CMD42_LOCK_UNLOCK = 42 - CMD55_APP_CMD = 55 - CMD56_GEN_CMD = 56 - CMD58_READ_OCR = 58 - CMD59_CRC_ON_OFF = 59 - ACMD6_SET_BUS_WIDTH = 6 - ACMD13_SD_STATUS = 13 - ACMD22_SEND_NUM_WR_BLOCKS = 22 - ACMD23_SET_WR_BLK_ERASE_COUNT = 23 - ACMD41_SD_APP_OP_COND = 41 - ACMD42_SET_CLR_CARD_DETECT = 42 - ACMD51_SEND_SCR = 51 - ACMD18_SECURE_READ_MULTI_BLOCK = 18 - ACMD25_SECURE_WRITE_MULTI_BLOCK = 25 - ACMD26_SECURE_WRITE_MKB = 26 - ACMD38_SECURE_ERASE = 38 - ACMD43_GET_MKB = 43 - ACMD44_GET_MID = 44 - ACMD45_SET_CER_RN1 = 45 - ACMD46_SET_CER_RN2 = 46 - ACMD47_SET_CER_RES2 = 47 - ACMD48_SET_CER_RES1 = 48 - ACMD49_CHANGE_SECURE_AREA = 49 + cmdGoIdleState command = 0 + cmdSendOpCnd command = 1 + cmdAllSendCID command = 2 + cmdSendRelativeAddr command = 3 + cmdSetDSR command = 4 + cmdSwitchFunc command = 6 + cmdSelectDeselectCard command = 7 + cmdSendIfCond command = 8 + cmdSendCSD command = 9 + cmdSendCID command = 10 + cmdStopTransmission command = 12 + cmdSendStatus command = 13 + cmdGoInactiveState command = 15 + cmdSetBlocklen command = 16 + cmdReadSingleBlock command = 17 + cmdReadMultipleBlock command = 18 + cmdWriteBlock command = 24 + cmdWriteMultipleBlock command = 25 + cmdProgramCSD command = 27 + cmdSetWriteProt command = 28 + cmdClrWriteProt command = 29 + cmdSendWriteProt command = 30 + cmdEraseWrBlkStartAddr command = 32 + cmdEraseWrBlkEndAddr command = 33 + cmdErase command = 38 + cmdLockUnlock command = 42 + cmdAppCmd command = 55 + cmdGenCmd command = 56 + cmdReadOCR command = 58 + cmdCRCOnOff command = 59 + + acmdSET_BUS_WIDTH appcommand = 6 + acmdSD_STATUS appcommand = 13 + acmdSEND_NUM_WR_BLOCKS appcommand = 22 + acmdSET_WR_BLK_ERASE_COUNT appcommand = 23 + acmdSD_APP_OP_COND appcommand = 41 + acmdSET_CLR_CARD_DETECT appcommand = 42 + acmdSEND_SCR appcommand = 51 + acmdSECURE_READ_MULTI_BLOCK appcommand = 18 + acmdSECURE_WRITE_MULTI_BLOCK appcommand = 25 + acmdSECURE_WRITE_MKB appcommand = 26 + acmdSECURE_ERASE appcommand = 38 + acmdGET_MKB appcommand = 43 + acmdGET_MID appcommand = 44 + acmdSET_CER_RN1 appcommand = 45 + acmdSET_CER_RN2 appcommand = 46 + acmdSET_CER_RES2 appcommand = 47 + acmdSET_CER_RES1 appcommand = 48 + acmdCHANGE_SECURE_AREA appcommand = 49 ) // CSD enum types. @@ -497,10 +504,14 @@ func CRC16(buf []byte) (crc uint16) { // CRC7 computes the CRC7 checksum for a given payload using the polynomial x^7 + x^3 + 1. func CRC7(data []byte) (crc uint8) { + return crc7noshift(data) >> 1 +} + +func crc7noshift(data []byte) (crc uint8) { for _, b := range data { crc = crc7_table[crc^b] } - return crc >> 1 + return crc } var crc7_table = [256]byte{