| uint8_t buf[BUF_DIM]; | uint8_t buf[BUF_DIM]; | ||||
| const uint32_t FILE_SIZE = 1000000; | const uint32_t FILE_SIZE = 1000000; | ||||
| const uint16_t NWRITE = FILE_SIZE/BUF_DIM; | |||||
| const uint32_t NWRITE = FILE_SIZE/BUF_DIM; | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // print error msg, any SD error codes, and halt. | // print error msg, any SD error codes, and halt. | ||||
| // store messages in flash | // store messages in flash | ||||
| Serial.println(F("Writing test.bin to sd1")); | Serial.println(F("Writing test.bin to sd1")); | ||||
| // write data to /Dir1/test.bin on sd1 | // write data to /Dir1/test.bin on sd1 | ||||
| for (uint16_t i = 0; i < NWRITE; i++) { | |||||
| for (uint32_t i = 0; i < NWRITE; i++) { | |||||
| if (file1.write(buf, sizeof(buf)) != sizeof(buf)) { | if (file1.write(buf, sizeof(buf)) != sizeof(buf)) { | ||||
| error("file1.write"); | error("file1.write"); | ||||
| } | } |
| } | } | ||||
| // fill buf with known data | // fill buf with known data | ||||
| for (uint16_t i = 0; i < (BUF_SIZE-2); i++) { | |||||
| buf[i] = 'A' + (i % 26); | |||||
| if (BUF_SIZE > 1) { | |||||
| for (size_t i = 0; i < (BUF_SIZE - 2); i++) { | |||||
| buf[i] = 'A' + (i % 26); | |||||
| } | |||||
| buf[BUF_SIZE-2] = '\r'; | |||||
| } | } | ||||
| buf[BUF_SIZE-2] = '\r'; | |||||
| buf[BUF_SIZE-1] = '\n'; | buf[BUF_SIZE-1] = '\n'; | ||||
| cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl; | cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl; | ||||
| cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n"); | cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n"); | ||||
| cout << F("Starting write test, please wait.") << endl << endl; | cout << F("Starting write test, please wait.") << endl << endl; | ||||
| m = micros() - m; | m = micros() - m; | ||||
| totalLatency += m; | totalLatency += m; | ||||
| if (buf[BUF_SIZE-1] != '\n') { | if (buf[BUF_SIZE-1] != '\n') { | ||||
| error("data check error"); | error("data check error"); | ||||
| } | } | ||||
| if (skipLatency) { | if (skipLatency) { |
| } | } | ||||
| // fill buf with known data | // fill buf with known data | ||||
| for (uint16_t i = 0; i < (BUF_SIZE-2); i++) { | |||||
| for (size_t_t i = 0; i < (BUF_SIZE-2); i++) { | |||||
| buf[i] = 'A' + (i % 26); | buf[i] = 'A' + (i % 26); | ||||
| } | } | ||||
| buf[BUF_SIZE-2] = '\r'; | buf[BUF_SIZE-2] = '\r'; |
| uint8_t buf[BUF_DIM]; | uint8_t buf[BUF_DIM]; | ||||
| const uint32_t FILE_SIZE = 1000000; | const uint32_t FILE_SIZE = 1000000; | ||||
| const uint16_t NWRITE = FILE_SIZE/BUF_DIM; | |||||
| const uint32_t NWRITE = FILE_SIZE/BUF_DIM; | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // print error msg, any SD error codes, and halt. | // print error msg, any SD error codes, and halt. | ||||
| // store messages in flash | // store messages in flash | ||||
| Serial.println(F("Writing test.bin to sd1")); | Serial.println(F("Writing test.bin to sd1")); | ||||
| // write data to /Dir1/test.bin on sd1 | // write data to /Dir1/test.bin on sd1 | ||||
| for (uint16_t i = 0; i < NWRITE; i++) { | |||||
| for (uint32_t i = 0; i < NWRITE; i++) { | |||||
| if (file1.write(buf, sizeof(buf)) != sizeof(buf)) { | if (file1.write(buf, sizeof(buf)) != sizeof(buf)) { | ||||
| sd1.errorExit("sd1.write"); | sd1.errorExit("sd1.write"); | ||||
| } | } |
| name=SdFat | name=SdFat | ||||
| version=2.0.0-beta.3 | |||||
| version=2.0.0-beta.4 | |||||
| license=MIT | license=MIT | ||||
| author=Bill Greiman <fat16lib@sbcglobal.net> | author=Bill Greiman <fat16lib@sbcglobal.net> | ||||
| maintainer=Bill Greiman <fat16lib@sbcglobal.net> | maintainer=Bill Greiman <fat16lib@sbcglobal.net> |
| #if USE_MULTI_SECTOR_IO | #if USE_MULTI_SECTOR_IO | ||||
| } else if (toRead >= 2*m_vol->bytesPerSector()) { | } else if (toRead >= 2*m_vol->bytesPerSector()) { | ||||
| uint32_t ns = toRead >> m_vol->bytesPerSectorShift(); | uint32_t ns = toRead >> m_vol->bytesPerSectorShift(); | ||||
| if (!isContiguous()) { | |||||
| uint32_t maxNs = m_vol->sectorsPerCluster() | |||||
| - (clusterOffset >> m_vol->bytesPerSectorShift()); | |||||
| if (ns > maxNs) { | |||||
| ns = maxNs; | |||||
| } | |||||
| // Limit writes to current cluster. | |||||
| uint32_t maxNs = m_vol->sectorsPerCluster() | |||||
| - (clusterOffset >> m_vol->bytesPerSectorShift()); | |||||
| if (ns > maxNs) { | |||||
| ns = maxNs; | |||||
| } | } | ||||
| n = ns << m_vol->bytesPerSectorShift(); | n = ns << m_vol->bytesPerSectorShift(); | ||||
| if (m_vol->dataCacheSector() <= sector | |||||
| // Check for cache sector in read range. | |||||
| if (sector <= m_vol->dataCacheSector() | |||||
| && m_vol->dataCacheSector() < (sector + ns)) { | && m_vol->dataCacheSector() < (sector + ns)) { | ||||
| // flush cache if a sector is in the cache | |||||
| // Flush cache if a cache sector is in the range. | |||||
| if (!m_vol->dataCacheSync()) { | if (!m_vol->dataCacheSync()) { | ||||
| DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
| goto fail; | goto fail; |
| ns = maxNs; | ns = maxNs; | ||||
| } | } | ||||
| n = ns << m_vol->bytesPerSectorShift(); | n = ns << m_vol->bytesPerSectorShift(); | ||||
| if (m_vol->dataCacheSector() <= sector | |||||
| // Check for cache sector in write range. | |||||
| if (sector <= m_vol->dataCacheSector() | |||||
| && m_vol->dataCacheSector() < (sector + ns)) { | && m_vol->dataCacheSector() < (sector + ns)) { | ||||
| // invalidate cache if sector is in cache | |||||
| // Invalidate cache if cache sector is in the range. | |||||
| m_vol->dataCacheInvalidate(); | m_vol->dataCacheInvalidate(); | ||||
| } | } | ||||
| if (!m_vol->writeSectors(sector, src, ns)) { | if (!m_vol->writeSectors(sector, src, ns)) { |
| memcpy(dst, src, n); | memcpy(dst, src, n); | ||||
| #if USE_MULTI_SECTOR_IO | #if USE_MULTI_SECTOR_IO | ||||
| } else if (toRead >= 2*m_vol->bytesPerSector()) { | } else if (toRead >= 2*m_vol->bytesPerSector()) { | ||||
| uint8_t ns = toRead >> m_vol->bytesPerSectorShift(); | |||||
| uint32_t ns = toRead >> m_vol->bytesPerSectorShift(); | |||||
| if (!isRootFixed()) { | if (!isRootFixed()) { | ||||
| uint8_t mb = m_vol->sectorsPerCluster() - sectorOfCluster; | |||||
| uint32_t mb = m_vol->sectorsPerCluster() - sectorOfCluster; | |||||
| if (mb < ns) { | if (mb < ns) { | ||||
| ns = mb; | ns = mb; | ||||
| } | } | ||||
| } | } | ||||
| n = ns << m_vol->bytesPerSectorShift(); | n = ns << m_vol->bytesPerSectorShift(); | ||||
| if (m_vol->cacheSectorNumber() <= sector | |||||
| // Check for cache sector in read range. | |||||
| if (sector <= m_vol->cacheSectorNumber() | |||||
| && sector < (m_vol->cacheSectorNumber() + ns)) { | && sector < (m_vol->cacheSectorNumber() + ns)) { | ||||
| // flush cache if a sector is in the cache | |||||
| // Flush cache if a cache sector is in the range. | |||||
| if (!m_vol->cacheSyncData()) { | if (!m_vol->cacheSyncData()) { | ||||
| DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
| goto fail; | goto fail; | ||||
| #if USE_MULTI_SECTOR_IO | #if USE_MULTI_SECTOR_IO | ||||
| } else if (nToWrite >= 2*m_vol->bytesPerSector()) { | } else if (nToWrite >= 2*m_vol->bytesPerSector()) { | ||||
| // use multiple sector write command | // use multiple sector write command | ||||
| uint8_t maxSectors = m_vol->sectorsPerCluster() - sectorOfCluster; | |||||
| uint8_t nSector = nToWrite >> m_vol->bytesPerSectorShift(); | |||||
| uint32_t maxSectors = m_vol->sectorsPerCluster() - sectorOfCluster; | |||||
| uint32_t nSector = nToWrite >> m_vol->bytesPerSectorShift(); | |||||
| if (nSector > maxSectors) { | if (nSector > maxSectors) { | ||||
| nSector = maxSectors; | nSector = maxSectors; | ||||
| } | } | ||||
| n = nSector << m_vol->bytesPerSectorShift(); | n = nSector << m_vol->bytesPerSectorShift(); | ||||
| if (m_vol->cacheSectorNumber() <= sector | |||||
| // Check for cache sector in write range. | |||||
| if (sector <= m_vol->cacheSectorNumber() | |||||
| && sector < (m_vol->cacheSectorNumber() + nSector)) { | && sector < (m_vol->cacheSectorNumber() + nSector)) { | ||||
| // invalidate cache if sector is in cache | |||||
| // Invalidate cache if cache sector is in the range. | |||||
| m_vol->cacheInvalidate(); | m_vol->cacheInvalidate(); | ||||
| } | } | ||||
| if (!m_vol->writeSectors(sector, src, nSector)) { | if (!m_vol->writeSectors(sector, src, nSector)) { |
| */ | */ | ||||
| #define FREE_STACK_CPP | #define FREE_STACK_CPP | ||||
| #include "FreeStack.h" | #include "FreeStack.h" | ||||
| #if HAS_UNUSED_STACK | |||||
| #ifdef __AVR__ | |||||
| inline char* heapEnd() { | |||||
| #if defined(HAS_UNUSED_STACK) && HAS_UNUSED_STACK | |||||
| //------------------------------------------------------------------------------ | |||||
| inline char* stackBegin() { | |||||
| #if defined(__AVR__) | |||||
| return __brkval ? __brkval : &__bss_end; | return __brkval ? __brkval : &__bss_end; | ||||
| } | |||||
| inline char* stackPointer() { | |||||
| return reinterpret_cast<char*>(SP); | |||||
| } | |||||
| #elif defined(__IMXRT1062__) | |||||
| return reinterpret_cast<char*>(&_ebss); | |||||
| #elif defined(__arm__) | #elif defined(__arm__) | ||||
| inline char* heapEnd() { | |||||
| return reinterpret_cast<char*>(sbrk(0)); | return reinterpret_cast<char*>(sbrk(0)); | ||||
| #else // defined(__AVR__) | |||||
| #error "undefined stackBegin" | |||||
| #endif // defined(__AVR__) | |||||
| } | } | ||||
| //------------------------------------------------------------------------------ | |||||
| inline char* stackPointer() { | inline char* stackPointer() { | ||||
| #if defined(__AVR__) | |||||
| return reinterpret_cast<char*>(SP); | |||||
| #elif defined(__arm__) | |||||
| register uint32_t sp asm("sp"); | register uint32_t sp asm("sp"); | ||||
| return reinterpret_cast<char*>(sp); | return reinterpret_cast<char*>(sp); | ||||
| #else // defined(__AVR__) | |||||
| #error "undefined stackPointer" | |||||
| #endif // defined(__AVR__) | |||||
| } | } | ||||
| #endif // #elif define(__arm__) | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** Stack fill pattern. */ | /** Stack fill pattern. */ | ||||
| const char FILL = 0x55; | const char FILL = 0x55; | ||||
| void FillStack() { | void FillStack() { | ||||
| char* p = heapEnd(); | |||||
| char* p = stackBegin(); | |||||
| char* top = stackPointer(); | char* top = stackPointer(); | ||||
| while (p < top) { | while (p < top) { | ||||
| *p++ = FILL; | *p++ = FILL; | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // May fail if malloc or new is used. | // May fail if malloc or new is used. | ||||
| int UnusedStack() { | int UnusedStack() { | ||||
| char* h = heapEnd(); | |||||
| char* h = stackBegin(); | |||||
| char* top = stackPointer(); | char* top = stackPointer(); | ||||
| int n; | int n; | ||||
| } | } | ||||
| return n; | return n; | ||||
| } | } | ||||
| #endif // HAS_UNUSED_STACK | |||||
| #endif // defined(HAS_UNUSED_STACK) && HAS_UNUSED_STACK |
| inline int FreeStack() { | inline int FreeStack() { | ||||
| return System.freeMemory(); | return System.freeMemory(); | ||||
| } | } | ||||
| #elif defined(__arm__) && !defined(__IMXRT1062__) | |||||
| #elif defined(__IMXRT1062__) | |||||
| #define HAS_UNUSED_STACK 1 | |||||
| extern uint8_t _ebss; | |||||
| inline int FreeStack() { | |||||
| register uint32_t sp asm("sp"); | |||||
| return reinterpret_cast<char*>(sp) - reinterpret_cast<char*>(&_ebss); | |||||
| } | |||||
| #elif defined(__arm__) | |||||
| #define HAS_UNUSED_STACK 1 | #define HAS_UNUSED_STACK 1 | ||||
| extern "C" char* sbrk(int incr); | extern "C" char* sbrk(int incr); | ||||
| inline int FreeStack() { | inline int FreeStack() { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| #endif // defined(__AVR__) || defined(DOXYGEN) | #endif // defined(__AVR__) || defined(DOXYGEN) | ||||
| #ifdef HAS_UNUSED_STACK | |||||
| #if defined(HAS_UNUSED_STACK) || defined(DOXYGEN) | |||||
| /** Fill stack with 0x55 pattern */ | /** Fill stack with 0x55 pattern */ | ||||
| void FillStack(); | void FillStack(); | ||||
| /** | /** | ||||
| #define HAS_UNUSED_STACK 0 | #define HAS_UNUSED_STACK 0 | ||||
| inline void FillStack() {} | inline void FillStack() {} | ||||
| inline int UnusedStack() {return 0;} | inline int UnusedStack() {return 0;} | ||||
| #endif // HAS_UNUSED_STACK | |||||
| #endif // defined(HAS_UNUSED_STACK) | |||||
| #endif // FreeStack_h | #endif // FreeStack_h |
| const uint8_t CMD9 = 0X09; | const uint8_t CMD9 = 0X09; | ||||
| /** SEND_CID - read the card identification information (CID register) */ | /** SEND_CID - read the card identification information (CID register) */ | ||||
| const uint8_t CMD10 = 0X0A; | const uint8_t CMD10 = 0X0A; | ||||
| /** VOLTAGE_SWITCH -Switch to 1.8V bus signaling level. */ | |||||
| const uint8_t CMD11 = 0X0B; | |||||
| /** STOP_TRANSMISSION - end multiple sector read sequence */ | /** STOP_TRANSMISSION - end multiple sector read sequence */ | ||||
| const uint8_t CMD12 = 0X0C; | const uint8_t CMD12 = 0X0C; | ||||
| /** SEND_STATUS - read the card status register */ | /** SEND_STATUS - read the card status register */ |
| const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2; | const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2; | ||||
| const uint32_t CMD11_XFERTYP = SDHC_XFERTYP_CMDINX(CMD11) | CMD_RESP_R1; | |||||
| const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b | | const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b | | ||||
| SDHC_XFERTYP_CMDTYP(3); | SDHC_XFERTYP_CMDTYP(3); | ||||