/** ****************************************************************************** * * @file pios_sdcard.c * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * Parts by Thorsten Klose (tk@midibox.org) * @brief Sets up basic system hardware, functions are called from Main. * @see The GNU Public License (GPL) Version 3 * @defgroup PIOS_SDCARD SDCard Functions * @{ * *****************************************************************************/ /* * This program 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 program 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 this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Project Includes */ #include "pios.h" #if defined(PIOS_INCLUDE_SDCARD) /* Global Variables */ VOLINFO PIOS_SDCARD_VolInfo; uint8_t PIOS_SDCARD_Sector[SECTOR_SIZE]; /* Local Definitions */ #if !defined(SDCARD_MUTEX_TAKE) #define SDCARD_MUTEX_TAKE {} #define SDCARD_MUTEX_GIVE {} #endif /* Definitions for MMC/SDC command */ #define SDCMD_GO_IDLE_STATE (0x40+0) #define SDCMD_GO_IDLE_STATE_CRC 0x95 #define SDCMD_SEND_OP_COND (0x40+1) #define SDCMD_SEND_OP_COND_CRC 0xf9 #define SDCMD_SEND_OP_COND_SDC (0xC0+41) #define SDCMD_SEND_OP_COND_SDC_CRC 0xff #define SDCMD_READ_OCR (0x40+58) #define SDCMD_READ_OCR_CRC 0xff #define SDCMD_APP_CMD (0x40+55) #define SDCMD_APP_CMD_CRC 0xff #define SDCMD_SEND_IF_COND (0x40+8) #define SDCMD_SEND_IF_COND_CRC 0x87 #define SDCMD_SEND_CSD (0x40+9) #define SDCMD_SEND_CSD_CRC 0xff #define SDCMD_SEND_CID (0x40+10) #define SDCMD_SEND_CID_CRC 0xff #define SDCMD_SEND_STATUS (0x40+13) #define SDCMD_SEND_STATUS_CRC 0xaf #define SDCMD_READ_SINGLE_BLOCK (0x40+17) #define SDCMD_READ_SINGLE_BLOCK_CRC 0xff #define SDCMD_SET_BLOCKLEN (0x40+16) #define SDCMD_SET_BLOCKLEN_CRC 0xff #define SDCMD_WRITE_SINGLE_BLOCK (0x40+24) #define SDCMD_WRITE_SINGLE_BLOCK_CRC 0xff /* Card type flags (CardType) */ #define CT_MMC 0x01 #define CT_SD1 0x02 #define CT_SD2 0x04 #define CT_SDC (CT_SD1|CT_SD2) #define CT_BLOCK 0x08 static uint8_t CardType; static int32_t sdcard_mounted; /** * Initialises SPI pins and peripheral to access MMC/SD Card * \param[in] mode currently only mode 0 supported * \return < 0 if initialisation failed */ int32_t PIOS_SDCARD_Init(void) { SDCARD_MUTEX_TAKE; sdcard_mounted = 0; /* Ensure that fast pin drivers are activated */ PIOS_SPI_IO_Init(PIOS_SDCARD_SPI, PIOS_SPI_PIN_DRIVER_STRONG); /* Init SPI port for slow frequency access (ca. 0.3 MBit/s) */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); SDCARD_MUTEX_GIVE; /* No error */ return 0; } /** * Connects to SD Card * \return < 0 if initialisation sequence failed */ int32_t PIOS_SDCARD_PowerOn(void) { int32_t status; int i; SDCARD_MUTEX_TAKE; /* Ensure that chip select line deactivated */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Init SPI port for slow frequency access (ca. 0.3 MBit/s) */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); /* Send 80 clock cycles to start up */ for(i=0; i<10; ++i) { PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); } /* Activate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 0); /* spi, pin_value */ /* wait for 1 mS */ PIOS_DELAY_WaituS(1000); /* Send CMD0 to reset the media */ if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_GO_IDLE_STATE, 0, SDCMD_GO_IDLE_STATE_CRC)) < 0) { goto error; } CardType = 0; /* A card is detected, what type is it? Use SEND_IF_COND (CMD8) to find out */ if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_IF_COND, 0x1AA, SDCMD_SEND_IF_COND_CRC)) == 0x01aa) { /* SDHC Card Detected. */ /* We now check to see if we should use block mode or byte mode. Command is SEND_OP_COND_SDC (ACMD41) with HCS (bit 30) set */ for (i=0;i<16384;i++) if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_OP_COND_SDC, 0x01<<30, SDCMD_SEND_OP_COND_SDC_CRC)) == 0 ) break; if(i < 16384) { status = PIOS_SDCARD_SendSDCCmd(SDCMD_READ_OCR, 0, SDCMD_READ_OCR_CRC); CardType = ((status>>24) & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; status = 0; } else { /* We waited long enough! */ status = -2; } } else { /* Card is SDv1 or MMC. */ /* MMC will accept ACMD41 (SDv1 won't and requires CMD1) so send ACMD41 first and then CMD1 if that fails */ if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_OP_COND_SDC, 0, SDCMD_SEND_OP_COND_SDC_CRC)) <= 1) { CardType = CT_SD1; } else { CardType = CT_MMC; } for (i=0;i<16384;i++) { if (CardType == CT_SD1) { status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_OP_COND_SDC, 0, SDCMD_SEND_OP_COND_SDC_CRC); } else { status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_OP_COND, 0, SDCMD_SEND_OP_COND_CRC); } if (status < 0) { break; } if(status==0) { break; } } /* The block size should already be 512 bytes but re-initialize just in case (ignore if it fails) */ PIOS_SDCARD_SendSDCCmd(SDCMD_SET_BLOCKLEN, 512, SDCMD_SEND_OP_COND_CRC); } if(i == 16384 || CardType == 0) { /* The last loop timed out or the cardtype was not detected... */ status = -2; } error: /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return status; /* Status should be 0 if nothing went wrong! */ } /** * Disconnects from SD Card * \return < 0 on errors */ int32_t PIOS_SDCARD_PowerOff(void) { return 0; // no error } /** * If SD card was previously available: Checks if the SD Card is still * available by sending the STATUS command.
* This takes ca. 10 uS * * If SD card was previously not available: Checks if the SD Card is * available by sending the IDLE command at low speed.
* This takes ca. 500 uS!
* Once we got a positive response, SDCARD_PowerOn() will be * called by this function to initialize the card completely. * * Example for Connection/Disconnection detection: * \code * // this function is called each second from a low-priority task * // If multiple tasks are accessing the SD card, add a semaphore/mutex * // to avoid IO access collisions with other tasks! * u8 sdcard_available; * int32_t CheckSDCard(void) * { * // check if SD card is available * // High speed access if the card was previously available * u8 prev_sdcard_available = sdcard_available; * sdcard_available = PIOS_SDCARD_CheckAvailable(prev_sdcard_available); * * if(sdcard_available && !prev_sdcard_available) { * // SD Card has been connected * * // now it's possible to read/write sectors * * } else if( !sdcard_available && prev_sdcard_available ) { * // SD Card has been disconnected * * // here you can notify your application about this state * } * * return 0; // no error * } * \endcode * \param[in] was_available should only be set if the SD card was previously available * \return 0 if no response from SD Card * \return 1 if SD card is accessible */ int32_t PIOS_SDCARD_CheckAvailable(uint8_t was_available) { int32_t ret; SDCARD_MUTEX_TAKE; if(was_available) { /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); /* Activate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 0); /* spi, pin_value */ /* Send STATUS command to check if media is available */ ret = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_STATUS, 0, SDCMD_SEND_STATUS_CRC); } else { /* Ensure that SPI interface is clocked at low speed */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_256); /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* send 80 clock cycles to start up */ uint8_t i; for(i = 0; i < 10; ++i) { PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); } /* Activate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 0); /* spi, pin_value */ /* Send CMD0 to reset the media */ if((ret = (PIOS_SDCARD_SendSDCCmd(SDCMD_GO_IDLE_STATE, 0, SDCMD_GO_IDLE_STATE_CRC))) < 0 ) { goto not_available; } /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ SDCARD_MUTEX_GIVE; /* Run power-on sequence (negative return = not available) */ ret = PIOS_SDCARD_PowerOn(); } not_available: /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return (ret == 0) ? 1 : 0; /* 1 = available, 0 = not available. */ } /** * Sends command to SD card * \param[in] cmd SD card command * \param[in] addr 32bit address * \param[in] crc precalculated CRC * \return >= 0x00 if command has been sent successfully (contains received byte) * \return -1 if no response from SD Card (timeout) */ int32_t PIOS_SDCARD_SendSDCCmd(uint8_t cmd, uint32_t addr, uint8_t crc) { int i; int32_t ret; if(cmd & 0x80) { /* ACMD is the command sequence of CMD55-CMD */ cmd &= 0x7F; ret = PIOS_SDCARD_SendSDCCmd(SDCMD_APP_CMD, 0,SDCMD_APP_CMD_CRC); if(ret > 1) { return ret; } } /* Activate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 0); /* spi, pin_value */ /* Transfer to card */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, (uint8_t)cmd); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, (addr >> 24) & 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, (addr >> 16) & 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, (addr >> 8) & 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, (addr >> 0) & 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, crc); uint8_t timeout = 0; if(cmd == SDCMD_SEND_STATUS) { /* One dummy read */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Read two bytes (only last value will be returned) */ ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* All-one read: we expect that SD card is not connected: notify timeout! */ if(ret == 0xff) { timeout = 1; } } else { /* Wait for standard R1 response */ for(i = 0; i < 8; ++i) { if((ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff)) != 0xff ) { break; } } if(i == 8) { timeout = 1; } } if ((cmd == SDCMD_SEND_IF_COND || cmd == SDCMD_READ_OCR) && timeout!=1) { /* This is a 4 byte R3 or R7 response. */ ret = (PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff) << 24); ret |= (PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff) << 16); ret |= (PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff) << 8); ret |= (PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff) << 0); } /* Required clocking (see spec) */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Deactivate chip-select on timeout, and return error code */ if(timeout) { PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); return -1; } /* Else return received value - don't deactivate chip select or mutex (for continuous access) */ return ret; } /** * Reads 512 bytes from selected sector * \param[in] sector 32bit sector * \param[in] *buffer pointer to 512 byte buffer * \return 0 if whole sector has been successfully read * \return -error if error occured during read operation:
* * \return -256 if timeout during command has been sent * \return -257 if timeout while waiting for start token */ int32_t PIOS_SDCARD_SectorRead(uint32_t sector, uint8_t *buffer) { int32_t status; int i; if(!(CardType & CT_BLOCK)) { sector *= 512; } SDCARD_MUTEX_TAKE; /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* this is required for the case that the SPI port is shared with other devices */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); if((status=PIOS_SDCARD_SendSDCCmd(SDCMD_READ_SINGLE_BLOCK, sector, SDCMD_READ_SINGLE_BLOCK_CRC))) { status = (status < 0) ? -256 : status; /* return timeout indicator or error flags */ goto error; } /* Wait for start token of the data block */ for(i=0; i<65536; ++i) { // TODO: check if sufficient uint8_t ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); if( ret != 0xff ) break; } if(i == 65536) { status = -257; goto error; } /* Read 512 bytes via DMA */ PIOS_SPI_TransferBlock(PIOS_SDCARD_SPI, NULL, buffer, 512, NULL); /* Read (and ignore) CRC */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Required for clocking (see spec) */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); error: /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); // spi, pin_value /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return status; } /** * Writes 512 bytes into selected sector * \param[in] sector 32bit sector * \param[in] *buffer pointer to 512 byte buffer * \return 0 if whole sector has been successfully read * \return -error if error occured during read operation:
* * \return -256 if timeout during command has been sent * \return -257 if write operation not accepted * \return -258 if timeout during write operation */ int32_t PIOS_SDCARD_SectorWrite(uint32_t sector, uint8_t *buffer) { int32_t status; int i; SDCARD_MUTEX_TAKE; if(!(CardType & CT_BLOCK)) { sector *= 512; } /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); if((status=PIOS_SDCARD_SendSDCCmd(SDCMD_WRITE_SINGLE_BLOCK, sector, SDCMD_WRITE_SINGLE_BLOCK_CRC))) { status = (status < 0) ? -256 : status; /* Return timeout indicator or error flags */ goto error; } /* Send start token */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xfe); /* Send 512 bytes of data via DMA */ PIOS_SPI_TransferBlock(PIOS_SDCARD_SPI, buffer, NULL, 512, NULL); /* Send CRC */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Read response */ uint8_t response = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); if((response & 0x0f) != 0x5) { status= -257; goto error; } /* Wait for write completion */ for(i=0; i < 32*65536; ++i) { /* TODO: check if sufficient */ uint8_t ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); if(ret != 0x00) { break; } } if(i == 32*65536) { status= -258; goto error; } /* Required for clocking (see spec) */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); error: /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return status; } /** * Reads the CID informations from SD Card * \param[in] *cid pointer to buffer which holds the CID informations * \return 0 if the informations haven been successfully read * \return -error if error occured during read operation * \return -256 if timeout during command has been sent * \return -257 if timeout while waiting for start token */ int32_t PIOS_SDCARD_CIDRead(SDCARDCidTypeDef *cid) { int32_t status; int i; /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ SDCARD_MUTEX_TAKE; PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_CID, 0, SDCMD_SEND_CID_CRC))) { status = (status < 0) ? -256 : status; /* return timeout indicator or error flags */ goto error; } /* Wait for start token of the data block */ for(i=0; i<65536; ++i) { /* TODO: check if sufficient */ uint8_t ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); if( ret != 0xff ) { break; } } if(i == 65536) { status= -257; } /* Read 16 bytes via DMA */ uint8_t cid_buffer[16]; PIOS_SPI_TransferBlock(PIOS_SDCARD_SPI, NULL, cid_buffer, 16, NULL); /* Read (and ignore) CRC */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Required for clocking (see spec) */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Sort returned informations into CID structure */ /* From STM Mass Storage example */ /* Byte 0 */ cid->ManufacturerID = cid_buffer[0]; /* Byte 1 */ cid->OEM_AppliID = cid_buffer[1] << 8; /* Byte 2 */ cid->OEM_AppliID |= cid_buffer[2]; /* Byte 3..7 */ for(i=0; i<5; ++i) cid->ProdName[i] = cid_buffer[3+i]; cid->ProdName[5] = 0; /* string terminator */ /* Byte 8 */ cid->ProdRev = cid_buffer[8]; /* Byte 9 */ cid->ProdSN = cid_buffer[9] << 24; /* Byte 10 */ cid->ProdSN |= cid_buffer[10] << 16; /* Byte 11 */ cid->ProdSN |= cid_buffer[11] << 8; /* Byte 12 */ cid->ProdSN |= cid_buffer[12]; /* Byte 13 */ cid->Reserved1 |= (cid_buffer[13] & 0xF0) >> 4; /* Byte 14 */ cid->ManufactDate = (cid_buffer[13] & 0x0F) << 8; /* Byte 15 */ cid->ManufactDate |= cid_buffer[14]; /* Byte 16 */ cid->msd_CRC = (cid_buffer[15] & 0xFE) >> 1; cid->Reserved2 = 1; error: /* deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return status; } /** * Reads the CSD informations from SD Card * \param[in] *csd pointer to buffer which holds the CSD informations * \return 0 if the informations haven been successfully read * \return -error if error occured during read operation * \return -256 if timeout during command has been sent * \return -257 if timeout while waiting for start token */ int32_t PIOS_SDCARD_CSDRead(SDCARDCsdTypeDef *csd) { int32_t status; int i; SDCARD_MUTEX_TAKE; /* Init SPI port for fast frequency access (ca. 18 MBit/s) */ /* This is required for the case that the SPI port is shared with other devices */ PIOS_SPI_TransferModeInit(PIOS_SDCARD_SPI, PIOS_SPI_MODE_CLK1_PHASE1, PIOS_SPI_PRESCALER_4); if((status = PIOS_SDCARD_SendSDCCmd(SDCMD_SEND_CSD, 0, SDCMD_SEND_CSD_CRC))) { status = (status < 0) ? -256 : status; /* Return timeout indicator or error flags */ goto error; } // wait for start token of the data block for(i=0; i<65536; ++i) { /* TODO: check if sufficient */ uint8_t ret = PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); if(ret != 0xff) { break; } } if(i == 65536) { status = -257; goto error; } /* Read 16 bytes via DMA */ uint8_t csd_buffer[16]; PIOS_SPI_TransferBlock(PIOS_SDCARD_SPI, NULL, csd_buffer, 16, NULL); /* Read (and ignore) CRC */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Required for clocking (see spec) */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); /* Sort returned informations into CSD structure */ /* from STM Mass Storage example */ /* Byte 0 */ csd->CSDStruct = (csd_buffer[0] & 0xC0) >> 6; csd->SysSpecVersion = (csd_buffer[0] & 0x3C) >> 2; csd->Reserved1 = csd_buffer[0] & 0x03; /* Byte 1 */ csd->TAAC = csd_buffer[1]; /* Byte 2 */ csd->NSAC = csd_buffer[2]; /* Byte 3 */ csd->MaxBusClkFrec = csd_buffer[3]; /* Byte 4 */ csd->CardComdClasses = csd_buffer[4] << 4; /* Byte 5 */ csd->CardComdClasses |= (csd_buffer[5] & 0xF0) >> 4; csd->RdBlockLen = csd_buffer[5] & 0x0F; /* Byte 6 */ csd->PartBlockRead = (csd_buffer[6] & 0x80) >> 7; csd->WrBlockMisalign = (csd_buffer[6] & 0x40) >> 6; csd->RdBlockMisalign = (csd_buffer[6] & 0x20) >> 5; csd->DSRImpl = (csd_buffer[6] & 0x10) >> 4; csd->Reserved2 = 0; /* Reserved */ csd->DeviceSize = (csd_buffer[6] & 0x03) << 10; /* Byte 7 */ csd->DeviceSize |= (csd_buffer[7]) << 2; /* Byte 8 */ csd->DeviceSize |= (csd_buffer[8] & 0xC0) >> 6; csd->MaxRdCurrentVDDMin = (csd_buffer[8] & 0x38) >> 3; csd->MaxRdCurrentVDDMax = (csd_buffer[8] & 0x07); /* Byte 9 */ csd->MaxWrCurrentVDDMin = (csd_buffer[9] & 0xE0) >> 5; csd->MaxWrCurrentVDDMax = (csd_buffer[9] & 0x1C) >> 2; csd->DeviceSizeMul = (csd_buffer[9] & 0x03) << 1; /* Byte 10 */ csd->DeviceSizeMul |= (csd_buffer[10] & 0x80) >> 7; csd->EraseGrSize = (csd_buffer[10] & 0x7C) >> 2; csd->EraseGrMul = (csd_buffer[10] & 0x03) << 3; /* Byte 11 */ csd->EraseGrMul |= (csd_buffer[11] & 0xE0) >> 5; csd->WrProtectGrSize = (csd_buffer[11] & 0x1F); /* Byte 12 */ csd->WrProtectGrEnable = (csd_buffer[12] & 0x80) >> 7; csd->ManDeflECC = (csd_buffer[12] & 0x60) >> 5; csd->WrSpeedFact = (csd_buffer[12] & 0x1C) >> 2; csd->MaxWrBlockLen = (csd_buffer[12] & 0x03) << 2; /* Byte 13 */ csd->MaxWrBlockLen |= (csd_buffer[13] & 0xc0) >> 6; csd->WriteBlockPaPartial = (csd_buffer[13] & 0x20) >> 5; csd->Reserved3 = 0; csd->ContentProtectAppli = (csd_buffer[13] & 0x01); /* Byte 14 */ csd->FileFormatGrouop = (csd_buffer[14] & 0x80) >> 7; csd->CopyFlag = (csd_buffer[14] & 0x40) >> 6; csd->PermWrProtect = (csd_buffer[14] & 0x20) >> 5; csd->TempWrProtect = (csd_buffer[14] & 0x10) >> 4; csd->FileFormat = (csd_buffer[14] & 0x0C) >> 2; csd->ECC = (csd_buffer[14] & 0x03); /* Byte 15 */ csd->msd_CRC = (csd_buffer[15] & 0xFE) >> 1; csd->Reserved4 = 1; error: /* Deactivate chip select */ PIOS_SPI_RC_PinSet(PIOS_SDCARD_SPI, 1); /* spi, pin_value */ /* Send dummy byte once deactivated to drop cards DO */ PIOS_SPI_TransferByte(PIOS_SDCARD_SPI, 0xff); SDCARD_MUTEX_GIVE; return status; } /** * Attempts to write a startup log to the SDCard * return 0 No errors * return -1 Error deleting file * return -2 Error opening file * return -3 Error writing file */ int32_t PIOS_SDCARD_StartupLog(void) { FILEINFO File; char Buffer[1024]; uint32_t Cache; /* Delete the file if it exists - ignore errors */ DFS_UnlinkFile(&PIOS_SDCARD_VolInfo, (uint8_t *)LOG_FILENAME, PIOS_SDCARD_Sector); if(DFS_OpenFile(&PIOS_SDCARD_VolInfo, (uint8_t *)LOG_FILENAME, DFS_WRITE, PIOS_SDCARD_Sector, &File)) { /* Error opening file */ return -2; } sprintf(Buffer, "PiOS Startup Log\r\n\r\nLog file creation completed.\r\n"); if(DFS_WriteFile(&File, PIOS_SDCARD_Sector, (uint8_t *)Buffer, &Cache, strlen(Buffer))) { /* Error writing to file */ return -3; } sprintf(Buffer, "------------------------------\r\nSD Card Information\r\n------------------------------\r\n"); if(DFS_WriteFile(&File, PIOS_SDCARD_Sector, (uint8_t *)Buffer, &Cache, strlen(Buffer))) { /* Error writing to file */ return -2; } /* Disabled because it takes ca. 7 seconds with my 2GB card */ /* sprintf(Buffer, "Total Space: %u MB\r\nFree Space: %u MB\r\n", (uint16_t)((VolInfo.numclusters * (VolInfo.secperclus / 2)) / 1024), (uint16_t)(PIOS_SDCARD_GetFree() / 1048576)); */ sprintf(Buffer, "Total Space: %u MB\r\n\r\n", (uint16_t)((PIOS_SDCARD_VolInfo.numclusters * (PIOS_SDCARD_VolInfo.secperclus / 2)) / 1024)); if(DFS_WriteFile(&File, PIOS_SDCARD_Sector, (uint8_t *)Buffer, &Cache, strlen(Buffer))) { /* Error writing to file */ return -2; } /* No errors */ return 0; } /** * Check if the SD card has been mounted * @return 0 if no * @return 1 if yes */ int32_t POIS_SDCARD_IsMounted() { return sdcard_mounted; } /** * Mounts the file system * param[in] CreateStartupLog 1 = True, 0 = False * return 0 No errors * return -1 SDCard not available * return -2 Cannot find first partition * return -3 No volume information * return -4 Error writing startup log file */ int32_t PIOS_SDCARD_MountFS(uint32_t CreateStartupLog) { uint32_t pstart, psize; uint8_t pactive, ptype; uint8_t sdcard_available = 0; sdcard_available = PIOS_SDCARD_CheckAvailable(0); if(!sdcard_available) { /* Disconnected */ return -1; } pstart = DFS_GetPtnStart(0, PIOS_SDCARD_Sector, 0, &pactive, &ptype, &psize); if (pstart == 0xffffffff) { /* Cannot find first partition */ return -2; } if(DFS_GetVolInfo(0, PIOS_SDCARD_Sector, pstart, &PIOS_SDCARD_VolInfo) != DFS_OK) { /* No volume information */ return -3; } if(CreateStartupLog == 1) { if(PIOS_SDCARD_StartupLog()) { /* Error writing startup log file */ return -4; } } /* No errors */ sdcard_mounted = 1; return 0; } /** * Mounts the file system * return Amount of free bytes */ int32_t PIOS_SDCARD_GetFree(void) { uint32_t VolFreeBytes = 0xffffffff; uint32_t ScratchCache = 0; /* This takes very long, since it scans ALL clusters */ /* It takes ca. 7 seconds to determine free clusters out of ~47000 (2Gb) */ /* Scan all the clusters */ for(uint32_t i = 2; i < PIOS_SDCARD_VolInfo.numclusters; ++i) { if(!DFS_GetFAT(&PIOS_SDCARD_VolInfo, PIOS_SDCARD_Sector, &ScratchCache, i)) { VolFreeBytes += PIOS_SDCARD_VolInfo.secperclus * SECTOR_SIZE; } } return VolFreeBytes; } /** * Read from file * return 0 No error * return -1 DFS_ReadFile failed * return -2 Less bytes read than expected */ int32_t PIOS_SDCARD_ReadBuffer(PFILEINFO fileinfo, uint8_t *buffer, uint32_t len) { uint32_t SuccessCount; if(DFS_ReadFile(fileinfo, PIOS_SDCARD_Sector, buffer, &SuccessCount, len)) { /* DFS_ReadFile failed */ return -1; } if(SuccessCount != len) { /* Less bytes read than expected */ return -2; } /* No error */ return 0; } /** * Read a line from file * returns Number of bytes read */ int32_t PIOS_SDCARD_ReadLine(PFILEINFO fileinfo, uint8_t *buffer, uint32_t max_len) { int32_t status; uint32_t num_read = 0; while(fileinfo->pointer < fileinfo->filelen) { status = PIOS_SDCARD_ReadBuffer(fileinfo, buffer, 1); if(status < 0) { return status; } ++num_read; if(*buffer == '\n' || *buffer == '\r') { break; } if(num_read < max_len) { ++buffer; } } /* Replace newline by terminator */ *buffer = 0; return num_read; } /** * Copy a file * WARNING: This will overwrite the destination file even if it exists * param[in] *Source Path to file to copy * param[in] *Destination Path to destination file * return 0 No errors * return -1 Source file doesn't exist * return -2 Failed to create destination file * return -3 DFS_ReadFile failed * return -4 DFS_WriteFile failed */ int32_t PIOS_SDCARD_FileCopy(char *Source, char *Destination) { FILEINFO SourceFile, DestFile; /* Disable caching to avoid file inconsistencies while using different sector buffers! */ DFS_CachingEnabledSet(0); if(DFS_OpenFile(&PIOS_SDCARD_VolInfo, (uint8_t *)Source, DFS_READ, PIOS_SDCARD_Sector, &SourceFile)) { /* Source file doesn't exist */ return -1; } else { /* Delete destination file if it already exists - ignore errors */ DFS_UnlinkFile(&PIOS_SDCARD_VolInfo, (uint8_t *)Destination, PIOS_SDCARD_Sector); if(DFS_OpenFile(&PIOS_SDCARD_VolInfo, (uint8_t *)Destination, DFS_WRITE, PIOS_SDCARD_Sector, &DestFile)) { /* Failed to create destination file */ return -2; } } /* Copy operation */ uint8_t WriteBuffer[SECTOR_SIZE]; uint32_t SuccessCountRead; uint32_t SuccessCountWrite; do { if(DFS_ReadFile(&SourceFile, PIOS_SDCARD_Sector, WriteBuffer, &SuccessCountRead, SECTOR_SIZE)) { /* DFS_ReadFile failed */ return -3; } else if(DFS_WriteFile(&DestFile, PIOS_SDCARD_Sector, WriteBuffer, &SuccessCountWrite, SuccessCountRead)) { /* DFS_WriteFile failed */ return -4; } } while(SuccessCountRead > 0); /* No errors */ return 0; } /** * Delete a file * param[in] *Filename File to delete * return 0 No errors * return -1 Error deleting file */ int32_t PIOS_SDCARD_FileDelete(char *Filename) { if(DFS_UnlinkFile(&PIOS_SDCARD_VolInfo, (uint8_t *)Filename, PIOS_SDCARD_Sector)) { /* Error deleting file */ return -1; } /* No errors */ return 0; } #endif