[136] | 1 | /* Arduino Sd2Card Library
|
---|
| 2 | * Copyright (C) 2009 by William Greiman
|
---|
| 3 | *
|
---|
| 4 | * This file is part of the Arduino Sd2Card Library
|
---|
| 5 | *
|
---|
| 6 | * This Library is free software: you can redistribute it and/or modify
|
---|
| 7 | * it under the terms of the GNU General Public License as published by
|
---|
| 8 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 9 | * (at your option) any later version.
|
---|
| 10 | *
|
---|
| 11 | * This Library is distributed in the hope that it will be useful,
|
---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 14 | * GNU General Public License for more details.
|
---|
| 15 | *
|
---|
| 16 | * You should have received a copy of the GNU General Public License
|
---|
| 17 | * along with the Arduino Sd2Card Library. If not, see
|
---|
| 18 | * <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #define USE_SPI_LIB
|
---|
| 21 | #include <Arduino.h>
|
---|
| 22 | #include "Sd2Card.h"
|
---|
[194] | 23 |
|
---|
| 24 | #ifdef TOPPERS_WITH_ARDUINO
|
---|
[260] | 25 | #include "r2ca.h"
|
---|
[194] | 26 | #define ENTER_CRITICAL wai_sem(SPI_SEM);
|
---|
| 27 | #define LEAVE_CRITICAL sig_sem(SPI_SEM);
|
---|
| 28 | #else /* !TOPPERS_WITH_ARDUINO */
|
---|
| 29 | #define WAIT_TIMEOUT
|
---|
| 30 | #define ENTER_CRITICAL
|
---|
| 31 | #define LEAVE_CRITICAL
|
---|
| 32 | #endif /* TOPPERS_WITH_ARDUINO */
|
---|
| 33 |
|
---|
[136] | 34 | //------------------------------------------------------------------------------
|
---|
| 35 | #ifndef SOFTWARE_SPI
|
---|
| 36 | #ifdef USE_SPI_LIB
|
---|
| 37 | #include <SPI.h>
|
---|
| 38 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 39 | static SPISettings settings;
|
---|
| 40 | #endif
|
---|
| 41 | #endif
|
---|
| 42 | // functions for hardware SPI
|
---|
| 43 | /** Send a byte to the card */
|
---|
| 44 | static void spiSend(uint8_t b) {
|
---|
| 45 | #ifndef USE_SPI_LIB
|
---|
| 46 | SPDR = b;
|
---|
| 47 | while (!(SPSR & (1 << SPIF)))
|
---|
| 48 | ;
|
---|
| 49 | #else
|
---|
| 50 | SPI.transfer(b);
|
---|
| 51 | #endif
|
---|
| 52 | }
|
---|
| 53 | /** Receive a byte from the card */
|
---|
| 54 | static uint8_t spiRec(void) {
|
---|
| 55 | #ifndef USE_SPI_LIB
|
---|
| 56 | spiSend(0XFF);
|
---|
| 57 | return SPDR;
|
---|
| 58 | #else
|
---|
| 59 | return SPI.transfer(0xFF);
|
---|
| 60 | #endif
|
---|
| 61 | }
|
---|
| 62 | #else // SOFTWARE_SPI
|
---|
| 63 | //------------------------------------------------------------------------------
|
---|
| 64 | /** nop to tune soft SPI timing */
|
---|
| 65 | #define nop asm volatile ("nop\n\t")
|
---|
| 66 | //------------------------------------------------------------------------------
|
---|
| 67 | /** Soft SPI receive */
|
---|
| 68 | uint8_t spiRec(void) {
|
---|
| 69 | uint8_t data = 0;
|
---|
| 70 | // no interrupts during byte receive - about 8 us
|
---|
| 71 | cli();
|
---|
| 72 | // output pin high - like sending 0XFF
|
---|
| 73 | fastDigitalWrite(SPI_MOSI_PIN, HIGH);
|
---|
| 74 |
|
---|
| 75 | for (uint8_t i = 0; i < 8; i++) {
|
---|
| 76 | fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
---|
| 77 |
|
---|
| 78 | // adjust so SCK is nice
|
---|
| 79 | nop;
|
---|
| 80 | nop;
|
---|
| 81 |
|
---|
| 82 | data <<= 1;
|
---|
| 83 |
|
---|
| 84 | if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
|
---|
| 85 |
|
---|
| 86 | fastDigitalWrite(SPI_SCK_PIN, LOW);
|
---|
| 87 | }
|
---|
| 88 | // enable interrupts
|
---|
| 89 | sei();
|
---|
| 90 | return data;
|
---|
| 91 | }
|
---|
| 92 | //------------------------------------------------------------------------------
|
---|
| 93 | /** Soft SPI send */
|
---|
| 94 | void spiSend(uint8_t data) {
|
---|
| 95 | // no interrupts during byte send - about 8 us
|
---|
| 96 | cli();
|
---|
| 97 | for (uint8_t i = 0; i < 8; i++) {
|
---|
| 98 | fastDigitalWrite(SPI_SCK_PIN, LOW);
|
---|
| 99 |
|
---|
| 100 | fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
|
---|
| 101 |
|
---|
| 102 | data <<= 1;
|
---|
| 103 |
|
---|
| 104 | fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
---|
| 105 | }
|
---|
| 106 | // hold SCK high for a few ns
|
---|
| 107 | nop;
|
---|
| 108 | nop;
|
---|
| 109 | nop;
|
---|
| 110 | nop;
|
---|
| 111 |
|
---|
| 112 | fastDigitalWrite(SPI_SCK_PIN, LOW);
|
---|
| 113 | // enable interrupts
|
---|
| 114 | sei();
|
---|
| 115 | }
|
---|
| 116 | #endif // SOFTWARE_SPI
|
---|
| 117 | //------------------------------------------------------------------------------
|
---|
| 118 | // send command and return error code. Return zero for OK
|
---|
| 119 | uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
---|
| 120 | // end read if in partialBlockRead mode
|
---|
| 121 | readEnd();
|
---|
| 122 |
|
---|
| 123 | // select card
|
---|
| 124 | chipSelectLow();
|
---|
| 125 |
|
---|
| 126 | // wait up to 300 ms if busy
|
---|
| 127 | waitNotBusy(300);
|
---|
| 128 |
|
---|
| 129 | // send command
|
---|
| 130 | spiSend(cmd | 0x40);
|
---|
| 131 |
|
---|
| 132 | // send argument
|
---|
| 133 | for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
---|
| 134 |
|
---|
| 135 | // send CRC
|
---|
| 136 | uint8_t crc = 0XFF;
|
---|
| 137 | if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
|
---|
| 138 | if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
|
---|
| 139 | spiSend(crc);
|
---|
| 140 |
|
---|
| 141 | // wait for response
|
---|
| 142 | for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++)
|
---|
| 143 | ;
|
---|
| 144 | return status_;
|
---|
| 145 | }
|
---|
| 146 | //------------------------------------------------------------------------------
|
---|
| 147 | /**
|
---|
| 148 | * Determine the size of an SD flash memory card.
|
---|
| 149 | *
|
---|
| 150 | * \return The number of 512 byte data blocks in the card
|
---|
| 151 | * or zero if an error occurs.
|
---|
| 152 | */
|
---|
| 153 | uint32_t Sd2Card::cardSize(void) {
|
---|
| 154 | csd_t csd;
|
---|
| 155 | if (!readCSD(&csd)) return 0;
|
---|
| 156 | if (csd.v1.csd_ver == 0) {
|
---|
| 157 | uint8_t read_bl_len = csd.v1.read_bl_len;
|
---|
| 158 | uint16_t c_size = (csd.v1.c_size_high << 10)
|
---|
| 159 | | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
|
---|
| 160 | uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
|
---|
| 161 | | csd.v1.c_size_mult_low;
|
---|
| 162 | return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
---|
| 163 | } else if (csd.v2.csd_ver == 1) {
|
---|
| 164 | uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
|
---|
| 165 | | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
|
---|
| 166 | return (c_size + 1) << 10;
|
---|
| 167 | } else {
|
---|
| 168 | error(SD_CARD_ERROR_BAD_CSD);
|
---|
| 169 | return 0;
|
---|
| 170 | }
|
---|
| 171 | }
|
---|
| 172 | //------------------------------------------------------------------------------
|
---|
| 173 | static uint8_t chip_select_asserted = 0;
|
---|
| 174 |
|
---|
| 175 | void Sd2Card::chipSelectHigh(void) {
|
---|
| 176 | digitalWrite(chipSelectPin_, HIGH);
|
---|
| 177 | #ifdef USE_SPI_LIB
|
---|
| 178 | if (chip_select_asserted) {
|
---|
| 179 | chip_select_asserted = 0;
|
---|
| 180 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 181 | SPI.endTransaction();
|
---|
| 182 | #endif
|
---|
| 183 | }
|
---|
| 184 | #endif
|
---|
| 185 | }
|
---|
| 186 | //------------------------------------------------------------------------------
|
---|
| 187 | void Sd2Card::chipSelectLow(void) {
|
---|
| 188 | #ifdef USE_SPI_LIB
|
---|
| 189 | if (!chip_select_asserted) {
|
---|
| 190 | chip_select_asserted = 1;
|
---|
| 191 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 192 | SPI.beginTransaction(settings);
|
---|
| 193 | #endif
|
---|
| 194 | }
|
---|
| 195 | #endif
|
---|
| 196 | digitalWrite(chipSelectPin_, LOW);
|
---|
| 197 | }
|
---|
| 198 | //------------------------------------------------------------------------------
|
---|
| 199 | /** Erase a range of blocks.
|
---|
| 200 | *
|
---|
| 201 | * \param[in] firstBlock The address of the first block in the range.
|
---|
| 202 | * \param[in] lastBlock The address of the last block in the range.
|
---|
| 203 | *
|
---|
| 204 | * \note This function requests the SD card to do a flash erase for a
|
---|
| 205 | * range of blocks. The data on the card after an erase operation is
|
---|
| 206 | * either 0 or 1, depends on the card vendor. The card must support
|
---|
| 207 | * single block erase.
|
---|
| 208 | *
|
---|
| 209 | * \return The value one, true, is returned for success and
|
---|
| 210 | * the value zero, false, is returned for failure.
|
---|
| 211 | */
|
---|
| 212 | uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
---|
[194] | 213 | ENTER_CRITICAL;
|
---|
[136] | 214 | if (!eraseSingleBlockEnable()) {
|
---|
| 215 | error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
---|
| 216 | goto fail;
|
---|
| 217 | }
|
---|
| 218 | if (type_ != SD_CARD_TYPE_SDHC) {
|
---|
| 219 | firstBlock <<= 9;
|
---|
| 220 | lastBlock <<= 9;
|
---|
| 221 | }
|
---|
| 222 | if (cardCommand(CMD32, firstBlock)
|
---|
| 223 | || cardCommand(CMD33, lastBlock)
|
---|
| 224 | || cardCommand(CMD38, 0)) {
|
---|
| 225 | error(SD_CARD_ERROR_ERASE);
|
---|
| 226 | goto fail;
|
---|
| 227 | }
|
---|
| 228 | if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
---|
| 229 | error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
---|
| 230 | goto fail;
|
---|
| 231 | }
|
---|
| 232 | chipSelectHigh();
|
---|
[194] | 233 | LEAVE_CRITICAL;
|
---|
[136] | 234 | return true;
|
---|
| 235 |
|
---|
| 236 | fail:
|
---|
| 237 | chipSelectHigh();
|
---|
[194] | 238 | LEAVE_CRITICAL;
|
---|
[136] | 239 | return false;
|
---|
| 240 | }
|
---|
| 241 | //------------------------------------------------------------------------------
|
---|
| 242 | /** Determine if card supports single block erase.
|
---|
| 243 | *
|
---|
| 244 | * \return The value one, true, is returned if single block erase is supported.
|
---|
| 245 | * The value zero, false, is returned if single block erase is not supported.
|
---|
| 246 | */
|
---|
| 247 | uint8_t Sd2Card::eraseSingleBlockEnable(void) {
|
---|
| 248 | csd_t csd;
|
---|
| 249 | return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
|
---|
| 250 | }
|
---|
| 251 | //------------------------------------------------------------------------------
|
---|
| 252 | /**
|
---|
| 253 | * Initialize an SD flash memory card.
|
---|
| 254 | *
|
---|
| 255 | * \param[in] sckRateID SPI clock rate selector. See setSckRate().
|
---|
| 256 | * \param[in] chipSelectPin SD chip select pin number.
|
---|
| 257 | *
|
---|
| 258 | * \return The value one, true, is returned for success and
|
---|
| 259 | * the value zero, false, is returned for failure. The reason for failure
|
---|
| 260 | * can be determined by calling errorCode() and errorData().
|
---|
| 261 | */
|
---|
| 262 | uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
|
---|
| 263 |
|
---|
| 264 | errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
|
---|
| 265 | chipSelectPin_ = chipSelectPin;
|
---|
| 266 | // 16-bit init start time allows over a minute
|
---|
| 267 | uint16_t t0 = (uint16_t)millis();
|
---|
| 268 | uint32_t arg;
|
---|
[194] | 269 |
|
---|
| 270 | ENTER_CRITICAL;
|
---|
[136] | 271 | // set pin modes
|
---|
| 272 | pinMode(chipSelectPin_, OUTPUT);
|
---|
| 273 | digitalWrite(chipSelectPin_, HIGH);
|
---|
| 274 | #ifndef USE_SPI_LIB
|
---|
| 275 | pinMode(SPI_MISO_PIN, INPUT);
|
---|
| 276 | pinMode(SPI_MOSI_PIN, OUTPUT);
|
---|
| 277 | pinMode(SPI_SCK_PIN, OUTPUT);
|
---|
| 278 | #endif
|
---|
| 279 |
|
---|
| 280 | #ifndef SOFTWARE_SPI
|
---|
| 281 | #ifndef USE_SPI_LIB
|
---|
| 282 | // SS must be in output mode even it is not chip select
|
---|
| 283 | pinMode(SS_PIN, OUTPUT);
|
---|
| 284 | digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
|
---|
| 285 | // Enable SPI, Master, clock rate f_osc/128
|
---|
| 286 | SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
|
---|
| 287 | // clear double speed
|
---|
| 288 | SPSR &= ~(1 << SPI2X);
|
---|
| 289 | #else // USE_SPI_LIB
|
---|
| 290 | SPI.begin();
|
---|
| 291 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 292 | settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
|
---|
| 293 | #endif
|
---|
| 294 | #endif // USE_SPI_LIB
|
---|
| 295 | #endif // SOFTWARE_SPI
|
---|
| 296 |
|
---|
| 297 | // must supply min of 74 clock cycles with CS high.
|
---|
| 298 | #ifdef USE_SPI_LIB
|
---|
| 299 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 300 | SPI.beginTransaction(settings);
|
---|
| 301 | #endif
|
---|
| 302 | #endif
|
---|
| 303 | for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
|
---|
| 304 | #ifdef USE_SPI_LIB
|
---|
| 305 | #ifndef ARDUINO_ARCH_SAMD
|
---|
| 306 | SPI.endTransaction();
|
---|
| 307 | #endif
|
---|
| 308 | #endif
|
---|
| 309 | chipSelectLow();
|
---|
| 310 |
|
---|
| 311 | // command to go idle in SPI mode
|
---|
| 312 | while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
|
---|
| 313 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
---|
| 314 | error(SD_CARD_ERROR_CMD0);
|
---|
| 315 | goto fail;
|
---|
| 316 | }
|
---|
| 317 | }
|
---|
| 318 | // check SD version
|
---|
| 319 | if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
---|
| 320 | type(SD_CARD_TYPE_SD1);
|
---|
| 321 | } else {
|
---|
| 322 | // only need last byte of r7 response
|
---|
| 323 | for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
|
---|
| 324 | if (status_ != 0XAA) {
|
---|
| 325 | error(SD_CARD_ERROR_CMD8);
|
---|
| 326 | goto fail;
|
---|
| 327 | }
|
---|
| 328 | type(SD_CARD_TYPE_SD2);
|
---|
| 329 | }
|
---|
| 330 | // initialize card and send host supports SDHC if SD2
|
---|
| 331 | arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
---|
| 332 |
|
---|
| 333 | while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
---|
| 334 | // check for timeout
|
---|
| 335 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
---|
| 336 | error(SD_CARD_ERROR_ACMD41);
|
---|
| 337 | goto fail;
|
---|
| 338 | }
|
---|
| 339 | }
|
---|
| 340 | // if SD2 read OCR register to check for SDHC card
|
---|
| 341 | if (type() == SD_CARD_TYPE_SD2) {
|
---|
| 342 | if (cardCommand(CMD58, 0)) {
|
---|
| 343 | error(SD_CARD_ERROR_CMD58);
|
---|
| 344 | goto fail;
|
---|
| 345 | }
|
---|
| 346 | if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
|
---|
| 347 | // discard rest of ocr - contains allowed voltage range
|
---|
| 348 | for (uint8_t i = 0; i < 3; i++) spiRec();
|
---|
| 349 | }
|
---|
| 350 | chipSelectHigh();
|
---|
[194] | 351 | LEAVE_CRITICAL;
|
---|
[136] | 352 | #ifndef SOFTWARE_SPI
|
---|
| 353 | return setSckRate(sckRateID);
|
---|
| 354 | #else // SOFTWARE_SPI
|
---|
| 355 | return true;
|
---|
| 356 | #endif // SOFTWARE_SPI
|
---|
| 357 |
|
---|
| 358 | fail:
|
---|
| 359 | chipSelectHigh();
|
---|
[194] | 360 | LEAVE_CRITICAL;
|
---|
[136] | 361 | return false;
|
---|
| 362 | }
|
---|
| 363 | //------------------------------------------------------------------------------
|
---|
| 364 | /**
|
---|
| 365 | * Enable or disable partial block reads.
|
---|
| 366 | *
|
---|
| 367 | * Enabling partial block reads improves performance by allowing a block
|
---|
| 368 | * to be read over the SPI bus as several sub-blocks. Errors may occur
|
---|
| 369 | * if the time between reads is too long since the SD card may timeout.
|
---|
| 370 | * The SPI SS line will be held low until the entire block is read or
|
---|
| 371 | * readEnd() is called.
|
---|
| 372 | *
|
---|
| 373 | * Use this for applications like the Adafruit Wave Shield.
|
---|
| 374 | *
|
---|
| 375 | * \param[in] value The value TRUE (non-zero) or FALSE (zero).)
|
---|
| 376 | */
|
---|
| 377 | void Sd2Card::partialBlockRead(uint8_t value) {
|
---|
[194] | 378 | ENTER_CRITICAL;
|
---|
[136] | 379 | readEnd();
|
---|
| 380 | partialBlockRead_ = value;
|
---|
[194] | 381 | LEAVE_CRITICAL;
|
---|
[136] | 382 | }
|
---|
| 383 | //------------------------------------------------------------------------------
|
---|
| 384 | /**
|
---|
| 385 | * Read a 512 byte block from an SD card device.
|
---|
| 386 | *
|
---|
| 387 | * \param[in] block Logical block to be read.
|
---|
| 388 | * \param[out] dst Pointer to the location that will receive the data.
|
---|
| 389 |
|
---|
| 390 | * \return The value one, true, is returned for success and
|
---|
| 391 | * the value zero, false, is returned for failure.
|
---|
| 392 | */
|
---|
| 393 | uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
|
---|
| 394 | return readData(block, 0, 512, dst);
|
---|
| 395 | }
|
---|
| 396 | //------------------------------------------------------------------------------
|
---|
| 397 | /**
|
---|
| 398 | * Read part of a 512 byte block from an SD card.
|
---|
| 399 | *
|
---|
| 400 | * \param[in] block Logical block to be read.
|
---|
| 401 | * \param[in] offset Number of bytes to skip at start of block
|
---|
| 402 | * \param[out] dst Pointer to the location that will receive the data.
|
---|
| 403 | * \param[in] count Number of bytes to read
|
---|
| 404 | * \return The value one, true, is returned for success and
|
---|
| 405 | * the value zero, false, is returned for failure.
|
---|
| 406 | */
|
---|
| 407 | uint8_t Sd2Card::readData(uint32_t block,
|
---|
| 408 | uint16_t offset, uint16_t count, uint8_t* dst) {
|
---|
| 409 | uint16_t n;
|
---|
| 410 | if (count == 0) return true;
|
---|
[194] | 411 | ENTER_CRITICAL;
|
---|
[136] | 412 | if ((count + offset) > 512) {
|
---|
| 413 | goto fail;
|
---|
| 414 | }
|
---|
| 415 | if (!inBlock_ || block != block_ || offset < offset_) {
|
---|
| 416 | block_ = block;
|
---|
| 417 | // use address if not SDHC card
|
---|
| 418 | if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
|
---|
| 419 | if (cardCommand(CMD17, block)) {
|
---|
| 420 | error(SD_CARD_ERROR_CMD17);
|
---|
| 421 | goto fail;
|
---|
| 422 | }
|
---|
| 423 | if (!waitStartBlock()) {
|
---|
| 424 | goto fail;
|
---|
| 425 | }
|
---|
| 426 | offset_ = 0;
|
---|
| 427 | inBlock_ = 1;
|
---|
| 428 | }
|
---|
| 429 |
|
---|
| 430 | #ifdef OPTIMIZE_HARDWARE_SPI
|
---|
| 431 | // start first spi transfer
|
---|
| 432 | SPDR = 0XFF;
|
---|
| 433 |
|
---|
| 434 | // skip data before offset
|
---|
| 435 | for (;offset_ < offset; offset_++) {
|
---|
| 436 | while (!(SPSR & (1 << SPIF)))
|
---|
| 437 | ;
|
---|
| 438 | SPDR = 0XFF;
|
---|
| 439 | }
|
---|
| 440 | // transfer data
|
---|
| 441 | n = count - 1;
|
---|
| 442 | for (uint16_t i = 0; i < n; i++) {
|
---|
| 443 | while (!(SPSR & (1 << SPIF)))
|
---|
| 444 | ;
|
---|
| 445 | dst[i] = SPDR;
|
---|
| 446 | SPDR = 0XFF;
|
---|
| 447 | }
|
---|
| 448 | // wait for last byte
|
---|
| 449 | while (!(SPSR & (1 << SPIF)))
|
---|
| 450 | ;
|
---|
| 451 | dst[n] = SPDR;
|
---|
| 452 |
|
---|
| 453 | #else // OPTIMIZE_HARDWARE_SPI
|
---|
| 454 |
|
---|
| 455 | // skip data before offset
|
---|
| 456 | for (;offset_ < offset; offset_++) {
|
---|
| 457 | spiRec();
|
---|
| 458 | }
|
---|
| 459 | // transfer data
|
---|
| 460 | for (uint16_t i = 0; i < count; i++) {
|
---|
| 461 | dst[i] = spiRec();
|
---|
| 462 | }
|
---|
| 463 | #endif // OPTIMIZE_HARDWARE_SPI
|
---|
| 464 |
|
---|
| 465 | offset_ += count;
|
---|
| 466 | if (!partialBlockRead_ || offset_ >= 512) {
|
---|
| 467 | // read rest of data, checksum and set chip select high
|
---|
| 468 | readEnd();
|
---|
| 469 | }
|
---|
[194] | 470 | LEAVE_CRITICAL;
|
---|
[136] | 471 | return true;
|
---|
| 472 |
|
---|
| 473 | fail:
|
---|
[194] | 474 | LEAVE_CRITICAL;
|
---|
[136] | 475 | chipSelectHigh();
|
---|
| 476 | return false;
|
---|
| 477 | }
|
---|
| 478 | //------------------------------------------------------------------------------
|
---|
| 479 | /** Skip remaining data in a block when in partial block read mode. */
|
---|
| 480 | void Sd2Card::readEnd(void) {
|
---|
| 481 | if (inBlock_) {
|
---|
| 482 | // skip data and crc
|
---|
| 483 | #ifdef OPTIMIZE_HARDWARE_SPI
|
---|
| 484 | // optimize skip for hardware
|
---|
| 485 | SPDR = 0XFF;
|
---|
| 486 | while (offset_++ < 513) {
|
---|
| 487 | while (!(SPSR & (1 << SPIF)))
|
---|
| 488 | ;
|
---|
| 489 | SPDR = 0XFF;
|
---|
| 490 | }
|
---|
| 491 | // wait for last crc byte
|
---|
| 492 | while (!(SPSR & (1 << SPIF)))
|
---|
| 493 | ;
|
---|
| 494 | #else // OPTIMIZE_HARDWARE_SPI
|
---|
| 495 | while (offset_++ < 514) spiRec();
|
---|
| 496 | #endif // OPTIMIZE_HARDWARE_SPI
|
---|
| 497 | chipSelectHigh();
|
---|
| 498 | inBlock_ = 0;
|
---|
| 499 | }
|
---|
| 500 | }
|
---|
| 501 | //------------------------------------------------------------------------------
|
---|
| 502 | /** read CID or CSR register */
|
---|
| 503 | uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
---|
| 504 | uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
---|
[194] | 505 | ENTER_CRITICAL;
|
---|
[136] | 506 | if (cardCommand(cmd, 0)) {
|
---|
| 507 | error(SD_CARD_ERROR_READ_REG);
|
---|
| 508 | goto fail;
|
---|
| 509 | }
|
---|
| 510 | if (!waitStartBlock()) goto fail;
|
---|
| 511 | // transfer data
|
---|
| 512 | for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
|
---|
| 513 | spiRec(); // get first crc byte
|
---|
| 514 | spiRec(); // get second crc byte
|
---|
| 515 | chipSelectHigh();
|
---|
[194] | 516 | LEAVE_CRITICAL;
|
---|
[136] | 517 | return true;
|
---|
| 518 |
|
---|
| 519 | fail:
|
---|
| 520 | chipSelectHigh();
|
---|
[194] | 521 | LEAVE_CRITICAL;
|
---|
[136] | 522 | return false;
|
---|
| 523 | }
|
---|
| 524 | //------------------------------------------------------------------------------
|
---|
| 525 | /**
|
---|
| 526 | * Set the SPI clock rate.
|
---|
| 527 | *
|
---|
| 528 | * \param[in] sckRateID A value in the range [0, 6].
|
---|
| 529 | *
|
---|
| 530 | * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
|
---|
| 531 | * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
|
---|
| 532 | * for \a scsRateID = 6.
|
---|
| 533 | *
|
---|
| 534 | * \return The value one, true, is returned for success and the value zero,
|
---|
| 535 | * false, is returned for an invalid value of \a sckRateID.
|
---|
| 536 | */
|
---|
| 537 | uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
|
---|
| 538 | if (sckRateID > 6) {
|
---|
| 539 | error(SD_CARD_ERROR_SCK_RATE);
|
---|
| 540 | return false;
|
---|
| 541 | }
|
---|
| 542 | #ifndef USE_SPI_LIB
|
---|
| 543 | // see avr processor datasheet for SPI register bit definitions
|
---|
| 544 | if ((sckRateID & 1) || sckRateID == 6) {
|
---|
| 545 | SPSR &= ~(1 << SPI2X);
|
---|
| 546 | } else {
|
---|
| 547 | SPSR |= (1 << SPI2X);
|
---|
| 548 | }
|
---|
| 549 | SPCR &= ~((1 <<SPR1) | (1 << SPR0));
|
---|
| 550 | SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
|
---|
| 551 | | (sckRateID & 2 ? (1 << SPR0) : 0);
|
---|
| 552 | #else // USE_SPI_LIB
|
---|
| 553 | #if defined(ARDUINO_ARCH_SAM)
|
---|
| 554 | switch (sckRateID) {
|
---|
| 555 | case 0: settings = SPISettings(25000000, MSBFIRST, SPI_MODE0); break;
|
---|
| 556 | case 1: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
|
---|
| 557 | case 2: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
|
---|
| 558 | case 3: settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break;
|
---|
| 559 | case 4: settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break;
|
---|
| 560 | case 5: settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break;
|
---|
| 561 | default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0);
|
---|
| 562 | }
|
---|
| 563 | #endif
|
---|
| 564 | #endif // USE_SPI_LIB
|
---|
| 565 | return true;
|
---|
| 566 | }
|
---|
| 567 | //------------------------------------------------------------------------------
|
---|
| 568 | // wait for card to go not busy
|
---|
| 569 | uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
|
---|
| 570 | uint16_t t0 = millis();
|
---|
| 571 | do {
|
---|
| 572 | if (spiRec() == 0XFF) return true;
|
---|
| 573 | }
|
---|
| 574 | while (((uint16_t)millis() - t0) < timeoutMillis);
|
---|
| 575 | return false;
|
---|
| 576 | }
|
---|
| 577 | //------------------------------------------------------------------------------
|
---|
| 578 | /** Wait for start block token */
|
---|
| 579 | uint8_t Sd2Card::waitStartBlock(void) {
|
---|
| 580 | uint16_t t0 = millis();
|
---|
| 581 | while ((status_ = spiRec()) == 0XFF) {
|
---|
| 582 | if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
|
---|
| 583 | error(SD_CARD_ERROR_READ_TIMEOUT);
|
---|
| 584 | goto fail;
|
---|
| 585 | }
|
---|
| 586 | }
|
---|
| 587 | if (status_ != DATA_START_BLOCK) {
|
---|
| 588 | error(SD_CARD_ERROR_READ);
|
---|
| 589 | goto fail;
|
---|
| 590 | }
|
---|
| 591 | return true;
|
---|
| 592 |
|
---|
| 593 | fail:
|
---|
| 594 | chipSelectHigh();
|
---|
| 595 | return false;
|
---|
| 596 | }
|
---|
| 597 | //------------------------------------------------------------------------------
|
---|
| 598 | /**
|
---|
| 599 | * Writes a 512 byte block to an SD card.
|
---|
| 600 | *
|
---|
| 601 | * \param[in] blockNumber Logical block to be written.
|
---|
| 602 | * \param[in] src Pointer to the location of the data to be written.
|
---|
| 603 | * \return The value one, true, is returned for success and
|
---|
| 604 | * the value zero, false, is returned for failure.
|
---|
| 605 | */
|
---|
| 606 | uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
---|
[194] | 607 | ENTER_CRITICAL;
|
---|
[136] | 608 | #if SD_PROTECT_BLOCK_ZERO
|
---|
| 609 | // don't allow write to first block
|
---|
| 610 | if (blockNumber == 0) {
|
---|
| 611 | error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
---|
| 612 | goto fail;
|
---|
| 613 | }
|
---|
| 614 | #endif // SD_PROTECT_BLOCK_ZERO
|
---|
| 615 |
|
---|
| 616 | // use address if not SDHC card
|
---|
| 617 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
---|
| 618 | if (cardCommand(CMD24, blockNumber)) {
|
---|
| 619 | error(SD_CARD_ERROR_CMD24);
|
---|
| 620 | goto fail;
|
---|
| 621 | }
|
---|
| 622 | if (!writeData(DATA_START_BLOCK, src)) goto fail;
|
---|
| 623 |
|
---|
| 624 | // wait for flash programming to complete
|
---|
| 625 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
---|
| 626 | error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
---|
| 627 | goto fail;
|
---|
| 628 | }
|
---|
| 629 | // response is r2 so get and check two bytes for nonzero
|
---|
| 630 | if (cardCommand(CMD13, 0) || spiRec()) {
|
---|
| 631 | error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
---|
| 632 | goto fail;
|
---|
| 633 | }
|
---|
| 634 | chipSelectHigh();
|
---|
[194] | 635 | LEAVE_CRITICAL;
|
---|
[136] | 636 | return true;
|
---|
| 637 |
|
---|
| 638 | fail:
|
---|
| 639 | chipSelectHigh();
|
---|
[194] | 640 | LEAVE_CRITICAL;
|
---|
[136] | 641 | return false;
|
---|
| 642 | }
|
---|
| 643 | //------------------------------------------------------------------------------
|
---|
| 644 | /** Write one data block in a multiple block write sequence */
|
---|
| 645 | uint8_t Sd2Card::writeData(const uint8_t* src) {
|
---|
[194] | 646 | uint8_t ret;
|
---|
| 647 | ENTER_CRITICAL;
|
---|
[136] | 648 | // wait for previous write to finish
|
---|
| 649 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
---|
| 650 | error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
---|
| 651 | chipSelectHigh();
|
---|
[194] | 652 | ret = false;
|
---|
[136] | 653 | }
|
---|
[194] | 654 | else {
|
---|
| 655 | ret = writeData(WRITE_MULTIPLE_TOKEN, src);
|
---|
| 656 | }
|
---|
| 657 | LEAVE_CRITICAL;
|
---|
| 658 | return ret;
|
---|
[136] | 659 | }
|
---|
| 660 | //------------------------------------------------------------------------------
|
---|
| 661 | // send one block of data for write block or write multiple blocks
|
---|
| 662 | uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
---|
| 663 | #ifdef OPTIMIZE_HARDWARE_SPI
|
---|
| 664 |
|
---|
| 665 | // send data - optimized loop
|
---|
| 666 | SPDR = token;
|
---|
| 667 |
|
---|
| 668 | // send two byte per iteration
|
---|
| 669 | for (uint16_t i = 0; i < 512; i += 2) {
|
---|
| 670 | while (!(SPSR & (1 << SPIF)))
|
---|
| 671 | ;
|
---|
| 672 | SPDR = src[i];
|
---|
| 673 | while (!(SPSR & (1 << SPIF)))
|
---|
| 674 | ;
|
---|
| 675 | SPDR = src[i+1];
|
---|
| 676 | }
|
---|
| 677 |
|
---|
| 678 | // wait for last data byte
|
---|
| 679 | while (!(SPSR & (1 << SPIF)))
|
---|
| 680 | ;
|
---|
| 681 |
|
---|
| 682 | #else // OPTIMIZE_HARDWARE_SPI
|
---|
| 683 | spiSend(token);
|
---|
| 684 | for (uint16_t i = 0; i < 512; i++) {
|
---|
| 685 | spiSend(src[i]);
|
---|
| 686 | }
|
---|
| 687 | #endif // OPTIMIZE_HARDWARE_SPI
|
---|
| 688 | spiSend(0xff); // dummy crc
|
---|
| 689 | spiSend(0xff); // dummy crc
|
---|
| 690 |
|
---|
| 691 | status_ = spiRec();
|
---|
| 692 | if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
---|
| 693 | error(SD_CARD_ERROR_WRITE);
|
---|
| 694 | chipSelectHigh();
|
---|
| 695 | return false;
|
---|
| 696 | }
|
---|
| 697 | return true;
|
---|
| 698 | }
|
---|
| 699 | //------------------------------------------------------------------------------
|
---|
| 700 | /** Start a write multiple blocks sequence.
|
---|
| 701 | *
|
---|
| 702 | * \param[in] blockNumber Address of first block in sequence.
|
---|
| 703 | * \param[in] eraseCount The number of blocks to be pre-erased.
|
---|
| 704 | *
|
---|
| 705 | * \note This function is used with writeData() and writeStop()
|
---|
| 706 | * for optimized multiple block writes.
|
---|
| 707 | *
|
---|
| 708 | * \return The value one, true, is returned for success and
|
---|
| 709 | * the value zero, false, is returned for failure.
|
---|
| 710 | */
|
---|
| 711 | uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
---|
[194] | 712 | ENTER_CRITICAL;
|
---|
[136] | 713 | #if SD_PROTECT_BLOCK_ZERO
|
---|
| 714 | // don't allow write to first block
|
---|
| 715 | if (blockNumber == 0) {
|
---|
| 716 | error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
---|
| 717 | goto fail;
|
---|
| 718 | }
|
---|
| 719 | #endif // SD_PROTECT_BLOCK_ZERO
|
---|
| 720 | // send pre-erase count
|
---|
| 721 | if (cardAcmd(ACMD23, eraseCount)) {
|
---|
| 722 | error(SD_CARD_ERROR_ACMD23);
|
---|
| 723 | goto fail;
|
---|
| 724 | }
|
---|
| 725 | // use address if not SDHC card
|
---|
| 726 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
---|
| 727 | if (cardCommand(CMD25, blockNumber)) {
|
---|
| 728 | error(SD_CARD_ERROR_CMD25);
|
---|
| 729 | goto fail;
|
---|
| 730 | }
|
---|
[194] | 731 | LEAVE_CRITICAL;
|
---|
[136] | 732 | return true;
|
---|
| 733 |
|
---|
| 734 | fail:
|
---|
| 735 | chipSelectHigh();
|
---|
[194] | 736 | LEAVE_CRITICAL;
|
---|
[136] | 737 | return false;
|
---|
| 738 | }
|
---|
| 739 | //------------------------------------------------------------------------------
|
---|
| 740 | /** End a write multiple blocks sequence.
|
---|
| 741 | *
|
---|
| 742 | * \return The value one, true, is returned for success and
|
---|
| 743 | * the value zero, false, is returned for failure.
|
---|
| 744 | */
|
---|
| 745 | uint8_t Sd2Card::writeStop(void) {
|
---|
[194] | 746 | ENTER_CRITICAL;
|
---|
[136] | 747 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
---|
| 748 | spiSend(STOP_TRAN_TOKEN);
|
---|
| 749 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
---|
| 750 | chipSelectHigh();
|
---|
[194] | 751 | LEAVE_CRITICAL;
|
---|
[136] | 752 | return true;
|
---|
| 753 |
|
---|
| 754 | fail:
|
---|
| 755 | error(SD_CARD_ERROR_STOP_TRAN);
|
---|
| 756 | chipSelectHigh();
|
---|
[194] | 757 | LEAVE_CRITICAL;
|
---|
[136] | 758 | return false;
|
---|
| 759 | }
|
---|