worked on FAT32 stuff

This commit is contained in:
2021-02-21 09:33:08 +01:00
parent da12992ae8
commit 4ac72c678f
13 changed files with 494 additions and 148 deletions

View File

@@ -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;
}
};