daily_automated

This commit is contained in:
topicchi
2023-03-17 11:59:21 +00:00
parent 252ecca9cf
commit e2f276193e
4496 changed files with 1178007 additions and 0 deletions

View File

@@ -0,0 +1,485 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef SdInfo_h
#define SdInfo_h
#include <stdint.h>
// Based on the document:
//
// SD Specifications
// Part 1
// Physical Layer
// Simplified Specification
// Version 5.00
// Aug 10, 2016
//
// https://www.sdcard.org/downloads/pls/
//------------------------------------------------------------------------------
// SD card errors
// See the SD Specification for command info.
typedef enum {
SD_CARD_ERROR_NONE = 0,
// Basic commands and switch command.
SD_CARD_ERROR_CMD0 = 0X20,
SD_CARD_ERROR_CMD2,
SD_CARD_ERROR_CMD3,
SD_CARD_ERROR_CMD6,
SD_CARD_ERROR_CMD7,
SD_CARD_ERROR_CMD8,
SD_CARD_ERROR_CMD9,
SD_CARD_ERROR_CMD10,
SD_CARD_ERROR_CMD12,
SD_CARD_ERROR_CMD13,
// Read, write, erase, and extension commands.
SD_CARD_ERROR_CMD17 = 0X30,
SD_CARD_ERROR_CMD18,
SD_CARD_ERROR_CMD24,
SD_CARD_ERROR_CMD25,
SD_CARD_ERROR_CMD32,
SD_CARD_ERROR_CMD33,
SD_CARD_ERROR_CMD38,
SD_CARD_ERROR_CMD58,
SD_CARD_ERROR_CMD59,
// Application specific commands.
SD_CARD_ERROR_ACMD6 = 0X40,
SD_CARD_ERROR_ACMD13,
SD_CARD_ERROR_ACMD23,
SD_CARD_ERROR_ACMD41,
// Read/write errors
SD_CARD_ERROR_READ = 0X50,
SD_CARD_ERROR_READ_CRC,
SD_CARD_ERROR_READ_FIFO,
SD_CARD_ERROR_READ_REG,
SD_CARD_ERROR_READ_START,
SD_CARD_ERROR_READ_TIMEOUT,
SD_CARD_ERROR_STOP_TRAN,
SD_CARD_ERROR_WRITE,
SD_CARD_ERROR_WRITE_FIFO,
SD_CARD_ERROR_WRITE_START,
SD_CARD_ERROR_FLASH_PROGRAMMING,
SD_CARD_ERROR_WRITE_TIMEOUT,
// Misc errors.
SD_CARD_ERROR_DMA = 0X60,
SD_CARD_ERROR_ERASE,
SD_CARD_ERROR_ERASE_SINGLE_BLOCK,
SD_CARD_ERROR_ERASE_TIMEOUT,
SD_CARD_ERROR_INIT_NOT_CALLED,
SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED
} sd_error_code_t;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
const uint8_t SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
const uint8_t SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
const uint8_t SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
#define SD_SCK_HZ(maxSpeed) SPISettings(maxSpeed, MSBFIRST, SPI_MODE0)
#define SD_SCK_MHZ(maxMhz) SPISettings(1000000UL*maxMhz, MSBFIRST, SPI_MODE0)
// SPI divisor constants
/** Set SCK to max rate of F_CPU/2. */
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
/** Set SCK rate to F_CPU/3 for Due */
#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3)
/** Set SCK rate to F_CPU/4. */
#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4)
/** Set SCK rate to F_CPU/6 for Due */
#define SPI_DIV6_SPEED SD_SCK_HZ(F_CPU/6)
/** Set SCK rate to F_CPU/8. */
#define SPI_QUARTER_SPEED SD_SCK_HZ(F_CPU/8)
/** Set SCK rate to F_CPU/16. */
#define SPI_EIGHTH_SPEED SD_SCK_HZ(F_CPU/16)
/** Set SCK rate to F_CPU/32. */
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(F_CPU/32)
//------------------------------------------------------------------------------
// SD operation timeouts
/** CMD0 retry count */
const uint8_t SD_CMD0_RETRY = 10;
/** command timeout ms */
const uint16_t SD_CMD_TIMEOUT = 300;
/** init timeout ms */
const uint16_t SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */
const uint16_t SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */
const uint16_t SD_READ_TIMEOUT = 1000;
/** write time out ms */
const uint16_t SD_WRITE_TIMEOUT = 2000;
//------------------------------------------------------------------------------
// SD card commands
/** GO_IDLE_STATE - init card in spi mode if CS low */
const uint8_t CMD0 = 0X00;
/** ALL_SEND_CID - Asks any card to send the CID. */
const uint8_t CMD2 = 0X02;
/** SEND_RELATIVE_ADDR - Ask the card to publish a new RCA. */
const uint8_t CMD3 = 0X03;
/** SWITCH_FUNC - Switch Function Command */
const uint8_t CMD6 = 0X06;
/** SELECT/DESELECT_CARD - toggles between the stand-by and transfer states. */
const uint8_t CMD7 = 0X07;
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
const uint8_t CMD8 = 0X08;
/** SEND_CSD - read the Card Specific Data (CSD register) */
const uint8_t CMD9 = 0X09;
/** SEND_CID - read the card identification information (CID register) */
const uint8_t CMD10 = 0X0A;
/** STOP_TRANSMISSION - end multiple block read sequence */
const uint8_t CMD12 = 0X0C;
/** SEND_STATUS - read the card status register */
const uint8_t CMD13 = 0X0D;
/** READ_SINGLE_BLOCK - read a single data block from the card */
const uint8_t CMD17 = 0X11;
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
const uint8_t CMD18 = 0X12;
/** WRITE_BLOCK - write a single data block to the card */
const uint8_t CMD24 = 0X18;
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
const uint8_t CMD25 = 0X19;
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
const uint8_t CMD32 = 0X20;
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
range to be erased*/
const uint8_t CMD33 = 0X21;
/** ERASE - erase all previously selected blocks */
const uint8_t CMD38 = 0X26;
/** APP_CMD - escape for application specific command */
const uint8_t CMD55 = 0X37;
/** READ_OCR - read the OCR register of a card */
const uint8_t CMD58 = 0X3A;
/** CRC_ON_OFF - enable or disable CRC checking */
const uint8_t CMD59 = 0X3B;
/** SET_BUS_WIDTH - Defines the data bus width for data transfer. */
const uint8_t ACMD6 = 0X06;
/** SD_STATUS - Send the SD Status. */
const uint8_t ACMD13 = 0X0D;
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
pre-erased before writing */
const uint8_t ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
const uint8_t ACMD41 = 0X29;
//==============================================================================
// CARD_STATUS
/** The command's argument was out of the allowed range for this card. */
const uint32_t CARD_STATUS_OUT_OF_RANGE = 1UL << 31;
/** A misaligned address which did not match the block length. */
const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30;
/** The transferred block length is not allowed for this card. */
const uint32_t CARD_STATUS_BLOCK_LEN_ERROR = 1UL << 29;
/** An error in the sequence of erase commands occurred. */
const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL <<28;
/** An invalid selection of write-blocks for erase occurred. */
const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27;
/** Set when the host attempts to write to a protected block. */
const uint32_t CARD_STATUS_WP_VIOLATION = 1UL << 26;
/** When set, signals that the card is locked by the host. */
const uint32_t CARD_STATUS_CARD_IS_LOCKED = 1UL << 25;
/** Set when a sequence or password error has been detected. */
const uint32_t CARD_STATUS_LOCK_UNLOCK_FAILED = 1UL << 24;
/** The CRC check of the previous command failed. */
const uint32_t CARD_STATUS_COM_CRC_ERROR = 1UL << 23;
/** Command not legal for the card state. */
const uint32_t CARD_STATUS_ILLEGAL_COMMAND = 1UL << 22;
/** Card internal ECC was applied but failed to correct the data. */
const uint32_t CARD_STATUS_CARD_ECC_FAILED = 1UL << 21;
/** Internal card controller error */
const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20;
/** A general or an unknown error occurred during the operation. */
const uint32_t CARD_STATUS_ERROR = 1UL << 19;
// bits 19, 18, and 17 reserved.
/** Permanent WP set or attempt to change read only values of CSD. */
const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL <<16;
/** partial address space was erased due to write protect. */
const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15;
/** The command has been executed without using the internal ECC. */
const uint32_t CARD_STATUS_CARD_ECC_DISABLED = 1UL << 14;
/** out of erase sequence command was received. */
const uint32_t CARD_STATUS_ERASE_RESET = 1UL << 13;
/** The state of the card when receiving the command.
* 0 = idle
* 1 = ready
* 2 = ident
* 3 = stby
* 4 = tran
* 5 = data
* 6 = rcv
* 7 = prg
* 8 = dis
* 9-14 = reserved
* 15 = reserved for I/O mode
*/
const uint32_t CARD_STATUS_CURRENT_STATE = 0XF << 9;
/** Shift for current state. */
const uint32_t CARD_STATUS_CURRENT_STATE_SHIFT = 9;
/** Corresponds to buffer empty signaling on the bus. */
const uint32_t CARD_STATUS_READY_FOR_DATA = 1UL << 8;
// bit 7 reserved.
/** Extension Functions may set this bit to get host to deal with events. */
const uint32_t CARD_STATUS_FX_EVENT = 1UL << 6;
/** The card will expect ACMD, or the command has been interpreted as ACMD */
const uint32_t CARD_STATUS_APP_CMD = 1UL << 5;
// bit 4 reserved.
/** Error in the sequence of the authentication process. */
const uint32_t CARD_STATUS_AKE_SEQ_ERROR = 1UL << 3;
// bits 2,1, and 0 reserved for manufacturer test mode.
//==============================================================================
/** status for card in the ready state */
const uint8_t R1_READY_STATE = 0X00;
/** status for card in the idle state */
const uint8_t R1_IDLE_STATE = 0X01;
/** status bit for illegal command */
const uint8_t R1_ILLEGAL_COMMAND = 0X04;
/** start data token for read or write single block*/
const uint8_t DATA_START_BLOCK = 0XFE;
/** stop token for write multiple blocks*/
const uint8_t STOP_TRAN_TOKEN = 0XFD;
/** start data token for write multiple blocks*/
const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC;
/** mask for data response tokens after a write block operation */
const uint8_t DATA_RES_MASK = 0X1F;
/** write data accepted token */
const uint8_t DATA_RES_ACCEPTED = 0X05;
//==============================================================================
/**
* \class CID
* \brief Card IDentification (CID) register.
*/
typedef struct CID {
// byte 0
/** Manufacturer ID */
unsigned char mid;
// byte 1-2
/** OEM/Application ID */
char oid[2];
// byte 3-7
/** Product name */
char pnm[5];
// byte 8
/** Product revision least significant digit */
unsigned char prv_m : 4;
/** Product revision most significant digit */
unsigned char prv_n : 4;
// byte 9-12
/** Product serial number */
uint32_t psn;
// byte 13
/** Manufacturing date year low digit */
unsigned char mdt_year_high : 4;
/** not used */
unsigned char reserved : 4;
// byte 14
/** Manufacturing date month */
unsigned char mdt_month : 4;
/** Manufacturing date year low digit */
unsigned char mdt_year_low : 4;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** CRC7 checksum */
unsigned char crc : 7;
} __attribute__((packed)) cid_t;
//==============================================================================
/**
* \class CSDV1
* \brief CSD register for version 1.00 cards .
*/
typedef struct CSDV1 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
unsigned char taac;
// byte 2
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
unsigned char c_size_high : 2;
unsigned char reserved2 : 2;
unsigned char dsr_imp : 1;
unsigned char read_blk_misalign : 1;
unsigned char write_blk_misalign : 1;
unsigned char read_bl_partial : 1;
// byte 7
unsigned char c_size_mid;
// byte 8
unsigned char vdd_r_curr_max : 3;
unsigned char vdd_r_curr_min : 3;
unsigned char c_size_low : 2;
// byte 9
unsigned char c_size_mult_high : 2;
unsigned char vdd_w_cur_max : 3;
unsigned char vdd_w_curr_min : 3;
// byte 10
unsigned char sector_size_high : 6;
unsigned char erase_blk_en : 1;
unsigned char c_size_mult_low : 1;
// byte 11
unsigned char wp_grp_size : 7;
unsigned char sector_size_low : 1;
// byte 12
unsigned char write_bl_len_high : 2;
unsigned char r2w_factor : 3;
unsigned char reserved3 : 2;
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved4 : 5;
unsigned char write_partial : 1;
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved5: 2;
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Indicates the file format on the card */
unsigned char file_format_grp : 1;
// byte 15
unsigned char always1 : 1;
unsigned char crc : 7;
} __attribute__((packed)) csd1_t;
//==============================================================================
/**
* \class CSDV2
* \brief CSD register for version 2.00 cards.
*/
typedef struct CSDV2 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
/** fixed to 0X0E */
unsigned char taac;
// byte 2
/** fixed to 0 */
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
/** not used */
unsigned char reserved2 : 4;
unsigned char dsr_imp : 1;
/** fixed to 0 */
unsigned char read_blk_misalign : 1;
/** fixed to 0 */
unsigned char write_blk_misalign : 1;
/** fixed to 0 - no partial read */
unsigned char read_bl_partial : 1;
// byte 7
/** high part of card size */
unsigned char c_size_high : 6;
/** not used */
unsigned char reserved3 : 2;
// byte 8
/** middle part of card size */
unsigned char c_size_mid;
// byte 9
/** low part of card size */
unsigned char c_size_low;
// byte 10
/** sector size is fixed at 64 KB */
unsigned char sector_size_high : 6;
/** fixed to 1 - erase single is supported */
unsigned char erase_blk_en : 1;
/** not used */
unsigned char reserved4 : 1;
// byte 11
unsigned char wp_grp_size : 7;
/** sector size is fixed at 64 KB */
unsigned char sector_size_low : 1;
// byte 12
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_high : 2;
/** fixed value of 2 */
unsigned char r2w_factor : 3;
/** not used */
unsigned char reserved5 : 2;
/** fixed value of 0 - no write protect groups */
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved6 : 5;
/** always zero - no partial block read*/
unsigned char write_partial : 1;
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved7: 2;
/** Do not use always 0 */
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Do not use always 0 */
unsigned char file_format_grp : 1;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** checksum */
unsigned char crc : 7;
} __attribute__((packed)) csd2_t;
//==============================================================================
/**
* \class csd_t
* \brief Union of old and new style CSD register.
*/
union csd_t {
csd1_t v1;
csd2_t v2;
};
//-----------------------------------------------------------------------------
inline uint32_t sdCardCapacity(csd_t* csd) {
if (csd->v1.csd_ver == 0) {
uint8_t read_bl_len = csd->v1.read_bl_len;
uint16_t c_size = (csd->v1.c_size_high << 10)
| (csd->v1.c_size_mid << 2) | csd->v1.c_size_low;
uint8_t c_size_mult = (csd->v1.c_size_mult_high << 1)
| csd->v1.c_size_mult_low;
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
} else if (csd->v2.csd_ver == 1) {
uint32_t c_size = 0X10000L * csd->v2.c_size_high + 0X100L
* (uint32_t)csd->v2.c_size_mid + csd->v2.c_size_low;
return (c_size + 1) << 10;
} else {
return 0;
}
}
#endif // SdInfo_h

View File

@@ -0,0 +1,777 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "SdSpiCard.h"
//==============================================================================
class Timeout {
public:
Timeout() {}
explicit Timeout(uint16_t ms) {set(ms);}
uint16_t millis16() {return millis();}
void set(uint16_t ms) {
m_endTime = ms + millis16();
}
bool timedOut() {
return (int16_t)(m_endTime - millis16()) < 0;
}
private:
uint16_t m_endTime;
};
//==============================================================================
#if USE_SD_CRC
// CRC functions
//------------------------------------------------------------------------------
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
uint8_t crc = 0;
for (uint8_t i = 0; i < n; i++) {
uint8_t d = data[i];
for (uint8_t j = 0; j < 8; j++) {
crc <<= 1;
if ((d & 0x80) ^ (crc & 0x80)) {
crc ^= 0x09;
}
d <<= 1;
}
}
return (crc << 1) | 1;
}
//------------------------------------------------------------------------------
#if USE_SD_CRC == 1
// Shift based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
uint16_t crc = 0;
for (size_t i = 0; i < n; i++) {
crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= data[i];
crc ^= (uint8_t)(crc & 0xff) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xff) << 5;
}
return crc;
}
#elif USE_SD_CRC > 1 // CRC_CCITT
//------------------------------------------------------------------------------
// Table based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
#ifdef __AVR__
static const uint16_t crctab[] PROGMEM = {
#else // __AVR__
static const uint16_t crctab[] = {
#endif // __AVR__
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
uint16_t crc = 0;
for (size_t i = 0; i < n; i++) {
#ifdef __AVR__
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
#else // __AVR__
crc = crctab[(crc >> 8 ^ data[i]) & 0XFF] ^ (crc << 8);
#endif // __AVR__
}
return crc;
}
#endif // CRC_CCITT
#endif // USE_SD_CRC
//==============================================================================
// SharedSpiCard member functions
//------------------------------------------------------------------------------
bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
Timeout timeout;
m_spiActive = false;
m_beginCalled = false;
m_errorCode = SD_CARD_ERROR_NONE;
m_type = 0;
m_csPin = spiConfig.csPin;
#if SPI_DRIVER_SELECT >= 2
m_spiDriverPtr = spiConfig.spiPort;
if (!m_spiDriverPtr) {
error(SD_CARD_ERROR_INVALID_CARD_CONFIG);
goto fail;
}
#endif // SPI_DRIVER_SELECT
sdCsInit(m_csPin);
spiUnselect();
spiSetSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ);
spiBegin(spiConfig);
m_beginCalled = true;
uint32_t arg;
m_state = IDLE_STATE;
spiStart();
// must supply min of 74 clock cycles with CS high.
spiUnselect();
for (uint8_t i = 0; i < 10; i++) {
spiSend(0XFF);
}
spiSelect();
// command to go idle in SPI mode
for (uint8_t i = 1;; i++) {
if (cardCommand(CMD0, 0) == R1_IDLE_STATE) {
break;
}
if (i == SD_CMD0_RETRY) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
// Force any active transfer to end for an already initialized card.
for (uint8_t j = 0; j < 0XFF; j++) {
spiSend(0XFF);
}
}
#if USE_SD_CRC
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
error(SD_CARD_ERROR_CMD59);
goto fail;
}
#endif // USE_SD_CRC
// check SD version
if (!(cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
type(SD_CARD_TYPE_SD2);
for (uint8_t i = 0; i < 4; i++) {
m_status = spiReceive();
}
if (m_status != 0XAA) {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
} else {
type(SD_CARD_TYPE_SD1);
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
timeout.set(SD_INIT_TIMEOUT);
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
// check for timeout
if (timeout.timedOut()) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiReceive() & 0XC0) == 0XC0) {
type(SD_CARD_TYPE_SDHC);
}
// Discard rest of ocr - contains allowed voltage range.
for (uint8_t i = 0; i < 3; i++) {
spiReceive();
}
}
spiStop();
spiSetSckSpeed(spiConfig.maxSck);
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::cardCMD6(uint32_t arg, uint8_t* status) {
if (cardCommand(CMD6, arg)) {
error(SD_CARD_ERROR_CMD6);
goto fail;
}
if (!readData(status, 64)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
if (!syncDevice()) {
return 0XFF;
}
// select card
if (!m_spiActive) {
spiStart();
}
if (cmd != CMD0 && cmd != CMD12 && !waitReady(SD_CMD_TIMEOUT)) {
return 0XFF;
}
#if USE_SD_CRC
// form message
uint8_t buf[6];
buf[0] = (uint8_t)0x40U | cmd;
buf[1] = (uint8_t)(arg >> 24U);
buf[2] = (uint8_t)(arg >> 16U);
buf[3] = (uint8_t)(arg >> 8U);
buf[4] = (uint8_t)arg;
// add CRC
buf[5] = CRC7(buf, 5);
// send message
spiSend(buf, 6);
#else // USE_SD_CRC
// send command
spiSend(cmd | 0x40);
// send argument
uint8_t* pa = reinterpret_cast<uint8_t*>(&arg);
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}
// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC
// discard first fill byte to avoid MISO pull-up problem.
spiReceive();
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
uint16_t n = 0;
do {
m_status = spiReceive();
} while (m_status & 0X80 && ++n < 10);
return m_status;
}
//------------------------------------------------------------------------------
void SharedSpiCard::end() {
if (m_beginCalled) {
spiStop();
spiEnd();
m_beginCalled = false;
}
}
//------------------------------------------------------------------------------
bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
csd_t csd;
if (!readCSD(&csd)) {
goto fail;
}
// check for single sector erase
if (!csd.eraseSingleBlock()) {
// erase size mask
uint8_t m = csd.eraseSize() - 1;
if ((firstSector & m) != 0 || ((lastSector + 1) & m) != 0) {
// error card can't erase specified area
error(SD_CARD_ERROR_ERASE_SINGLE_SECTOR);
goto fail;
}
}
if (m_type != SD_CARD_TYPE_SDHC) {
firstSector <<= 9;
lastSector <<= 9;
}
if (cardCommand(CMD32, firstSector)
|| cardCommand(CMD33, lastSector)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
if (!waitReady(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::eraseSingleSectorEnable() {
csd_t csd;
return readCSD(&csd) ? csd.eraseSingleBlock() : false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::isBusy() {
if (m_state == READ_STATE) {
return false;
}
bool spiActive = m_spiActive;
if (!spiActive) {
spiStart();
}
bool rtn = 0XFF != spiReceive();
if (!spiActive) {
spiStop();
}
return rtn;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readData(uint8_t* dst) {
return readData(dst, 512);
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC
uint16_t crc;
#endif // USE_SD_CRC
// wait for start sector token
Timeout timeout(SD_READ_TIMEOUT);
while ((m_status = spiReceive()) == 0XFF) {
if (timeout.timedOut()) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
if (m_status != DATA_START_SECTOR) {
error(SD_CARD_ERROR_READ_TOKEN);
goto fail;
}
// transfer data
if ((m_status = spiReceive(dst, count))) {
error(SD_CARD_ERROR_DMA);
goto fail;
}
#if USE_SD_CRC
// get crc
crc = (spiReceive() << 8) | spiReceive();
if (crc != CRC_CCITT(dst, count)) {
error(SD_CARD_ERROR_READ_CRC);
goto fail;
}
#else // USE_SD_CRC
// discard crc
spiReceive();
spiReceive();
#endif // USE_SD_CRC
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readOCR(uint32_t* ocr) {
uint8_t* p = reinterpret_cast<uint8_t*>(ocr);
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
for (uint8_t i = 0; i < 4; i++) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
p[3 - i] = spiReceive();
#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
p[i] = spiReceive();
#endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
bool SharedSpiCard::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
goto fail;
}
if (!readData(dst, 16)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSCR(scr_t* scr) {
uint8_t* dst = reinterpret_cast<uint8_t*>(scr);
if (cardAcmd(ACMD51, 0)) {
error(SD_CARD_ERROR_ACMD51);
goto fail;
}
if (!readData(dst, sizeof(scr_t))) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
}
if (cardCommand(CMD17, sector)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
if (!readData(dst, 512)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
if (!readStart(sector)) {
goto fail;
}
for (size_t i = 0; i < ns; i++, dst += 512) {
if (!readData(dst, 512)) {
goto fail;
}
}
return readStop();
fail:
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readStart(uint32_t sector) {
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
}
if (cardCommand(CMD18, sector)) {
error(SD_CARD_ERROR_CMD18);
goto fail;
}
m_state = READ_STATE;
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readStatus(SdStatus* status) {
uint8_t* dst = reinterpret_cast<uint8_t*>(status);
// retrun is R2 so read extra status byte.
if (cardAcmd(ACMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_ACMD13);
goto fail;
}
if (!readData(dst, 64)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::readStop() {
m_state = IDLE_STATE;
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
uint32_t SharedSpiCard::sectorCount() {
csd_t csd;
return readCSD(&csd) ? csd.capacity() : 0;
}
//------------------------------------------------------------------------------
void SharedSpiCard::spiStart() {
if (!m_spiActive) {
spiActivate();
m_spiActive = true;
spiSelect();
// Dummy byte to drive MISO busy status.
spiSend(0XFF);
}
}
//------------------------------------------------------------------------------
void SharedSpiCard::spiStop() {
if (m_spiActive) {
spiUnselect();
// Insure MISO goes to low Z.
spiSend(0XFF);
spiDeactivate();
m_spiActive = false;
}
}
//------------------------------------------------------------------------------
bool SharedSpiCard::syncDevice() {
if (m_state == WRITE_STATE) {
return writeStop();
}
if (m_state == READ_STATE) {
return readStop();
}
return true;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::waitReady(uint16_t ms) {
Timeout timeout(ms);
while (spiReceive() != 0XFF) {
if (timeout.timedOut()) {
return false;
}
}
return true;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeData(const uint8_t* src) {
// wait for previous write to finish
if (!waitReady(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
// send one sector of data for write sector or write multiple sectors
bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
#if USE_SD_CRC
uint16_t crc = CRC_CCITT(src, 512);
#else // USE_SD_CRC
uint16_t crc = 0XFFFF;
#endif // USE_SD_CRC
spiSend(token);
spiSend(src, 512);
spiSend(crc >> 8);
spiSend(crc & 0XFF);
m_status = spiReceive();
if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE_DATA);
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
}
if (cardCommand(CMD24, sector)) {
error(SD_CARD_ERROR_CMD24);
goto fail;
}
if (!writeData(DATA_START_SECTOR, src)) {
goto fail;
}
#if CHECK_FLASH_PROGRAMMING
// wait for flash programming to complete
if (!waitReady(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
goto fail;
}
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_CMD13);
goto fail;
}
#endif // CHECK_FLASH_PROGRAMMING
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeSectors(uint32_t sector,
const uint8_t* src, size_t ns) {
if (!writeStart(sector)) {
goto fail;
}
for (size_t i = 0; i < ns; i++, src += 512) {
if (!writeData(src)) {
goto fail;
}
}
return writeStop();
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeStart(uint32_t sector) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
sector <<= 9;
}
if (cardCommand(CMD25, sector)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
m_state = WRITE_STATE;
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SharedSpiCard::writeStop() {
if (!waitReady(SD_WRITE_TIMEOUT)) {
goto fail;
}
spiSend(STOP_TRAN_TOKEN);
spiStop();
m_state = IDLE_STATE;
return true;
fail:
error(SD_CARD_ERROR_STOP_TRAN);
spiStop();
return false;
}
//==============================================================================
bool DedicatedSpiCard::begin(SdSpiConfig spiConfig) {
if (!SharedSpiCard::begin(spiConfig)) {
return false;
}
m_dedicatedSpi = spiOptionDedicated(spiConfig.options);
return true;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
return readSectors(sector, dst, 1);
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::readSectors(
uint32_t sector, uint8_t* dst, size_t ns) {
if (sdState() != READ_STATE || sector != m_curSector) {
if (!readStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, dst += 512) {
if (!readData(dst)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : readStop();
fail:
return false;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::setDedicatedSpi(bool value) {
if (!syncDevice()) {
return false;
}
m_dedicatedSpi = value;
return true;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
if (m_dedicatedSpi) {
return writeSectors(sector, src, 1);
}
return SharedSpiCard::writeSector(sector, src);
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSectors(
uint32_t sector, const uint8_t* src, size_t ns) {
if (sdState() != WRITE_STATE || m_curSector != sector) {
if (!writeStart(sector)) {
goto fail;
}
m_curSector = sector;
}
for (size_t i = 0; i < ns; i++, src += 512) {
if (!writeData(src)) {
goto fail;
}
}
m_curSector += ns;
return m_dedicatedSpi ? true : writeStop();
fail:
return false;
}

View File

@@ -0,0 +1,451 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
/**
* \file
* \brief SdSpiCard class for V2 SD/SDHC cards
*/
#ifndef SdSpiCard_h
#define SdSpiCard_h
#include <stddef.h>
#include "../common/SysCall.h"
#include "SdCardInfo.h"
#include "SdCardInterface.h"
#include "../SpiDriver/SdSpiDriver.h"
/** Verify correct SPI active if non-zero. */
#define CHECK_SPI_ACTIVE 0
#if CHECK_SPI_ACTIVE
/** Check SPI active. */
#define SPI_ASSERT_ACTIVE {if (!m_spiActive) {\
Serial.print(F("SPI_ASSERTACTIVE"));\
Serial.println(__LINE__);}}
#else // CHECK_SPI_ACTIVE
/** Do not check SPI active. */
#define SPI_ASSERT_ACTIVE
#endif // CHECK_SPI_ACTIVE
//==============================================================================
/**
* \class SharedSpiCard
* \brief Raw access to SD and SDHC flash memory cards via shared SPI port.
*/
#if HAS_SDIO_CLASS
class SharedSpiCard : public SdCardInterface {
#elif USE_BLOCK_DEVICE_INTERFACE
class SharedSpiCard : public FsBlockDeviceInterface {
#else // HAS_SDIO_CLASS
class SharedSpiCard {
#endif // HAS_SDIO_CLASS
public:
/** SD is in idle state */
static const uint8_t IDLE_STATE = 0;
/** SD is in multi-sector read state. */
static const uint8_t READ_STATE = 1;
/** SD is in multi-sector write state. */
static const uint8_t WRITE_STATE = 2;
/** Construct an instance of SharedSpiCard. */
SharedSpiCard() {}
/** Initialize the SD card.
* \param[in] spiConfig SPI card configuration.
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig);
/** CMD6 Switch mode: Check Function Set Function.
* \param[in] arg CMD6 argument.
* \param[out] status return status data.
*
* \return true for success or false for failure.
*/
bool cardCMD6(uint32_t arg, uint8_t* status);
/** End use of card */
void end();
/** Erase a range of sectors.
*
* \param[in] firstSector The address of the first sector in the range.
* \param[in] lastSector The address of the last sector in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of sectors. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single sector erase.
*
* \return true for success or false for failure.
*/
bool erase(uint32_t firstSector, uint32_t lastSector);
/** Determine if card supports single sector erase.
*
* \return true is returned if single sector erase is supported.
* false is returned if single sector erase is not supported.
*/
bool eraseSingleSectorEnable();
/**
* Set SD error code.
* \param[in] code value for error code.
*/
void error(uint8_t code) {
// (void)code;
m_errorCode = code;
}
/**
* \return code for the last error. See SdCardInfo.h for a list of error codes.
*/
uint8_t errorCode() const {
return m_errorCode;
}
/** \return error data for last error. */
uint32_t errorData() const {
return m_status;
}
/** \return false for shared class. */
bool hasDedicatedSpi() {return false;}
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return false, can't be in dedicated state. */
bool isDedicatedSpi() {return false;}
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
/** Read one data sector in a multiple sector read sequence
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return true for success or false for failure.
*/
bool readData(uint8_t* dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success or false for failure.
*/
bool readOCR(uint32_t* ocr);
/** Read SCR register.
*
* \param[out] scr Value of SCR register.
* \return true for success or false for failure.
*/
bool readSCR(scr_t* scr);
/**
* Read a 512 byte sector from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSector(uint32_t sector, uint8_t* dst);
/**
* Read multiple 512 byte sectors from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[in] ns Number of sectors to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/** Start a read multiple sector sequence.
*
* \param[in] sector Address of first sector in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple sector reads. SPI chipSelect must be low for the entire sequence.
*
* \return true for success or false for failure.
*/
bool readStart(uint32_t sector);
/** Return the 64 byte card status
* \param[out] status location for 64 status bytes.
* \return true for success or false for failure.
*/
bool readStatus(SdStatus* status);
/** End a read multiple sectors sequence.
*
* \return true for success or false for failure.
*/
bool readStop();
/** \return SD multi-sector read/write state */
uint8_t sdState() {return m_state;}
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte data sectors in the card
* or zero if an error occurs.
*/
uint32_t sectorCount();
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Use sectorCount(). cardSize() will be removed in the future.
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Set SPI sharing state
* \param[in] value desired state.
* \return false for shared card
*/
bool setDedicatedSpi(bool value) {
(void)value;
return false;
}
/** end a mult-sector transfer.
*
* \return true for success or false for failure.
*/
bool stopTransfer();
/** \return success if sync successful. Not for user apps. */
bool syncDevice();
/** Return the card type: SD V1, SD V2 or SDHC/SDXC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC.
*/
uint8_t type() const {
return m_type;
}
/**
* Write a 512 byte sector to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSector(uint32_t sector, const uint8_t* src);
/**
* Write multiple 512 byte sectors to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] ns Number of sectors to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
/** Write one data sector in a multiple sector write sequence.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple sector writes.
*
* \return true for success or false for failure.
*/
bool writeStart(uint32_t sector);
/** End a write multiple sectors sequence.
*
* \return true for success or false for failure.
*/
bool writeStop();
private:
// private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);
void spiSelect() {
sdCsWrite(m_csPin, false);
}
void spiStart();
void spiStop();
void spiUnselect() {
sdCsWrite(m_csPin, true);
}
void type(uint8_t value) {
m_type = value;
}
bool waitReady(uint16_t ms);
bool writeData(uint8_t token, const uint8_t* src);
#if SPI_DRIVER_SELECT < 2
void spiActivate() {
m_spiDriver.activate();
}
void spiBegin(SdSpiConfig spiConfig) {
m_spiDriver.begin(spiConfig);
}
void spiDeactivate() {
m_spiDriver.deactivate();
}
void spiEnd() {
m_spiDriver.end();
}
uint8_t spiReceive() {
SPI_ASSERT_ACTIVE;
return m_spiDriver.receive();
}
uint8_t spiReceive(uint8_t* buf, size_t n) {
SPI_ASSERT_ACTIVE;
return m_spiDriver.receive(buf, n);
}
void spiSend(uint8_t data) {
SPI_ASSERT_ACTIVE;
m_spiDriver.send(data);
}
void spiSend(const uint8_t* buf, size_t n) {
SPI_ASSERT_ACTIVE;
m_spiDriver.send(buf, n);
}
void spiSetSckSpeed(uint32_t maxSck) {
m_spiDriver.setSckSpeed(maxSck);
}
SdSpiDriver m_spiDriver;
#else // SPI_DRIVER_SELECT < 2
void spiActivate() {
m_spiDriverPtr->activate();
}
void spiBegin(SdSpiConfig spiConfig) {
m_spiDriverPtr->begin(spiConfig);
}
void spiDeactivate() {
m_spiDriverPtr->deactivate();
}
void spiEnd() {
m_spiDriverPtr->end();
}
uint8_t spiReceive() {
SPI_ASSERT_ACTIVE;
return m_spiDriverPtr->receive();
}
uint8_t spiReceive(uint8_t* buf, size_t n) {
SPI_ASSERT_ACTIVE;
return m_spiDriverPtr->receive(buf, n);
}
void spiSend(uint8_t data) {
SPI_ASSERT_ACTIVE;
m_spiDriverPtr->send(data);
}
void spiSend(const uint8_t* buf, size_t n) {
SPI_ASSERT_ACTIVE;
m_spiDriverPtr->send(buf, n);
}
void spiSetSckSpeed(uint32_t maxSck) {
m_spiDriverPtr->setSckSpeed(maxSck);
}
SdSpiDriver* m_spiDriverPtr;
#endif // SPI_DRIVER_SELECT < 2
bool m_beginCalled = false;
SdCsPin_t m_csPin;
uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
bool m_spiActive;
uint8_t m_state;
uint8_t m_status;
uint8_t m_type = 0;
};
//==============================================================================
/**
* \class DedicatedSpiCard
* \brief Raw access to SD and SDHC flash memory cards via dedicate SPI port.
*/
class DedicatedSpiCard : public SharedSpiCard {
public:
/** Construct an instance of DedicatedSpiCard. */
DedicatedSpiCard() {}
/** Initialize the SD card.
* \param[in] spiConfig SPI card configuration.
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig);
/** \return true, can be in dedicaded state. */
bool hasDedicatedSpi() {return true;}
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi() {return m_dedicatedSpi;}
/**
* Read a 512 byte sector from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSector(uint32_t sector, uint8_t* dst);
/**
* Read multiple 512 byte sectors from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[in] ns Number of sectors to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value);
/**
* Write a 512 byte sector to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSector(uint32_t sector, const uint8_t* src);
/**
* Write multiple 512 byte sectors to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] ns Number of sectors to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
private:
uint32_t m_curSector;
bool m_dedicatedSpi = false;
};
//==============================================================================
#if ENABLE_DEDICATED_SPI
/** typedef for dedicated SPI. */
typedef DedicatedSpiCard SdSpiCard;
#else
/** typedef for shared SPI. */
typedef SharedSpiCard SdSpiCard;
#endif
#endif // SdSpiCard_h

View File

@@ -0,0 +1,94 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "SdSpiCard.h"
bool SdSpiCardEX::readBlock(uint32_t block, uint8_t* dst) {
if (m_curState != READ_STATE || block != m_curBlock) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::readStart(block)) {
return false;
}
m_curBlock = block;
m_curState = READ_STATE;
}
if (!SdSpiCard::readData(dst)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(block + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::writeBlock(uint32_t block, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curBlock != block) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::writeStart(block)) {
return false;
}
m_curBlock = block;
m_curState = WRITE_STATE;
}
if (!SdSpiCard::writeData(src)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::writeBlocks(uint32_t block,
const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(block + i, src + i*512UL)) {
return false;
}
}
return true;
}

View File

@@ -0,0 +1,267 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef SdioCard_h
#define SdioCard_h
#include "../common/SysCall.h"
#include "SdCardInterface.h"
#define FIFO_SDIO 0
#define DMA_SDIO 1
/**
* \class SdioConfig
* \brief SDIO card configuration.
*/
class SdioConfig {
public:
SdioConfig() {}
/**
* SdioConfig constructor.
* \param[in] opt SDIO options.
*/
explicit SdioConfig(uint8_t opt) : m_options(opt) {}
/** \return SDIO card options. */
uint8_t options() {return m_options;}
/** \return true if DMA_SDIO. */
bool useDma() {return m_options & DMA_SDIO;}
private:
uint8_t m_options = FIFO_SDIO;
};
//------------------------------------------------------------------------------
/**
* \class SdioCard
* \brief Raw SDIO access to SD and SDHC flash memory cards.
*/
class SdioCard : public SdCardInterface {
public:
/** Initialize the SD card.
* \param[in] sdioConfig SDIO card configuration.
* \return true for success or false for failure.
*/
bool begin(SdioConfig sdioConfig);
/** CMD6 Switch mode: Check Function Set Function.
* \param[in] arg CMD6 argument.
* \param[out] status return status data.
*
* \return true for success or false for failure.
*/
bool cardCMD6(uint32_t arg, uint8_t* status);
/** Disable an SDIO card.
* not implemented.
*/
void end() {}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Erase a range of sectors.
*
* \param[in] firstSector The address of the first sector in the range.
* \param[in] lastSector The address of the last sector in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of sectors. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single sector erase.
*
* \return true for success or false for failure.
*/
bool erase(uint32_t firstSector, uint32_t lastSector);
/**
* \return code for the last error. See SdCardInfo.h for a list of error codes.
*/
uint8_t errorCode() const;
/** \return error data for last error. */
uint32_t errorData() const;
/** \return error line for last error. Tmp function for debug. */
uint32_t errorLine() const;
/**
* Check for busy with CMD13.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return the SD clock frequency in kHz. */
uint32_t kHzSdClk();
/**
* Read a 512 byte sector from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSector(uint32_t sector, uint8_t* dst);
/**
* Read multiple 512 byte sectors from an SD card.
*
* \param[in] sector Logical sector to be read.
* \param[in] ns Number of sectors to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid);
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd);
/** Read one data sector in a multiple sector read sequence
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return true for success or false for failure.
*/
bool readData(uint8_t* dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success or false for failure.
*/
bool readOCR(uint32_t* ocr);
/** Read SCR register.
*
* \param[out] scr Value of SCR register.
* \return true for success or false for failure.
*/
bool readSCR(scr_t *scr);
/** Start a read multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple sector reads. SPI chipSelect must be low for the entire sequence.
*
* \return true for success or false for failure.
*/
bool readStart(uint32_t sector);
/** Start a read multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
* \param[in] count Maximum sector count.
* \note This function is used with readData() and readStop() for optimized
* multiple sector reads. SPI chipSelect must be low for the entire sequence.
*
* \return true for success or false for failure.
*/
bool readStart(uint32_t sector, uint32_t count);
/** End a read multiple sectors sequence.
*
* \return true for success or false for failure.
*/
bool readStop();
/** \return SDIO card status. */
uint32_t status();
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte data sectors in the card
* or zero if an error occurs.
*/
uint32_t sectorCount();
/**
* Send CMD12 to stop read or write.
*
* \param[in] blocking If true, wait for command complete.
*
* \return true for success or false for failure.
*/
bool stopTransmission(bool blocking);
/** \return success if sync successful. Not for user apps. */
bool syncDevice();
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
uint8_t type() const;
/**
* Writes a 512 byte sector to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSector(uint32_t sector, const uint8_t* src);
/**
* Write multiple 512 byte sectors to an SD card.
*
* \param[in] sector Logical sector to be written.
* \param[in] ns Number of sectors to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
/** Write one data sector in a multiple sector write sequence.
* \param[in] src Pointer to the location of the data to be written.
* \return true for success or false for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple sector writes.
*
* \return true for success or false for failure.
*/
bool writeStart(uint32_t sector);
/** Start a write multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
* \param[in] count Maximum sector count.
* \note This function is used with writeData() and writeStop()
* for optimized multiple sector writes.
*
* \return true for success or false for failure.
*/
bool writeStart(uint32_t sector, uint32_t count);
/** End a write multiple sectors sequence.
*
* \return true for success or false for failure.
*/
bool writeStop();
private:
static const uint8_t IDLE_STATE = 0;
static const uint8_t READ_STATE = 1;
static const uint8_t WRITE_STATE = 2;
uint32_t m_curSector;
SdioConfig m_sdioConfig;
uint8_t m_curState = IDLE_STATE;
};
#endif // SdioCard_h

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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 THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "SdioCard.h"
// limit of K66 due to errata KINETIS_K_0N65N.
const uint32_t MAX_SDHC_COUNT = 0XFFFF;
// Max RU is 1024 blocks.
const uint32_t RU_MASK = 0X03FF;
bool SdioCardEX::readBlock(uint32_t lba, uint8_t* dst) {
if (m_curState != READ_STATE || lba != m_curLba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::readStart(lba, m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = READ_STATE;
}
if (!SdioCard::readData(dst)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::readBlocks(uint32_t lba, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(lba + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlock(uint32_t lba, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curLba != lba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::writeStart(lba , m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = WRITE_STATE;
}
if (!SdioCard::writeData(src)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlocks(uint32_t lba, const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(lba + i, src + i*512UL)) {
return false;
}
}
return true;
}

File diff suppressed because it is too large Load Diff