/* Arduino FAT16 Library * Copyright (C) 2008 by William Greiman * * This file is part of the Arduino FAT16 Library * * This Library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with the Arduino Fat16 Library. If not, see * . */ #include #include "Fat16Config.h" #include "SdCard.h" #include "spiBus.h" #include "sdInfo.h" #define CMD0 0X00 //GO_IDLE_STATE - init card spi mode if CS low #define CMD9 0X09 //SEND_CSD #define CMD16 0X10 //SET_BLKLEN #define CMD17 0X11 //READ_BLOCK #define CMD24 0X18 //WRITE_BLOCK #define CMD55 0X37 //APP_CMD - escape for application specific command #define ACMD41 0X29 //SD_SEND_OP_COMD // #define R1_READY_STATE 0 #define R1_IDLE_STATE 1 //start data token for read or write #define DATA_START_BLOCK 0XFE //data response tokens for write block #define DATA_RES_MASK 0X1F #define DATA_RES_ACCEPTED 0X05 #define DATA_RES_CRC_ERROR 0X0B #define DATA_RES_WRITE_ERROR 0X0D static uint8_t cardCommand(uint8_t cmd, uint32_t arg) { uint8_t r1; // some cards need extra clocks after transaction to go to ready state // easiest to put extra clocks before next transaction spiRec(); spiSend(cmd | 0x40); for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); spiSend(cmd == CMD0 ? 0x95 : 0XFF);//must send valid CRC for CMD0 //wait for not busy for (uint8_t retry = 0; (r1 = spiRec()) == 0xFF && retry != 0XFF; retry++); return r1; } static uint8_t readTransfer(uint8_t *dst, uint16_t count) { //wait for start of data for (uint16_t retry = 0; spiRec() != DATA_START_BLOCK; retry++) { if (retry == 0XFFFF) { spiSSHigh(); return 0; } } //transfer data for (uint16_t i = 0; i < count; i++) { dst[i] = spiRec(); } spiRec();//first CRC byte spiRec();//second CRC byte spiSSHigh(); return 1; } // #if SD_CARD_SIZE_SUPPORT /** * Determine the size of a standard SD flash memory card * \return The number of 512 byte data blocks in the card */ uint32_t SdCard::cardSize(void) { csd_t csd; spiSSLow(); if (cardCommand(CMD9, 0)) { spiSSHigh(); return 0; } if (!readTransfer((uint8_t *)&csd, sizeof(csd))) return 0; uint8_t read_bl_len = csd.read_bl_len; uint16_t c_size = (csd.c_size_high << 10) | (csd.c_size_mid << 2) | csd.c_size_low; uint8_t c_size_mult = (csd.c_size_mult_high << 1) | csd.c_size_mult_low; return (uint32_t)(c_size+1) << (c_size_mult + read_bl_len - 7); } #endif //SD_CARD_SIZE_SUPPORT /** * Initialize a SD flash memory card. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. * */ uint8_t SdCard::init(void) { spiInit(); //must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); spiSSLow(); uint8_t r = cardCommand(CMD0, 0); for (uint16_t retry = 0; r != R1_IDLE_STATE; retry++){ if (retry == 0XFFFF) { spiSSHigh(); return 0; } r = spiRec(); } for (uint16_t retry = 0; ; retry++) { cardCommand(CMD55, 0); if (cardCommand(ACMD41, 0) == R1_READY_STATE)break; if (retry == 1000) { spiSSHigh(); return 0; } } //use max SPI frequency spiMaxSpeed(); //set block length to 512 (not required? default is 512) r = cardCommand(CMD16, 512) ? 0 : 1; spiSSHigh(); return r; return 1; } /** * Reads a 512 byte block from a storage device. * * \param[in] blockNumber Logical block to be read. * \param[out] dst Pointer to the location that will receive the data. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t SdCard::readBlock(uint32_t blockNumber, uint8_t *dst) { spiSSLow(); if (cardCommand(CMD17, blockNumber << 9)) { spiSSHigh(); return 0; } return readTransfer(dst, 512); } /** * Writes a 512 byte block to a storage device. * * \param[in] blockNumber Logical block to be written. * \param[in] src Pointer to the location of the data to be written. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t SdCard::writeBlock(uint32_t blockNumber, uint8_t *src) { #if FAT16_WRITE_SUPPORT uint32_t address = blockNumber << 9; #if SD_PROTECT_BLOCK_ZERO //don't allow write to first block if (address == 0) return 0; #endif //SD_PROTECT_BLOCK_ZERO spiSSLow(); if (cardCommand(CMD24, address)) { spiSSHigh(); return 0; } spiSend(DATA_START_BLOCK); //transfer block for (uint16_t i = 0; i < 512; i++) { spiSend(src[i]); } spiSend(0xff);// dummy crc spiSend(0xff);// dummy crc uint8_t r1 = spiRec(); if ((r1 & DATA_RES_MASK) != DATA_RES_ACCEPTED) return 0; // wait for card to complete write programming for (uint16_t retry = 0; spiRec() != 0XFF ; retry++) { if (retry == 0XFFFF) { spiSSHigh(); return 0; } } spiSSHigh(); return 1; #else //FAT16_WRITE_SUPPORT return 0; #endif // FAT16_WRITE_SUPPORT } #if SD_CARD_READ_REG_SUPPORT uint8_t SdCard::readReg(uint8_t cmd, uint8_t *dst, uint16_t count) { spiSSLow(); if (cardCommand(cmd, 0)) { spiSSHigh(); return 0; } return readTransfer(dst, count); } #endif//SD_CARD_READ_REG_SUPPORT