name=SD | name=SD | ||||
version=1.0.8 | |||||
version=1.2.2 | |||||
author=Arduino, SparkFun | author=Arduino, SparkFun | ||||
maintainer=Paul Stoffregen | maintainer=Paul Stoffregen | ||||
sentence=Enables reading and writing on SD cards. This version is optimized for Teensy. | sentence=Enables reading and writing on SD cards. This version is optimized for Teensy. |
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
#include "kinetis.h" | #include "kinetis.h" | ||||
#include "core_pins.h" // testing only | |||||
//#include "core_pins.h" // testing only | |||||
//#include "HardwareSerial.h" // testing only | |||||
// Missing in Teensyduino 1.30 | // Missing in Teensyduino 1.30 | ||||
#ifndef MPU_CESR_VLD_MASK | #ifndef MPU_CESR_VLD_MASK | ||||
SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h | SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h | ||||
}; | }; | ||||
/*void print_result(int n) | |||||
{ | |||||
switch (n) { | |||||
case SDHC_RESULT_OK: serial_print("OK\n"); break; | |||||
case SDHC_RESULT_ERROR: serial_print("R/W Error\n"); break; | |||||
case SDHC_RESULT_WRPRT: serial_print("Write Protect\n"); break; | |||||
case SDHC_RESULT_NOT_READY: serial_print("Not Ready\n"); break; | |||||
case SDHC_RESULT_PARERR: serial_print("Invalid Param\n"); break; | |||||
case SDHC_RESULT_NO_RESPONSE: serial_print("No Response\n"); break; | |||||
default: serial_print("Unknown result\n"); | |||||
} | |||||
}*/ | |||||
#define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */ | #define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */ | ||||
#define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */ | #define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */ | ||||
#define SDHC_STATUS_PROTECT 0x04 /* Write protected */ | #define SDHC_STATUS_PROTECT 0x04 /* Write protected */ | ||||
// prescale can be 2, 4, 8, 16, 32, 64, 128, 256 | // prescale can be 2, 4, 8, 16, 32, 64, 128, 256 | ||||
// divisor can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 | // divisor can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 | ||||
#define SDHC_SYSCTL_DIVISOR(prescale, divisor) \ | #define SDHC_SYSCTL_DIVISOR(prescale, divisor) \ | ||||
(SDHC_SYSCTL_DVS((prescale)>>1)|SDHC_SYSCTL_SDCLKFS((divisor)-1)) | |||||
(SDHC_SYSCTL_SDCLKFS((prescale)>>1)|SDHC_SYSCTL_DVS((divisor)-1)) | |||||
#if (F_CPU == 240000000) | |||||
#if (F_CPU == 256000000) | |||||
#define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 400 kHz | |||||
#define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 6) // 21.3 MHz | |||||
#define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 42.6 MHz | |||||
#elif (F_CPU == 240000000) | |||||
#define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 375 kHz | #define SDHC_SYSCTL_400KHZ SDHC_SYSCTL_DIVISOR(64, 10) // 375 kHz | ||||
#define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 5) // 24 MHz | #define SDHC_SYSCTL_25MHZ SDHC_SYSCTL_DIVISOR(2, 5) // 24 MHz | ||||
#define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 40 MHz | #define SDHC_SYSCTL_50MHZ SDHC_SYSCTL_DIVISOR(2, 3) // 40 MHz | ||||
* Private functions | * Private functions | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
static uint8_t SDHC_Init(void); | |||||
static void SDHC_InitGPIO(void); | static void SDHC_InitGPIO(void); | ||||
static void SDHC_ReleaseGPIO(void); | static void SDHC_ReleaseGPIO(void); | ||||
static void SDHC_SetClock(uint32_t sysctl); | static void SDHC_SetClock(uint32_t sysctl); | ||||
// initialize the SDHC Controller | // initialize the SDHC Controller | ||||
// returns status of initialization(OK, nonInit, noCard, CardProtected) | // returns status of initialization(OK, nonInit, noCard, CardProtected) | ||||
uint8_t SDHC_Init(void) | |||||
static uint8_t SDHC_Init(void) | |||||
{ | { | ||||
int i; | |||||
// Enable clock to SDHC peripheral | // Enable clock to SDHC peripheral | ||||
SIM_SCGC3 |= SIM_SCGC3_SDHC; | SIM_SCGC3 |= SIM_SCGC3_SDHC; | ||||
SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | SIM_SCGC6 |= SIM_SCGC6_DMAMUX; | ||||
SIM_SCGC7 |= SIM_SCGC7_DMA; | SIM_SCGC7 |= SIM_SCGC7_DMA; | ||||
// Switch of MPU unit (maybe bug of silicon) | |||||
// Enable DMA access via MPU (not currently used) | |||||
MPU_CESR &= ~MPU_CESR_VLD_MASK; | MPU_CESR &= ~MPU_CESR_VLD_MASK; | ||||
// De-init GPIO - to prevent unwanted clocks on bus | // De-init GPIO - to prevent unwanted clocks on bus | ||||
SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN | | SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN | | ||||
SDHC_IRQSTATEN_CRMSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; | SDHC_IRQSTATEN_CRMSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; | ||||
/* 80 initial clocks */ | |||||
SDHC_SYSCTL |= SDHC_SYSCTL_INITA; | |||||
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) { }; | |||||
// initial clocks... SD spec says only 74 clocks are needed, but if Teensy rebooted | |||||
// while the card was in middle of an operation, thousands of clock cycles can be | |||||
// needed to get the card to complete a prior command and return to a usable state. | |||||
for (i=0; i < 500; i++) { | |||||
SDHC_SYSCTL |= SDHC_SYSCTL_INITA; | |||||
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) { }; | |||||
} | |||||
// to do - check if this needed | // to do - check if this needed | ||||
SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; | SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; | ||||
} | } | ||||
resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern | resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern | ||||
if (resR > 0) { | |||||
sdCardDesc.status = SDHC_STATUS_NOINIT; | |||||
return SDHC_STATUS_NOINIT; | |||||
} | |||||
if (resR == 0) { | |||||
if (resR == SDHC_RESULT_OK) { | |||||
if (SDHC_CMDRSP0 != 0x000001AA) { | if (SDHC_CMDRSP0 != 0x000001AA) { | ||||
sdCardDesc.status = SDHC_STATUS_NOINIT; | sdCardDesc.status = SDHC_STATUS_NOINIT; | ||||
return SDHC_STATUS_NOINIT; | return SDHC_STATUS_NOINIT; | ||||
} | } | ||||
sdCardDesc.highCapacity = 1; | sdCardDesc.highCapacity = 1; | ||||
} else if (resR == SDHC_RESULT_NO_RESPONSE) { | |||||
// version 1 cards do not respond to CMD8 | |||||
} else { | |||||
sdCardDesc.status = SDHC_STATUS_NOINIT; | |||||
return SDHC_STATUS_NOINIT; | |||||
} | } | ||||
if (SDHC_ACMD41_SendOperationCond(0)) { | if (SDHC_ACMD41_SendOperationCond(0)) { | ||||
// release the SDHC Controller signals | // release the SDHC Controller signals | ||||
static void SDHC_ReleaseGPIO(void) | static void SDHC_ReleaseGPIO(void) | ||||
{ | { | ||||
PORTE_PCR0 = 0; | |||||
PORTE_PCR1 = 0; | |||||
PORTE_PCR2 = 0; | |||||
PORTE_PCR3 = 0; | |||||
PORTE_PCR4 = 0; | |||||
PORTE_PCR5 = 0; | |||||
PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */ | |||||
PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */ | |||||
PORTE_PCR2 = 0; /* SDHC.CLK */ | |||||
PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */ | |||||
PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */ | |||||
PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */ | |||||
} | } | ||||
static void SDHC_SetClock(uint32_t sysctl) | static void SDHC_SetClock(uint32_t sysctl) | ||||
{ | { | ||||
uint32_t n, timeout; | uint32_t n, timeout; |
} | } | ||||
/** SPI send multiple bytes */ | /** SPI send multiple bytes */ | ||||
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) | |||||
#define USE_TEENSY4_SPI | |||||
static void spiInit(uint8_t spiRate) { | |||||
switch (spiRate) { | |||||
// the top 2 speeds are set to 24 MHz, for the SD library defaults | |||||
case 0: settings = SPISettings(25200000, MSBFIRST, SPI_MODE0); break; | |||||
case 1: settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break; | |||||
case 2: settings = SPISettings(8000000, MSBFIRST, SPI_MODE0); break; | |||||
case 3: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break; | |||||
case 4: settings = SPISettings(3000000, MSBFIRST, SPI_MODE0); break; | |||||
case 5: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break; | |||||
default: settings = SPISettings(400000, MSBFIRST, SPI_MODE0); | |||||
} | |||||
SPI.begin(); | |||||
} | |||||
static void spiSend(uint8_t b) { | |||||
SPI.transfer(b); | |||||
} | |||||
static uint8_t spiRec(void) { | |||||
return SPI.transfer(0xff); | |||||
} | |||||
static void spiRec(uint8_t* buf, size_t len) { | |||||
SPI.transfer(buf, len); | |||||
} | |||||
static void spiRecIgnore(size_t len) { | |||||
for (size_t i=0; i < len; i++) | |||||
SPI.transfer(0xff); | |||||
} | |||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
#else | #else | ||||
// functions for hardware SPI | // functions for hardware SPI | ||||
type_ = 0; | type_ = 0; | ||||
chipSelectPin_ = chipSelectPin; | chipSelectPin_ = chipSelectPin; | ||||
// 16-bit init start time allows over a minute | // 16-bit init start time allows over a minute | ||||
uint16_t t0 = (uint16_t)millis(); | |||||
unsigned int t0 = millis(); | |||||
uint32_t arg; | uint32_t arg; | ||||
digitalWrite(chipSelectPin_, HIGH); | digitalWrite(chipSelectPin_, HIGH); | ||||
pinMode(chipSelectPin_, OUTPUT); | pinMode(chipSelectPin_, OUTPUT); | ||||
digitalWrite(chipSelectPin_, HIGH); | digitalWrite(chipSelectPin_, HIGH); | ||||
#ifdef USE_TEENSY3_SPI | |||||
#if defined(USE_TEENSY3_SPI) | |||||
spiBegin(); | spiBegin(); | ||||
spiInit(6); | spiInit(6); | ||||
#elif defined(USE_TEENSY4_SPI) | |||||
spiInit(6); | |||||
pinMode(SS_PIN, OUTPUT); | |||||
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin | |||||
#else | #else | ||||
// set pin modes | // set pin modes | ||||
pinMode(SPI_MISO_PIN, INPUT); | pinMode(SPI_MISO_PIN, INPUT); | ||||
settings = SPISettings(250000, MSBFIRST, SPI_MODE0); | settings = SPISettings(250000, MSBFIRST, SPI_MODE0); | ||||
#endif | #endif | ||||
#endif // not USE_TEENSY3_SPI | #endif // not USE_TEENSY3_SPI | ||||
// must supply min of 74 clock cycles with CS high. | // must supply min of 74 clock cycles with CS high. | ||||
#ifdef SPI_HAS_TRANSACTION | #ifdef SPI_HAS_TRANSACTION | ||||
SPI.beginTransaction(settings); | SPI.beginTransaction(settings); | ||||
#ifdef SPI_HAS_TRANSACTION | #ifdef SPI_HAS_TRANSACTION | ||||
SPI.endTransaction(); | SPI.endTransaction(); | ||||
#endif | #endif | ||||
chipSelectLow(); | chipSelectLow(); | ||||
// command to go idle in SPI mode | // command to go idle in SPI mode | ||||
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { | while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { | ||||
if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { | |||||
unsigned int d = millis() - t0; | |||||
if (d > SD_INIT_TIMEOUT) { | |||||
goto fail; // SD_CARD_ERROR_CMD0 | goto fail; // SD_CARD_ERROR_CMD0 | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// initialize card and send host supports SDHC if SD2 | // initialize card and send host supports SDHC if SD2 | ||||
arg = (type_ == SD_CARD_TYPE_SD2) ? 0X40000000 : 0; | arg = (type_ == SD_CARD_TYPE_SD2) ? 0X40000000 : 0; | ||||
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { | while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { | ||||
// check for timeout | // check for timeout | ||||
if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { | |||||
unsigned int d = millis() - t0; | |||||
if (d > SD_INIT_TIMEOUT) { | |||||
goto fail; // SD_CARD_ERROR_ACMD41 | goto fail; // SD_CARD_ERROR_ACMD41 | ||||
} | } | ||||
} | } | ||||
if (!waitStartBlock()) { | if (!waitStartBlock()) { | ||||
goto fail; | goto fail; | ||||
} | } | ||||
#ifdef USE_TEENSY3_SPI | |||||
#if defined(USE_TEENSY3_SPI) | defined(USE_TEENSY4_SPI) | |||||
spiRec(dst, 512); | spiRec(dst, 512); | ||||
spiRecIgnore(2); | spiRecIgnore(2); | ||||
#else // OPTIMIZE_HARDWARE_SPI | #else // OPTIMIZE_HARDWARE_SPI | ||||
* false, is returned for an invalid value of \a sckRateID. | * false, is returned for an invalid value of \a sckRateID. | ||||
*/ | */ | ||||
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { | uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { | ||||
#ifdef USE_TEENSY3_SPI | |||||
#if defined(USE_TEENSY3_SPI) || defined(USE_TEENSY4_SPI) | |||||
spiInit(sckRateID); | spiInit(sckRateID); | ||||
return true; | return true; | ||||
#else | #else | ||||
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
// wait for card to go not busy | // wait for card to go not busy | ||||
uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) { | |||||
uint16_t t0 = millis(); | |||||
uint8_t Sd2Card::waitNotBusy(unsigned int timeoutMillis) { | |||||
unsigned int t0 = millis(); | |||||
unsigned int d; | |||||
do { | do { | ||||
if (spiRec() == 0XFF) return true; | if (spiRec() == 0XFF) return true; | ||||
d = millis() - t0; | |||||
} | } | ||||
while (((uint16_t)millis() - t0) < timeoutMillis); | |||||
while (d < timeoutMillis); | |||||
return false; | return false; | ||||
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** Wait for start block token */ | /** Wait for start block token */ | ||||
uint8_t Sd2Card::waitStartBlock(void) { | uint8_t Sd2Card::waitStartBlock(void) { | ||||
uint16_t t0 = millis(); | |||||
unsigned int t0 = millis(); | |||||
while ((status_ = spiRec()) == 0XFF) { | while ((status_ = spiRec()) == 0XFF) { | ||||
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { | |||||
unsigned int d = millis() - t0; | |||||
if (d > SD_READ_TIMEOUT) { | |||||
return false; // SD_CARD_ERROR_READ_TIMEOUT | return false; // SD_CARD_ERROR_READ_TIMEOUT | ||||
} | } | ||||
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
// send one block of data for write block or write multiple blocks | // send one block of data for write block or write multiple blocks | ||||
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { | uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { | ||||
#ifdef OPTIMIZE_HARDWARE_SPI | |||||
#if defined(OPTIMIZE_HARDWARE_SPI) && !defined(USE_TEENSY4_SPI) | |||||
// send data - optimized loop | // send data - optimized loop | ||||
SPDR = token; | SPDR = token; | ||||
#else // OPTIMIZE_HARDWARE_SPI | #else // OPTIMIZE_HARDWARE_SPI | ||||
spiSend(token); | spiSend(token); | ||||
for (uint16_t i = 0; i < 512; i++) { | for (uint16_t i = 0; i < 512; i++) { | ||||
spiSend(src[i]); | |||||
spiSend(src[i]); | |||||
} | } | ||||
#endif // OPTIMIZE_HARDWARE_SPI | #endif // OPTIMIZE_HARDWARE_SPI | ||||
spiSend(0xff); // dummy crc | spiSend(0xff); // dummy crc |
/** Protect block zero from write if nonzero */ | /** Protect block zero from write if nonzero */ | ||||
#define SD_PROTECT_BLOCK_ZERO 1 | #define SD_PROTECT_BLOCK_ZERO 1 | ||||
/** init timeout ms */ | /** init timeout ms */ | ||||
uint16_t const SD_INIT_TIMEOUT = 2000; | |||||
const unsigned int SD_INIT_TIMEOUT = 2000; | |||||
/** erase timeout ms */ | /** erase timeout ms */ | ||||
uint16_t const SD_ERASE_TIMEOUT = 10000; | |||||
const unsigned int SD_ERASE_TIMEOUT = 10000; | |||||
/** read timeout ms */ | /** read timeout ms */ | ||||
uint16_t const SD_READ_TIMEOUT = 300; | |||||
const unsigned int SD_READ_TIMEOUT = 300; | |||||
/** write time out ms */ | /** write time out ms */ | ||||
uint16_t const SD_WRITE_TIMEOUT = 600; | |||||
const unsigned int SD_WRITE_TIMEOUT = 600; | |||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
// card types | // card types | ||||
/** Standard capacity V1 SD card */ | /** Standard capacity V1 SD card */ | ||||
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); | uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); | ||||
void chipSelectHigh(void); | void chipSelectHigh(void); | ||||
void chipSelectLow(void); | void chipSelectLow(void); | ||||
uint8_t waitNotBusy(uint16_t timeoutMillis); | |||||
uint8_t waitNotBusy(unsigned int timeoutMillis); | |||||
uint8_t writeData(uint8_t token, const uint8_t* src); | uint8_t writeData(uint8_t token, const uint8_t* src); | ||||
uint8_t waitStartBlock(void); | uint8_t waitStartBlock(void); | ||||
uint8_t setSckRate(uint8_t sckRateID); | uint8_t setSckRate(uint8_t sckRateID); |
#ifndef Sd2PinMap_h | #ifndef Sd2PinMap_h | ||||
#define Sd2PinMap_h | #define Sd2PinMap_h | ||||
#if defined(__arm__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#if defined(__arm__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
uint8_t b; | uint8_t b; | ||||
return read(&b, 1) == 1 ? b : -1; | return read(&b, 1) == 1 ? b : -1; | ||||
} | } | ||||
int16_t read(void* buf, uint16_t nbyte); | |||||
int32_t read(void* buf, size_t nbyte); | |||||
int8_t readDir(dir_t* dir); | int8_t readDir(dir_t* dir); | ||||
static uint8_t remove(SdFile* dirFile, const char* fileName); | static uint8_t remove(SdFile* dirFile, const char* fileName); | ||||
uint8_t remove(void); | uint8_t remove(void); | ||||
/** \return SdVolume that contains this file. */ | /** \return SdVolume that contains this file. */ | ||||
SdVolume* volume(void) const {return vol_;} | SdVolume* volume(void) const {return vol_;} | ||||
size_t write(uint8_t b); | size_t write(uint8_t b); | ||||
size_t write(const void* buf, uint16_t nbyte); | |||||
size_t write(const void* buf, size_t nbyte); | |||||
size_t write(const char* str); | size_t write(const char* str); | ||||
void write_P(PGM_P str); | void write_P(PGM_P str); | ||||
void writeln_P(PGM_P str); | void writeln_P(PGM_P str); |
* read() called before a file has been opened, corrupt file system | * read() called before a file has been opened, corrupt file system | ||||
* or an I/O error occurred. | * or an I/O error occurred. | ||||
*/ | */ | ||||
int16_t SdFile::read(void* buf, uint16_t nbyte) { | |||||
int32_t SdFile::read(void* buf, size_t nbyte) { | |||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf); | uint8_t* dst = reinterpret_cast<uint8_t*>(buf); | ||||
// error if not open or write only | // error if not open or write only | ||||
if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; | if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; | ||||
// amount left to read | // amount left to read | ||||
uint16_t toRead = nbyte; | |||||
uint32_t toRead = nbyte; | |||||
while (toRead > 0) { | while (toRead > 0) { | ||||
uint32_t block; // raw device block number | uint32_t block; // raw device block number | ||||
uint16_t offset = curPosition_ & 0X1FF; // offset in block | uint16_t offset = curPosition_ & 0X1FF; // offset in block | ||||
} | } | ||||
block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; | block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; | ||||
} | } | ||||
uint16_t n = toRead; | |||||
int32_t n = toRead; | |||||
// amount to be read from current block | // amount to be read from current block | ||||
if (n > (512 - offset)) n = 512 - offset; | if (n > (512 - offset)) n = 512 - offset; | ||||
* for a read-only file, device is full, a corrupt file system or an I/O error. | * for a read-only file, device is full, a corrupt file system or an I/O error. | ||||
* | * | ||||
*/ | */ | ||||
size_t SdFile::write(const void* buf, uint16_t nbyte) { | |||||
size_t SdFile::write(const void* buf, size_t nbyte) { | |||||
// convert void* to uint8_t* - must be before goto statements | // convert void* to uint8_t* - must be before goto statements | ||||
const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); | const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); | ||||
// number of bytes left to write - must be before goto statements | // number of bytes left to write - must be before goto statements | ||||
uint16_t nToWrite = nbyte; | |||||
size_t nToWrite = nbyte; | |||||
// error if not a normal file or is read-only | // error if not a normal file or is read-only | ||||
if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; | if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; |