📄 sd_drv.c
字号:
/******************************************************************************
(c) COPYRIGHT 2002- by Shenzhen Allywll Information Co.,Ltd
All rights reserved.
File: spi_drv.c
Desc: Common interface for SPI SD card.
Modification history(no, author, date, desc)
1. luke 2006-03-31 create file
2 .william 2006-10-15 modify
3 william 2006-10-29
暂时没有完善CRC功能,初始化时调用CMD59可以,但读写
CSD(CMD9)时没有正确应答,并且读 写块时的硬件CRC与软件
预先计算的值不一致。
*****************************************************************************/
#include "syscfg.h"
#if( AOS_INCLUDE_DRIVER_SPI == TRUE )
#ifdef __cplusplus
extern "C" {
#endif
#include "aos.h"
#include "os/ker/ssp_cputick.h"
#include "spi_drv.h"
#include "sdcard.h"
#include "drv/bsp_pub.h"
#include "drv/sdcard_pub.h"
#include "drv/flash_pub.h"
#define SINGLE_WRITE // 是单块写,还是多块写
//#define CRC_ON //是否CRC 校验
//extern U16 aos_CalCRC ( U8 *ptr, U32 count ); //16 bit CRC
//计算SD容量要用
SD_CSD_T g_stCSD;
SD_CID_T g_stCID;
BOOL_T sdcard_pos=FALSE;
U32 g_SDVolume=0; //sh 命令用
U32 g_readBlock_usec; //sh 命令用
// SD擦写缓冲区,多块写要用到
BOOL_T g_bFirstFlag =FALSE;
BOOL_T g_bLastFlag =FALSE;
U8 g_szBuf0[BLOCK_SIZE];
U8 g_szBuf1[BLOCK_SIZE];
//CMD test
static U8 szTestBuf[5120];
static U8 szTestBuf1[512];
// After this command, CRC values are ignore unless explicitly enabled using CMD59
U8 CMD0_GO_IDLE_STATE[] = {0x00,0x00,0x00,0x00,0x00,0x95};
// Wait for SD Card to initialize
U8 CMD1_SEND_OP_COND[] = {0x01,0x00,0x00,0x00,0x00,0xFF};
// Send CMD55, required to precede all "application specific" commands
U8 CMD55_APP_CMD[] = {55,0x00,0x00,0x00,0x00,0xFF};
U8 ACMD41_SD_SEND_OP_COND[] = {41,0x00,0x00,0x00,0x00,0xFF};
#ifdef CRC_ON
U8 CMD1_SEND_OP_COND[] = {0x01,0x00,0x00,0x00,0x00,0xF9};
U8 CMD9_READ_CSD[] = { 9,0x00,0x00,0x00,0x00,0xAF};
U8 CMD10_READ_CID[] = {10,0x00,0x00,0x00,0x00,0xFF};
U8 CMD55_APP_CMD[] = {55,0x00,0x00,0x00,0x00,0x65};
U8 ACMD41_SD_SEND_OP_COND[] = {41,0x00,0x00,0x00,0x00,0xE5};
#endif
U8 CMD9_READ_CSD[] = { 9,0x00,0x00,0x00,0x00,0xFF};
U8 CMD10_READ_CID[] = {10,0x00,0x00,0x00,0x00,0xFF};
U8 CMD17_READ_SINGLE_BLOCK[] = {17,0x00,0x00,0x00,0x00,0xFF};
U8 CMD18_READ_MULTI_BLOCK[] = {18,0x00,0x00,0x00,0x00,0xFF};
U8 CMD24_WRITE_SINGLE_BLOCK[] = {24,0x00,0x00,0x00,0x00,0xFF};
U8 CMD25_WRITE_MULTI_BLOCK[] = {25,0x00,0x00,0x00,0x00,0xFF};
U8 CMD13_SEND_STATUS_BLOCK[] ={13,0x00,0x00,0x00,0x00,0xFF};
U8 CMD32_ERASE_START_BLOCK[] = {32,0x00,0x00,0x00,0x00,0xFF};
U8 CMD33_ERASE_END_BLOCK[] = {33,0x00,0x00,0x00,0x00,0xFF};
U8 CMD38_ERASE_BLOCK[] = {38,0x00,0x00,0x00,0x00,0xFF};
U8 CMD59_CRC_0N[] = {59,0x00,0x00,0x00,0x01,0x83};
U8 CMD59_CRC_0FF[] = {59,0x00,0x00,0x00,0x00,0xFF};
#define SD_CHECK_BUSY(loop) { U32 cnt; \
U8 resp; \
for(cnt=0; cnt< loop; cnt++) \
{ \
resp = spi_read(); \
if( resp != 0 ) \
{ \
break; \
} \
} \
}
/******************************************************************************
函数: sd_crc7
描述:
8位CRC ,多项式为x^7+x^3+1
输入:
U8 *chr 指向要校验的数据
U32 cnt 数据字节数
输出:
返回: 8位CRC 值( 7 位或一个置1 位)
******************************************************************************/
U8 sd_crc7(U8 * chr, U32 cnt)
{
U8 crc_7,Data;
U32 i,a;
crc_7=0;
for ( a=0; a<cnt; a++)
{
Data=chr[a];
for (i=0;i<8;i++)
{
crc_7 <<= 1;
if ((Data & 0x80)^(crc_7 & 0x80))
crc_7 ^=0x09;
Data <<= 1;
}
}
crc_7=(crc_7<<1)|1;
return(crc_7);
}
/******************************************************************************
函数: hw_delay
描述:
硬件延时 要使用volatile
输入:
U32 value ,延时的值
输出:
返回: void
******************************************************************************/
VOID hw_delay(U32 value)
{
volatile U32 i;
for (i=0;i<value;i++);
}
//R1 is a byte long
//bit 0 in idle state
//bit 1 erase reset
//bit 2 illegal command
//bit 3 com CRC error
//bit 4 Erase_Seq_Error
//bit 5 Address Error
//bit 6 Parameter Error
//bit 7 always 0
/******************************************************************************
函数: sd_wait_for_r1
描述:
每次发送命令后有一个R1 应答
输入: void
输出:
返回: 应答
******************************************************************************/
U8 sd_wait_for_r1(void)
{
U32 i;
U8 response;
U8 status;
// Wait for the response
for( i=0;i <250; i++ )
{
response = spi_read();
if( response != 0xFF )
{
break;
}
}
//add eight clock ,complete
status=0xFF;
spi_write(&status,1);
return response;
}
/******************************************************************************
函数: sd_write_cmd_r2
描述:
R2 is 2 bytes long response sent by the card as a response to the SEND_STATUS command
输入:
U8 *cmd 指向命令的指针 ( 一般为数组)
输出:
返回: U16 的应答
******************************************************************************/
U16 sd_write_cmd_r2(U8* cmd)
{
U8 status;
U8 r_hi=0xFF,r_lo=0xFF;
U16 response=0xFFFF;
U32 i;
// SD Card Command Format 48Bit
// (from Section 5.2.1 of SanDisk SD Card Product Manual v1.9).
// Frame 7 = 0
// Frame 6 = 1
// Command (6 bits)
// Address (32 bits)
// Frame 0 = 1
// Set the framing bits correctly (never change)
cmd[0] |= (1<<6);
cmd[0] &= ~(1<<7);
cmd[5] |= (1<<0);
#ifdef CRC_ON
cmd[5] =sd_crc7(cmd,5);
#endif
// Send the 6 byte command
for(i=0;i<6;i++)
spi_write(&cmd[i],1);
// Wait for the response
for( i=0;i <500; i++ )
{
r_hi = spi_read();
r_lo = spi_read();
response = (r_hi<<8) +r_lo;
if( response != 0xFFFF )
{
break;
}
}
// Following any command, the SD Card needs 8 clocks to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
status=0xFF;
spi_write(&status,1);
return(response);
}
/******************************************************************************
函数: sd_write_command
描述:
向SD卡写一个命令字
输入:
U8 *cmd 指向命令的指针 ( 一般为数组)
输出:
返回: U8的应答
******************************************************************************/
U8 sd_write_command(U8* cmd)
{
U8 response=0xFF;
U8 status;
U32 i;
// SD Card Command Format 48Bit
// (from Section 5.2.1 of SanDisk SD Card Product Manual v1.9).
// Frame 7 = 0
// Frame 6 = 1
// Command (6 bits)
// Address (32 bits)
// Frame 0 = 1
// Set the framing bits correctly (never change)
cmd[0] |= (1<<6);
cmd[0] &= ~(1<<7);
cmd[5] |= (1<<0);
#ifdef CRC_ON
cmd[5] = sd_crc7(cmd,5);
#endif
// Send the 6 byte command
for(i=0;i<6;i++)
spi_write(&cmd[i],1);
// Wait for the response
i=0;
do
{
response = spi_read();
i++;
if (i==500)
break;
}
while(response == 0xFF );
// Following any command, the SD Card needs 8 clocks to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
status=0xFF;
spi_write(&status,1);
return(response);
}
/******************************************************************************
函数: spi_sdcard_init
描述:
SD卡的SPI 模式初始化
输入:
输出:
返回:
成功返回AOS_SUCC,失败返回其它值(1,2,3,4)
******************************************************************************/
U32 spi_sdcard_init()
{
U8 status;
U32 i;
spi_enable_cs();
// Wait for the SD Card to go into IDLE state
i = 0;
do
{
status = sd_write_command(CMD0_GO_IDLE_STATE);
if(i++ > 1000)
{
AOS_ASSERT(0);
return 1;
}
} while( status != R1_IN_IDLE_STATE );
// aos_printf(MPE_DRV,"cmd0 response is %d,time is %d",status,i);
i = 0;
do
{
status = sd_write_command(CMD1_SEND_OP_COND);
if(i++ > 8000 ) //适应不同卡
{
AOS_ASSERT(0);
return 2;
}
} while( status != 0 );
// aos_printf(MPE_DRV,"cmd1 response is %d,time is %d,cmd[5] is 0x%x",status,i,CMD1_SEND_OP_COND[5]);
hw_delay(500);
status = sd_write_command(CMD55_APP_CMD);
//aos_printf(MPE_SYS,"cmd55 response is %d,cmd[5] is 0x%x",status, CMD55_APP_CMD[5] );
// ACMD41的工作频率按标准应该100Khz<f<400KHz 使用前需调用CMD55_APP_CMD
hw_delay(500);
// aos_printf(MPE_SYS,"ACMD41 cmd[5] is 0x%x",ACMD41_SD_SEND_OP_COND[5]);
i = 0;
do
{
status = sd_write_command(ACMD41_SD_SEND_OP_COND);
if(i++ > 500 )
{
AOS_ASSERT(0);
return 4;
}
} while( status != 0 );
// Might return 0x04 for Invalid Command if MMC card is connected
//aos_printf(MPE_DRV,"ACMD41 response is %d,time is %d",status,i);
#ifdef CRC_ON
status = sd_write_command(CMD59_CRC_0N);
if (status!=0)
{
AOS_ASSERT(0);
}
#endif
spi_disable_cs();
return AOS_SUCC;
}
/******************************************************************************
函数: sd_card_init
描述:
SD卡的初始化,检查是否存在,读CSD ,CID,
输入:
输出:
返回:
成功返回AOS_SUCC,失败返回AOS_FAIL或重启动
******************************************************************************/
U32 sd_card_init()
{
U8 ucBuf[32];
U32 result;
spi_init();
if( !is_sd_card_in() )
{
aos_printf(MPE_SYS," SD-Card is no exist!");
return AOS_FAIL;
}
// Wait for power to really come up
spi_enable_cs();
// We need to give SD Card about a hundred clock cycles to boot up
aos_memset(ucBuf,0xFF,16);
// write dummy data to pump clock signal line
spi_write(ucBuf,16);
spi_disable_cs();
aos_printf(MPE_SYS, "SD-Card: %s %s",
(is_sd_card_in()?"OnBoard":"NoExist"),
(is_sd_card_protect()?"Protected":"unProtected"));
aos_task_delay(50);
result= spi_sdcard_init();
if( result == AOS_SUCC )
{
sd_read_cid_config();
sd_read_csd_config();
sd_get_card_volume();
sdcard_pos = TRUE;
}
spi_fast_clock();
return result;
}
/*
device size 12bit R[73:62]
size multiper 2bit R[49:47]
erase sector size 7bit R[45:39]
memory capacity = BLOCKNR * BLOCK_LEN
Where:
BLOCKNR = (C_SIZE+1) * MULT
MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
BLOCK_LEN = 2^READ_BL_LEN (READ_BL_LEN < 12)
Therefore, the maximum capacity which can be coded is 4096*512*2048 = 4 GBytes.
Example: A four MByte card with BLOCK_LEN = 512 can be coded with
C_SIZE_MULT = 0 and C_SIZE = 2047.
*/
/******************************************************************************
函数: sd_get_card_volume
描述:
计算SD卡的容量
输入:
输出:
返回: SD卡的容量
******************************************************************************/
U32 sd_get_card_volume()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -