worked on FAT32 stuff
This commit is contained in:
238
ext/sd/SDCard.h
238
ext/sd/SDCard.h
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../../io/GPIO.h"
|
||||
#include "../../Debug.h"
|
||||
#include "CRC16.h"
|
||||
|
||||
#define TEENSY_SD_PIN_CS 46
|
||||
#define TEENSY_SD_PIN_MOSI 45
|
||||
@@ -17,7 +18,7 @@
|
||||
template <typename SPI, int PIN_CS> class SDCard {
|
||||
|
||||
SPI& spi;
|
||||
|
||||
|
||||
union R1 { // SanDisk Manual Page 5-13
|
||||
uint8_t raw;
|
||||
struct {
|
||||
@@ -60,7 +61,7 @@ template <typename SPI, int PIN_CS> class SDCard {
|
||||
public:
|
||||
|
||||
SDCard(SPI& spi) : spi(spi) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool init() {
|
||||
@@ -117,39 +118,111 @@ public:
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//LBA512 lastReadBlock = 0xFFFFFFFF;
|
||||
//LBA512 lastWriteBlock = 0xFFFFFFFF;
|
||||
|
||||
public:
|
||||
|
||||
/** read a single block of 512 bytes, addr = byteAddr/512 */
|
||||
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
|
||||
|
||||
sendCMD(17, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
|
||||
R1 res; readResponse(&res.raw, 1);
|
||||
bool readBlock(LBA512 addr, uint8_t* dst) {
|
||||
|
||||
Log::addInfo(NAME, "readBlock(%d*512): %02x", addr, res.raw);
|
||||
/*
|
||||
if (lastReadBlock == 0xFFFFFFFF) {
|
||||
if (!startMultiRead(addr)) {endCMD(); return false;}
|
||||
if (!readMultiBlock(dst)) {endCMD(); return false;}
|
||||
|
||||
// read command OK?
|
||||
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
|
||||
|
||||
// wait for data to become available
|
||||
for (uint16_t i = 0; ; ++i) {
|
||||
uint8_t res = spi.readWriteByte(0xFF);
|
||||
if (res == 0xFE) {break;} // available!
|
||||
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
|
||||
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
|
||||
} else if ((lastReadBlock + 1) == addr) {
|
||||
if (!readMultiBlock(dst)) {endCMD(); return false;}
|
||||
|
||||
} else {
|
||||
if (!stopMultiRead()) {endCMD(); return false;}
|
||||
if (!startMultiRead(addr)) {endCMD(); return false;}
|
||||
if (!readMultiBlock(dst)) {endCMD(); return false;}
|
||||
}
|
||||
|
||||
// read data
|
||||
for (uint16_t i = 0; i < 512; ++i) {
|
||||
dst[i] = spi.readWriteByte(0xFF);
|
||||
}
|
||||
|
||||
// done
|
||||
endCMD();
|
||||
|
||||
lastReadBlock = addr;
|
||||
return true;
|
||||
|
||||
*/
|
||||
|
||||
// bulletproof, but slower
|
||||
return readSingleBlock(addr, dst);
|
||||
|
||||
}
|
||||
|
||||
/** write a single block of 512 bytes, addr = byteAddr/512 */
|
||||
bool writeBlock(LBA512 addr, const uint8_t* src) {
|
||||
|
||||
// bulletproof, but slow
|
||||
return writeSingleBlock(addr, src);
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/*
|
||||
bool startMultiRead(LBA512 addr) {
|
||||
|
||||
sendCMD(18, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
|
||||
R1 res; readResponse(&res.raw, 1);
|
||||
|
||||
Log::addInfo(NAME, "startMultiRead(%d*512): %02x", addr, res.raw);
|
||||
|
||||
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
|
||||
|
||||
// wait for data to become available
|
||||
for (uint16_t i = 0; ; ++i) {
|
||||
uint8_t res = spi.readWriteByte(0xFF);
|
||||
if (res == 0xFE) {break;} // available!
|
||||
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
|
||||
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool readMultiBlock(uint8_t* dst) {
|
||||
|
||||
Log::addInfo(NAME, "readMultiBlock()");
|
||||
|
||||
for (uint16_t i = 0; i < 512; ++i) {
|
||||
dst[i] = spi.readWriteByte(0xFF);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool stopMultiRead() {
|
||||
|
||||
sendCMD(12, 0,0,0,0, 0xFF);
|
||||
R1 res; readResponse(&res.raw, 1);
|
||||
|
||||
Log::addInfo(NAME, "stopMultiRead(): %02x", res.raw);
|
||||
|
||||
endCMD();
|
||||
lastReadBlock = 0xFFFFFFFF;
|
||||
|
||||
return true;//(res.raw == 0);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
/** select the card (CS = low) */
|
||||
void select() {
|
||||
spi.writeByte(0xFF);
|
||||
MyGPIO::clear(PIN_CS);
|
||||
spi.writeByte(0xFF);
|
||||
}
|
||||
|
||||
/** deselect the card (CS = high) */
|
||||
void deselect() {
|
||||
spi.writeByte(0xFF);
|
||||
MyGPIO::set(PIN_CS);
|
||||
spi.writeByte(0xFF);
|
||||
}
|
||||
|
||||
/** send a new command */
|
||||
void sendCMD(uint8_t cmd, uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t arg3, uint8_t crc) {
|
||||
@@ -226,11 +299,8 @@ private:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** read the card's response to the last command */
|
||||
void readResponse(uint8_t* dst, uint8_t len) {
|
||||
|
||||
// the SD card takes some time to answer, but must receive clock signals meanwhile!
|
||||
@@ -253,18 +323,102 @@ private:
|
||||
|
||||
|
||||
|
||||
/** select the card (CS = low) */
|
||||
void select() {
|
||||
spi.writeByte(0xFF);
|
||||
MyGPIO::clear(PIN_CS);
|
||||
spi.writeByte(0xFF);
|
||||
private:
|
||||
|
||||
/** most simple read operation: read a single block of 512 bytes, addr = byteAddr/512 */
|
||||
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
|
||||
|
||||
sendCMD(17, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
|
||||
R1 res; readResponse(&res.raw, 1);
|
||||
|
||||
Log::addInfo(NAME, "readSingleBlock(%d*512): %02x", addr, res.raw);
|
||||
|
||||
// read command OK?
|
||||
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
|
||||
|
||||
// wait for data to become available
|
||||
for (uint16_t i = 0; ; ++i) {
|
||||
uint8_t res = spi.readWriteByte(0xFF);
|
||||
if (res == 0xFE) {break;} // available!
|
||||
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
|
||||
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
|
||||
}
|
||||
|
||||
// read data
|
||||
for (uint16_t i = 0; i < 512; ++i) {
|
||||
dst[i] = spi.readWriteByte(0xFF);
|
||||
}
|
||||
|
||||
// done
|
||||
endCMD();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/** deselect the card (CS = high) */
|
||||
void deselect() {
|
||||
spi.writeByte(0xFF);
|
||||
MyGPIO::set(PIN_CS);
|
||||
spi.writeByte(0xFF);
|
||||
|
||||
bool waitWhileBusy() {
|
||||
|
||||
Log::addInfo(NAME, "waitWhileBusy()");
|
||||
|
||||
uint8_t res = 0;
|
||||
for (uint16_t i = 0; ; ++i) {
|
||||
res = spi.readWriteByte(0xFF);
|
||||
if (res == 0xFF) {return true;}
|
||||
if (i >= 1024) {return false;} // timeout
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** most simple write operation: write a single block of 512 bytes, addr = byteAddr/512 */
|
||||
bool writeSingleBlock(LBA512 addr, const uint8_t* src) {
|
||||
|
||||
sendCMD(24, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
|
||||
R1 res; readResponse(&res.raw, 1);
|
||||
|
||||
Log::addInfo(NAME, "writeSingleBlock(%d*512): %02x", addr, res.raw);
|
||||
|
||||
// write command OK?
|
||||
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
|
||||
|
||||
// wait while the card is busy
|
||||
if (!waitWhileBusy()) {Log::addError(NAME, "busy timeout"); endCMD(); return false;}
|
||||
|
||||
// send BLOCK_START
|
||||
spi.writeByte(0xFE);
|
||||
|
||||
// send data
|
||||
for (uint16_t i = 0; i < 512; ++i) {
|
||||
spi.writeByte(src[i]);
|
||||
}
|
||||
|
||||
// send CRC16
|
||||
// NOTE: it seems that it doesnt matter what we send here
|
||||
// the card is always fine with it?!
|
||||
//const uint16_t crc = CRC16::get(src, 512);
|
||||
//spi.writeByte(crc >> 8);
|
||||
//spi.writeByte(crc);
|
||||
spi.writeByte(0xFF);
|
||||
spi.writeByte(0xFF);
|
||||
|
||||
//const uint8_t DATA_RESPONSE_MASK = 0x1F;
|
||||
//const uint8_t DATA_RESPONSE_DATA_ACCEPTED = ((2 << 1) | 1);
|
||||
|
||||
//uint8_t crcRes = spi.readWriteByte(0xFF);
|
||||
const uint8_t crcRes = spi.readWriteByte(0xFF); // response to CRC
|
||||
//R1 res2; readResponse(&res2.raw, 1);
|
||||
//Log::addInfo(NAME, "writeSingleBlockCRC(): %02x %02x", tmp, res2.raw);
|
||||
|
||||
// wait for card to finish writing
|
||||
// should be a series of 0x00 followed by something != 0x00 and then a series of 0xFF
|
||||
// TODO: check the non 0x00 value?
|
||||
while(true) {
|
||||
if (spi.readWriteByte(0xFF) == 0xFF) {break;}
|
||||
}
|
||||
|
||||
endCMD();
|
||||
return true;
|
||||
//return (crcRes & DATA_RESPONSE_MASK) == DATA_RESPONSE_DATA_ACCEPTED;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user