/*********************************************************** * Function: * Description: * Input: * Input: * Output: * Return: * Others: ***********************************************************/ static rt_uint8_t _spi_sd_sendcmd_hold( rt_uint8_t cmd, rt_uint32_t arg, rt_uint8_t crc ) { rt_uint32_t r1, n; #if 1 if( cmd & 0x80 ) /* ACMD<n> is the command sequence of CMD55-CMD<n> */ { cmd &= 0x7F; r1 = _spi_sd_sendcmd( APP_CMD, 0, DUMMY_CRC ); /* CMD55 */ if( r1 > 1 ) { return r1; /* cmd send failed */ } } #endif _spi_send_recv( DUMMY_BYTE ); _card_enable( ); _spi_send_recv( cmd ); _spi_send_recv( arg >> 24 ); _spi_send_recv( arg >> 16 ); _spi_send_recv( arg >> 8 ); _spi_send_recv( arg ); _spi_send_recv( crc ); for( n = 0; n < 200; n++ ) { r1 = _spi_send_recv( DUMMY_BYTE ); if( r1 != 0xFF ) { break; } } return ( r1 ); /* Return with the response value */ }
/* Read MMC/SD Card device configuration. */ static rt_uint8_t _spi_sd_readcfg( SDCFG *cfg ) { rt_uint8_t i; rt_uint16_t csize; rt_uint8_t n, csd[16]; rt_uint8_t retv = false; /* Read the OCR - Operations Condition Register. */ if( _spi_sd_sendcmd_hold( READ_OCR, 0, DUMMY_CRC ) != 0x00 ) { goto x; } for( i = 0; i < 4; i++ ) { cfg->ocr[i] = _spi_send_recv( DUMMY_BYTE ); } _card_disable( ); _spi_send_recv( DUMMY_BYTE ); /* Read the CID - Card Identification. */ if( _spi_sd_sendcmd_hold( SEND_CID, 0, DUMMY_CRC ) != 0x00 ) { goto x; } if( _spi_sd_readdatablock( cfg->cid, 16, RELEASE ) == false ) { goto x; } rt_kprintf("\r\nCID="); for (i=0;i<16;i++) rt_kprintf("%02x ",cfg->cid[i]); /* Read the CSD - Card Specific Data. */ if( ( _spi_sd_sendcmd_hold( SEND_CSD, 0, DUMMY_CRC ) != 0x00 ) || ( _spi_sd_readdatablock( cfg->csd, 16, RELEASE ) == false ) ) { goto x; } rt_kprintf("\r\nCSD="); for (i=0;i<16;i++) rt_kprintf("%02x ",cfg->csd[i]); cfg->sectorsize = SD_SECTOR_SIZE; /* Get number of sectors on the disk (DWORD) */ if( ( cfg->csd[0] >> 6 ) == 1 ) /* SDC ver 2.00 */ { csize = cfg->csd[9] + ( (rt_uint16_t)cfg->csd[8] << 8 ) + 1; cfg->sectorcnt = (rt_uint32_t)csize << 10; } else /* SDC ver 1.XX or MMC*/ {
/***************************************************************************** Write "count" Sector(s) starting from sector index "sector", buff -> [sector, sector+1, ... sector+count-1] if success, return true, otherwise return false *****************************************************************************/ static rt_uint8_t _spi_sd_writesector( rt_uint32_t sector, const rt_uint8_t *buff, rt_uint32_t count ) { if( !( CardType & CT_BLOCK ) ) { sector *= 512; /* Convert to byte address if needed */ } if( count == 1 ) /* Single block write */ { if( ( _spi_sd_sendcmd( WRITE_BLOCK, sector, DUMMY_CRC ) == 0 ) && _spi_sd_writedatablock( buff, TOKEN_SINGLE_BLOCK ) ) { count = 0; } } else /* Multiple block write */ { if( CardType & CT_SDC ) { _spi_sd_sendcmd( SET_WR_BLK_ERASE_COUNT, count, DUMMY_CRC ); } if( _spi_sd_sendcmd( WRITE_MULT_BLOCK, sector, DUMMY_CRC ) == 0 ) { do { if( !_spi_sd_writedatablock( buff, TOKEN_MULTI_BLOCK ) ) { break; } buff += 512; } while( --count ); #if 1 if( !_spi_sd_writedatablock( 0, TOKEN_STOP_TRAN ) ) /* STOP_TRAN token */ { count = 1; } #else _spi_send_recv( TOKEN_STOP_TRAN ); #endif } } //LPC17xx_SPI_Release(); //SPI_SSOutputCmd(SPI1,DISABLE); _card_disable( ); _spi_send_recv( DUMMY_BYTE ); return count ? false : true; }
/* wait until the card is not busy */ static rt_uint8_t _spi_sd_wait4ready( void ) { rt_uint8_t res; rt_uint32_t timeout = 400000; do { res = _spi_send_recv( DUMMY_BYTE ); } while( ( res != DUMMY_BYTE ) && timeout-- ); return ( res == 0xFF ? true : false ); }
/***************************************************************************** Send a Command to Flash card and get a Response cmd: cmd index arg: argument for the cmd return the received response of the commond *****************************************************************************/ static rt_uint8_t _spi_sd_sendcmd( rt_uint8_t cmd, rt_uint32_t arg, rt_uint8_t crc ) { rt_uint32_t n; rt_uint8_t r1; #if 1 if( cmd & 0x80 ) /* ACMD<n> is the command sequence of CMD55-CMD<n> */ { cmd &= 0x7F; r1 = _spi_sd_sendcmd( APP_CMD, 0, DUMMY_CRC ); /* CMD55 */ if( r1 > 1 ) { return r1; /* cmd send failed */ } } #endif /* Select the card and wait for ready */ // LPC17xx_SPI_DeSelect(); // LPC17xx_SPI_Select(); // if (_spi_sd_wait4ready() == false ) return 0xFF; _spi_send_recv( DUMMY_BYTE ); _card_enable( ); _spi_send_recv( cmd ); _spi_send_recv( arg >> 24 ); _spi_send_recv( arg >> 16 ); _spi_send_recv( arg >> 8 ); _spi_send_recv( arg ); _spi_send_recv( crc ); #if 0 n = 10; /* Wait for a valid response in timeout of 10 attempts */ do { r1 = _spi_send_recv( DUMMY_BYTE ); } while( ( r1 & 0x80 ) && --n ); #endif #if 1 for( n = 0; n < 200; n++ ) { r1 = _spi_send_recv( DUMMY_BYTE ); if( r1 != 0xFF ) { break; } } #endif _card_disable( ); _spi_send_recv( DUMMY_BYTE ); return r1; /* Return with the response value */ }
/*********************************************************** * Function: * Description: * Input: * Input: * Output: * Return: * Others: ***********************************************************/ static rt_uint8_t _spi_sd_readdatablock( rt_uint8_t *buff, rt_uint32_t cnt, rt_uint8_t release ) { rt_uint8_t r1; rt_uint16_t retry; _card_enable( ); for( retry = 0; retry < 2000; retry++ ) { r1 = _spi_send_recv( DUMMY_BYTE ); if( r1 == 0xFE ) { retry = 0; break; } } if( retry == 2000 ) { _card_disable( ); return false; } for( retry = 0; retry < cnt; retry++ ) { *( buff + retry ) = _spi_send_recv( DUMMY_BYTE ); } // 2bytes dummy CRC _spi_send_recv( DUMMY_BYTE ); _spi_send_recv( DUMMY_BYTE ); // chip disable and dummy byte if( release ) { _card_disable( ); _spi_send_recv( DUMMY_BYTE ); } return true; }
/***************************************************************************** Read "count" Sector(s) starting from sector index "sector", buff <- [sector, sector+1, ... sector+count-1] if success, return true, otherwise return false *****************************************************************************/ static rt_uint8_t _spi_sd_readsector( rt_uint32_t sector, rt_uint8_t * buff, rt_uint32_t count ) { /* Convert to byte address if needed */ if( !( CardType & CT_BLOCK ) ) { sector *= SD_SECTOR_SIZE; } if( count == 1 ) /* Single block read */ { if( _spi_sd_sendcmd_hold( READ_BLOCK, sector, DUMMY_CRC ) != 0x0 ) { return false; } if( !_spi_sd_readdatablock( buff, SD_SECTOR_SIZE, RELEASE ) ) { return false; } //if (_spi_sd_sendcmd(STOP_TRAN, 0,DUMMY_CRC) != 0x0) return false; return true; } else /* Multiple block read */ { if( !_spi_sd_sendcmd( READ_MULT_BLOCK, sector, DUMMY_CRC ) ) { return false; } do { if( !_spi_sd_readdatablock( buff, SD_SECTOR_SIZE, HOLD ) ) { return false; } buff += SD_SECTOR_SIZE; } while( --count ); _spi_sd_sendcmd( STOP_TRAN, 0, DUMMY_CRC ); /* STOP_TRANSMISSION */ } //LPC17xx_SPI_Release(); //SPI_SSOutputCmd(SPI1,DISABLE); _card_disable( ); _spi_send_recv( DUMMY_BYTE ); return true; }
/***************************************************************************** Write 512 bytes buffer: 512 byte data block to be transmitted token: 0xFE -> single block 0xFC -> multi block 0xFD -> Stop *****************************************************************************/ static rt_uint8_t _spi_sd_writedatablock( const rt_uint8_t *buff, rt_uint8_t token ) { rt_uint8_t resp, i=0; i = i; // avoid warning _card_enable( ); _spi_send_recv( DUMMY_BYTE ); _spi_send_recv( DUMMY_BYTE ); _spi_send_recv( DUMMY_BYTE ); _spi_send_recv( token ); /* send data token first*/ if( token != TOKEN_STOP_TRAN ) { for( i = 512 / 4; i; i-- ) { _spi_send_recv( *buff++ ); _spi_send_recv( *buff++ ); _spi_send_recv( *buff++ ); _spi_send_recv( *buff++ ); } _spi_send_recv( DUMMY_CRC ); /* 16-bit CRC (Dummy) */ _spi_send_recv( DUMMY_CRC ); resp = _spi_send_recv( DUMMY_BYTE ); /* Receive data response */ if( ( resp & 0x1F ) != 0x05 ) /* If not accepted, return with error */ { return false; } if( _spi_sd_wait4ready( ) == false ) /* Wait while Flash Card is busy. */ { return false; } } return true; }