|
发表于 2012-5-14 21:26:04
|
显示全部楼层
给你一个我正在用的程序,是在LM3S9B95上面用的,调用的是硬件SPI,所以你需要换用你自己的SPI函数,我实际使用,读扇区,写扇区,以及连续读扇区都没有问题,注释的话,有些地方可能还不是很准确,因为也是才写的,还没有完善到家
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
UCHAR DISK_TYPE=0;
// 选择SD卡, SFLASH_CS_PIN置高,SDCARD_CS_PIN置低
static void SD_CS_ON (void)
{
GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN);
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, 0);
}
// 禁用SD卡,SDCARD_CS_PIN置高
static void SD_CS_OFF (void)
{
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN);
}
// 设置SPI运行速度
static void set_spi_speed(UINT speed)
{
unsigned long i;
SSIDisable(SDC_SSI_BASE);
if(speed > (SysCtlClockGet()/2000) ) i = SysCtlClockGet() / 2;
else i = speed;
if(i > 12500)
{ i = 12500; }
i=i*1000;
SSIConfigSetExpClk(SDC_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, i, 8);
SSIEnable(SDC_SSI_BASE);
}
//-----------------------------------------------------------------------
// 通过SPI向MMC发送一个字节数据
//-----------------------------------------------------------------------
static void spi_write_byte(BYTE dat)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, dat); /* 写一个字节到SPI的发送缓存 tx fifo */
SSIDataGet(SDC_SSI_BASE, &rcvdat); /* 写的同时,读取flush data */
}
//-----------------------------------------------------------------------
// 通过SPI接受来自MMC的一个字节数据
//-----------------------------------------------------------------------
static BYTE spi_read_byte (void)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, 0xFF); /* 写虚假数据 */
SSIDataGet(SDC_SSI_BASE, &rcvdat); /* 从SPI接受缓存中读取数据 rx fifo */
return (BYTE)rcvdat;
}
//等待disk准备就绪,超过50次则等待超时
static BYTE spi_wait_ready (void)
{
BYTE res;
UINT Timer = 20000;
do
res = spi_read_byte();
while ((res != 0xFF) && Timer--);
return res;
}
//-----------------------------------------------------------------------
// 发送80个时钟,CS和DI保持高电平
// SD卡上电后,转入SPI模式的时序要求
//-----------------------------------------------------------------------
static void write_initial_80_clock (void)
{
unsigned int i;
DWORD dat;
SD_CS_OFF();
//切换SPI_TX端口为普通GPIO,且输出高电平
GPIOPinTypeGPIOOutput(SDC_GPIO_PORT_BASE, SDC_SSI_TX);
GPIOPinWrite(SDC_GPIO_PORT_BASE, SDC_SSI_TX, SDC_SSI_TX);
//输出10字节0xff,使clock端口输出80个时钟信号
for(i = 0 ; i < 20 ; i++)
{
SSIDataPut(SDC_SSI_BASE, 0xFF); //传输虚拟数据
SSIDataGet(SDC_SSI_BASE, &dat); //结收虚拟数据
}
//切换SPI_TX端口为SPI模式
GPIOPinTypeSSI(SDC_GPIO_PORT_BASE, SDC_SSI_TX);
}
//---------------------------------------------------
// 函数名:spi_write_cmd
// 功 能:发送卡命令
// 参 数:uint8 Cmd: SD指令
// 参 数:uint32 arg
// 返回值:uint8
//---------------------------------------------------
UINT8 spi_write_cmd(UINT8 Cmd, UINT32 arg, UINT8 CRC)
{
UINT8 r1;
UINT8 retry=0;
if (spi_wait_ready() != 0xFF) return 0xFF;
spi_write_byte(Cmd); //写入命令
spi_write_byte(arg>>24); //写入命令参数,有些命令没有参数,写00
spi_write_byte(arg>>16);
spi_write_byte(arg>>8);
spi_write_byte(arg);
spi_write_byte(CRC); //写入有效的 CRC值
retry = 10;
do
r1 = spi_read_byte();
while ((r1 & 0x80) && --retry); //等待响应, 超时退出
return r1; //返回状态值
}
//-----------------------------------------------------------------------
// 函数名:disk_read_sectors
// 功 能:读扇区
// 参 数:UINT32 start_sector 起始扇区地址
// 参 数:BYTE sector_number 连续读出的扇区数,有效值1-255
// 参 数:BYTE *buff读出数据缓存区
// 返回值:TRUE/FALSE
//-----------------------------------------------------------------------
BYTE disk_read_sectors ( UINT32 sector, BYTE sector_number, BYTE *buff )
{
UINT8 r1;
UINT16 i;
SD_CS_ON (); //开片选
if(sector_number==1)
{
r1 = spi_write_cmd(CMD17, sector<<9, 0xff); // 发读扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return (0); // 如果写命令返回值无效,则返回失败
while(spi_read_byte() != 0xFE); // 等待数据的起始令牌号
for(i=0; i<512; i++) // 读512个数据
{
*buff = spi_read_byte();
buff++;
}
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
}
else if(sector_number>1)
{
r1 = spi_write_cmd(CMD18, sector<<9, 0xff); // 发读扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return (0); // 如果写命令返回值无效,则返回失败
do
{
while(spi_read_byte() != 0xFE); // 等待数据的起始令牌号
for(i=0; i<512; i++) // 读512个数据
{
*buff = spi_read_byte();
buff++;
}
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
} while(--sector_number);
spi_write_cmd(CMD12, 0, 0xff); // 发读扇区命令,读取有效返回值(0x00)
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
}
SD_CS_OFF(); // 关闭SD Card
return (1);
}
//-----------------------------------------------------------------------
// 函数名:disk_write_sectors
// 功 能:写扇区
// 参 数:UINT32 start_sector 起始扇区地址
// 参 数:BYTE sector_number 连续写入的扇区数,有效值1-255
// 参 数:BYTE *buff等待写入的数据
// 返回值:TRUE/FALSE
//-----------------------------------------------------------------------
#if READONLY == 0
BYTE disk_write_sectors ( UINT32 sector, BYTE sector_number, BYTE *buff )
{
UINT8 r1=0;
UINT16 i=0;
SD_CS_ON (); //开片选
r1 = spi_write_cmd(CMD24, sector<<9, 0xff); // 发写扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return 0x00; // 如果写命令返回值无效,则返回失败
if(spi_wait_ready() != 0xFF) return 0x00;
spi_write_byte(0xFE); // 发送数据起始令牌号
for(i=0; i<512; i++) // 以扇区为单位写入数据
{
spi_write_byte(*buff);
buff++;
}
spi_write_byte(0xFF); // 发送两字节伪CRC
spi_write_byte(0xFF);
r1 = spi_read_byte(); // 读数据应答令牌号(有效令牌xxx00101B)
if( (r1&0x1F) != 0x05) // 判断令牌是否正确
{
SD_CS_OFF(); // 如果令牌错误,关闭SD Card
return 0x00; // 如果令牌错误,返回失败
}
while(spi_read_byte()==0); //--等待操作完成--
SD_CS_OFF(); // 关闭SD Card
return 0x01;
}
#endif
// SPI初始化
void spi_Interface_Init(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); // 使能SSI模块
SysCtlPeripheralEnable(SDC_SSI_SYSCTL_PERIPH); // 使能SSI0接口所在的GPIO端口
SysCtlPeripheralEnable(SDC_GPIO_SYSCTL_PERIPH);
SysCtlPeripheralEnable(SDCARD_CS_PERIPH);
SysCtlPeripheralEnable(SFLASH_CS_PERIPH);
GPIOPinTypeSSI(SDC_GPIO_PORT_BASE, SDC_SSI_TX | SDC_SSI_RX | SDC_SSI_CLK); //定义SPI端口
GPIOPinTypeGPIOOutput(SDCARD_CS_BASE, SDCARD_CS_PIN); //设置SDCARD_CS_PIN
GPIOPinTypeGPIOOutput(SFLASH_CS_BASE, SFLASH_CS_PIN); //设置SFLASH_CS_PIN
GPIOPadConfigSet(SDC_GPIO_PORT_BASE, SDC_SSI_PINS | SDC_SSI_TX | SDC_SSI_RX | SDC_SSI_CLK,
GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(SDCARD_CS_BASE, SDCARD_CS_PIN, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(SFLASH_CS_BASE, SFLASH_CS_PIN, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN); //SDCARD_CS_PIN 置1
GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN); //SFLASH_CS_PIN 置1
// SSI配置:基址,协议格式,主/从模式,位速率,数据宽度
SSIConfigSetExpClk(SDC_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 100000, 8);
SSIEnable(SSI0_BASE); // 使能SSI收发
}
//---------------------------------------------------
// 函数名:MMC_SD_Init
// 功 能:sd卡初始化
// 参 数:无
// 返回值:uint8 type // 卡类型返回值: 0x10 SD, 0x20 MMC
//---------------------------------------------------
BYTE SD_Init(void)
{
UINT8 retry;
UINT8 r1=0;
spi_Interface_Init();
set_spi_speed(100); //低速 SPI=100k
retry = 0;
do
{
write_initial_80_clock(); // 发送80个时钟,使卡同步
SD_CS_ON(); // 使能Card
r1 = spi_write_cmd(CMD0, 0, 0x95); // 发Cmd0(复位)命令
retry++;
if(retry > 200) return (ERROR); //超时退出,个别卡需要更多次循环才有反应
} while(r1 != 0x01); // MMC、SD卡成功转到SPI模式
retry = 2;
while(retry--)spi_write_byte(0xFF);
do
{
r1 = spi_write_cmd(CMD55, 0, 0xff); // 先发送 Cmd55
if(r1 == 0x01) // 如果有反应
{
r1 = spi_write_cmd(CMD41,0, 0xff); // 再发送 Cmd41 进行激活
if(r1 == 0x00) DISK_TYPE = SD_CARD; // 激活成功就是SD卡
}
else { // 如果发送 Cmd55无反应,改发送 Cmd1
r1 = spi_write_cmd(CMD1,0, 0xff);
if(r1 == 0x00) DISK_TYPE = MMC_CARD; // 激活成功就是MMC卡
}
retry++;
if(retry > 255) return (TIME_OUT); // 超时退出, 个别卡需要更多次循环才有反应
} while(r1 != 0x00); // MMC、SD卡激活后的返回值均为0x00
r1 = spi_write_cmd(CMD16, 512, 0xff); //设置读取一次的字节数
if(r1!=0x00)return (TIME_OUT);
SD_CS_OFF(); // 关闭Card
spi_write_byte(0xFF); // 高速SPI前先发送8个时钟
if(DISK_TYPE!=0) set_spi_speed(12500); // 初始化成功,切换到高速 SPI 12.5M
return SUCCESS; //参数返回,1为初始化错误,10为SD卡,20为MMC卡
}
|
|