📄 sdcard.java
字号:
/*---------------------------------------------------------------------------
* Copyright (C) 2008 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED PRODUCTS INC. BE LIABLE FOR ANY CLAIM,
* DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated Products,
* Inc. shall not be used except as stated in the Maxim Integrated Products,
* Inc. Branding Policy.
* ---------------------------------------------------------------------------
*/
package com.dalsemi.fs.fat;
import com.dalsemi.fs.fat.*;
import com.dalsemi.comm.*;
import com.dalsemi.system.*;
import java.util.*;
public class SDCard implements DiskInterface
{
private static final byte CMD0_GO_IDLE_STATE = 0x00;
private static final byte CMD1_SEND_OPCOND = 0x01;
private static final byte CMD9_SEND_CSD = 0x09;
private static final byte CMD10_SEND_CID = 0x0a;
private static final byte CMD12_STOP_TRANSMISSION = 0x0b;
private static final byte CMD13_SEND_STATUS = 0x0c;
private static final byte CMD16_SET_BLOCKLEN = 0x10;
private static final byte CMD17_READ_SINGLE_BLOCK = 0x11;
private static final byte CMD18_READ_MULTIPLE_BLOCK = 0x12;
private static final byte CMD24_WRITE_BLOCK = 0x18;
private static final byte CMD25_WRITE_MULTIPLE_BLOCK = 0x19;
private static final byte CMD27_PROGRAM_CSD = 0x1b;
private static final byte CMD28_SET_WRITE_PROT = 0x1c;
private static final byte CMD29_CLR_WRITE_PROT = 0x1d;
private static final byte CMD30_SEND_WRITE_PROT = 0x1e;
private static final byte CMD32_ERASE_WR_BLK_START_ADDR = 0x20;
private static final byte CMD33_ERASE_WR_BLK_END_ADDR = 0x21;
private static final byte CMD38_ERASE = 0x26;
private static final byte CMD55_APP_CMD = 0x37;
private static final byte CMD56_GEN_CMD = 0x38;
private static final byte CMD58_READ_OCR = 0x3a;
private static final byte CMD59_CRC_ON_OFF = 0x3b;
private static final byte ACMD13_SD_STATUS = 0x0d;
private static final byte ACMD22_SEND_NUM_WR_BLOCKS = 0x16;
private static final byte ACMD23_SET_WR_BLK_ERASE_COUNT = 0x17;
private static final byte ACMD41_SEND_OP_COND = 0x29;
private static final byte ACMD42_SET_CLR_CARD_DETECT = 0x2a;
private static final byte ACMD51_SEND_SCR = 0x33;
private static final byte R1_NOERROR = 0x00;
private static final byte R1_IDLE = 0x01;
private static final byte R1_ERASE = 0x02;
private static final byte R1_ILLEGAL = 0x04;
private static final byte R1_CRC_ERR = 0x08;
private static final byte R1_ERASE_SEQ = 0x10;
private static final byte R1_ADDR_ERR = 0x20;
private static final byte R1_PARAM_ERR = 0x40;
// private static final byte R1_NO_RESPONSE = (byte)0xFF;
private static final int CACHE_SIZE = 100;
public static BitPort bp = new BitPort(BitPort.Port5Bit2); //Port 3.5 for 390
private class CachedSector
{
byte cache[];
boolean dirty = false;
int address;
CachedSector(int address)
{
cache = new byte[blockSize + 3];
this.address = address;
readblock(this);
}
boolean isSector(int address, int length)
{
return ((address >= this.address) && ((address + length) <= (this.address + blockSize)));
}
}
private Vector cache;
private boolean immediateWrite = false;
private int blockSize;
private int cardSize;
private int startAddress = 0;
private SPI spi = new SPI();
private byte[] cmd = new byte[6];
public SDCard() throws Exception
{
if(!flushSPI())
{
throw new Exception("Unable to communicate with SD Card");
}
int tries = 0;
byte r1;
do
{
if(tries++ == 10)
{
throw new Exception("Unable to connect to SD Card");
}
clearArgs();
r1 = sendCommand(CMD0_GO_IDLE_STATE);
} while(r1 != R1_IDLE);
tries = 0;
do
{
if(tries++ == 10)
{
throw new Exception("SD Card timed out");
}
clearArgs();
r1 = sendCommand(CMD55_APP_CMD);
if(r1 != R1_IDLE)
{
r1 = 1;
continue;
}
clearArgs();
r1 = sendCommand(ACMD41_SEND_OP_COND);
} while(r1 != R1_NOERROR);
clearArgs();
cmd[4] = 0x01;
r1 = sendCommand(CMD59_CRC_ON_OFF);
if(r1 != R1_NOERROR)
{
throw new Exception("Error enabling CRC for SD Card");
}
getCSD();
cache = new Vector(CACHE_SIZE);
}
private void clearArgs()
{
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
}
private boolean flushSPI()
{
for(int i = 0; i < 100; i++)
{
com.dalsemi.system.ArrayUtils.arrayFill(cmd, 0, 5, (byte)0xFF);
spi.xmit(cmd, 0, 5);
int j;
for(j = 0; j < 5; j++)
{
if(cmd[j] != (byte)0xFF)
{
break;
}
}
if(j == 5)
{
return true;
}
}
return false;
}
private byte sendCommand(byte command) throws Exception
{
byte recv = sendSPI((byte)0xFF);
cmd[0] = (byte)(0x40 | (command & 0x3F));
cmd[5] = (byte)((crc7(cmd, 0, 5) << 1) | 0x01);
spi.xmit(cmd, 0, 6);
return receiveR1();
}
private byte receiveR1() throws Exception
{
int tries = 0;
byte recv;
do
{
if(tries++ > 100)
{
throw new Exception("Timed out waiting for R1 response");
}
recv = sendSPI((byte)0xFF);
} while((recv & 0x80) != 0);
return recv;
}
private void receiveData(byte[] b, int off, int len) throws Exception
{
byte recv = (byte)0xFF;
int tries = 0;
do
{
if(tries++ > 50)
{
throw new Exception("Timed out receiving data");
}
recv = sendSPI(recv);
} while(recv == (byte)0xFF);
if(recv != (byte)0xFE)
{
throw new Exception("Bad value read before receiving data");
}
com.dalsemi.system.ArrayUtils.arrayFill(b, off, off + len, (byte)0x0FF);
spi.xmit(b, off, len);
recv = sendSPI((byte)0xff);
if(recv != (byte)0xff)
{
throw new Exception("Bad value read after receiving data");
}
}
private static byte crc7(byte[] data, int offset, int len)
{
byte crc = 0;
for(int i = 0; i < len; i++)
{
for(int x = 7; x >= 0; x--)
{
crc <<= 1;
crc |= ((data[offset + i] >> x) & 1);
if((crc & 0x80) == 0x80)
{
crc ^= 0x89;
}
}
}
for(int x = 0; x < 7; x++)
{
crc <<= 1;
if((crc & 0x80) == 0x80)
{
crc ^= 0x89;
}
}
return crc;
}
private byte[] spiout = new byte[1];
private byte sendSPI(byte in)
{
spiout[0] = in;
spi.xmit(spiout, 0, 1);
return spiout[0];
}
private byte[] csdData = new byte[18];
private void getCSD() throws Exception
{
clearArgs();
if(sendCommand(CMD9_SEND_CSD) != R1_NOERROR)
{
throw new Exception("Unable to read CSD");
}
receiveData(csdData, 0, 18);
verifyCRC16(csdData, 0, 16, (short)((csdData[16] << 8) | (csdData[17] & 0x0FF)));
verifyCRC7(csdData, 0, 15, (byte)(csdData[15] >> 1));
/* Blocksize is easy to decode */
// blockSize = 0x01 << (csdData[5] & 0x0f);
blockSize = 512;
/* Cardsize is split over several bytes */
cardSize = ((csdData[6] & 0x03) << 10) | ((csdData[7] & 0x0FF) << 2) | (csdData[8] & 0x0c0);
/* Multiplier is also split over several bytes */
byte multiplier = (byte)(((csdData[9] & 0x03) << 1) | ((csdData[10] & 0x0FF) >> 7));
/* Compute final card size */
cardSize <<= (multiplier + 2); /* Multiplier is 2^(m+2) */
switch (blockSize)
{
case 512:
cardSize >>= 11;
break;
case 1024:
break;
case 2048:
cardSize <<= 9;
break;
default:
throw new Exception("Unsupported block size");
}
cardSize *= 1048576;
}
private static void verifyCRC16(byte[] b, int off, int len, short expect) throws Exception
{
short crc = crc16(b, off, len);
if((crc & 0x0FFFF) != (expect & 0x0FFFF))
{
throw new Exception("CRC16 check failed");
}
}
private static void verifyCRC7(byte[] b, int off, int len, byte expect) throws Exception
{
if((crc7(b, off, len) & 0x07F) != (expect & 0x07F))
{
throw new Exception("CRC7 check failed");
}
}
private static short crc16(byte[] data, int offset, int len)
{
short crc = 0;
for(int i = 0; i < len; i++)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -